Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -213,17 +213,16 @@ 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 @@ # 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() Index: lib/ubsan/ubsan_diag.h =================================================================== --- lib/ubsan/ubsan_diag.h +++ lib/ubsan/ubsan_diag.h @@ -113,11 +113,11 @@ 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 @@ /// 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 @@ 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 @@ ~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); Index: lib/ubsan/ubsan_diag.cc =================================================================== --- lib/ubsan/ubsan_diag.cc +++ lib/ubsan/ubsan_diag.cc @@ -165,8 +165,13 @@ case Diag::AK_String: Printf("%s", A.String); break; - case Diag::AK_Mangled: { + 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)); +#endif break; } case Diag::AK_SInt: Index: lib/ubsan/ubsan_handlers_cxx.cc =================================================================== --- lib/ubsan/ubsan_handlers_cxx.cc +++ lib/ubsan/ubsan_handlers_cxx.cc @@ -54,19 +54,19 @@ // 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 @@ 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, Index: lib/ubsan/ubsan_type_hash.cc =================================================================== --- lib/ubsan/ubsan_type_hash.cc +++ lib/ubsan/ubsan_type_hash.cc @@ -19,6 +19,8 @@ #include "sanitizer_common/sanitizer_common.h" +#if !SANITIZER_WINDOWS + // 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. @@ -111,10 +113,6 @@ 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, @@ -241,11 +239,6 @@ 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); @@ -258,4 +251,68 @@ ObjectType ? ObjectType->__type_name : ""); } +#else // SANITIZER_WINDOWS + +#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 // SANITIZER_WINDOWS + +/// A cache of recently-checked hashes. Mini hash table with "random" evictions. +__ubsan::HashValue +__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize]; + +__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfoFromObject(void *Object) { + void *VtablePtr = *reinterpret_cast(Object); + return getDynamicTypeInfoFromVtable(VtablePtr); +} + #endif // CAN_SANITIZE_UB Index: test/cfi/CMakeLists.txt =================================================================== --- test/cfi/CMakeLists.txt +++ test/cfi/CMakeLists.txt @@ -21,6 +21,11 @@ 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" Index: test/cfi/anon-namespace.cpp =================================================================== --- test/cfi/anon-namespace.cpp +++ 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 @@ 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"); } Index: test/cfi/bad-cast.cpp =================================================================== --- test/cfi/bad-cast.cpp +++ 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 -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 -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 -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 -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 -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_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 -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 %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 %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 %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 %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 %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 %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 @@ 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 @@ break; } - // FAIL-NOT: 2 - // PASS: 2 + // FAIL-NOT: {{^2$}} + // PASS: {{^2$}} fprintf(stderr, "2\n"); } Index: test/cfi/multiple-inheritance.cpp =================================================================== --- test/cfi/multiple-inheritance.cpp +++ 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 @@ 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"); } Index: test/cfi/nvcall.cpp =================================================================== --- test/cfi/nvcall.cpp +++ 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 @@ 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"); } Index: test/cfi/overwrite.cpp =================================================================== --- test/cfi/overwrite.cpp +++ 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 @@ // CFI-DIAG-NEXT: note: invalid vtable a->f(); - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } Index: test/cfi/sibling.cpp =================================================================== --- test/cfi/sibling.cpp +++ 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. Index: test/cfi/simple-fail.cpp =================================================================== --- test/cfi/simple-fail.cpp +++ 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 @@ 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"); } Index: test/cfi/vdtor.cpp =================================================================== --- test/cfi/vdtor.cpp +++ 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 @@ 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"); } Index: test/lit.common.cfg =================================================================== --- test/lit.common.cfg +++ test/lit.common.cfg @@ -121,13 +121,20 @@ 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 Index: test/ubsan/lit.common.cfg =================================================================== --- test/ubsan/lit.common.cfg +++ test/ubsan/lit.common.cfg @@ -54,6 +54,11 @@ 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: