This is the mail archive of the cygwin@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Workaround for virtual function/dllimport bug, also patch guidance request


Mumit Khan <khan@nanotech.wisc.edu> writes: 
> There are a few nasty bugs when you have virtual functions and also
> inline functions in DLL imported classes. It's going to take quite
> a few tweaks in the C++ front end to fix these, and unfortunately
> I don't have the time right now. Hopefully someone else will jump
> in fix these ... the vtable issue is particular harder to fix since
> the GNU C++ vtables use offsets, which don't work for dllimported
> functions.

I finally gritted my teeth and dove into the source last night.

My understanding of the problem is that dllimported functions
currently can't appear in vtables, so when you derive a child class
from a parent class exported from a DLL and don't override all of the
virtual members, you get the aforementioned error.  Normally when you
take the address of a dllimported function in global scope, ie

void func(void) __declspec(dllimport);
void (*some_pointer)(void) = func;

GCC works around the problem of func not having an address knowable at
compiletime by generating an initialization function that's called
automatically at startup that sets func to the correct value.  But
vtables are handled separately and GCC aborts instead of knowing to
add the vtable to the runtime-init list.  As far as I can tell the
offset data, whether in the vtable or a thunk function, isn't part of
the problem -- it can be computed at compile-time from the header
files, right?

A workaround exists.  Keep in mind that if a function isn't declared
dllimport but is in fact imported from a DLL, the springboard function
in the import library gets used (at a slight performance penalty.)
Since you *can* take the address of the springboard function at
compile time, it can go in the vtable, so if you simply *don't declare
virtual functions as dllimport* but just make sure they're exported
correctly when the import library is made, everything will be fine
(except for the small performance hit.)

However, you still must declare any static class data as dllimport.
So instead of tagging the whole class __declspec(dllimport), you have
to individually tag just the static data members, and optionally
non-virtual functions for performace.  I've tested this in a toy case
and it seems to work as reasoned.

Since I don't want to go through the whole library retagging all of
the classes, and since I want to keep MSVC compatibility, and since
this case should really be handled correctly, I've been thinking about
the best way to patch this.  I know very little about GCC so any
suggestions are appreciated.  Should I:

-- add code to finish_file or thereabouts to catch the case where a
vtable would contain addresses not known at compiletime and tack stuff
on to the static storage duration function (the ___static_initialization_
and_destruction thingy) to init the vtable at runtime?  this is the
"right way" in the sense that the springboard function isn't used, so
it's most efficient at the expense of a few extra bytes of init
function..

-- hack the dllimport attribute so that when it's applied to a class,
it filters down only to members that are static data or non-virtual
functions, and is automatically turned off for virtual functions (even
if you try to do it manually, I guess)?  this has the advantage of not
touching the front end, just config/i386/winnt.c (or that's my initial
impression)..

-- something else?

thanks,

Geoff Schmidt
gschmidt@mit.edu

--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]