From 1db450fe70e07fa889f1ab41ce13806b1c1dcd5b Mon Sep 17 00:00:00 2001 From: dim Date: Thu, 2 Aug 2018 17:33:19 +0000 Subject: [PATCH] Vendor import of compiler-rt trunk r338536: https://llvm.org/svn/llvm-project/compiler-rt/trunk@338536 --- lib/asan/asan_mapping.h | 2 +- lib/asan/tests/asan_test.cc | 2 +- lib/builtins/CMakeLists.txt | 9 +++ lib/profile/InstrProfilingUtil.c | 11 +++- lib/profile/InstrProfilingUtil.h | 6 ++ lib/sanitizer_common/sanitizer_mutex.h | 7 +-- lib/sanitizer_common/sanitizer_win.cc | 35 +++-------- lib/ubsan/ubsan_checks.inc | 2 + lib/ubsan/ubsan_diag.h | 2 +- lib/ubsan/ubsan_handlers.cc | 43 +++++++++++++ lib/ubsan/ubsan_handlers.h | 17 +++++ lib/ubsan/ubsan_interface.inc | 2 + lib/ubsan_minimal/ubsan_minimal_handlers.cc | 1 + lib/xray/tests/unit/profile_collector_test.cc | 36 ++++++++++- lib/xray/xray_buffer_queue.cc | 55 ++++++++++++---- lib/xray/xray_profile_collector.cc | 30 ++++++++- lib/xray/xray_profiling.cc | 19 +----- .../TestCases/intercept-rethrow-exception.cc | 2 +- test/fuzzer/ImplicitIntegerTruncationTest.cpp | 27 ++++++++ .../fuzzer-implicit-integer-truncation.test | 5 ++ test/profile/Inputs/instrprof-gcov-fork.c | 15 +++++ .../profile/Inputs/instrprof-gcov-fork.c.gcov | 23 +++++++ test/profile/Inputs/instrprof-gcov-switch1.c | 18 ++++++ .../Inputs/instrprof-gcov-switch1.c.gcov | 23 +++++++ test/profile/Inputs/instrprof-gcov-switch2.c | 18 ++++++ .../Inputs/instrprof-gcov-switch2.c.gcov | 23 +++++++ test/profile/Posix/instrprof-gcov-fork.test | 12 ++++ test/profile/instrprof-gcov-switch.test | 16 +++++ test/profile/instrprof-set-dir-mode.c | 48 ++++++++++++++ .../integer-truncation-blacklist.c | 20 ++++++ .../integer-truncation-summary.cpp | 13 ++++ .../ImplicitConversion/integer-truncation.c | 63 +++++++++++++++++++ .../TestCases/implicit-integer-truncation.c | 24 +++++++ .../Posix/profiling-multi-threaded.cc | 5 +- .../Posix/profiling-single-threaded.cc | 7 ++- 35 files changed, 566 insertions(+), 75 deletions(-) create mode 100644 test/fuzzer/ImplicitIntegerTruncationTest.cpp create mode 100644 test/fuzzer/fuzzer-implicit-integer-truncation.test create mode 100644 test/profile/Inputs/instrprof-gcov-fork.c create mode 100644 test/profile/Inputs/instrprof-gcov-fork.c.gcov create mode 100644 test/profile/Inputs/instrprof-gcov-switch1.c create mode 100644 test/profile/Inputs/instrprof-gcov-switch1.c.gcov create mode 100644 test/profile/Inputs/instrprof-gcov-switch2.c create mode 100644 test/profile/Inputs/instrprof-gcov-switch2.c.gcov create mode 100644 test/profile/Posix/instrprof-gcov-fork.test create mode 100644 test/profile/instrprof-gcov-switch.test create mode 100644 test/profile/instrprof-set-dir-mode.c create mode 100644 test/ubsan/TestCases/ImplicitConversion/integer-truncation-blacklist.c create mode 100644 test/ubsan/TestCases/ImplicitConversion/integer-truncation-summary.cpp create mode 100644 test/ubsan/TestCases/ImplicitConversion/integer-truncation.c create mode 100644 test/ubsan_minimal/TestCases/implicit-integer-truncation.c diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index 3f8cc004b95f..f3696da62b30 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -122,7 +122,7 @@ // || `[0x400000000000, 0x47ffffffffff]` || LowShadow || // || `[0x000000000000, 0x3fffffffffff]` || LowMem || // -// Shadow mapping on NerBSD/i386 with SHADOW_OFFSET == 0x40000000: +// Shadow mapping on NetBSD/i386 with SHADOW_OFFSET == 0x40000000: // || `[0x60000000, 0xfffff000]` || HighMem || // || `[0x4c000000, 0x5fffffff]` || HighShadow || // || `[0x48000000, 0x4bffffff]` || ShadowGap || diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 11a3506a4853..25d6a2083450 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -963,7 +963,7 @@ TEST(AddressSanitizer, ThreadNamesTest) { #if ASAN_NEEDS_SEGV TEST(AddressSanitizer, ShadowGapTest) { #if SANITIZER_WORDSIZE == 32 - char *addr = (char*)0x22000000; + char *addr = (char*)0x23000000; #else # if defined(__powerpc64__) char *addr = (char*)0x024000800000; diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 75ff66405649..82332967b104 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -567,6 +567,15 @@ else () set(_arch "arm") endif() + # For ARM archs, exclude any VFP builtins if VFP is not supported + if (${arch} MATCHES "^(arm|armhf|armv7|armv7s|armv7k|armv7m|armv7em)$") + string(REPLACE ";" " " _TARGET_${arch}_CFLAGS "${TARGET_${arch}_CFLAGS}") + check_compile_definition(__VFP_FP__ "${CMAKE_C_FLAGS} ${_TARGET_${arch}_CFLAGS}" COMPILER_RT_HAS_${arch}_VFP) + if(NOT COMPILER_RT_HAS_${arch}_VFP) + list(REMOVE_ITEM ${arch}_SOURCES ${arm_Thumb1_VFPv2_SOURCES} ${arm_Thumb1_SjLj_EH_SOURCES}) + endif() + endif() + # Filter out generic versions of routines that are re-implemented in # architecture specific manner. This prevents multiple definitions of the # same symbols, making the symbol selection non-deterministic. diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index d053ab160ca7..083bf14a3260 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -35,6 +35,8 @@ #include "InstrProfiling.h" #include "InstrProfilingUtil.h" +COMPILER_RT_WEAK unsigned lprofDirMode = 0755; + COMPILER_RT_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; @@ -47,12 +49,19 @@ void __llvm_profile_recursive_mkdir(char *path) { #ifdef _WIN32 _mkdir(path); #else - mkdir(path, 0755); /* Some of these will fail, ignore it. */ + /* Some of these will fail, ignore it. */ + mkdir(path, __llvm_profile_get_dir_mode()); #endif path[i] = save; } } +COMPILER_RT_VISIBILITY +void __llvm_profile_set_dir_mode(unsigned Mode) { lprofDirMode = Mode; } + +COMPILER_RT_VISIBILITY +unsigned __llvm_profile_get_dir_mode(void) { return lprofDirMode; } + #if COMPILER_RT_HAS_ATOMICS != 1 COMPILER_RT_VISIBILITY uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) { diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h index 2f2ea1b876a8..147677fc8700 100644 --- a/lib/profile/InstrProfilingUtil.h +++ b/lib/profile/InstrProfilingUtil.h @@ -16,6 +16,12 @@ /*! \brief Create a directory tree. */ void __llvm_profile_recursive_mkdir(char *Pathname); +/*! Set the mode used when creating profile directories. */ +void __llvm_profile_set_dir_mode(unsigned Mode); + +/*! Return the directory creation mode. */ +unsigned __llvm_profile_get_dir_mode(void); + int lprofLockFd(int fd); int lprofUnlockFd(int fd); diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h index 4bb878ee19dc..a93705be6918 100644 --- a/lib/sanitizer_common/sanitizer_mutex.h +++ b/lib/sanitizer_common/sanitizer_mutex.h @@ -73,13 +73,8 @@ class SpinMutex : public StaticSpinMutex { class BlockingMutex { public: -#if SANITIZER_WINDOWS - // Windows does not currently support LinkerInitialized - explicit BlockingMutex(LinkerInitialized); -#else explicit constexpr BlockingMutex(LinkerInitialized) - : opaque_storage_ {0, }, owner_(0) {} -#endif + : opaque_storage_ {0, }, owner_ {0} {} BlockingMutex(); void Lock(); void Unlock(); diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index b8060b2e640c..38e567d9a732 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -767,43 +767,22 @@ void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } void internal_join_thread(void *th) { } // ---------------------- BlockingMutex ---------------- {{{1 -const uptr LOCK_UNINITIALIZED = 0; -const uptr LOCK_READY = (uptr)-1; - -BlockingMutex::BlockingMutex(LinkerInitialized li) { - // FIXME: see comments in BlockingMutex::Lock() for the details. - CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); - - CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); - InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); - owner_ = LOCK_READY; -} BlockingMutex::BlockingMutex() { - CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); - InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); - owner_ = LOCK_READY; + CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); + internal_memset(this, 0, sizeof(*this)); } void BlockingMutex::Lock() { - if (owner_ == LOCK_UNINITIALIZED) { - // FIXME: hm, global BlockingMutex objects are not initialized?!? - // This might be a side effect of the clang+cl+link Frankenbuild... - new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); - - // FIXME: If it turns out the linker doesn't invoke our - // constructors, we should probably manually Lock/Unlock all the global - // locks while we're starting in one thread to avoid double-init races. - } - EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); - CHECK_EQ(owner_, LOCK_READY); + AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); + CHECK_EQ(owner_, 0); owner_ = GetThreadSelf(); } void BlockingMutex::Unlock() { - CHECK_EQ(owner_, GetThreadSelf()); - owner_ = LOCK_READY; - LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); + CheckLocked(); + owner_ = 0; + ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); } void BlockingMutex::CheckLocked() { diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc index 73c69363215a..5a7bdec2df12 100644 --- a/lib/ubsan/ubsan_checks.inc +++ b/lib/ubsan/ubsan_checks.inc @@ -30,6 +30,8 @@ UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero", "integer-divide-by-zero") UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero") UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use") +UBSAN_CHECK(ImplicitIntegerTruncation, "implicit-integer-truncation", + "implicit-integer-truncation") UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base") UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent") UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds") diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index d9ea410c358c..bde749684c65 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -178,7 +178,7 @@ class Diag { }; private: - static const unsigned MaxArgs = 5; + static const unsigned MaxArgs = 8; static const unsigned MaxRanges = 1; /// The arguments which have been added to this diagnostic so far. diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 49c6bcacbe27..e72a32cf32c2 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -451,6 +451,49 @@ void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, Die(); } +static void handleImplicitConversion(ImplicitConversionData *Data, + ReportOptions Opts, ValueHandle Src, + ValueHandle Dst) { + SourceLocation Loc = Data->Loc.acquire(); + ErrorType ET = ErrorType::GenericUB; + + switch (Data->Kind) { + case ICCK_IntegerTruncation: + ET = ErrorType::ImplicitIntegerTruncation; + break; + } + + if (ignoreReport(Loc, Opts, ET)) + return; + + const TypeDescriptor &SrcTy = Data->FromType; + const TypeDescriptor &DstTy = Data->ToType; + + ScopedReport R(Opts, Loc, ET); + + // FIXME: is it possible to dump the values as hex with fixed width? + + Diag(Loc, DL_Error, ET, + "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to " + "type %4 changed the value to %5 (%6-bit, %7signed)") + << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth() + << (SrcTy.isSignedIntegerTy() ? "" : "un") << DstTy << Value(DstTy, Dst) + << DstTy.getIntegerBitWidth() << (DstTy.isSignedIntegerTy() ? "" : "un"); +} + +void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data, + ValueHandle Src, + ValueHandle Dst) { + GET_REPORT_OPTIONS(false); + handleImplicitConversion(Data, Opts, Src, Dst); +} +void __ubsan::__ubsan_handle_implicit_conversion_abort( + ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) { + GET_REPORT_OPTIONS(true); + handleImplicitConversion(Data, Opts, Src, Dst); + Die(); +} + static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); ErrorType ET = ErrorType::InvalidBuiltin; diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index ed3c8f0b1b0e..07644b7ea15d 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -122,6 +122,23 @@ struct InvalidValueData { /// \brief Handle a load of an invalid value for the type. RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val) +/// Known implicit conversion check kinds. +/// Keep in sync with the enum of the same name in CGExprScalar.cpp +enum ImplicitConversionCheckKind : unsigned char { + ICCK_IntegerTruncation = 0, +}; + +struct ImplicitConversionData { + SourceLocation Loc; + const TypeDescriptor &FromType; + const TypeDescriptor &ToType; + /* ImplicitConversionCheckKind */ unsigned char Kind; +}; + +/// \brief Implict conversion that changed the value. +RECOVERABLE(implicit_conversion, ImplicitConversionData *Data, ValueHandle Src, + ValueHandle Dst) + /// Known builtin check kinds. /// Keep in sync with the enum of the same name in CodeGenFunction.h enum BuiltinCheckKind : unsigned char { diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 782c621a2b47..0be6010ad27b 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -22,6 +22,8 @@ INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch) INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_abort) +INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion) +INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion_abort) INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin) INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort) INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value) diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc index f25a75a863c4..e8fc3a8499b5 100644 --- a/lib/ubsan_minimal/ubsan_minimal_handlers.cc +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -109,6 +109,7 @@ HANDLER(float_cast_overflow, "float-cast-overflow") HANDLER(load_invalid_value, "load-invalid-value") HANDLER(invalid_builtin, "invalid-builtin") HANDLER(function_type_mismatch, "function-type-mismatch") +HANDLER(implicit_conversion, "implicit-conversion") HANDLER(nonnull_arg, "nonnull-arg") HANDLER(nonnull_return, "nonnull-return") HANDLER(nullability_arg, "nullability-arg") diff --git a/lib/xray/tests/unit/profile_collector_test.cc b/lib/xray/tests/unit/profile_collector_test.cc index b7dbe567312a..67049af2cd5f 100644 --- a/lib/xray/tests/unit/profile_collector_test.cc +++ b/lib/xray/tests/unit/profile_collector_test.cc @@ -15,6 +15,8 @@ #include "xray_profile_collector.h" #include "xray_profiling_flags.h" #include +#include +#include #include #include #include @@ -24,6 +26,29 @@ namespace { static constexpr auto kHeaderSize = 16u; +constexpr uptr ExpectedProfilingVersion = 0x20180424; + +struct ExpectedProfilingFileHeader { + const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling + // files 'xrayprof' in hex. + const u64 Version = ExpectedProfilingVersion; + u64 Timestamp = 0; + u64 PID = 0; +}; + +void ValidateFileHeaderBlock(XRayBuffer B) { + ASSERT_NE(static_cast(B.Data), nullptr); + ASSERT_EQ(B.Size, sizeof(ExpectedProfilingFileHeader)); + typename std::aligned_storage::type + FileHeaderStorage; + ExpectedProfilingFileHeader ExpectedHeader; + std::memcpy(&FileHeaderStorage, B.Data, B.Size); + auto &FileHeader = + *reinterpret_cast(&FileHeaderStorage); + ASSERT_EQ(ExpectedHeader.MagicBytes, FileHeader.MagicBytes); + ASSERT_EQ(ExpectedHeader.Version, FileHeader.Version); +} + void ValidateBlock(XRayBuffer B) { profilingFlags()->setDefaults(); ASSERT_NE(static_cast(B.Data), nullptr); @@ -107,9 +132,13 @@ TEST(profileCollectorServiceTest, PostSerializeCollect) { // Then we serialize the data. profileCollectorService::serialize(); - // Then we go through a single buffer to see whether we're getting the data we - // expect. + // Then we go through two buffers to see whether we're getting the data we + // expect. The first block must always be as large as a file header, which + // will have a fixed size. auto B = profileCollectorService::nextBuffer({nullptr, 0}); + ValidateFileHeaderBlock(B); + + B = profileCollectorService::nextBuffer(B); ValidateBlock(B); u32 BlockSize; u32 BlockNum; @@ -169,6 +198,9 @@ TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) { // Ensure that we see two buffers. auto B = profileCollectorService::nextBuffer({nullptr, 0}); + ValidateFileHeaderBlock(B); + + B = profileCollectorService::nextBuffer(B); ValidateBlock(B); B = profileCollectorService::nextBuffer(B); diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 8dfcc23540b1..3ce728900787 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -13,17 +13,50 @@ // //===----------------------------------------------------------------------===// #include "xray_buffer_queue.h" -#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_posix.h" #include +#include + +#ifndef MAP_NORESERVE +// no-op on NetBSD (at least), unsupported flag on FreeBSD +#define MAP_NORESERVE 0 +#endif using namespace __xray; using namespace __sanitizer; +template static T *allocRaw(size_t N) { + // TODO: Report errors? + // We use MAP_NORESERVE on platforms where it's supported to ensure that the + // pages we're allocating for XRay never end up in pages that can be swapped + // in/out. We're doing this because for FDR mode, we want to ensure that + // writes to the buffers stay resident in memory to prevent XRay itself from + // causing swapping/thrashing. + // + // In the case when XRay pages cannot be swapped in/out or there's not enough + // RAM to back these pages, we're willing to cause a segmentation fault + // instead of introducing latency in the measurement. We assume here that + // there are enough pages that are swappable in/out outside of the buffers + // being used by FDR mode (which are bounded and configurable anyway) to allow + // us to keep using always-resident memory. + // + // TODO: Make this configurable? + void *A = reinterpret_cast( + internal_mmap(NULL, N * sizeof(T), PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0)); + return (A == MAP_FAILED) ? nullptr : reinterpret_cast(A); +} + +template static void deallocRaw(T *ptr, size_t N) { + // TODO: Report errors? + if (ptr != nullptr) + internal_munmap(ptr, N); +} + template static T *initArray(size_t N) { - auto A = reinterpret_cast( - InternalAlloc(N * sizeof(T), nullptr, kCacheLineSize)); + auto A = allocRaw(N); if (A != nullptr) while (N > 0) new (A + (--N)) T(); @@ -42,19 +75,19 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) // Clean up the buffers we've already allocated. for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B) B->~BufferRep(); - InternalFree(Buffers); + deallocRaw(Buffers, N); Success = false; return; }; for (size_t i = 0; i < N; ++i) { auto &T = Buffers[i]; - void *Tmp = InternalAlloc(BufferSize, nullptr, 64); + void *Tmp = allocRaw(BufferSize); if (Tmp == nullptr) { Success = false; return; } - void *Extents = InternalAlloc(sizeof(BufferExtents), nullptr, 64); + auto *Extents = allocRaw(1); if (Extents == nullptr) { Success = false; return; @@ -62,7 +95,7 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) auto &Buf = T.Buff; Buf.Data = Tmp; Buf.Size = B; - Buf.Extents = reinterpret_cast(Extents); + Buf.Extents = Extents; OwnedBuffers[i] = Tmp; } Success = true; @@ -128,11 +161,11 @@ BufferQueue::~BufferQueue() { for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { auto &T = *I; auto &Buf = T.Buff; - InternalFree(Buf.Data); - InternalFree(Buf.Extents); + deallocRaw(Buf.Data, Buf.Size); + deallocRaw(Buf.Extents, 1); } for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B) B->~BufferRep(); - InternalFree(Buffers); - InternalFree(OwnedBuffers); + deallocRaw(Buffers, BufferCount); + deallocRaw(OwnedBuffers, BufferCount); } diff --git a/lib/xray/xray_profile_collector.cc b/lib/xray/xray_profile_collector.cc index a43744d9a0cb..17a611eeacb8 100644 --- a/lib/xray/xray_profile_collector.cc +++ b/lib/xray/xray_profile_collector.cc @@ -37,6 +37,19 @@ struct ProfileBuffer { size_t Size; }; +// Current version of the profile format. +constexpr u64 XRayProfilingVersion = 0x20180424; + +// Identifier for XRay profiling files 'xrayprof' in hex. +constexpr u64 XRayMagicBytes = 0x7872617970726f66; + +struct XRayProfilingFileHeader { + const u64 MagicBytes = XRayMagicBytes; + const u64 Version = XRayProfilingVersion; + u64 Timestamp = 0; // System time in nanoseconds. + u64 PID = 0; // Process ID. +}; + struct BlockHeader { u32 BlockSize; u32 BlockNum; @@ -302,7 +315,22 @@ XRayBuffer nextBuffer(XRayBuffer B) { if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0) return {nullptr, 0}; - if (B.Data == nullptr) + static pthread_once_t Once = PTHREAD_ONCE_INIT; + static typename std::aligned_storage::type + FileHeaderStorage; + pthread_once(&Once, + +[] { new (&FileHeaderStorage) XRayProfilingFileHeader{}; }); + + if (UNLIKELY(B.Data == nullptr)) { + // The first buffer should always contain the file header information. + auto &FileHeader = + *reinterpret_cast(&FileHeaderStorage); + FileHeader.Timestamp = NanoTime(); + FileHeader.PID = internal_getpid(); + return {&FileHeaderStorage, sizeof(XRayProfilingFileHeader)}; + } + + if (UNLIKELY(B.Data == &FileHeaderStorage)) return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size}; BlockHeader Header; diff --git a/lib/xray/xray_profiling.cc b/lib/xray/xray_profiling.cc index 786084c77226..d4b4345d764a 100644 --- a/lib/xray/xray_profiling.cc +++ b/lib/xray/xray_profiling.cc @@ -32,16 +32,6 @@ namespace __xray { namespace { -constexpr uptr XRayProfilingVersion = 0x20180424; - -struct XRayProfilingFileHeader { - const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling - // files 'xrayprof' in hex. - const uptr Version = XRayProfilingVersion; - uptr Timestamp = 0; // System time in nanoseconds. - uptr PID = 0; // Process ID. -}; - atomic_sint32_t ProfilerLogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; @@ -144,14 +134,7 @@ XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT { if (Verbosity()) Report("profiling: Failed to flush to file, dropping data.\n"); } else { - XRayProfilingFileHeader Header; - Header.Timestamp = NanoTime(); - Header.PID = internal_getpid(); - retryingWriteAll(Fd, reinterpret_cast(&Header), - reinterpret_cast(&Header) + - sizeof(Header)); - - // Now for each of the threads, write out the profile data as we would + // Now for each of the buffers, write out the profile data as we would // see it in memory, verbatim. while (B.Data != nullptr && B.Size != 0) { retryingWriteAll(Fd, reinterpret_cast(B.Data), diff --git a/test/asan/TestCases/intercept-rethrow-exception.cc b/test/asan/TestCases/intercept-rethrow-exception.cc index fa9ea7d3b09e..e81dc5398a98 100644 --- a/test/asan/TestCases/intercept-rethrow-exception.cc +++ b/test/asan/TestCases/intercept-rethrow-exception.cc @@ -1,7 +1,7 @@ // Regression test for // https://bugs.llvm.org/show_bug.cgi?id=32434 -// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %clangxx_asan -fexceptions -O0 %s -o %t // RUN: %run %t #include diff --git a/test/fuzzer/ImplicitIntegerTruncationTest.cpp b/test/fuzzer/ImplicitIntegerTruncationTest.cpp new file mode 100644 index 000000000000..cb935da0c13e --- /dev/null +++ b/test/fuzzer/ImplicitIntegerTruncationTest.cpp @@ -0,0 +1,27 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test for signed-integer-overflow. +#include +#include +#include +#include +#include +#include + +static volatile int Sink; +static unsigned char Large = UINT8_MAX; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + Large = Large + 1; // 'char overflow'. + } + } + } + return 0; +} diff --git a/test/fuzzer/fuzzer-implicit-integer-truncation.test b/test/fuzzer/fuzzer-implicit-integer-truncation.test new file mode 100644 index 000000000000..212559bdca3c --- /dev/null +++ b/test/fuzzer/fuzzer-implicit-integer-truncation.test @@ -0,0 +1,5 @@ +RUN: rm -f %t-ImplicitIntegerTruncationTest-Ubsan +RUN: %cpp_compiler -fsanitize=implicit-integer-truncation -fno-sanitize-recover=all %S/ImplicitIntegerTruncationTest.cpp -o %t-ImplicitIntegerTruncationTest-Ubsan +RUN: not %run %t-ImplicitIntegerTruncationTest-Ubsan 2>&1 | FileCheck %s +CHECK: runtime error: implicit conversion from type 'int' of value 256 (32-bit, signed) to type 'unsigned char' changed the value to 0 (8-bit, unsigned) +CHECK: Test unit written to ./crash- diff --git a/test/profile/Inputs/instrprof-gcov-fork.c b/test/profile/Inputs/instrprof-gcov-fork.c new file mode 100644 index 000000000000..818c459c50dd --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-fork.c @@ -0,0 +1,15 @@ +#include + +void func1() {} +void func2() {} + +int main(void) +{ + func1(); + + fork(); + + func2(); + + return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-fork.c.gcov b/test/profile/Inputs/instrprof-gcov-fork.c.gcov new file mode 100644 index 000000000000..9591f62ed602 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-fork.c.gcov @@ -0,0 +1,23 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-gcov-fork.c +// CHECK-NEXT: -: 0:Graph:instrprof-gcov-fork.gcno +// CHECK-NEXT: -: 0:Data:instrprof-gcov-fork.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:#include +// CHECK-NEXT: -: 2: +// CHECK-NEXT:function func1 called 1 returned 100% blocks executed 100% +// CHECK-NEXT: 1: 3:void func1() {} +// CHECK-NEXT:function func2 called 2 returned 100% blocks executed 100% +// CHECK-NEXT: 2: 4:void func2() {} +// CHECK-NEXT: -: 5: +// CHECK-NEXT:function main called 1 returned 100% blocks executed 100% +// CHECK-NEXT: -: 6:int main(void) +// CHECK-NEXT: -: 7:{ +// CHECK-NEXT: 1: 8: func1(); +// CHECK-NEXT: -: 9: +// CHECK-NEXT: 1: 10: fork(); +// CHECK-NEXT: -: 11: +// CHECK-NEXT: 2: 12: func2(); +// CHECK-NEXT: -: 13: +// CHECK-NEXT: 2: 14: return 0; +// CHECK-NEXT: -: 15:} diff --git a/test/profile/Inputs/instrprof-gcov-switch1.c b/test/profile/Inputs/instrprof-gcov-switch1.c new file mode 100644 index 000000000000..25544323c555 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-switch1.c @@ -0,0 +1,18 @@ +int main(void) +{ + int i = 22; + + switch (i) { + case 7: + break; + + case 22: + i = 7; + break; + + case 42: + break; + } + + return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-switch1.c.gcov b/test/profile/Inputs/instrprof-gcov-switch1.c.gcov new file mode 100644 index 000000000000..7d136dc98ec3 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-switch1.c.gcov @@ -0,0 +1,23 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-gcov-switch1.c +// CHECK-NEXT: -: 0:Graph:instrprof-gcov-switch1.gcno +// CHECK-NEXT: -: 0:Data:instrprof-gcov-switch1.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:int main(void) +// CHECK-NEXT: -: 2:{ +// CHECK-NEXT: 2: 3: int i = 22; +// CHECK-NEXT: -: 4: +// CHECK-NEXT: 2: 5: switch (i) { +// CHECK-NEXT: -: 6: case 7: +// CHECK-NEXT: #####: 7: break; +// CHECK-NEXT: -: 8: +// CHECK-NEXT: -: 9: case 22: +// CHECK-NEXT: 1: 10: i = 7; +// CHECK-NEXT: 1: 11: break; +// CHECK-NEXT: -: 12: +// CHECK-NEXT: -: 13: case 42: +// CHECK-NEXT: #####: 14: break; +// CHECK-NEXT: -: 15: } +// CHECK-NEXT: -: 16: +// CHECK-NEXT: 1: 17: return 0; +// CHECK-NEXT: -: 18:} diff --git a/test/profile/Inputs/instrprof-gcov-switch2.c b/test/profile/Inputs/instrprof-gcov-switch2.c new file mode 100644 index 000000000000..14e8a84de507 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-switch2.c @@ -0,0 +1,18 @@ +int main(void) +{ + int i = 22; + + switch (i) { + case 7: + break; + + case 22: + i = 7; + + case 42: + i = 22; + break; + } + + return 0; +} diff --git a/test/profile/Inputs/instrprof-gcov-switch2.c.gcov b/test/profile/Inputs/instrprof-gcov-switch2.c.gcov new file mode 100644 index 000000000000..67f408606a39 --- /dev/null +++ b/test/profile/Inputs/instrprof-gcov-switch2.c.gcov @@ -0,0 +1,23 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-gcov-switch2.c +// CHECK-NEXT: -: 0:Graph:instrprof-gcov-switch2.gcno +// CHECK-NEXT: -: 0:Data:instrprof-gcov-switch2.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:int main(void) +// CHECK-NEXT: -: 2:{ +// CHECK-NEXT: 3: 3: int i = 22; +// CHECK-NEXT: -: 4: +// CHECK-NEXT: 3: 5: switch (i) { +// CHECK-NEXT: -: 6: case 7: +// CHECK-NEXT: #####: 7: break; +// CHECK-NEXT: -: 8: +// CHECK-NEXT: -: 9: case 22: +// CHECK-NEXT: 1: 10: i = 7; +// CHECK-NEXT: -: 11: +// CHECK-NEXT: -: 12: case 42: +// CHECK-NEXT: 1: 13: i = 22; +// CHECK-NEXT: 1: 14: break; +// CHECK-NEXT: -: 15: } +// CHECK-NEXT: -: 16: +// CHECK-NEXT: 1: 17: return 0; +// CHECK-NEXT: -: 18:} diff --git a/test/profile/Posix/instrprof-gcov-fork.test b/test/profile/Posix/instrprof-gcov-fork.test new file mode 100644 index 000000000000..436d7e663faa --- /dev/null +++ b/test/profile/Posix/instrprof-gcov-fork.test @@ -0,0 +1,12 @@ +XFAIL: * + +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o %t %S/../Inputs/instrprof-gcov-fork.c +RUN: test -f instrprof-gcov-fork.gcno + +RUN: rm -f instrprof-gcov-fork.gcda +RUN: %run %t +RUN: llvm-cov gcov -b -c instrprof-gcov-fork.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-fork.c.gcov %S/../Inputs/instrprof-gcov-fork.c.gcov diff --git a/test/profile/instrprof-gcov-switch.test b/test/profile/instrprof-gcov-switch.test new file mode 100644 index 000000000000..9c43a93dc646 --- /dev/null +++ b/test/profile/instrprof-gcov-switch.test @@ -0,0 +1,16 @@ +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o %t %S/Inputs/instrprof-gcov-switch1.c +RUN: test -f instrprof-gcov-switch1.gcno +RUN: rm -f instrprof-gcov-switch1.gcda +RUN: %run %t +RUN: llvm-cov gcov instrprof-gcov-switch1.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-switch1.c.gcov %S/Inputs/instrprof-gcov-switch1.c.gcov + +RUN: %clang --coverage -o %t %S/Inputs/instrprof-gcov-switch2.c +RUN: test -f instrprof-gcov-switch2.gcno +RUN: rm -f instrprof-gcov-switch2.gcda +RUN: %run %t +RUN: llvm-cov gcov instrprof-gcov-switch2.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-gcov-switch2.c.gcov %S/Inputs/instrprof-gcov-switch2.c.gcov diff --git a/test/profile/instrprof-set-dir-mode.c b/test/profile/instrprof-set-dir-mode.c new file mode 100644 index 000000000000..25eb29db533d --- /dev/null +++ b/test/profile/instrprof-set-dir-mode.c @@ -0,0 +1,48 @@ +// UNSUPPORTED: windows +// RUN: %clang_pgogen -o %t.bin %s -DTESTPATH=\"%t.dir\" +// RUN: rm -rf %t.dir +// RUN: %run %t.bin + +#include +#include +#include +#include + +void __llvm_profile_set_dir_mode(unsigned Mode); +unsigned __llvm_profile_get_dir_mode(void); +void __llvm_profile_recursive_mkdir(char *Path); + +static int test(unsigned Mode, const char *TestDir) { + int Ret = 0; + + /* Create a dir and set the mode accordingly. */ + char *Dir = strdup(TestDir); + if (!Dir) + return -1; + __llvm_profile_set_dir_mode(Mode); + __llvm_profile_recursive_mkdir(Dir); + + if (Mode != __llvm_profile_get_dir_mode()) + Ret = -1; + else { + const unsigned Expected = ~umask(0) & Mode; + struct stat DirSt; + if (stat(Dir, &DirSt) == -1) + Ret = -1; + else if (DirSt.st_mode != Expected) { + printf("Modes do not match: Expected %o but found %o (%s)\n", Expected, + DirSt.st_mode, Dir); + Ret = -1; + } + } + + free(Dir); + return Ret; +} + +int main(void) { + if (test(S_IFDIR | 0777, TESTPATH "/foo/bar/baz/") || + test(S_IFDIR | 0666, TESTPATH "/foo/bar/qux/")) + return -1; + return 0; +} diff --git a/test/ubsan/TestCases/ImplicitConversion/integer-truncation-blacklist.c b/test/ubsan/TestCases/ImplicitConversion/integer-truncation-blacklist.c new file mode 100644 index 000000000000..13d4dca4ff14 --- /dev/null +++ b/test/ubsan/TestCases/ImplicitConversion/integer-truncation-blacklist.c @@ -0,0 +1,20 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// I'm not sure this is actually *that* issue, but this seems oddly similar to the other XFAIL'ed cases. +// XFAIL: android +// UNSUPPORTED: ios + +// RUN: rm -f %tmp +// RUN: echo "[implicit-integer-truncation]" >> %tmp +// RUN: echo "fun:*implicitTruncation*" >> %tmp +// RUN: %clang -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation -fsanitize-blacklist=%tmp -O0 %s -o %t && not %run %t 2>&1 +// RUN: %clang -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation -fsanitize-blacklist=%tmp -O1 %s -o %t && not %run %t 2>&1 +// RUN: %clang -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation -fsanitize-blacklist=%tmp -O2 %s -o %t && not %run %t 2>&1 +// RUN: %clang -fsanitize=implicit-integer-truncation -fno-sanitize-recover=implicit-integer-truncation -fsanitize-blacklist=%tmp -O3 %s -o %t && not %run %t 2>&1 + +unsigned char implicitTruncation(unsigned int argc) { + return argc; // BOOM +} + +int main(int argc, char **argv) { + return implicitTruncation(~0U); +} diff --git a/test/ubsan/TestCases/ImplicitConversion/integer-truncation-summary.cpp b/test/ubsan/TestCases/ImplicitConversion/integer-truncation-summary.cpp new file mode 100644 index 000000000000..a92e01fb4ab6 --- /dev/null +++ b/test/ubsan/TestCases/ImplicitConversion/integer-truncation-summary.cpp @@ -0,0 +1,13 @@ +// RUN: %clangxx -fsanitize=implicit-integer-truncation %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOTYPE +// RUN: %env_ubsan_opts=report_error_type=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TYPE +// REQUIRES: !ubsan-standalone && !ubsan-standalone-static + +#include + +int main() { + uint8_t t0 = (~(uint32_t(0))); + // CHECK-NOTYPE: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:16 + // CHECK-TYPE: SUMMARY: UndefinedBehaviorSanitizer: implicit-integer-truncation {{.*}}summary.cpp:[[@LINE-2]]:16 + return 0; +} diff --git a/test/ubsan/TestCases/ImplicitConversion/integer-truncation.c b/test/ubsan/TestCases/ImplicitConversion/integer-truncation.c new file mode 100644 index 000000000000..995eb7d0faf4 --- /dev/null +++ b/test/ubsan/TestCases/ImplicitConversion/integer-truncation.c @@ -0,0 +1,63 @@ +// RUN: %clang -x c -fsanitize=implicit-integer-truncation %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK +// RUN: %clangxx -x c++ -fsanitize=implicit-integer-truncation %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include + +#if !defined(__cplusplus) +#define bool _Bool +#endif + +int main() { +// CHECK-NOT: integer-truncation.c + + // Negative tests. Even if they produce unexpected results, this sanitizer does not care. + int8_t n0 = (~((uint32_t)0)); // ~0 -> -1, but do not warn. + uint8_t n2 = 128; + uint8_t n3 = 255; + // Bools do not count + bool b0 = (~((uint32_t)0)); + bool b1 = 255; + + // Explicit and-ing of bits will silence it. + uint8_t nc0 = (~((uint32_t)0)) & 255; + + // Explicit casts + uint8_t i0 = (uint8_t)(~((uint32_t)0)); + +#if defined(__cplusplus) + uint8_t i1 = uint8_t(~(uint32_t(0))); + uint8_t i2 = static_cast(~(uint32_t(0))); +#endif + + // Positive tests. + + uint8_t t_b0 = (~((uint16_t)(0))); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:18: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'uint8_t' (aka 'unsigned char') changed the value to 255 (8-bit, unsigned) + + uint8_t t_b1 = (~((uint32_t)0)); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:18: runtime error: implicit conversion from type 'uint32_t' (aka 'unsigned int') of value 4294967295 (32-bit, unsigned) to type 'uint8_t' (aka 'unsigned char') changed the value to 255 (8-bit, unsigned) + uint16_t t_b2 = (~((uint32_t)0)); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:19: runtime error: implicit conversion from type 'uint32_t' (aka 'unsigned int') of value 4294967295 (32-bit, unsigned) to type 'uint16_t' (aka 'unsigned short') changed the value to 65535 (16-bit, unsigned) + + uint8_t t_b3 = ~((uint64_t)0); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:18: runtime error: implicit conversion from type 'uint64_t' (aka 'unsigned long{{[^']*}}') of value 18446744073709551615 (64-bit, unsigned) to type 'uint8_t' (aka 'unsigned char') changed the value to 255 (8-bit, unsigned) + uint16_t t_b4 = ~((uint64_t)0); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:19: runtime error: implicit conversion from type 'uint64_t' (aka 'unsigned long{{[^']*}}') of value 18446744073709551615 (64-bit, unsigned) to type 'uint16_t' (aka 'unsigned short') changed the value to 65535 (16-bit, unsigned) + uint32_t t_b5 = ~((uint64_t)0); +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:19: runtime error: implicit conversion from type 'uint64_t' (aka 'unsigned long{{[^']*}}') of value 18446744073709551615 (64-bit, unsigned) to type 'uint32_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned) + + int8_t t1 = 255; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:15: runtime error: implicit conversion from type 'int' of value 255 (32-bit, signed) to type 'int8_t' (aka 'signed char') changed the value to -1 (8-bit, signed) + uint8_t t2 = 256; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:16: runtime error: implicit conversion from type 'int' of value 256 (32-bit, signed) to type 'uint8_t' (aka 'unsigned char') changed the value to 0 (8-bit, unsigned) + int8_t t3 = 256; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:15: runtime error: implicit conversion from type 'int' of value 256 (32-bit, signed) to type 'int8_t' (aka 'signed char') changed the value to 0 (8-bit, signed) + uint8_t t4 = 257; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:16: runtime error: implicit conversion from type 'int' of value 257 (32-bit, signed) to type 'uint8_t' (aka 'unsigned char') changed the value to 1 (8-bit, unsigned) + int8_t t5 = 257; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:15: runtime error: implicit conversion from type 'int' of value 257 (32-bit, signed) to type 'int8_t' (aka 'signed char') changed the value to 1 (8-bit, signed) + int8_t t6 = 128; +// CHECK: {{.*}}integer-truncation.c:[[@LINE-1]]:15: runtime error: implicit conversion from type 'int' of value 128 (32-bit, signed) to type 'int8_t' (aka 'signed char') changed the value to -128 (8-bit, signed) + + return 0; +} diff --git a/test/ubsan_minimal/TestCases/implicit-integer-truncation.c b/test/ubsan_minimal/TestCases/implicit-integer-truncation.c new file mode 100644 index 000000000000..1db6e6976815 --- /dev/null +++ b/test/ubsan_minimal/TestCases/implicit-integer-truncation.c @@ -0,0 +1,24 @@ +// RUN: %clang -fsanitize=implicit-integer-truncation %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include + +int main() { +// CHECK-NOT: integer-truncation.c + + // Negative tests. Even if they produce unexpected results, this sanitizer does not care. + int8_t n0 = (~((uint32_t)(0))); // ~0 -> -1, but do not warn. + uint8_t n2 = 128; + uint8_t n3 = 255; + // Bools do not count + _Bool b0 = (~((uint32_t)(0))); + _Bool b1 = 255; + + // Explicit and-ing of bits will silence it. + uint8_t nc0 = ((~((uint32_t)(0))) & 255); + + // Positive tests. + uint8_t t0 = (~((uint32_t)(0))); +// CHECK: implicit-conversion + + return 0; +} diff --git a/test/xray/TestCases/Posix/profiling-multi-threaded.cc b/test/xray/TestCases/Posix/profiling-multi-threaded.cc index 7ccad1bac1fd..45e5e70226da 100644 --- a/test/xray/TestCases/Posix/profiling-multi-threaded.cc +++ b/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -51,7 +51,8 @@ volatile int buffer_counter = 0; assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - // We're running three threds, so we expect three buffers. - assert(buffer_counter == 3); + // We're running three threads, so we expect four buffers (including the file + // header buffer). + assert(buffer_counter == 4); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); } diff --git a/test/xray/TestCases/Posix/profiling-single-threaded.cc b/test/xray/TestCases/Posix/profiling-single-threaded.cc index fd508b1acd14..fc518145edbb 100644 --- a/test/xray/TestCases/Posix/profiling-single-threaded.cc +++ b/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -47,7 +47,10 @@ volatile int buffer_counter = 0; f0(); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - assert(buffer_counter == 1); + // There's always at least one buffer, containing the profile file header. We + // assert that we have two, to indicate that we're expecting exactly one + // thread's worth of data. + assert(buffer_counter == 2); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); // Let's reset the counter. @@ -60,6 +63,6 @@ volatile int buffer_counter = 0; f0(); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - assert(buffer_counter == 1); + assert(buffer_counter == 2); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); }