Vendor import of compiler-rt trunk r304149:
https://llvm.org/svn/llvm-project/compiler-rt/trunk@304149
This commit is contained in:
parent
99ea5e489f
commit
224c1c721b
@ -63,7 +63,9 @@ else()
|
||||
set(COMPILER_RT_TEST_COMPILER_ID GNU)
|
||||
endif()
|
||||
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
if(NOT DEFINED COMPILER_RT_OS_DIR)
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
endif()
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
|
@ -24,7 +24,7 @@ int foo(int x, int y) {
|
||||
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf armv6m)
|
||||
set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k)
|
||||
set(X86 i386 i686)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
|
@ -357,28 +357,22 @@ DEFINE_REAL_PTHREAD_FUNCTIONS
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(bsd_signal)(signum, handler);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(signal)(signum, handler);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(sigaction)(signum, act, oldact);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
|
||||
INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
|
||||
CHECK(REAL(SetUnhandledExceptionFilter));
|
||||
if (ExceptionFilter == &SEHHandler || common_flags()->allow_user_segv_handler)
|
||||
if (ExceptionFilter == &SEHHandler)
|
||||
return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
|
||||
// We record the user provided exception handler to be called for all the
|
||||
// exceptions unhandled by asan.
|
||||
|
@ -327,11 +327,6 @@ exec $_to \$@
|
||||
EOF
|
||||
}
|
||||
|
||||
# On Android-L not allowing user segv handler breaks some applications.
|
||||
if [[ PRE_L -eq 0 ]]; then
|
||||
ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
|
||||
fi
|
||||
|
||||
if [[ x$extra_options != x ]] ; then
|
||||
ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
|
||||
fi
|
||||
|
@ -102,9 +102,6 @@ TEST(AddressSanitizerInterface, GetHeapSizeTest) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __powerpc64__
|
||||
// FIXME: This has not reliably worked on powerpc since r279664. Re-enable
|
||||
// this once the problem is tracked down and fixed.
|
||||
static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
|
||||
static const size_t kManyThreadsIterations = 250;
|
||||
static const size_t kManyThreadsNumThreads =
|
||||
@ -138,7 +135,6 @@ TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
|
||||
// so we can't check for equality here.
|
||||
EXPECT_LT(after_test, before_test + (1UL<<20));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DoDoubleFree() {
|
||||
int *x = Ident(new int);
|
||||
|
@ -97,9 +97,6 @@ TEST(AddressSanitizer, NoInstMallocTest) {
|
||||
MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
|
||||
}
|
||||
|
||||
#ifndef __powerpc64__
|
||||
// FIXME: This has not reliably worked on powerpc since r279664. Re-enable
|
||||
// this once the problem is tracked down and fixed.
|
||||
TEST(AddressSanitizer, ThreadedMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
|
||||
@ -112,7 +109,6 @@ TEST(AddressSanitizer, ThreadedMallocStressTest) {
|
||||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PrintShadow(const char *tag, uptr ptr, size_t size) {
|
||||
fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
|
||||
@ -210,10 +206,6 @@ void *ThreadedOneSizeMallocStress(void *unused) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef __powerpc64__
|
||||
// FIXME: This has not reliably worked on powerpc since r279664. Re-enable
|
||||
// this once the problem is tracked down and fixed.
|
||||
|
||||
TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
pthread_t t[kNumThreads];
|
||||
@ -224,7 +216,6 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
|
||||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
|
||||
using __asan::kHighMemEnd;
|
||||
|
@ -251,7 +251,8 @@ TEST(AddressSanitizer, BitFieldNegativeTest) {
|
||||
namespace {
|
||||
|
||||
const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address";
|
||||
const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
|
||||
const char kOverriddenSigactionHandler[] = "Test sigaction handler\n";
|
||||
const char kOverriddenSignalHandler[] = "Test signal handler\n";
|
||||
|
||||
TEST(AddressSanitizer, WildAddressTest) {
|
||||
char *c = (char*)0x123;
|
||||
@ -259,12 +260,12 @@ TEST(AddressSanitizer, WildAddressTest) {
|
||||
}
|
||||
|
||||
void my_sigaction_sighandler(int, siginfo_t*, void*) {
|
||||
fprintf(stderr, kOverriddenHandler);
|
||||
fprintf(stderr, kOverriddenSigactionHandler);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void my_signal_sighandler(int signum) {
|
||||
fprintf(stderr, kOverriddenHandler);
|
||||
fprintf(stderr, kOverriddenSignalHandler);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -273,16 +274,20 @@ TEST(AddressSanitizer, SignalTest) {
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = my_sigaction_sighandler;
|
||||
sigact.sa_flags = SA_SIGINFO;
|
||||
// ASan should silently ignore sigaction()...
|
||||
char *c = (char *)0x123;
|
||||
|
||||
EXPECT_DEATH(*c = 0, kSEGVCrash);
|
||||
|
||||
// ASan should allow to set sigaction()...
|
||||
EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
|
||||
#ifdef __APPLE__
|
||||
EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
|
||||
#endif
|
||||
char *c = (char*)0x123;
|
||||
EXPECT_DEATH(*c = 0, kSEGVCrash);
|
||||
EXPECT_DEATH(*c = 0, kOverriddenSigactionHandler);
|
||||
|
||||
// ... and signal().
|
||||
EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
|
||||
EXPECT_DEATH(*c = 0, kSEGVCrash);
|
||||
EXPECT_NE(SIG_ERR, signal(SIGSEGV, my_signal_sighandler));
|
||||
EXPECT_DEATH(*c = 0, kOverriddenSignalHandler);
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
@ -42,6 +42,8 @@ set(GENERIC_SOURCES
|
||||
ashlti3.c
|
||||
ashrdi3.c
|
||||
ashrti3.c
|
||||
bswapdi2.c
|
||||
bswapsi2.c
|
||||
clear_cache.c
|
||||
clzdi2.c
|
||||
clzsi2.c
|
||||
@ -163,8 +165,7 @@ set(GENERIC_SOURCES
|
||||
udivti3.c
|
||||
umoddi3.c
|
||||
umodsi3.c
|
||||
umodti3.c
|
||||
emutls.c)
|
||||
umodti3.c)
|
||||
|
||||
set(GENERIC_TF_SOURCES
|
||||
comparetf2.c
|
||||
@ -193,6 +194,7 @@ option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN
|
||||
if(NOT COMPILER_RT_BAREMETAL_BUILD)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
emutls.c
|
||||
enable_execute_stack.c)
|
||||
endif()
|
||||
|
||||
|
@ -57,8 +57,8 @@ si_int __popcountsi2(si_int a); // bit population
|
||||
si_int __popcountdi2(di_int a); // bit population
|
||||
si_int __popcountti2(ti_int a); // bit population
|
||||
|
||||
uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
|
||||
uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
|
||||
uint32_t __bswapsi2(uint32_t a); // a byteswapped
|
||||
uint64_t __bswapdi2(uint64_t a); // a byteswapped
|
||||
|
||||
// Integral arithmetic
|
||||
|
||||
|
@ -48,7 +48,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
||||
// NaN has been ruled out, so __aeabi_cdcmple can't trap
|
||||
bne __aeabi_cdcmple
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, #APSR_C
|
||||
#endif
|
||||
JMP(lr)
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
||||
@ -95,17 +100,23 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
ITT(eq)
|
||||
moveq ip, #0
|
||||
beq 1f
|
||||
|
||||
ldm sp, {r0-r3}
|
||||
bl __aeabi_dcmpeq
|
||||
cmp r0, #1
|
||||
ITE(eq)
|
||||
moveq ip, #(APSR_C | APSR_Z)
|
||||
movne ip, #(APSR_C)
|
||||
|
||||
1:
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, ip
|
||||
#endif
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
|
@ -48,7 +48,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
||||
// NaN has been ruled out, so __aeabi_cfcmple can't trap
|
||||
bne __aeabi_cfcmple
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, #APSR_C
|
||||
#endif
|
||||
JMP(lr)
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
||||
@ -95,17 +100,23 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
ITT(eq)
|
||||
moveq ip, #0
|
||||
beq 1f
|
||||
|
||||
ldm sp, {r0-r3}
|
||||
bl __aeabi_fcmpeq
|
||||
cmp r0, #1
|
||||
ITE(eq)
|
||||
moveq ip, #(APSR_C | APSR_Z)
|
||||
movne ip, #(APSR_C)
|
||||
|
||||
1:
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, ip
|
||||
#endif
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(eq)
|
||||
moveq r0, #1 // set result register to 1 if equal
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(eq)
|
||||
moveq r0, #1 // set result register to 1 if equal
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ge)
|
||||
movge r0, #1 // set result register to 1 if greater than or equal
|
||||
movlt r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ge)
|
||||
movge r0, #1 // set result register to 1 if greater than or equal
|
||||
movlt r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(gt)
|
||||
movgt r0, #1 // set result register to 1 if equal
|
||||
movle r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(gt)
|
||||
movgt r0, #1 // set result register to 1 if equal
|
||||
movle r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ls)
|
||||
movls r0, #1 // set result register to 1 if equal
|
||||
movhi r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ls)
|
||||
movls r0, #1 // set result register to 1 if equal
|
||||
movhi r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(mi)
|
||||
movmi r0, #1 // set result register to 1 if equal
|
||||
movpl r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(mi)
|
||||
movmi r0, #1 // set result register to 1 if equal
|
||||
movpl r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ne)
|
||||
movne r0, #1 // set result register to 0 if unequal
|
||||
moveq r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(ne)
|
||||
movne r0, #1 // set result register to 1 if unequal
|
||||
moveq r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
|
||||
vcmp.f64 d6, d7
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(vs)
|
||||
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
|
||||
movvc r0, #0
|
||||
bx lr
|
||||
|
@ -27,6 +27,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
|
||||
vcmp.f32 s14, s15
|
||||
#endif
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ITE(vs)
|
||||
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
|
||||
movvc r0, #0
|
||||
bx lr
|
||||
|
@ -96,9 +96,11 @@
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
#define IT(cond) it cond
|
||||
#define ITT(cond) itt cond
|
||||
#define ITE(cond) ite cond
|
||||
#else
|
||||
#define IT(cond)
|
||||
#define ITT(cond)
|
||||
#define ITE(cond)
|
||||
#endif
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
|
27
lib/builtins/bswapdi2.c
Normal file
27
lib/builtins/bswapdi2.c
Normal file
@ -0,0 +1,27 @@
|
||||
/* ===-- bswapdi2.c - Implement __bswapdi2 ---------------------------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*
|
||||
* This file implements __bswapdi2 for the compiler_rt library.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include "int_lib.h"
|
||||
|
||||
COMPILER_RT_ABI uint64_t __bswapdi2(uint64_t u) {
|
||||
return (
|
||||
(((u)&0xff00000000000000ULL) >> 56) |
|
||||
(((u)&0x00ff000000000000ULL) >> 40) |
|
||||
(((u)&0x0000ff0000000000ULL) >> 24) |
|
||||
(((u)&0x000000ff00000000ULL) >> 8) |
|
||||
(((u)&0x00000000ff000000ULL) << 8) |
|
||||
(((u)&0x0000000000ff0000ULL) << 24) |
|
||||
(((u)&0x000000000000ff00ULL) << 40) |
|
||||
(((u)&0x00000000000000ffULL) << 56));
|
||||
}
|
23
lib/builtins/bswapsi2.c
Normal file
23
lib/builtins/bswapsi2.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* ===-- bswapsi2.c - Implement __bswapsi2 ---------------------------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*
|
||||
* This file implements __bswapsi2 for the compiler_rt library.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include "int_lib.h"
|
||||
|
||||
COMPILER_RT_ABI uint32_t __bswapsi2(uint32_t u) {
|
||||
return (
|
||||
(((u)&0xff000000) >> 24) |
|
||||
(((u)&0x00ff0000) >> 8) |
|
||||
(((u)&0x0000ff00) << 8) |
|
||||
(((u)&0x000000ff) << 24));
|
||||
}
|
@ -265,19 +265,21 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
|
||||
}
|
||||
|
||||
if (flags()->use_tls) {
|
||||
LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
|
||||
if (cache_begin == cache_end) {
|
||||
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
|
||||
} else {
|
||||
// Because LSan should not be loaded with dlopen(), we can assume
|
||||
// that allocator cache will be part of static TLS image.
|
||||
CHECK_LE(tls_begin, cache_begin);
|
||||
CHECK_GE(tls_end, cache_end);
|
||||
if (tls_begin < cache_begin)
|
||||
ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
|
||||
kReachable);
|
||||
if (tls_end > cache_end)
|
||||
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
|
||||
if (tls_begin) {
|
||||
LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
|
||||
// If the tls and cache ranges don't overlap, scan full tls range,
|
||||
// otherwise, only scan the non-overlapping portions
|
||||
if (cache_begin == cache_end || tls_end < cache_begin ||
|
||||
tls_begin > cache_end) {
|
||||
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
|
||||
} else {
|
||||
if (tls_begin < cache_begin)
|
||||
ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
|
||||
kReachable);
|
||||
if (tls_end > cache_end)
|
||||
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS",
|
||||
kReachable);
|
||||
}
|
||||
}
|
||||
if (dtls && !DTLSInDestruction(dtls)) {
|
||||
for (uptr j = 0; j < dtls->dtv_size; ++j) {
|
||||
|
@ -91,12 +91,7 @@ LoadedModule *GetLinker() { return nullptr; }
|
||||
|
||||
// Required on Linux for initialization of TLS behavior, but should not be
|
||||
// required on Darwin.
|
||||
void InitializePlatformSpecificModules() {
|
||||
if (flags()->use_tls) {
|
||||
Report("use_tls=1 is not supported on Darwin.\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
void InitializePlatformSpecificModules() {}
|
||||
|
||||
// Scans global variables for heap pointers.
|
||||
void ProcessGlobalRegions(Frontier *frontier) {
|
||||
|
@ -30,7 +30,7 @@ LSAN_FLAG(bool, use_globals, true,
|
||||
"Root set: include global variables (.data and .bss)")
|
||||
LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks")
|
||||
LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers")
|
||||
LSAN_FLAG(bool, use_tls, !SANITIZER_MAC,
|
||||
LSAN_FLAG(bool, use_tls, true,
|
||||
"Root set: include TLS and thread-specific storage")
|
||||
LSAN_FLAG(bool, use_root_regions, true,
|
||||
"Root set: include regions added via __lsan_register_root_region().")
|
||||
|
@ -319,5 +319,3 @@ class SizeClassAllocator32 {
|
||||
ByteMap possible_regions;
|
||||
SizeClassInfo size_class_info_array[kNumClasses];
|
||||
};
|
||||
|
||||
|
||||
|
@ -380,7 +380,7 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
|
||||
|
||||
// Functions related to signal handling.
|
||||
typedef void (*SignalHandlerType)(int, void *, void *);
|
||||
bool IsHandledDeadlySignal(int signum);
|
||||
HandleSignalMode GetHandleSignalMode(int signum);
|
||||
void InstallDeadlySignalHandlers(SignalHandlerType handler);
|
||||
const char *DescribeSignalOrException(int signo);
|
||||
// Alternative signal stack (POSIX-only).
|
||||
|
@ -64,6 +64,11 @@ inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
|
||||
*t_ = b ? kHandleSignalYes : kHandleSignalNo;
|
||||
return true;
|
||||
}
|
||||
if (internal_strcmp(value, "2") == 0 ||
|
||||
internal_strcmp(value, "exclusive") == 0) {
|
||||
*t_ = kHandleSignalExclusive;
|
||||
return true;
|
||||
}
|
||||
Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
|
||||
return false;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ namespace __sanitizer {
|
||||
enum HandleSignalMode {
|
||||
kHandleSignalNo,
|
||||
kHandleSignalYes,
|
||||
kHandleSignalExclusive,
|
||||
};
|
||||
|
||||
struct CommonFlags {
|
||||
|
@ -75,12 +75,13 @@ COMMON_FLAG(bool, print_summary, true,
|
||||
"If false, disable printing error summaries in addition to error "
|
||||
"reports.")
|
||||
COMMON_FLAG(int, print_module_map, 0,
|
||||
"OS X only. 0 = don't print, 1 = print only once before process "
|
||||
"exits, 2 = print after each report.")
|
||||
"OS X only (0 - don't print, 1 - print only once before process "
|
||||
"exits, 2 - print after each report).")
|
||||
COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
|
||||
#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \
|
||||
"Controls custom tool's " #signal " handler (0 - do not registers the " \
|
||||
"handler, 1 - register the handler). "
|
||||
"handler, 1 - register the handler and allow user to set own, " \
|
||||
"2 - registers the handler and block user from changing it). "
|
||||
COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes,
|
||||
COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV))
|
||||
COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes,
|
||||
@ -92,9 +93,6 @@ COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo,
|
||||
COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes,
|
||||
COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE))
|
||||
#undef COMMON_FLAG_HANDLE_SIGNAL_HELP
|
||||
COMMON_FLAG(bool, allow_user_segv_handler, false,
|
||||
"If set, allows user to register a SEGV handler even if the tool "
|
||||
"registers one.")
|
||||
COMMON_FLAG(bool, use_sigaltstack, true,
|
||||
"If set, uses alternate stack for signal handling.")
|
||||
COMMON_FLAG(bool, detect_deadlocks, false,
|
||||
|
@ -549,7 +549,7 @@ void BlockingMutex::Lock() {
|
||||
|
||||
void BlockingMutex::Unlock() {
|
||||
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
|
||||
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
|
||||
u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
|
||||
CHECK_NE(v, MtxUnlocked);
|
||||
if (v == MtxSleeping) {
|
||||
#if SANITIZER_FREEBSD
|
||||
@ -1394,7 +1394,7 @@ AndroidApiLevel AndroidGetApiLevel() {
|
||||
|
||||
#endif
|
||||
|
||||
bool IsHandledDeadlySignal(int signum) {
|
||||
HandleSignalMode GetHandleSignalMode(int signum) {
|
||||
switch (signum) {
|
||||
case SIGABRT:
|
||||
return common_flags()->handle_abort;
|
||||
@ -1407,7 +1407,7 @@ bool IsHandledDeadlySignal(int signum) {
|
||||
case SIGBUS:
|
||||
return common_flags()->handle_sigbus;
|
||||
}
|
||||
return false;
|
||||
return kHandleSignalNo;
|
||||
}
|
||||
|
||||
#if !SANITIZER_GO
|
||||
|
@ -178,6 +178,13 @@ static bool FixedCVE_2016_2143() {
|
||||
// 4.4.6+ is OK.
|
||||
if (minor == 4 && patch >= 6)
|
||||
return true;
|
||||
if (minor == 4 && patch == 0 && ptr[0] == '-' &&
|
||||
internal_strstr(buf.version, "Ubuntu")) {
|
||||
// Check Ubuntu 16.04
|
||||
int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
|
||||
if (r1 >= 13) // 4.4.0-13 or later
|
||||
return true;
|
||||
}
|
||||
// Otherwise, OK if 4.5+.
|
||||
return minor >= 5;
|
||||
} else {
|
||||
|
@ -370,6 +370,27 @@ uptr GetTlsSize() {
|
||||
void InitTlsSize() {
|
||||
}
|
||||
|
||||
uptr TlsBaseAddr() {
|
||||
uptr segbase = 0;
|
||||
#if defined(__x86_64__)
|
||||
asm("movq %%gs:0,%0" : "=r"(segbase));
|
||||
#elif defined(__i386__)
|
||||
asm("movl %%gs:0,%0" : "=r"(segbase));
|
||||
#endif
|
||||
return segbase;
|
||||
}
|
||||
|
||||
// The size of the tls on darwin does not appear to be well documented,
|
||||
// however the vm memory map suggests that it is 1024 uptrs in size,
|
||||
// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.
|
||||
uptr TlsSize() {
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
return 1024 * sizeof(uptr);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
uptr *tls_addr, uptr *tls_size) {
|
||||
#if !SANITIZER_GO
|
||||
@ -377,8 +398,8 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
|
||||
*stk_addr = stack_bottom;
|
||||
*stk_size = stack_top - stack_bottom;
|
||||
*tls_addr = 0;
|
||||
*tls_size = 0;
|
||||
*tls_addr = TlsBaseAddr();
|
||||
*tls_size = TlsSize();
|
||||
#else
|
||||
*stk_addr = 0;
|
||||
*stk_size = 0;
|
||||
@ -393,10 +414,10 @@ void ListOfModules::init() {
|
||||
memory_mapping.DumpListOfModules(&modules_);
|
||||
}
|
||||
|
||||
bool IsHandledDeadlySignal(int signum) {
|
||||
HandleSignalMode GetHandleSignalMode(int signum) {
|
||||
// Handling fatal signals on watchOS and tvOS devices is disallowed.
|
||||
if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
|
||||
return false;
|
||||
return kHandleSignalNo;
|
||||
switch (signum) {
|
||||
case SIGABRT:
|
||||
return common_flags()->handle_abort;
|
||||
@ -409,7 +430,7 @@ bool IsHandledDeadlySignal(int signum) {
|
||||
case SIGBUS:
|
||||
return common_flags()->handle_sigbus;
|
||||
}
|
||||
return false;
|
||||
return kHandleSignalNo;
|
||||
}
|
||||
|
||||
MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
|
||||
|
@ -134,7 +134,8 @@ void SleepForMillis(int millis) {
|
||||
void Abort() {
|
||||
#if !SANITIZER_GO
|
||||
// If we are handling SIGABRT, unhandle it first.
|
||||
if (IsHandledDeadlySignal(SIGABRT)) {
|
||||
// TODO(vitalybuka): Check if handler belongs to sanitizer.
|
||||
if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
|
||||
struct sigaction sigact;
|
||||
internal_memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
|
||||
@ -188,8 +189,26 @@ void UnsetAlternateSignalStack() {
|
||||
|
||||
static void MaybeInstallSigaction(int signum,
|
||||
SignalHandlerType handler) {
|
||||
if (!IsHandledDeadlySignal(signum))
|
||||
return;
|
||||
switch (GetHandleSignalMode(signum)) {
|
||||
case kHandleSignalNo:
|
||||
return;
|
||||
case kHandleSignalYes: {
|
||||
struct sigaction sigact;
|
||||
internal_memset(&sigact, 0, sizeof(sigact));
|
||||
CHECK_EQ(0, internal_sigaction(signum, nullptr, &sigact));
|
||||
if (sigact.sa_flags & SA_SIGINFO) {
|
||||
if (sigact.sa_sigaction) return;
|
||||
} else {
|
||||
if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN &&
|
||||
sigact.sa_handler != SIG_ERR)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kHandleSignalExclusive:
|
||||
break;
|
||||
}
|
||||
|
||||
struct sigaction sigact;
|
||||
internal_memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = (sa_sigaction_t)handler;
|
||||
|
@ -832,9 +832,9 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
bool IsHandledDeadlySignal(int signum) {
|
||||
HandleSignalMode GetHandleSignalMode(int signum) {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
return false;
|
||||
return kHandleSignalNo;
|
||||
}
|
||||
|
||||
// Check based on flags if we should handle this exception.
|
||||
|
@ -78,13 +78,15 @@ TEST(SanitizerCommon, HandleSignalMode) {
|
||||
TestFlag(kHandleSignalYes, "flag_name=0", kHandleSignalNo);
|
||||
TestFlag(kHandleSignalYes, "flag_name=no", kHandleSignalNo);
|
||||
TestFlag(kHandleSignalYes, "flag_name=false", kHandleSignalNo);
|
||||
TestFlag(kHandleSignalNo, "flag_name=2", kHandleSignalExclusive);
|
||||
TestFlag(kHandleSignalYes, "flag_name=exclusive", kHandleSignalExclusive);
|
||||
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name", kHandleSignalNo),
|
||||
"expected '='");
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=", kHandleSignalNo),
|
||||
"Invalid value for signal handler option: ''");
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=2", kHandleSignalNo),
|
||||
"Invalid value for signal handler option: '2'");
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=3", kHandleSignalNo),
|
||||
"Invalid value for signal handler option: '3'");
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=-1", kHandleSignalNo),
|
||||
"Invalid value for signal handler option: '-1'");
|
||||
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=on", kHandleSignalNo),
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#include "scudo_tls.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace __scudo {
|
||||
@ -32,15 +31,17 @@ __attribute__((tls_model("initial-exec")))
|
||||
THREADLOCAL ScudoThreadContext ThreadLocalContext;
|
||||
|
||||
static void teardownThread(void *Ptr) {
|
||||
uptr Iteration = reinterpret_cast<uptr>(Ptr);
|
||||
uptr I = reinterpret_cast<uptr>(Ptr);
|
||||
// The glibc POSIX thread-local-storage deallocation routine calls user
|
||||
// provided destructors in a loop of PTHREAD_DESTRUCTOR_ITERATIONS.
|
||||
// We want to be called last since other destructors might call free and the
|
||||
// like, so we wait until PTHREAD_DESTRUCTOR_ITERATIONS before draining the
|
||||
// quarantine and swallowing the cache.
|
||||
if (Iteration < PTHREAD_DESTRUCTOR_ITERATIONS) {
|
||||
pthread_setspecific(PThreadKey, reinterpret_cast<void *>(Iteration + 1));
|
||||
return;
|
||||
if (I > 1) {
|
||||
// If pthread_setspecific fails, we will go ahead with the teardown.
|
||||
if (LIKELY(pthread_setspecific(PThreadKey,
|
||||
reinterpret_cast<void *>(I - 1)) == 0))
|
||||
return;
|
||||
}
|
||||
ThreadLocalContext.commitBack();
|
||||
ScudoThreadState = ThreadTornDown;
|
||||
@ -53,8 +54,9 @@ static void initOnce() {
|
||||
}
|
||||
|
||||
void initThread() {
|
||||
pthread_once(&GlobalInitialized, initOnce);
|
||||
pthread_setspecific(PThreadKey, reinterpret_cast<void *>(1));
|
||||
CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0);
|
||||
CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(
|
||||
GetPthreadDestructorIterations())), 0);
|
||||
ThreadLocalContext.init();
|
||||
ScudoThreadState = ThreadInitialized;
|
||||
}
|
||||
|
@ -816,6 +816,7 @@ void FlushShadowMemory();
|
||||
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
|
||||
int ExtractResolvFDs(void *state, int *fds, int nfd);
|
||||
int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
|
||||
void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
|
||||
|
||||
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
|
||||
void *abstime), void *c, void *m, void *abstime,
|
||||
|
@ -320,6 +320,20 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
|
||||
return res;
|
||||
}
|
||||
|
||||
void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
|
||||
// Check that the thr object is in tls;
|
||||
const uptr thr_beg = (uptr)thr;
|
||||
const uptr thr_end = (uptr)thr + sizeof(*thr);
|
||||
CHECK_GE(thr_beg, tls_addr);
|
||||
CHECK_LE(thr_beg, tls_addr + tls_size);
|
||||
CHECK_GE(thr_end, tls_addr);
|
||||
CHECK_LE(thr_end, tls_addr + tls_size);
|
||||
// Since the thr object is huge, skip it.
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, thr_beg - tls_addr);
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/2, thr_end,
|
||||
tls_addr + tls_size - thr_end);
|
||||
}
|
||||
|
||||
// Note: this function runs with async signals enabled,
|
||||
// so it must not touch any tsan state.
|
||||
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
|
||||
|
@ -75,12 +75,18 @@ static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
|
||||
static uptr main_thread_identity = 0;
|
||||
ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
|
||||
|
||||
ThreadState **cur_thread_location() {
|
||||
ThreadState **thread_identity = (ThreadState **)pthread_self();
|
||||
return ((uptr)thread_identity == main_thread_identity) ? nullptr
|
||||
: thread_identity;
|
||||
}
|
||||
|
||||
ThreadState *cur_thread() {
|
||||
uptr thread_identity = (uptr)pthread_self();
|
||||
if (thread_identity == main_thread_identity || main_thread_identity == 0) {
|
||||
ThreadState **thr_state_loc = cur_thread_location();
|
||||
if (thr_state_loc == nullptr || main_thread_identity == 0) {
|
||||
return (ThreadState *)&main_thread_state;
|
||||
}
|
||||
ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
|
||||
ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
|
||||
ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
|
||||
(uptr *)fake_tls, sizeof(ThreadState));
|
||||
return thr;
|
||||
@ -90,13 +96,13 @@ ThreadState *cur_thread() {
|
||||
// munmap first and then clear `fake_tls`; if we receive a signal in between,
|
||||
// handler will try to access the unmapped ThreadState.
|
||||
void cur_thread_finalize() {
|
||||
uptr thread_identity = (uptr)pthread_self();
|
||||
if (thread_identity == main_thread_identity) {
|
||||
ThreadState **thr_state_loc = cur_thread_location();
|
||||
if (thr_state_loc == nullptr) {
|
||||
// Calling dispatch_main() or xpc_main() actually invokes pthread_exit to
|
||||
// exit the main thread. Let's keep the main thread's ThreadState.
|
||||
return;
|
||||
}
|
||||
ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
|
||||
ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
|
||||
internal_munmap(*fake_tls, sizeof(ThreadState));
|
||||
*fake_tls = nullptr;
|
||||
}
|
||||
@ -239,6 +245,29 @@ void InitializePlatform() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SANITIZER_GO
|
||||
void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
|
||||
// The pointer to the ThreadState object is stored in the shadow memory
|
||||
// of the tls.
|
||||
uptr tls_end = tls_addr + tls_size;
|
||||
ThreadState **thr_state_loc = cur_thread_location();
|
||||
if (thr_state_loc == nullptr) {
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, tls_size);
|
||||
} else {
|
||||
uptr thr_state_start = (uptr)thr_state_loc;
|
||||
uptr thr_state_end = thr_state_start + sizeof(uptr);
|
||||
CHECK_GE(thr_state_start, tls_addr);
|
||||
CHECK_LE(thr_state_start, tls_addr + tls_size);
|
||||
CHECK_GE(thr_state_end, tls_addr);
|
||||
CHECK_LE(thr_state_end, tls_addr + tls_size);
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr,
|
||||
thr_state_start - tls_addr);
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/2, thr_state_end,
|
||||
tls_end - thr_state_end);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_GO
|
||||
// Note: this function runs with async signals enabled,
|
||||
// so it must not touch any tsan state.
|
||||
|
@ -248,19 +248,7 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread) {
|
||||
if (stk_addr && stk_size)
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
|
||||
|
||||
if (tls_addr && tls_size) {
|
||||
// Check that the thr object is in tls;
|
||||
const uptr thr_beg = (uptr)thr;
|
||||
const uptr thr_end = (uptr)thr + sizeof(*thr);
|
||||
CHECK_GE(thr_beg, tls_addr);
|
||||
CHECK_LE(thr_beg, tls_addr + tls_size);
|
||||
CHECK_GE(thr_end, tls_addr);
|
||||
CHECK_LE(thr_end, tls_addr + tls_size);
|
||||
// Since the thr object is huge, skip it.
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
|
||||
MemoryRangeImitateWrite(thr, /*pc=*/ 2,
|
||||
thr_end, tls_addr + tls_size - thr_end);
|
||||
}
|
||||
if (tls_addr && tls_size) ImitateTlsWrite(thr, tls_addr, tls_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
105
test/asan/TestCases/Linux/preinstalled_signal.cc
Normal file
105
test/asan/TestCases/Linux/preinstalled_signal.cc
Normal file
@ -0,0 +1,105 @@
|
||||
// clang-format off
|
||||
// RUN: %clangxx -std=c++11 %s -o %t
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// RUN: %clangxx -std=c++11 -DTEST_INSTALL_SIG_HANDLER %s -o %t
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-HANDLER %s
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// RUN: %clangxx -std=c++11 -DTEST_INSTALL_SIG_ACTION %s -o %t
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ACTION %s
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: asan-dynamic-runtime
|
||||
|
||||
// This way of setting LD_PRELOAD does not work with Android test runner.
|
||||
// REQUIRES: not-android
|
||||
// clang-format on
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *handler = nullptr;
|
||||
void SigHandler(int signum) { handler = "TestSigHandler"; }
|
||||
void SigAction(int, siginfo_t *, void *) { handler = "TestSigAction"; }
|
||||
|
||||
struct KernelSigaction {
|
||||
__sighandler_t handler;
|
||||
unsigned long flags;
|
||||
void (*restorer)();
|
||||
char unused[1024];
|
||||
};
|
||||
|
||||
#if defined(__x86_64__)
|
||||
extern "C" void restorer();
|
||||
asm("restorer:mov $15,%rax\nsyscall");
|
||||
#endif
|
||||
|
||||
int InternalSigaction(int sig, KernelSigaction *act, KernelSigaction *oact) {
|
||||
if (act) {
|
||||
#if defined(__x86_64__)
|
||||
act->flags |= 0x04000000;
|
||||
act->restorer = &restorer;
|
||||
#endif
|
||||
}
|
||||
return syscall(__NR_rt_sigaction, sig, act, oact, NSIG / 8);
|
||||
}
|
||||
|
||||
struct KernelSigaction sigact = {};
|
||||
|
||||
static void Init() {
|
||||
int res = InternalSigaction(SIGSEGV, nullptr, &sigact);
|
||||
assert(res >= 0);
|
||||
assert(sigact.handler == SIG_DFL || sigact.handler == SIG_IGN);
|
||||
#if defined(TEST_INSTALL_SIG_HANDLER)
|
||||
sigact = {};
|
||||
sigact.handler = &SigHandler;
|
||||
res = InternalSigaction(SIGSEGV, &sigact, nullptr);
|
||||
assert(res >= 0);
|
||||
#elif defined(TEST_INSTALL_SIG_ACTION)
|
||||
sigact = {};
|
||||
sigact.flags = SA_SIGINFO | SA_NODEFER;
|
||||
sigact.handler = (__sighandler_t)&SigAction;
|
||||
res = InternalSigaction(SIGSEGV, &sigact, nullptr);
|
||||
assert(res >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((section(".preinit_array"), used))
|
||||
void (*__local_test_preinit)(void) = Init;
|
||||
|
||||
bool ShouldAsanInstallHandlers() {
|
||||
#if defined(TEST_INSTALL_SIG_HANDLER) || defined(TEST_INSTALL_SIG_ACTION)
|
||||
return !strcmp(getenv("ASAN_OPTIONS"), "handle_segv=2");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
KernelSigaction sigact_asan = {};
|
||||
InternalSigaction(SIGSEGV, nullptr, &sigact_asan);
|
||||
|
||||
assert(sigact_asan.handler != SIG_DFL);
|
||||
assert(sigact_asan.handler != SIG_IGN);
|
||||
assert(ShouldAsanInstallHandlers() ==
|
||||
(sigact_asan.handler != sigact.handler));
|
||||
|
||||
raise(SIGSEGV);
|
||||
printf("%s\n", handler);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// CHECK-NOT: TestSig
|
||||
// CHECK: ASAN:DEADLYSIGNAL
|
||||
|
||||
// CHECK-HANDLER-NOT: ASAN:DEADLYSIGNAL
|
||||
// CHECK-HANDLER: TestSigHandler
|
||||
|
||||
// CHECK-ACTION-NOT: ASAN:DEADLYSIGNAL
|
||||
// CHECK-ACTION: TestSigAction
|
@ -14,17 +14,15 @@ int main() {
|
||||
|
||||
if (unshare(CLONE_NEWUSER)) {
|
||||
printf("unshare failed\n");
|
||||
abort();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// remove access to /proc/self/maps
|
||||
if (chroot("/tmp")) {
|
||||
printf("chroot failed\n");
|
||||
abort();
|
||||
return 2;
|
||||
}
|
||||
|
||||
*(volatile int*)0x42 = 0;
|
||||
// CHECK: AddressSanitizer: SEGV on unknown address 0x000000000042
|
||||
// CHECK-NOT: AddressSanitizer CHECK failed
|
||||
// CHECK: SUMMARY: AddressSanitizer: SEGV
|
||||
// CHECK-NOT: CHECK failed
|
||||
}
|
||||
|
@ -1,8 +1,14 @@
|
||||
// Regression test for
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=180
|
||||
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
|
||||
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
|
||||
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@ -22,10 +28,14 @@ void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
|
||||
printf("Invalid signum");
|
||||
exit(1);
|
||||
}
|
||||
if (original_sigaction.sa_flags | SA_SIGINFO)
|
||||
original_sigaction.sa_sigaction(signum, siginfo, context);
|
||||
else
|
||||
original_sigaction.sa_handler(signum);
|
||||
if (original_sigaction.sa_flags | SA_SIGINFO) {
|
||||
if (original_sigaction.sa_sigaction)
|
||||
original_sigaction.sa_sigaction(signum, siginfo, context);
|
||||
} else {
|
||||
if (original_sigaction.sa_handler)
|
||||
original_sigaction.sa_handler(signum);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int DoSEGV() {
|
||||
@ -33,27 +43,38 @@ int DoSEGV() {
|
||||
return *x;
|
||||
}
|
||||
|
||||
int InstallHandler(int signum, struct sigaction *original_sigaction) {
|
||||
bool InstallHandler(int signum, struct sigaction *original_sigaction) {
|
||||
struct sigaction user_sigaction;
|
||||
user_sigaction.sa_sigaction = User_OnSIGSEGV;
|
||||
user_sigaction.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(signum, &user_sigaction, original_sigaction)) {
|
||||
perror("sigaction");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite
|
||||
// 32-bit Darwin triggers SIGBUS instead.
|
||||
if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv)) return 1;
|
||||
if (InstallHandler(SIGBUS, &original_sigaction_sigbus)) return 1;
|
||||
fprintf(stderr, "User sigaction installed\n");
|
||||
if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv) &&
|
||||
InstallHandler(SIGBUS, &original_sigaction_sigbus)) {
|
||||
fprintf(stderr, "User sigaction installed\n");
|
||||
}
|
||||
return DoSEGV();
|
||||
}
|
||||
|
||||
// CHECK: User sigaction installed
|
||||
// CHECK-NEXT: User sigaction called
|
||||
// CHECK-NEXT: ASAN:DEADLYSIGNAL
|
||||
// CHECK: AddressSanitizer: SEGV on unknown address
|
||||
// CHECK0-NOT: ASAN:DEADLYSIGNAL
|
||||
// CHECK0-NOT: AddressSanitizer: SEGV on unknown address
|
||||
// CHECK0: User sigaction installed
|
||||
// CHECK0-NEXT: User sigaction called
|
||||
|
||||
// CHECK1: User sigaction installed
|
||||
// CHECK1-NEXT: User sigaction called
|
||||
// CHECK1-NEXT: ASAN:DEADLYSIGNAL
|
||||
// CHECK1: AddressSanitizer: SEGV on unknown address
|
||||
|
||||
// CHECK2-NOT: User sigaction called
|
||||
// CHECK2: User sigaction installed
|
||||
// CHECK2-NEXT: ASAN:DEADLYSIGNAL
|
||||
// CHECK2: AddressSanitizer: SEGV on unknown address
|
||||
|
@ -1,9 +1,6 @@
|
||||
// RUN: %clangxx_asan -O0 %s -pthread -o %t && %run %t
|
||||
// RUN: %clangxx_asan -O2 %s -pthread -o %t && %run %t
|
||||
// REQUIRES: stable-runtime
|
||||
// UNSUPPORTED: powerpc64le
|
||||
// FIXME: This test occasionally fails on powerpc64 LE possibly starting with
|
||||
// r279664. Re-enable the test once the problem(s) have been fixed.
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
@ -4,6 +4,7 @@
|
||||
// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// UNSUPPORTED: darwin
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -4,7 +4,7 @@
|
||||
// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// UNSUPPORTED: android
|
||||
// UNSUPPORTED: android,darwin
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -5,6 +5,7 @@
|
||||
// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// XFAIL: android
|
||||
// UNSUPPORTED: darwin
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -1,6 +1,8 @@
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// UNSUPPORTED: darwin
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
@ -13,34 +13,25 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern uint64_t __bswapdi2(uint64_t);
|
||||
|
||||
#if __arm__
|
||||
int test__bswapdi2(uint64_t a, uint64_t expected)
|
||||
{
|
||||
uint64_t actual = __bswapdi2(a);
|
||||
if (actual != expected)
|
||||
printf("error in test__bswapsi2(0x%0llX) = 0x%0llX, expected 0x%0llX\n",
|
||||
a, actual, expected);
|
||||
return actual != expected;
|
||||
int test__bswapdi2(uint64_t a, uint64_t expected) {
|
||||
uint64_t actual = __bswapdi2(a);
|
||||
if (actual != expected)
|
||||
printf("error in test__bswapsi2(0x%0llX) = 0x%0llX, expected 0x%0llX\n", a,
|
||||
actual, expected);
|
||||
return actual != expected;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#if __arm__
|
||||
if (test__bswapdi2(0x123456789ABCDEF0LL, 0xF0DEBC9A78563412LL))
|
||||
return 1;
|
||||
if (test__bswapdi2(0x0000000100000002LL, 0x0200000001000000LL))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
int main() {
|
||||
if (test__bswapdi2(0x123456789ABCDEF0LL, 0xF0DEBC9A78563412LL))
|
||||
return 1;
|
||||
if (test__bswapdi2(0x0000000100000002LL, 0x0200000001000000LL))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,34 +13,25 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern uint32_t __bswapsi2(uint32_t);
|
||||
|
||||
#if __arm__
|
||||
int test__bswapsi2(uint32_t a, uint32_t expected)
|
||||
{
|
||||
uint32_t actual = __bswapsi2(a);
|
||||
if (actual != expected)
|
||||
printf("error in test__bswapsi2(0x%0X) = 0x%0X, expected 0x%0X\n",
|
||||
a, actual, expected);
|
||||
return actual != expected;
|
||||
int test__bswapsi2(uint32_t a, uint32_t expected) {
|
||||
uint32_t actual = __bswapsi2(a);
|
||||
if (actual != expected)
|
||||
printf("error in test__bswapsi2(0x%0X) = 0x%0X, expected 0x%0X\n", a,
|
||||
actual, expected);
|
||||
return actual != expected;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#if __arm__
|
||||
if (test__bswapsi2(0x12345678, 0x78563412))
|
||||
return 1;
|
||||
if (test__bswapsi2(0x00000001, 0x01000000))
|
||||
return 1;
|
||||
#else
|
||||
printf("skipped\n");
|
||||
#endif
|
||||
return 0;
|
||||
int main() {
|
||||
if (test__bswapsi2(0x12345678, 0x78563412))
|
||||
return 1;
|
||||
if (test__bswapsi2(0x00000001, 0x01000000))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
97
test/lsan/TestCases/many_tls_keys.cc
Normal file
97
test/lsan/TestCases/many_tls_keys.cc
Normal file
@ -0,0 +1,97 @@
|
||||
// Test that lsan handles tls correctly for many threads
|
||||
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
|
||||
// RUN: %clangxx_lsan %s -DUSE_THREAD -o %t-thread
|
||||
// RUN: %clangxx_lsan %s -DUSE_PTHREAD -o %t-pthread
|
||||
// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t-thread 2>&1 | FileCheck %s
|
||||
// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t-thread 2>&1
|
||||
// RUN: %env_lsan_opts="" %run %t-thread 2>&1
|
||||
// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t-pthread 2>&1 | FileCheck %s
|
||||
// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t-pthread 2>&1
|
||||
// RUN: %env_lsan_opts="" %run %t-pthread 2>&1
|
||||
|
||||
// Patch r303906 did not fix all the problems.
|
||||
// UNSUPPORTED: arm-linux,armhf-linux
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const int NUM_THREADS = 10;
|
||||
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
int finished = 0;
|
||||
|
||||
#if USE_THREAD
|
||||
__thread void *ptr1;
|
||||
__thread void *ptr2;
|
||||
__thread void *ptr3;
|
||||
__thread void *ptr4;
|
||||
__thread void *ptr5;
|
||||
|
||||
void alloc() {
|
||||
ptr1 = malloc(1111);
|
||||
ptr2 = malloc(2222);
|
||||
ptr3 = malloc(3333);
|
||||
ptr4 = malloc(4444);
|
||||
ptr5 = malloc(5555);
|
||||
}
|
||||
|
||||
#elif USE_PTHREAD
|
||||
// We won't be able to create the maximum number of keys, due to other users
|
||||
// of the tls, but we'll use as many keys as we can before failing to create
|
||||
// a new key.
|
||||
pthread_key_t keys[PTHREAD_KEYS_MAX];
|
||||
static const int PTHREAD_KEY_INVALID = 0xffffffff;
|
||||
|
||||
void alloc() {
|
||||
for (int i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
void *ptr = malloc(123);
|
||||
if ((keys[i] == PTHREAD_KEY_INVALID) || pthread_setspecific(keys[i], ptr)) {
|
||||
free(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pthread_destructor(void *arg) {
|
||||
assert(0 && "pthread destructors shouldn't be called");
|
||||
}
|
||||
#endif
|
||||
|
||||
void *thread_start(void *arg) {
|
||||
alloc();
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
finished++;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
// don't exit, to intentionally leak tls data
|
||||
while (1)
|
||||
sleep(100);
|
||||
}
|
||||
|
||||
int main() {
|
||||
#if USE_PTHREAD
|
||||
for (int i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if (pthread_key_create(&keys[i], pthread_destructor)) {
|
||||
keys[i] = PTHREAD_KEY_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_t thread[NUM_THREADS];
|
||||
for (int i = 0; i < NUM_THREADS; ++i) {
|
||||
assert(0 == pthread_create(&thread[i], 0, thread_start, 0));
|
||||
}
|
||||
// spin until all threads have finished
|
||||
while (finished < NUM_THREADS)
|
||||
sleep(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// CHECK: LeakSanitizer: detected memory leaks
|
||||
// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
|
@ -8,8 +8,12 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// On powerpc64be semval_t must be 64 bits even with "old" versions of glibc.
|
||||
#if __PPC64__ && __BIG_ENDIAN__
|
||||
typedef uint64_t semval_t;
|
||||
|
||||
// This condition needs to correspond to __HAVE_64B_ATOMICS macro in glibc.
|
||||
#if (defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \
|
||||
#elif (defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \
|
||||
defined(__s390x__) || defined(__sparc64__) || defined(__alpha__) || \
|
||||
defined(__ia64__) || defined(__m68k__)) && __GLIBC_PREREQ(2, 21)
|
||||
typedef uint64_t semval_t;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" ASAN_OPTIONS="handle_segv=0 allow_user_segv_handler=1" %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" ASAN_OPTIONS="handle_segv=0" %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// JVM uses SEGV to preempt threads. All threads do a load from a known address
|
||||
// periodically. When runtime needs to preempt threads, it unmaps the page.
|
||||
|
@ -6,7 +6,9 @@ int main() {
|
||||
// CHECKU: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int'
|
||||
// CHECKU-NOT: cast to an unsigned
|
||||
-unsigned(-0x7fffffff - 1); // ok
|
||||
// CHECKS: negate-overflow.cpp:[[@LINE+2]]:10: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
|
||||
// CHECKS: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
|
||||
// CHECKU-NOT: runtime error
|
||||
return -(-0x7fffffff - 1);
|
||||
-(-0x7fffffff - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user