Should a "typeinfo" variable be "linkonce_odr constant" or just "constant"

Hello Clang folks,

I have a question about typeinfo variables:

% cat a1.cc
struct AAA {
public:
virtual ~ AAA ();
};
AAA::~AAA() { }
void foo () { throw AAA (); }

% clang++ a1.cc -S -o - -emit-llvm | grep ‘_ZTI3AAA.=.[^{]*’ -o
_ZTI3AAA = constant

% clang++ a1.cc -S -o - -emit-llvm -fno-rtti | grep ‘_ZTI3AAA.=.[^{]*’ -o
_ZTI3AAA = linkonce_odr constant

As you can see, depending on the compilation mode (-fno-rtti) the definition of _ZTI3AAA
(typeinfo for AAA) is different. Is that expected?

This difference causes problem for AddressSanitizer, if one part of the code is built with
-fno-rtti and another part w/o -fno-rtti.
asan instruments global constants but can not instrument linkonce_odr variables,
as a result we mix an instrumented and a non-instrumented global in the same binary.
https://code.google.com/p/address-sanitizer/issues/detail?id=327

Thanks,

–kcc

Anders Carlsson added this logic to CGRTTI.cpp in r124096. Currently it lives in ItaniumCXXABI.cpp.

Anders, why is this necessary?

Andres, anyone?

Hello Clang folks,

I have a question about typeinfo variables:

% cat a1.cc
struct AAA {
public:
  virtual ~ AAA ();
};
AAA::~AAA() { }
void foo () { throw AAA (); }

% clang++ a1.cc -S -o - -emit-llvm | grep '_ZTI3AAA.=.[^{]*' -o
_ZTI3AAA = constant

% clang++ a1.cc -S -o - -emit-llvm -fno-rtti | grep '_ZTI3AAA.=.[^{]*'
-o
_ZTI3AAA = linkonce_odr constant

As you can see, depending on the compilation mode (-fno-rtti) the
definition of _ZTI3AAA
(typeinfo for AAA) is different. Is that expected?

Yes, I think so: if we have a key function, we can emit the type_info as a
strong symbol with that key function, because we know there will only be
one such translation unit in the program. (We could emit the _ZTI3AAA
symbol as strong in both cases in the above program, but in the second case
we're explicitly not required to provide a definition for other TUs, so we
reduce the linkage to linkonce_odr).

This difference causes problem for AddressSanitizer, if one part of the

code is built with
-fno-rtti and another part w/o -fno-rtti.
asan instruments global constants but can not instrument linkonce_odr
variables,
as a result we mix an instrumented and a non-instrumented global in the
same binary.

Per the LangRef, it seems that it's permissible to have both a linkonce_odr
definition and an external definition of the same entity in the same
program, so this seems like an ASan issue. We could work around it by
reducing the linkage to linkonce_odr in the -frtti case (the global will
not be discarded because it's used by the vtable). That is apparently what
GCC does. But ASan will presumably still have problems with this:

tu1.c:
__attribute__((weak)) int n = 1;

tu2.c:
int n = 2;

https://code.google.com/p/address-sanitizer/issues/detail?id=327

I don't fully understand the problem here. It seems that:
  1) weak linkage globals don't get instrumented
  2) instrumented globals get 8 byte alignment
  3) you're seeing a global with both a weak definition and a non-weak
definition
  4) the assert fails because you believe the variable is instrumented, but
it doesn't have 8 byte alignment
If so, I wonder why you're seeing the weak definition rather than the
strong, 8-byte-aligned instrumented definition that you should see?

I am puzzled too, but I do see the weak definition instead of the strong
one (no simple reproducer though...).
Are you saying this should not happen?

It is surprising to me that you don't see the strong definition, I don't
know if that's actually correct behavior somehow.