ubsan: check type_info equality via strcmp
Stephan Bergmann
sbergman at redhat.com
Fri Aug 16 02:38:54 PDT 2013
I was trying out -fsanitizer=undefined on the LibreOffice code base
(with a recent Clang trunk build), and ran into false positives claiming
member calls were made on base class subobjects of wrong type.
Turns out LibreOffice is somewhat over-eager with -fvisibility=hidden,
leading to some classes that are used across multiple dynamic libraries
nevertheless having their RTTI name symbols bound locally per library.
While that is in violation of the Itanium ABI, it at least works with
recent libstdc++ (which resorts to strcmp rather than pointer comparison
these days, see [1])---and wouldn't normally get noticed anyway as there
should not be uses of dynamic_cast involving those classes in the
LibreOffice code base.
Scenarios like this would easily be catered for in the ubsan code, by
conservatively using strcmp rather than pointer comparison to determine
type_info equality:
> Index: lib/ubsan/ubsan_type_hash.cc
> ===================================================================
> --- lib/ubsan/ubsan_type_hash.cc (revision 188367)
> +++ lib/ubsan/ubsan_type_hash.cc (working copy)
> @@ -13,6 +13,8 @@
> //
> //===----------------------------------------------------------------------===//
>
> +#include <cstring>
> +
> #include "ubsan_type_hash.h"
>
> #include "sanitizer_common/sanitizer_common.h"
> @@ -116,7 +118,7 @@
> static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
> const abi::__class_type_info *Base,
> sptr Offset) {
> - if (Derived->__type_name == Base->__type_name)
> + if (std::strcmp(Derived->__type_name, Base->__type_name) == 0)
> return Offset == 0;
>
> if (const abi::__si_class_type_info *SI =
Stephan
For [1], see libstdc++-v3/libsupc++/typeinfo comment:
> // 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
> // is used where the object files are to be portable to multiple systems,
> // some of which may not be able to use pointer comparison, but the
> // particular system for which libstdc++ is being built can use pointer
> // comparison; in particular for most ARM EABI systems, where the ABI
> // specifies out-of-line comparison. The compiler's target configuration
> // can override the defaults by defining __GXX_TYPEINFO_EQUALITY_INLINE to
> // 1 or 0 to indicate whether or not comparison is inline, and
> // __GXX_MERGED_TYPEINFO_NAMES to 1 or 0 to indicate whether or not pointer
> // comparison can be used.
More information about the cfe-commits
mailing list