views:

121

answers:

4

In my application I have quite some void-pointers (this is because of historical reasons, application was originally written in pure C). In one of my modules I know that the void-pointers points to instances of classes that could inherit from a known base class, but I cannot be 100% sure of it. Therefore, doing a dynamic_cast on the void-pointer might give problems. Possibly, the void-pointer even points to a plain-struct (so no vptr in the struct).

I would like to investigate the first 4 bytes of the memory the void-pointer is pointing to, to see if this is the address of the valid vtable. I know this is platform, maybe even compiler-version-specific, but it could help me in moving the application forward, and getting rid of all the void-pointers over a limited time period (let's say 3 years).

Is there a way to get a list of all vtables in the application, or a way to check whether a pointer points to a valid vtable, and whether that instance pointing to the vtable inherits from a known base class?

A: 

I would say it is not possible without related reference (header declaration).

YeenFei
A: 

If you want to replace those void pointers to correct interface type, here is what I think to automate it:

  1. Go through your codebase to get a list of all classes that has virtual functions, you could do this fast by writing script, like Perl

  2. Write an function which take a void* pointer as input, and iterate over those classes try to dynamic_cast it, and log information if succeeded, such as interface type, code line

  3. Call this function anywhere you used void* pointer, maybe you could wrap it with a macro so you could get file, line information easy

  4. Run a full automation (if you have) and analyse the output.

lz_prgmr
You cannot dynamic cast a void pointer.
anon
really? I even didn't notice that, so if I hold a pointer to void, what would I do if I know it does pointer to some interface and want to cast to it?
lz_prgmr
@Dbger Why would you have a void pointer in the first place? Of course you can (on-dynamically) cast the void pointer to a base pointer (or anything else) but that defeats the object of this particular exercise.
anon
@Neil Butterworth: I guess "on-dynamically" means "non-dynamically" :-)
Gorpik
+4  A: 

I would like to investigate the first 4 bytes of the memory the void-pointer is pointing to, to see if this is the address of the valid vtable.

You can do that, but you have no guarantees whatsoever it will work. Y don't even know if the void* will point to the vtable. Last time I looked into this (5+ years ago) I believe some compiler stored the vtable pointer before the address pointed to by the instance*.

I know this is platform, maybe even compiler-version-specific,

It may also be compiler-options speciffic, depending on what optimizations you use and so on.

but it could help me in moving the application forward, and getting rid of all the void-pointers over a limited time period (let's say 3 years).

Is this the only option you can see for moving the application forward? Have you considered others?

Is there a way to get a list of all vtables in the application,

No :(

or a way to check whether a pointer points to a valid vtable,

No standard way. What you can do is open some class pointers in your favorite debugger (or cast the memory to bytes and log it to a file) and compare it and see if it makes sense. Even so, you have no guarantees that any of your data (or other pointers in the application) will not look similar enough (when cast as bytes) to confuse whatever code you like.

and whether that instance pointing to the vtable inherits from a known base class?

No again.

Here are some questions (you may have considered them already). Answers to these may give you more options, or may give us other ideas to propose:

  • how large is the code base? Is it feasible to introduce global changes, or is functionality to spread-around for that?

  • do you treat all pointers uniformly (that is: are there common points in your source code where you could plug in and add your own metadata?)

  • what can you change in your sourcecode? (If you have access to your memory allocation subroutines or could plug in your own for example you may be able to plug in your own metadata).

  • If different data types are cast to void* in various parts of your code, how do you decide later what is in those pointers? Can you use the code that discriminates the void* to decide if they are classes or not?

  • Does your code-base allow for refactoring methodologies? (refactoring in small iterations, by plugging in alternate implementations for parts of your code, then removing the initial implementation and testing everything)

Edit (proposed solution):

Do the following steps:

  • define a metadata (base) class

  • replace your memory allocation routines with custom ones which just refer to the standard / old routines (and make sure your code still works with the custom routines).

  • on each allocation, allocate the requested size + sizeof(Metadata*) (and make sure your code still works).

  • replace the first sizeof(Metadata*) bytes of your allocation with a standard byte sequence that you can easily test for (I'm partial to 0xDEADBEEF :D). Then, return [allocated address] + sizeof(Metadata*) to the application. On deallocation, take the recieved pointer, decrement it by `sizeof(Metadata*), then call the system / previous routine to perform the deallocation. Now, you have an extra buffer allocated in your code, specifically for metadata on each allocation.

  • In the cases you're interested in having metadata for, create/obtain a metadata class pointer, then set it in the 0xDEADBEEF zone. When you need to check metadata, reinterpret_cast<Metadata*>([your void* here]), decrement it, then check if the pointer value is 0xDEADBEEF (no metadata) or something else.

Note that this code should only be there for refactoring - for production code it is slow, error prone and generally other bad things that you do not want your production code to be. I would make all this code dependent on some REFACTORING_SUPPORT_ENABLED macro that would never allow your Metadata class to see the light of a production release (except for testing builds maybe).

utnapistim
On all of your questions: yes, I can refactor and change a lot. But I was actually looking for tricks so parts of the software can still work with void-pointers (during the transition), or ways to find problems (in case some void-pointers were 'forgotten').
Patrick
See my edit above for a solution.
utnapistim
Great idea. Luckily I have even experience with custom allocation routines, so that should be quite easy to implement. Thanks.
Patrick
Sorry I had to edit this. SO seemed to have undone my +1 and refused me to add +1 again until it was edited. Therefore I just added an empty line at the end.
Patrick
I think this trick doesn't work if you want to allocate a vector of instances and address every element in it as a void-pointer, but this isn't a problem in my case.
Patrick
No, it wouldn't work for allocating multiple elements. It is not a complete solution, but it works for other cases.
utnapistim
A: 

The easier way would be to overload operator new for your particular base class. That way, if you know your void* pointers are to heap objects, then you can also with 100% certainty determine whether they're pointing to your object.

MSalters