libcxx: support typeids across DLL boundary

Yaron Keren yaron.keren at gmail.com
Fri Nov 22 15:08:11 PST 2013


MSVC is confused by the same-named source file!
If the code is split into  t1.cpp:

#include <typeinfo>
namespace { struct Foo { int a; }; }
const std::type_info &tu1() { return typeid(Foo); }

and t2.cpp:

#include <typeinfo>
namespace { struct Foo { float b; }; }
const std::type_info &tu1();
const std::type_info &tu2() { return typeid(Foo); }
extern "C" void printf(const char *, ...);
int main() {
  printf("tu1() == tu2(): %d\n", tu1() == tu2());
}

then (with MSVC 2012) :

sh-3.1$ cl -c t1.cpp && cl -c t2.cpp  && cl t1.obj t2.obj && ./t1.exe
tu1() == tu2(): 0

sh-3.1$ cl t1.cpp t2.cpp && ./t1.exe
tu1() == tu2(): 0

(I tested both forms to see it's not related to everything compiled at once)

However, your point IS valid, since when the actual names are printed
(names which will be used in the strcmp):

  printf("tu1().name: %s\n", tu1().name());
  printf("tu2().name: %s\n", tu2().name());

with MSVC we get

tu1() == tu2(): 0
tu1().name: struct `anonymous namespace'::Foo
tu2().name: struct `anonymous namespace'::Foo

and with gcc:

tu1() == tu2(): 0
tu1().name: *N12_GLOBAL__N_13FooE
tu2().name: *N12_GLOBAL__N_13FooE

So when comparing type ids only, we'll miss exceptions from DLLs, while if
we compare type names as well we may catch a same-named class coming from
the same namespace even it's actually something different.

Given only these two options (maybe there is a better solution?), I'd still
go with the first, since many C++ DLL libraries throw exceptions which
*must* be caught, else the library is not usable. This is a showstopper.

OTOH, same-named classes - in the same namespace - in different TU are
probably uncommon and throwing them around where they might be confused is
probably even less common.

Yaron



2013/11/23 Reid Kleckner <rnk at google.com>

> One other thing to think about is: are typeid names of internal types
> unique?  MSVC seems to get it wrong, as in this prints 1:
>
> $ cat t.cpp
> #include <typeinfo>
> #ifdef CONFIG_1
> namespace { struct Foo { int a; }; }
> const std::type_info &tu1() { return typeid(Foo); }
> #else
> namespace { struct Foo { float b; }; }
> const std::type_info &tu1();
> const std::type_info &tu2() { return typeid(Foo); }
> extern "C" void printf(const char *, ...);
> int main() {
>   printf("tu1() == tu2(): %d\n", tu1() == tu2());
> }
> #endif
>
> $ cl -c t.cpp && cl -c -DCONFIG_1 t.cpp -Fot2.obj && cl t.obj t2.obj &&
> ./t.exe
> ...
> tu1() == tu2(): 1
>


On Fri, Nov 22, 2013 at 1:48 PM, Yaron Keren <yaron.keren at gmail.com> wrote:

> OK, fixed.
>
>
>
> 2013/11/22 Reid Kleckner <rnk at google.com>
>
>> Yes, this is just a property of COFF, so it should be _WIN32.
>
>
>
> On Fri, Nov 22, 2013 at 5:18 AM, Yaron Keren <yaron.keren at gmail.com>wrote:
>
>> On Windows, typeids are different between DLLs and EXEs, so comparing
>> type_info* will work for typeids from the same compiled file but fail for
>> typeids from a DLL and an executable. Among other things, exceptions are
>> not caught by handlers since can_catch() returns false.
>>
>> Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls
>> is_equal() with use_strcmp=false so the string names are not compared.
>>
>> This patch compares typeids first (cheap) and only they are different
>> calls strcmp.
>>
>> If libcxxabi with Visual C++ has the same problem, __MINGW32__ should be
>> replaced with _WIN32 in both locations.
>>
>> Yaron
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131123/1e8b9997/attachment.html>


More information about the cfe-commits mailing list