libcxx: support typeids across DLL boundary

Yaron Keren yaron.keren at gmail.com
Sat Nov 23 02:49:20 PST 2013


In MSVC raw_name does return a unique name:

tu1().raw_name: .?AUFoo@?A0x08cd7644@@
tu2().raw_name: .?AUFoo@?A0x8e5904ea@@

In gcc these are the same.

libsupc++ code compares pointer to type, pointers to the name or the name
itself depending upon defines. It says:

// Determine whether typeinfo names for the same type are merged (in which
// case comparison can just compare pointers) or not (in which case strings
// must be compared), and whether comparison is to be implemented inline or
// not.  We used to do inline pointer comparison by default if weak symbols
// are available, but even with weak symbols sometimes names are not merged
// when objects are loaded with RTLD_LOCAL, so now we always use strcmp by
// default.  For ABI compatibility, we do the strcmp inline if weak symbols
// are available, and out-of-line if not.  Out-of-line pointer comparison
...
// Even with the new abi, on systems that support dlopen
// we can run into cases where type_info names aren't merged,
// so we still need to do string comparison.

The problem goes beyond anonymous namespace. Without them, the catch
handler will catch based on  name only, leading to interesting C-like bugs.

 x1.cpp:

#include <typeinfo>
struct Foo { int a; int b; Foo(int a_, int b_) : a(a_), b(b_) {} };
extern "C" void printf(const char *, ...);
const std::type_info &tu1() { return typeid(Foo); }
__declspec(dllexport) void x1() {
  printf("tu1().name: %s,%x\n", tu1().name(), (unsigned)tu1().name());
  throw Foo(12,34);
}

x2.cpp:

#include <typeinfo>
struct Foo { double x; };
extern void x1();
extern "C" void printf(const char *, ...);
const std::type_info &tu2() { return typeid(Foo); }
int main() {
  printf("tu2().name: %s,%x\n", tu2().name(), (unsigned)tu2().name());
  try { x1(); }
  catch (Foo F) { printf("Caught Foo x=%g\n", F.x); }
  return 0;
}

with either gcc 4.8.1 or Visual C++ 2012 gets bad result:

gcc -shared x1.cpp -o x1.dll -lstdc++ && gcc x2.cpp x1.dll -o x1.exe
-lstdc++ && ./x1
tu2().name: 3Foo,4088b8
tu1().name: 3Foo,69404188
Caught Foo x=7.21479e-313

cl -EHsc  -LD x1.cpp -Fex1.dll && cl -EHsc x2.cpp x1.lib && x2
tu2().name: struct Foo,5be448
tu1().name: struct Foo,5be460
Caught Foo x=7.21479e-313

(without a namespace, VC raw_name() are identical)

The problem is nothing encodes the internal structure of Foo. Maybe the
typeid could be a 64-bit hash based on everything relevant: namespace,
name, members and then it would be the same even for different TU and could
be used in all situations.

Yaron







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

> On Fri, Nov 22, 2013 at 3:08 PM, Yaron Keren <yaron.keren at gmail.com>wrote:
>
>> MSVC is confused by the same-named source file!
>> If the code is split into  t1.cpp:
>>
>
> Oh, right, I discovered that yesterday.  It's really annoying, considering
> that my standard testing methodology is to use the same file compiled
> twice.  :(
>
>
>> 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.
>>
>
> MSDN says MSVC lets you get at the mangled/decorated name with
> .raw_name(), and this should be good enough, barring people like me
> recompiling the same source file with different macros.  :)
>
> I don't see how to fix this for gcc, though, if they don't surface a
> unique mangled name for types in anonymous namespaces.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131123/b220c7de/attachment.html>


More information about the cfe-commits mailing list