diff --git a/CMakeLists.txt b/CMakeLists.txt index 35619347..66334869 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,17 +213,16 @@ append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS) if(MSVC) - # Replace the /MD[d] flags with /MT. + # Replace the /M[DT][d] flags with /MT, and strip any definitions of _DEBUG, + # which cause definition mismatches at link time. # FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214. if(COMPILER_RT_HAS_MT_FLAG) foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if(${flag_var} MATCHES "/MD") - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - elseif(${flag_var} MATCHES "/MDd") - string(REGEX REPLACE "/MDd" "/MT" ${flag_var} "${${flag_var}}") - endif() + string(REGEX REPLACE "/M[DT]d" "/MT" ${flag_var} "${${flag_var}}") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + string(REGEX REPLACE "/D_DEBUG" "" ${flag_var} "${${flag_var}}") endforeach() endif() append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS) @@ -333,9 +332,6 @@ if(APPLE AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") # Mac OS X prior to 10.9 had problems with exporting symbols from # libc++/libc++abi. set(SANITIZER_CAN_USE_CXXABI FALSE) -elseif(WIN32) - # We do not currently support the Microsoft C++ ABI. - set(SANITIZER_CAN_USE_CXXABI FALSE) else() set(SANITIZER_CAN_USE_CXXABI TRUE) endif() diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index f9222daf..246236b7 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -15,6 +15,8 @@ set(UBSAN_STANDALONE_SOURCES set(UBSAN_CXX_SOURCES ubsan_handlers_cxx.cc ubsan_type_hash.cc + ubsan_type_hash_itanium.cc + ubsan_type_hash_win.cc ) include_directories(..) diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index b1441221..3d5042b5 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -165,8 +165,12 @@ static void renderText(const char *Message, const Diag::Arg *Args) { case Diag::AK_String: Printf("%s", A.String); break; - case Diag::AK_Mangled: { - Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); + case Diag::AK_TypeName: { + if (SANITIZER_WINDOWS) + // The Windows implementation demangles names early. + Printf("'%s'", A.String); + else + Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); break; } case Diag::AK_SInt: diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 44dca90b..615a646d 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -113,11 +113,11 @@ public: const char *getText() const { return Text; } }; -/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'. -class MangledName { +/// \brief A C++ type name. Really just a strong typedef for 'const char*'. +class TypeName { const char *Name; public: - MangledName(const char *Name) : Name(Name) {} + TypeName(const char *Name) : Name(Name) {} const char *getName() const { return Name; } }; @@ -141,7 +141,7 @@ public: /// Kinds of arguments, corresponding to members of \c Arg's union. enum ArgKind { AK_String, ///< A string argument, displayed as-is. - AK_Mangled,///< A C++ mangled name, demangled before display. + AK_TypeName,///< A C++ type name, possibly demangled before display. AK_UInt, ///< An unsigned integer argument. AK_SInt, ///< A signed integer argument. AK_Float, ///< A floating-point argument. @@ -152,7 +152,7 @@ public: struct Arg { Arg() {} Arg(const char *String) : Kind(AK_String), String(String) {} - Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {} + Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {} Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {} Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {} Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {} @@ -202,7 +202,7 @@ public: ~Diag(); Diag &operator<<(const char *Str) { return AddArg(Str); } - Diag &operator<<(MangledName MN) { return AddArg(MN); } + Diag &operator<<(TypeName TN) { return AddArg(TN); } Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); } Diag &operator<<(const void *V) { return AddArg(V); } Diag &operator<<(const TypeDescriptor &V); diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index 83b9939d..6984a963 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -54,19 +54,19 @@ static void HandleDynamicTypeCacheMiss( // If possible, say what type it actually points to. if (!DTI.isValid()) Diag(Pointer, DL_Note, "object has invalid vptr") - << MangledName(DTI.getMostDerivedTypeName()) + << TypeName(DTI.getMostDerivedTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); else if (!DTI.getOffset()) Diag(Pointer, DL_Note, "object is of type %0") - << MangledName(DTI.getMostDerivedTypeName()) + << TypeName(DTI.getMostDerivedTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); else // FIXME: Find the type at the specified offset, and include that // in the note. Diag(Pointer - DTI.getOffset(), DL_Note, "object is base class subobject at offset %0 within object of type %1") - << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName()) - << MangledName(DTI.getSubobjectTypeName()) + << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName()) + << TypeName(DTI.getSubobjectTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1"); } @@ -104,7 +104,7 @@ static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable, Diag(Vtable, DL_Note, "invalid vtable"); else Diag(Vtable, DL_Note, "vtable is of type %0") - << MangledName(DTI.getMostDerivedTypeName()); + << TypeName(DTI.getMostDerivedTypeName()); } void __ubsan::__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data, diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc index c130afdb..a217c862 100644 --- a/lib/ubsan/ubsan_type_hash.cc +++ b/lib/ubsan/ubsan_type_hash.cc @@ -11,6 +11,9 @@ // relationships. This file is only linked into C++ compilations, and is // permitted to use language features which require a C++ ABI library. // +// Most of the implementation lives in an ABI-specific source file +// (ubsan_type_hash_{itanium,win}.cc). +// //===----------------------------------------------------------------------===// #include "ubsan_platform.h" @@ -19,243 +22,13 @@ #include "sanitizer_common/sanitizer_common.h" -// The following are intended to be binary compatible with the definitions -// given in the Itanium ABI. We make no attempt to be ODR-compatible with -// those definitions, since existing ABI implementations aren't. - -namespace std { - class type_info { - public: - virtual ~type_info(); - - const char *__type_name; - }; -} - -namespace __cxxabiv1 { - -/// Type info for classes with no bases, and base class for type info for -/// classes with bases. -class __class_type_info : public std::type_info { - ~__class_type_info() override; -}; - -/// Type info for classes with simple single public inheritance. -class __si_class_type_info : public __class_type_info { -public: - ~__si_class_type_info() override; - - const __class_type_info *__base_type; -}; - -class __base_class_type_info { -public: - const __class_type_info *__base_type; - long __offset_flags; - - enum __offset_flags_masks { - __virtual_mask = 0x1, - __public_mask = 0x2, - __offset_shift = 8 - }; -}; - -/// Type info for classes with multiple, virtual, or non-public inheritance. -class __vmi_class_type_info : public __class_type_info { -public: - ~__vmi_class_type_info() override; - - unsigned int flags; - unsigned int base_count; - __base_class_type_info base_info[1]; -}; - -} - -namespace abi = __cxxabiv1; - -// We implement a simple two-level cache for type-checking results. For each -// (vptr,type) pair, a hash is computed. This hash is assumed to be globally -// unique; if it collides, we will get false negatives, but: -// * such a collision would have to occur on the *first* bad access, -// * the probability of such a collision is low (and for a 64-bit target, is -// negligible), and -// * the vptr, and thus the hash, can be affected by ASLR, so multiple runs -// give better coverage. -// -// The first caching layer is a small hash table with no chaining; buckets are -// reused as needed. The second caching layer is a large hash table with open -// chaining. We can freely evict from either layer since this is just a cache. -// -// FIXME: Make these hash table accesses thread-safe. The races here are benign: -// assuming the unsequenced loads and stores don't misbehave too badly, -// the worst case is false negatives or poor cache behavior, not false -// positives or crashes. - -/// Find a bucket to store the given hash value in. -static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) { - static const unsigned HashTableSize = 65537; - static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize]; - - unsigned First = (V & 65535) ^ 1; - unsigned Probe = First; - for (int Tries = 5; Tries; --Tries) { - if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V) - return &__ubsan_vptr_hash_set[Probe]; - Probe += ((V >> 16) & 65535) + 1; - if (Probe >= HashTableSize) - Probe -= HashTableSize; - } - // FIXME: Pick a random entry from the probe sequence to evict rather than - // just taking the first. - return &__ubsan_vptr_hash_set[First]; -} - /// A cache of recently-checked hashes. Mini hash table with "random" evictions. __ubsan::HashValue __ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize]; -/// \brief Determine whether \p Derived has a \p Base base class subobject at -/// offset \p Offset. -static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, - const abi::__class_type_info *Base, - sptr Offset) { - if (Derived->__type_name == Base->__type_name) - return Offset == 0; - - if (const abi::__si_class_type_info *SI = - dynamic_cast(Derived)) - return isDerivedFromAtOffset(SI->__base_type, Base, Offset); - - const abi::__vmi_class_type_info *VTI = - dynamic_cast(Derived); - if (!VTI) - // No base class subobjects. - return false; - - // Look for a base class which is derived from \p Base at the right offset. - for (unsigned int base = 0; base != VTI->base_count; ++base) { - // FIXME: Curtail the recursion if this base can't possibly contain the - // given offset. - sptr OffsetHere = VTI->base_info[base].__offset_flags >> - abi::__base_class_type_info::__offset_shift; - if (VTI->base_info[base].__offset_flags & - abi::__base_class_type_info::__virtual_mask) - // For now, just punt on virtual bases and say 'yes'. - // FIXME: OffsetHere is the offset in the vtable of the virtual base - // offset. Read the vbase offset out of the vtable and use it. - return true; - if (isDerivedFromAtOffset(VTI->base_info[base].__base_type, - Base, Offset - OffsetHere)) - return true; - } - - return false; -} - -/// \brief Find the derived-most dynamic base class of \p Derived at offset -/// \p Offset. -static const abi::__class_type_info *findBaseAtOffset( - const abi::__class_type_info *Derived, sptr Offset) { - if (!Offset) - return Derived; - - if (const abi::__si_class_type_info *SI = - dynamic_cast(Derived)) - return findBaseAtOffset(SI->__base_type, Offset); - - const abi::__vmi_class_type_info *VTI = - dynamic_cast(Derived); - if (!VTI) - // No base class subobjects. - return 0; - - for (unsigned int base = 0; base != VTI->base_count; ++base) { - sptr OffsetHere = VTI->base_info[base].__offset_flags >> - abi::__base_class_type_info::__offset_shift; - if (VTI->base_info[base].__offset_flags & - abi::__base_class_type_info::__virtual_mask) - // FIXME: Can't handle virtual bases yet. - continue; - if (const abi::__class_type_info *Base = - findBaseAtOffset(VTI->base_info[base].__base_type, - Offset - OffsetHere)) - return Base; - } - - return 0; -} - -namespace { - -struct VtablePrefix { - /// The offset from the vptr to the start of the most-derived object. - /// This should never be greater than zero, and will usually be exactly - /// zero. - sptr Offset; - /// The type_info object describing the most-derived class type. - std::type_info *TypeInfo; -}; -VtablePrefix *getVtablePrefix(void *Vtable) { - VtablePrefix *Vptr = reinterpret_cast(Vtable); - if (!Vptr) - return 0; - VtablePrefix *Prefix = Vptr - 1; - if (Prefix->Offset > 0 || !Prefix->TypeInfo) - // This can't possibly be a valid vtable. - return 0; - return Prefix; -} - -} - -bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { - // A crash anywhere within this function probably means the vptr is corrupted. - // FIXME: Perform these checks more cautiously. - - // Check whether this is something we've evicted from the cache. - HashValue *Bucket = getTypeCacheHashTableBucket(Hash); - if (*Bucket == Hash) { - __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash; - return true; - } - - void *VtablePtr = *reinterpret_cast(Object); - VtablePrefix *Vtable = getVtablePrefix(VtablePtr); - if (!Vtable) - return false; - - // Check that this is actually a type_info object for a class type. - abi::__class_type_info *Derived = - dynamic_cast(Vtable->TypeInfo); - if (!Derived) - return false; - - abi::__class_type_info *Base = (abi::__class_type_info*)Type; - if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset)) - return false; - - // Success. Cache this result. - __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash; - *Bucket = Hash; - return true; -} - __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfoFromObject(void *Object) { void *VtablePtr = *reinterpret_cast(Object); return getDynamicTypeInfoFromVtable(VtablePtr); } -__ubsan::DynamicTypeInfo -__ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { - VtablePrefix *Vtable = getVtablePrefix(VtablePtr); - if (!Vtable) - return DynamicTypeInfo(0, 0, 0); - const abi::__class_type_info *ObjectType = findBaseAtOffset( - static_cast(Vtable->TypeInfo), - -Vtable->Offset); - return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset, - ObjectType ? ObjectType->__type_name : ""); -} - #endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_type_hash_itanium.cc b/lib/ubsan/ubsan_type_hash_itanium.cc new file mode 100644 index 00000000..5cd46df1 --- /dev/null +++ b/lib/ubsan/ubsan_type_hash_itanium.cc @@ -0,0 +1,251 @@ +//===-- ubsan_type_hash_itanium.cc ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of type hashing/lookup for Itanium C++ ABI. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB && !SANITIZER_WINDOWS +#include "ubsan_type_hash.h" + +#include "sanitizer_common/sanitizer_common.h" + +// The following are intended to be binary compatible with the definitions +// given in the Itanium ABI. We make no attempt to be ODR-compatible with +// those definitions, since existing ABI implementations aren't. + +namespace std { + class type_info { + public: + virtual ~type_info(); + + const char *__type_name; + }; +} + +namespace __cxxabiv1 { + +/// Type info for classes with no bases, and base class for type info for +/// classes with bases. +class __class_type_info : public std::type_info { + ~__class_type_info() override; +}; + +/// Type info for classes with simple single public inheritance. +class __si_class_type_info : public __class_type_info { +public: + ~__si_class_type_info() override; + + const __class_type_info *__base_type; +}; + +class __base_class_type_info { +public: + const __class_type_info *__base_type; + long __offset_flags; + + enum __offset_flags_masks { + __virtual_mask = 0x1, + __public_mask = 0x2, + __offset_shift = 8 + }; +}; + +/// Type info for classes with multiple, virtual, or non-public inheritance. +class __vmi_class_type_info : public __class_type_info { +public: + ~__vmi_class_type_info() override; + + unsigned int flags; + unsigned int base_count; + __base_class_type_info base_info[1]; +}; + +} + +namespace abi = __cxxabiv1; + +// We implement a simple two-level cache for type-checking results. For each +// (vptr,type) pair, a hash is computed. This hash is assumed to be globally +// unique; if it collides, we will get false negatives, but: +// * such a collision would have to occur on the *first* bad access, +// * the probability of such a collision is low (and for a 64-bit target, is +// negligible), and +// * the vptr, and thus the hash, can be affected by ASLR, so multiple runs +// give better coverage. +// +// The first caching layer is a small hash table with no chaining; buckets are +// reused as needed. The second caching layer is a large hash table with open +// chaining. We can freely evict from either layer since this is just a cache. +// +// FIXME: Make these hash table accesses thread-safe. The races here are benign: +// assuming the unsequenced loads and stores don't misbehave too badly, +// the worst case is false negatives or poor cache behavior, not false +// positives or crashes. + +/// Find a bucket to store the given hash value in. +static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) { + static const unsigned HashTableSize = 65537; + static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize]; + + unsigned First = (V & 65535) ^ 1; + unsigned Probe = First; + for (int Tries = 5; Tries; --Tries) { + if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V) + return &__ubsan_vptr_hash_set[Probe]; + Probe += ((V >> 16) & 65535) + 1; + if (Probe >= HashTableSize) + Probe -= HashTableSize; + } + // FIXME: Pick a random entry from the probe sequence to evict rather than + // just taking the first. + return &__ubsan_vptr_hash_set[First]; +} + +/// \brief Determine whether \p Derived has a \p Base base class subobject at +/// offset \p Offset. +static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, + const abi::__class_type_info *Base, + sptr Offset) { + if (Derived->__type_name == Base->__type_name) + return Offset == 0; + + if (const abi::__si_class_type_info *SI = + dynamic_cast(Derived)) + return isDerivedFromAtOffset(SI->__base_type, Base, Offset); + + const abi::__vmi_class_type_info *VTI = + dynamic_cast(Derived); + if (!VTI) + // No base class subobjects. + return false; + + // Look for a base class which is derived from \p Base at the right offset. + for (unsigned int base = 0; base != VTI->base_count; ++base) { + // FIXME: Curtail the recursion if this base can't possibly contain the + // given offset. + sptr OffsetHere = VTI->base_info[base].__offset_flags >> + abi::__base_class_type_info::__offset_shift; + if (VTI->base_info[base].__offset_flags & + abi::__base_class_type_info::__virtual_mask) + // For now, just punt on virtual bases and say 'yes'. + // FIXME: OffsetHere is the offset in the vtable of the virtual base + // offset. Read the vbase offset out of the vtable and use it. + return true; + if (isDerivedFromAtOffset(VTI->base_info[base].__base_type, + Base, Offset - OffsetHere)) + return true; + } + + return false; +} + +/// \brief Find the derived-most dynamic base class of \p Derived at offset +/// \p Offset. +static const abi::__class_type_info *findBaseAtOffset( + const abi::__class_type_info *Derived, sptr Offset) { + if (!Offset) + return Derived; + + if (const abi::__si_class_type_info *SI = + dynamic_cast(Derived)) + return findBaseAtOffset(SI->__base_type, Offset); + + const abi::__vmi_class_type_info *VTI = + dynamic_cast(Derived); + if (!VTI) + // No base class subobjects. + return 0; + + for (unsigned int base = 0; base != VTI->base_count; ++base) { + sptr OffsetHere = VTI->base_info[base].__offset_flags >> + abi::__base_class_type_info::__offset_shift; + if (VTI->base_info[base].__offset_flags & + abi::__base_class_type_info::__virtual_mask) + // FIXME: Can't handle virtual bases yet. + continue; + if (const abi::__class_type_info *Base = + findBaseAtOffset(VTI->base_info[base].__base_type, + Offset - OffsetHere)) + return Base; + } + + return 0; +} + +namespace { + +struct VtablePrefix { + /// The offset from the vptr to the start of the most-derived object. + /// This should never be greater than zero, and will usually be exactly + /// zero. + sptr Offset; + /// The type_info object describing the most-derived class type. + std::type_info *TypeInfo; +}; +VtablePrefix *getVtablePrefix(void *Vtable) { + VtablePrefix *Vptr = reinterpret_cast(Vtable); + if (!Vptr) + return 0; + VtablePrefix *Prefix = Vptr - 1; + if (Prefix->Offset > 0 || !Prefix->TypeInfo) + // This can't possibly be a valid vtable. + return 0; + return Prefix; +} + +} + +bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { + // A crash anywhere within this function probably means the vptr is corrupted. + // FIXME: Perform these checks more cautiously. + + // Check whether this is something we've evicted from the cache. + HashValue *Bucket = getTypeCacheHashTableBucket(Hash); + if (*Bucket == Hash) { + __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash; + return true; + } + + void *VtablePtr = *reinterpret_cast(Object); + VtablePrefix *Vtable = getVtablePrefix(VtablePtr); + if (!Vtable) + return false; + + // Check that this is actually a type_info object for a class type. + abi::__class_type_info *Derived = + dynamic_cast(Vtable->TypeInfo); + if (!Derived) + return false; + + abi::__class_type_info *Base = (abi::__class_type_info*)Type; + if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset)) + return false; + + // Success. Cache this result. + __ubsan_vptr_type_cache[Hash % VptrTypeCacheSize] = Hash; + *Bucket = Hash; + return true; +} + +__ubsan::DynamicTypeInfo +__ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { + VtablePrefix *Vtable = getVtablePrefix(VtablePtr); + if (!Vtable) + return DynamicTypeInfo(0, 0, 0); + const abi::__class_type_info *ObjectType = findBaseAtOffset( + static_cast(Vtable->TypeInfo), + -Vtable->Offset); + return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset, + ObjectType ? ObjectType->__type_name : ""); +} + +#endif // CAN_SANITIZE_UB && !SANITIZER_WINDOWS diff --git a/lib/ubsan/ubsan_type_hash_win.cc b/lib/ubsan/ubsan_type_hash_win.cc new file mode 100644 index 00000000..44fa627c --- /dev/null +++ b/lib/ubsan/ubsan_type_hash_win.cc @@ -0,0 +1,72 @@ +//===-- ubsan_type_hash_win.cc --------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of type hashing/lookup for Microsoft C++ ABI. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB && SANITIZER_WINDOWS +#include "ubsan_type_hash.h" + +#include "sanitizer_common/sanitizer_common.h" + +#include +#include + +struct CompleteObjectLocator { + int is_image_relative; + int offset_to_top; + int vfptr_offset; +}; + +bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { + // FIXME: Implement. + return false; +} + +__ubsan::DynamicTypeInfo +__ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { + // The virtual table may not have a complete object locator if the object + // was compiled without RTTI (i.e. we might be reading from some other global + // laid out before the virtual table), so we need to carefully validate each + // pointer dereference and perform sanity checks. + CompleteObjectLocator **obj_locator_ptr = + ((CompleteObjectLocator**)VtablePtr)-1; + if (!IsAccessibleMemoryRange((uptr)obj_locator_ptr, sizeof(void*))) + return DynamicTypeInfo(0, 0, 0); + + CompleteObjectLocator *obj_locator = *obj_locator_ptr; + if (!IsAccessibleMemoryRange((uptr)obj_locator, + sizeof(CompleteObjectLocator)+sizeof(void*))) + return DynamicTypeInfo(0, 0, 0); + + std::type_info *tinfo; + if (obj_locator->is_image_relative == 1) { + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(obj_locator, &mbi, sizeof(mbi)); + tinfo = (std::type_info*)(*(int*)(obj_locator+1) + + (char*)mbi.AllocationBase); + } else if (obj_locator->is_image_relative == 0) + tinfo = *(std::type_info**)(obj_locator+1); + else + // Probably not a complete object locator. + return DynamicTypeInfo(0, 0, 0); + + if (!IsAccessibleMemoryRange((uptr)tinfo, sizeof(std::type_info))) + return DynamicTypeInfo(0, 0, 0); + + // Okay, this is probably a std::type_info. Request its name. + // FIXME: Implement a base class search like we do for Itanium. + return DynamicTypeInfo(tinfo->name(), obj_locator->offset_to_top, + ""); +} + +#endif // CAN_SANITIZE_UB && SANITIZER_WINDOWS diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index a6f13651..21463ac4 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -21,6 +21,11 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LTO ) endif() + if(WIN32 AND EXISTS ${CMAKE_SOURCE_DIR}/tools/lld) + list(APPEND CFI_TEST_DEPS + lld + ) + endif() endif() add_lit_testsuite(check-cfi "Running the cfi regression tests" diff --git a/test/cfi/anon-namespace.cpp b/test/cfi/anon-namespace.cpp index 555bcc7b..f25f3405 100644 --- a/test/cfi/anon-namespace.cpp +++ b/test/cfi/anon-namespace.cpp @@ -1,32 +1,32 @@ // RUN: %clangxx_cfi -c -DTU1 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %t1.o %t2.o +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB32 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB32 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t2 %t1.o %t2.o +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB64 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB64 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t3 %t1.o %t2.o +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DBM -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DBM -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t4 %t1.o %t2.o +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -c -DTU1 -o %t1.o %s // RUN: %clangxx -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx -o %t %t1.o %t2.o -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %t1.o %t2.o +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -c -DTU1 -o %t1.o %s // RUN: %clangxx_cfi_diag -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi_diag -o %t %t1.o %t2.o -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %clangxx_cfi_diag -o %t6 %t1.o %t2.o +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism treats classes in the anonymous namespace in // different translation units as having distinct identities. This is done by @@ -91,13 +91,13 @@ int main() { fprintf(stderr, "1\n"); // CFI-DIAG: runtime error: control flow integrity check for type '(anonymous namespace)::B' failed during base-to-derived cast - // CFI-DIAG-NEXT: note: vtable is of type '(anonymous namespace)::B' + // CFI-DIAG-NEXT: note: vtable is of type '{{.*}}anonymous namespace{{.*}}::B' // CFI-DIAG: runtime error: control flow integrity check for type '(anonymous namespace)::B' failed during virtual call - // CFI-DIAG-NEXT: note: vtable is of type '(anonymous namespace)::B' + // CFI-DIAG-NEXT: note: vtable is of type '{{.*}}anonymous namespace{{.*}}::B' ((B *)a)->f(); // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/bad-cast.cpp b/test/cfi/bad-cast.cpp index c9a6fb90..9ba6f6db 100644 --- a/test/cfi/bad-cast.cpp +++ b/test/cfi/bad-cast.cpp @@ -1,68 +1,68 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t1 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t1 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t1 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t1 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t1 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t1 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t1 h 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t2 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t2 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t2 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t2 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t2 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t2 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t2 h 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t3 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t3 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t3 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t3 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t3 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t3 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t3 h 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t4 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t4 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t4 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t4 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t4 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t4 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t4 h 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %clangxx_cfi -fsanitize=cfi-cast-strict -o %t %s -// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t d 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t e 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t f 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: not --crash %t h 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %clangxx_cfi -fsanitize=cfi-cast-strict -o %t5 %s +// RUN: %expect_crash %t5 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 d 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 e 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 f 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 h 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %clangxx -o %t %s -// RUN: %t a 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t b 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t c 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t g 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %clangxx -o %t6 %s +// RUN: %t6 a 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 b 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 c 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 g 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 h 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t a 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t b 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t c 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t g 2>&1 | FileCheck --check-prefix=CFI-DIAG-U %s +// RUN: %clangxx_cfi_diag -o %t7 %s +// RUN: %t7 a 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 b 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 c 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 g 2>&1 | FileCheck --check-prefix=CFI-DIAG-U %s // Tests that the CFI enforcement detects bad casts. @@ -112,10 +112,10 @@ int main(int argc, char **argv) { A a; // CFI-DIAG-D: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast - // CFI-DIAG-D-NEXT: note: vtable is of type 'A' + // CFI-DIAG-D-NEXT: note: vtable is of type '{{(struct )?}}A' // CFI-DIAG-U: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type - // CFI-DIAG-U-NEXT: note: vtable is of type 'A' + // CFI-DIAG-U-NEXT: note: vtable is of type '{{(struct )?}}A' switch (argv[1][0]) { case 'a': @@ -144,7 +144,7 @@ int main(int argc, char **argv) { break; } - // FAIL-NOT: 2 - // PASS: 2 + // FAIL-NOT: {{^2$}} + // PASS: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/multiple-inheritance.cpp b/test/cfi/multiple-inheritance.cpp index 50e966b2..e2a9abeb 100644 --- a/test/cfi/multiple-inheritance.cpp +++ b/test/cfi/multiple-inheritance.cpp @@ -1,26 +1,26 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t1 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t2 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t3 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t4 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t x 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG2 %s -// RUN: %t x 2>&1 | FileCheck --check-prefix=CFI-DIAG1 %s +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG2 %s +// RUN: %t6 x 2>&1 | FileCheck --check-prefix=CFI-DIAG1 %s // Tests that the CFI mechanism is sensitive to multiple inheritance and only // permits calls via virtual tables for the correct base class. @@ -77,16 +77,16 @@ int main(int argc, char **argv) { if (argc > 1) { A *a = c; // CFI-DIAG1: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type - // CFI-DIAG1-NEXT: note: vtable is of type 'C' + // CFI-DIAG1-NEXT: note: vtable is of type '{{(struct )?}}C' ((B *)a)->g(); // UB here } else { // CFI-DIAG2: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type - // CFI-DIAG2-NEXT: note: vtable is of type 'C' + // CFI-DIAG2-NEXT: note: vtable is of type '{{(struct )?}}C' B *b = c; ((A *)b)->f(); // UB here } - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/nvcall.cpp b/test/cfi/nvcall.cpp index 91619457..04419bd9 100644 --- a/test/cfi/nvcall.cpp +++ b/test/cfi/nvcall.cpp @@ -1,20 +1,20 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism crashes the program when making a non-virtual // call to an object of the wrong class, by casting a pointer to such an object @@ -63,10 +63,10 @@ int main() { fprintf(stderr, "1\n"); // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during non-virtual call - // CFI-DIAG-NEXT: note: vtable is of type 'A' + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' ((B *)a)->f(); // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/overwrite.cpp b/test/cfi/overwrite.cpp index b3ea0e2e..a24e6283 100644 --- a/test/cfi/overwrite.cpp +++ b/test/cfi/overwrite.cpp @@ -1,20 +1,20 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism crashes the program when a virtual table is // replaced with a compatible table of function pointers that does not belong to @@ -68,7 +68,7 @@ int main() { // CFI-DIAG-NEXT: note: invalid vtable a->f(); - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/sibling.cpp b/test/cfi/sibling.cpp index c8b95e9d..a865cbc0 100644 --- a/test/cfi/sibling.cpp +++ b/test/cfi/sibling.cpp @@ -1,19 +1,19 @@ // XFAIL: * -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI enforcement distinguishes betwen non-overriding siblings. // XFAILed as not implemented yet. diff --git a/test/cfi/simple-fail.cpp b/test/cfi/simple-fail.cpp index 9c25fc0a..c7bebb0d 100644 --- a/test/cfi/simple-fail.cpp +++ b/test/cfi/simple-fail.cpp @@ -1,56 +1,56 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -o %t5 %s +// RUN: %expect_crash %t5 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DB32 -o %t6 %s +// RUN: %expect_crash %t6 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DB64 -o %t7 %s +// RUN: %expect_crash %t7 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DBM -o %t8 %s +// RUN: %expect_crash %t8 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -o %t9 %s +// RUN: %expect_crash %t9 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DB32 -o %t10 %s +// RUN: %expect_crash %t10 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DB64 -o %t11 %s +// RUN: %expect_crash %t11 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DBM -o %t12 %s +// RUN: %expect_crash %t12 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -o %t13 %s +// RUN: %expect_crash %t13 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DB32 -o %t14 %s +// RUN: %expect_crash %t14 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DB64 -o %t15 %s +// RUN: %expect_crash %t15 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DBM -o %t16 %s +// RUN: %expect_crash %t16 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %clangxx_cfi_diag -o %t17 %s +// RUN: %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t18 %s +// RUN: %t18 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a @@ -97,12 +97,12 @@ int main() { fprintf(stderr, "1\n"); // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type - // CFI-DIAG-NEXT: note: vtable is of type 'A' + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during virtual call - // CFI-DIAG-NEXT: note: vtable is of type 'A' + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' ((B *)a)->f(); // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/vdtor.cpp b/test/cfi/vdtor.cpp index 6b1951c4..fb484ea7 100644 --- a/test/cfi/vdtor.cpp +++ b/test/cfi/vdtor.cpp @@ -1,20 +1,20 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI enforcement also applies to virtual destructor calls made // via 'delete'. @@ -60,10 +60,10 @@ int main() { fprintf(stderr, "1\n"); // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during virtual call - // CFI-DIAG-NEXT: note: vtable is of type 'A' + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' delete (B *)a; // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/lit.common.cfg b/test/lit.common.cfg index b4cf396c..02a3cd61 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -121,13 +121,20 @@ def is_linux_lto_supported(): return True -if sys.platform == 'darwin' and is_darwin_lto_supported(): +def is_windows_lto_supported(): + return os.path.exists(os.path.join(config.llvm_tools_dir, 'lld-link2.exe')) + +if config.host_os == 'Darwin' and is_darwin_lto_supported(): config.lto_supported = True config.lto_launch = ["env", "DYLD_LIBRARY_PATH=" + config.llvm_shlib_dir] config.lto_flags = [] -elif sys.platform.startswith('linux') and is_linux_lto_supported(): +elif config.host_os == 'Linux' and is_linux_lto_supported(): config.lto_supported = True config.lto_launch = [] config.lto_flags = ["-fuse-ld=gold"] +elif config.host_os == 'Windows' and is_windows_lto_supported(): + config.lto_supported = True + config.lto_launch = [] + config.lto_flags = ["-fuse-ld=lld-link2"] else: config.lto_supported = False diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index d20dcdff..7ae078a8 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -54,6 +54,11 @@ config.suffixes = ['.c', '.cc', '.cpp'] if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']: config.unsupported = True +if config.host_os == 'Windows': + # We do not currently support enough of the Microsoft ABI for UBSan to work on + # Windows. + config.available_features.remove('cxxabi') + # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL # because the test hangs or fails on one configuration and not the other. if config.target_arch.startswith('arm') == False: