www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - determining if a void* points to a valid Object

reply =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
Hello all,

I'm making a transition of a code base from C to D. I wish to alleviate 
the transition by making it gradual, but that requires being able to 
distinguish D Objects from the existing C structs, given a pointer.

Could you help me with this please?

1. You have a "void *ptr".
2. You have a struct NotDObject whose declaration you can control. (e.g. 
add fields and require that they possess certain values)

How do you determine with fairly good reliability if ptr points to an 
Object or to a NotDObject struct?

You are allowed to assume that DMD/GDC is used, and even a specific 
version of that compiler. I don't care much if it is a kludge (it's a 
temporary solution), but extra points if you can make it implementation 
independent.

Thanks a lot,
Luís Marques
Aug 17 2006
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Luís Marques wrote:
 Hello all,
 
 I'm making a transition of a code base from C to D. I wish to alleviate 
 the transition by making it gradual, but that requires being able to 
 distinguish D Objects from the existing C structs, given a pointer.
 
 Could you help me with this please?
 
 1. You have a "void *ptr".
 2. You have a struct NotDObject whose declaration you can control. (e.g. 
 add fields and require that they possess certain values)
 
 How do you determine with fairly good reliability if ptr points to an 
 Object or to a NotDObject struct?

It would be a horrible hack, but you might be able to test whether the location reserved for the vtbl ptr points to a location where vtbls are known to reside. The ABI might be of help here: http://www.digitalmars.com/d/abi.html You will have to ask Walter or do some sleuthing to sort out how to determine this address range, however. Sean
Aug 17 2006
parent =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
Sean Kelly wrote:
 It would be a horrible hack, but you might be able to test whether the 
 location reserved for the vtbl ptr points to a location where vtbls are 
 known to reside.  The ABI might be of help here: 
 http://www.digitalmars.com/d/abi.html  You will have to ask Walter or do 
 some sleuthing to sort out how to determine this address range, however.

http://www.digitalmars.com/d/abi.html tells us: An object consists of: offset contents 0 pointer to vtable 4 monitor 8... non-static members So if the NotDObject struct was defined as { void *isobject = null; ... } then we could look at isobject and if was not null it would be a D Object. Or can a D Object not have a vtable? That is, could the "pointer to vtable" be null? Even if that was the case I could add dummy virtual methods to my classes... Btw: I guess this ABI is 32 bit only :/ Thanks Sean! Luís
Aug 17 2006
prev sibling next sibling parent reply BCS <BCS pathlink.com> writes:
Luís Marques wrote:
 Hello all,
 
 I'm making a transition of a code base from C to D. I wish to alleviate 
 the transition by making it gradual, but that requires being able to 
 distinguish D Objects from the existing C structs, given a pointer.
 
 Could you help me with this please?
 
 1. You have a "void *ptr".
 2. You have a struct NotDObject whose declaration you can control. (e.g. 
 add fields and require that they possess certain values)
 
 How do you determine with fairly good reliability if ptr points to an 
 Object or to a NotDObject struct?
 
 You are allowed to assume that DMD/GDC is used, and even a specific 
 version of that compiler. I don't care much if it is a kludge (it's a 
 temporary solution), but extra points if you can make it implementation 
 independent.
 
 Thanks a lot,
 Luís Marques

void* ptr; // set ptr; if(null !is cast(Object)ptr) { // ptr is an object } This should work because type checking is done on object up cast. However it dosn't seem to work. Maybe this is a bug.
Aug 17 2006
parent reply =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
BCS wrote:
 void* ptr;
 // set ptr;
 if(null !is cast(Object)ptr)
 {
     // ptr is an object
 }
 
 This should work because type checking is done on object up cast.
 
 However it dosn't seem to work.

According to my experience, from void* to any type it always works. Only from Object to subclasses (or among other types, I guess) it actually does type checking. So if you want to force a cast to another incompatible classe you can do "cast(OtherClass)cast(void*)". Luís
Aug 17 2006
parent reply BCS <BCS pathlink.com> writes:
Luís Marques wrote:
 BCS wrote:
 
 void* ptr;
 // set ptr;
 if(null !is cast(Object)ptr)
 {
     // ptr is an object
 }

 This should work because type checking is done on object up cast.

 However it dosn't seem to work.

According to my experience, from void* to any type it always works. Only from Object to subclasses (or among other types, I guess) it actually does type checking. So if you want to force a cast to another incompatible classe you can do "cast(OtherClass)cast(void*)". Luís

casting works but the result is invalid. This OTOH cast(Derived)cast(Object)v; seg-v's on a struct. Should this be a bug?
Aug 17 2006
parent reply =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
BCS wrote:
 casting works but the result is invalid.
 
 This OTOH
 
 cast(Derived)cast(Object)v;
 
 seg-v's on a struct.
 
 Should this be a bug?

How are you doing that? if v is a struct than casting it to Object fails (it does here...). If you cast it to void* first than that would be your way of saying "I know what I'm doing", so I guess it wouldn't be a bug (not the case, right?).
Aug 17 2006
parent BCS <BCS pathlink.com> writes:
Luís Marques wrote:
 BCS wrote:
 
 casting works but the result is invalid.

 This OTOH

 cast(Derived)cast(Object)v;

 seg-v's on a struct.

 Should this be a bug?

How are you doing that? if v is a struct than casting it to Object fails (it does here...). If you cast it to void* first than that would be your way of saying "I know what I'm doing", so I guess it wouldn't be a bug (not the case, right?).

The bug is the Seg-v on the /second/ cast, IMHO trying to cast a pointer shoud never seg-v if the pointer points to valid data What the code is trying to say is: "Take this void* and pretend it is an Object. Now cast it to Derived with the dynamic_cast like checking." The problem (I assume) is that the way that the cast check is done assumes that the pointer is pointing to an Object. This might be because it is using something in the v-tbl to do the checking, for instance: <code> Object o; auto d = cast(Derived)o; // in effect: auto d = o.__CastToSomething(Derived.typeid); </code> this fails if o[0] isn't a valid v-tbl a more robust system would use something like: <code> auto d = cast(Derived)o; // in effect: auto d = Derived.__CastFromSomething(o); </code> where __CastFromSomething only requiters o to be a valid pointer. This could be done by having __CastFromSomething check if o[0] is a known v-tbl for Derived or one of it's descendants. This has the problem that making the table for __CastFromSomething can't be done at compile time because Derived won't known about all of it's descendants. Crud, now this is getting into ABI design...
Aug 19 2006
prev sibling parent reply nobody <nobody mailinator.com> writes:
Luís Marques wrote:
 Hello all,
 
 I'm making a transition of a code base from C to D. I wish to alleviate 
 the transition by making it gradual, but that requires being able to 
 distinguish D Objects from the existing C structs, given a pointer.
 
 Could you help me with this please?
 
 1. You have a "void *ptr".
 2. You have a struct NotDObject whose declaration you can control. (e.g. 
 add fields and require that they possess certain values)
 
 How do you determine with fairly good reliability if ptr points to an 
 Object or to a NotDObject struct?
 
 You are allowed to assume that DMD/GDC is used, and even a specific 
 version of that compiler. I don't care much if it is a kludge (it's a 
 temporary solution), but extra points if you can make it implementation 
 independent.
 
 Thanks a lot,
 Luís Marques

D Application Binary Interface http://digitalmars.com/d/class.html Classes An object consists of: offset contents 0 pointer to vtable 4 monitor 8... non-static members I think if I understand your question correctly then I believe what you can do if first assert( ptr !is null ). Now if I can define NotDObject and initialize the members I would do the following: struct NotDObject { int reserveredA = 0; int reserveredB = 0; // anything you want follows here } Now since we know ptr is not null then it it points to a NotDObject then dereferencing the pointer should give us a null value. Otherwise we now have a pointer to the vtable from the D ABI above. if((*(cast(void*)) is null ) // NotDObject else // Object
Aug 17 2006
parent reply =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
nobody wrote:
 I think if I understand your question correctly then I believe what you 
 can do if first assert( ptr !is null ). Now if I can define NotDObject 
 and initialize the members I would do the following:
 
 
   struct NotDObject
   {
     int reserveredA = 0;
     int reserveredB = 0;
     // anything you want follows here
   }
 
 Now since we know ptr is not null then it it points to a NotDObject then 
 dereferencing the pointer should give us a null value. Otherwise we now 
 have a pointer to the vtable from the D ABI above.
 
   if((*(cast(void*)) is null ) // NotDObject
   else                         // Object

Yes, that's exactly what I need (thanks). But 1) I guess reserveredB is unnecessary, no? 2) see my previous question: 'can a D Object not have a vtable? That is, could the "pointer to vtable" be null?' (what happens? it points to a 0 entry table?) Luís
Aug 17 2006
parent reply nobody <nobody mailinator.com> writes:
Luís Marques wrote:
 nobody wrote:
 I think if I understand your question correctly then I believe what 
 you can do if first assert( ptr !is null ). Now if I can define 
 NotDObject and initialize the members I would do the following:


   struct NotDObject
   {
     int reserveredA = 0;
     int reserveredB = 0;
     // anything you want follows here
   }

 Now since we know ptr is not null then it it points to a NotDObject 
 then dereferencing the pointer should give us a null value. Otherwise 
 we now have a pointer to the vtable from the D ABI above.

   if((*(cast(void*)) is null ) // NotDObject
   else                         // Object

Yes, that's exactly what I need (thanks). But 1) I guess reserveredB is unnecessary, no? 2) see my previous question: 'can a D Object not have a vtable? That is, could the "pointer to vtable" be null?' (what happens? it points to a 0 entry table?) Luís

Question 1) is easy... I meant to indicate that both A and B should be left intact. If you really want to remove one then use this instead: align(4) // guarantee reserved is actually first struct NotDObject { int reservered = 0; // anything you want follows here } Question 2) is a bit trickier. I am honestly not very clear on the specifics of how polymorphism is handled down at the level of the vtable. However I do know vtables are required for polymorphism and should be a real cause for surprise if you ever have an Object instance without a vtable given the D ABI docs. However I feel I should make clear that only a class instance will have a vtable. Structs are just raw aggregates of data and will never contain a vtable. Inheritance is not allowed for structs. Good luck!
Aug 17 2006
parent reply xs0 <xs0 xs0.com> writes:
 Question 2) is a bit trickier. I am honestly not very clear on the 
 specifics of how polymorphism is handled down at the level of the 
 vtable. However I do know vtables are required for polymorphism and 
 should be a real cause for surprise if you ever have an Object instance 
 without a vtable given the D ABI docs.

It can't happen - Object is the base class of all other classes and has several virtual methods itself, so any object is guaranteed to have a vtable (if only Object's). xs0
Aug 17 2006
parent =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> writes:
xs0 wrote:
 It can't happen - Object is the base class of all other classes and has 
 several virtual methods itself, so any object is guaranteed to have a 
 vtable (if only Object's).

Okay, thanks for the great info! Btw: should this have been asked in D.learn? When I posted I felt that this might be going a bit too low-level for D.learn, but I guess "nobody" is probably right. PS: I am not able to follow the newsgroups during most of the day anyway, since the web interface is down :( Luís
Aug 17 2006