From 1b3f1014cef7e8fe3b532dae88d91a1bf3a6a73f Mon Sep 17 00:00:00 2001 From: Filipe Cabecinhas Date: Tue, 14 Mar 2017 10:26:37 +0000 Subject: Some ASan bots (AArch64 at least) use SEGV for a unit test error instead of SIGBUS git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297728 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7bc230afa..425e7fc9c 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -945,7 +945,7 @@ TEST(AddressSanitizer, ShadowGapTest) { char *addr = (char*)0x0000100000080000; # endif #endif - EXPECT_DEATH(*addr = 1, "AddressSanitizer: BUS on unknown"); + EXPECT_DEATH(*addr = 1, "AddressSanitizer: (SEGV|BUS) on unknown"); } #endif // ASAN_NEEDS_SEGV -- cgit v1.2.1 From eac3043502e263e5140f12e7b2ed655aa51e9f9d Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 14 Mar 2017 16:32:27 +0000 Subject: [ubsan] Add diagnostic handlers for nullability errors Add 'nullability_arg' and 'nullability_return' diagnostic handlers, and also add a TypeCheckKind for null assignments to _Nonnull. With this in place, we can update clang to use the nicer handlers for nullability diagnostics. The alternative to this approach is to update the existing 'nonnull_arg' and 'nonnull_return' handlers to accept a boolean parameter. However, versioning the existing handlers would cause code size bloat, and the complexity cost of introducing new handlers into the runtime is low. I will add tests for this, and all of -fsanitize=nullability, into check-ubsan once the clang side of the changes is in. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297748 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 51 +++++++++++++++++++++++++++++++++++---------- lib/ubsan/ubsan_handlers.h | 8 +++++-- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 6ffffae7b..4e025a8dd 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -38,7 +38,7 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { const char *TypeCheckKinds[] = { "load of", "store to", "reference binding to", "member access within", "member call on", "constructor call on", "downcast of", "downcast of", - "upcast of", "cast to virtual base of"}; + "upcast of", "cast to virtual base of", "_Nonnull binding to"}; } static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, @@ -472,7 +472,8 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort( Die(); } -static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { +static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts, + bool IsAttr) { SourceLocation Loc = Data->Loc.acquire(); ErrorType ET = ErrorType::InvalidNullReturn; @@ -484,21 +485,35 @@ static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { Diag(Loc, DL_Error, "null pointer returned from function declared to never " "return null"); if (!Data->AttrLoc.isInvalid()) - Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); + Diag(Data->AttrLoc, DL_Note, "%0 specified here") + << (IsAttr ? "returns_nonnull attribute" + : "_Nonnull return type annotation"); } void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { GET_REPORT_OPTIONS(false); - handleNonNullReturn(Data, Opts); + handleNonNullReturn(Data, Opts, true); } void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { GET_REPORT_OPTIONS(true); - handleNonNullReturn(Data, Opts); + handleNonNullReturn(Data, Opts, true); Die(); } -static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { +void __ubsan::__ubsan_handle_nullability_return(NonNullReturnData *Data) { + GET_REPORT_OPTIONS(false); + handleNonNullReturn(Data, Opts, false); +} + +void __ubsan::__ubsan_handle_nullability_return_abort(NonNullReturnData *Data) { + GET_REPORT_OPTIONS(true); + handleNonNullReturn(Data, Opts, false); + Die(); +} + +static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts, + bool IsAttr) { SourceLocation Loc = Data->Loc.acquire(); ErrorType ET = ErrorType::InvalidNullArgument; @@ -507,20 +522,34 @@ static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { ScopedReport R(Opts, Loc, ET); - Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " - "never be null") << Data->ArgIndex; + Diag(Loc, DL_Error, + "null pointer passed as argument %0, which is declared to " + "never be null") + << Data->ArgIndex; if (!Data->AttrLoc.isInvalid()) - Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); + Diag(Data->AttrLoc, DL_Note, "%0 specified here") + << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation"); } void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { GET_REPORT_OPTIONS(false); - handleNonNullArg(Data, Opts); + handleNonNullArg(Data, Opts, true); } void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { GET_REPORT_OPTIONS(true); - handleNonNullArg(Data, Opts); + handleNonNullArg(Data, Opts, true); + Die(); +} + +void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) { + GET_REPORT_OPTIONS(false); + handleNonNullArg(Data, Opts, false); +} + +void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { + GET_REPORT_OPTIONS(true); + handleNonNullArg(Data, Opts, false); Die(); } diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 350eb91d1..5857bc249 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -136,8 +136,10 @@ struct NonNullReturnData { SourceLocation AttrLoc; }; -/// \brief Handle returning null from function with returns_nonnull attribute. +/// \brief Handle returning null from function with the returns_nonnull +/// attribute, or a return type annotated with _Nonnull. RECOVERABLE(nonnull_return, NonNullReturnData *Data) +RECOVERABLE(nullability_return, NonNullReturnData *Data) struct NonNullArgData { SourceLocation Loc; @@ -145,8 +147,10 @@ struct NonNullArgData { int ArgIndex; }; -/// \brief Handle passing null pointer to function with nonnull attribute. +/// \brief Handle passing null pointer to a function parameter with the nonnull +/// attribute, or a _Nonnull type annotation. RECOVERABLE(nonnull_arg, NonNullArgData *Data) +RECOVERABLE(nullability_arg, NonNullArgData *Data) /// \brief Known CFI check kinds. /// Keep in sync with the enum of the same name in CodeGenFunction.h -- cgit v1.2.1 From d112f65e1dd555f069e8f3e33ab3dafbacb5435b Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 14 Mar 2017 16:36:03 +0000 Subject: [ubsan] Add nullability handlers to interface file git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297749 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_interface.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 75f080d15..0e43ebc68 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -30,6 +30,10 @@ INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg) INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg_abort) INTERFACE_FUNCTION(__ubsan_handle_nonnull_return) INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_abort) +INTERFACE_FUNCTION(__ubsan_handle_nullability_arg) +INTERFACE_FUNCTION(__ubsan_handle_nullability_arg_abort) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds) -- cgit v1.2.1 From 38d71b5b496882878eed03bb3f741af2797fa83c Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 14 Mar 2017 17:53:37 +0000 Subject: [compiler-rt][builtins] __isOSVersionAtLeast should load CoreFoundation symbols dynamically The CoreFoundation symbols uses by __isOSVersionAtLeast should be loaded at runtime to ensure that the programs that don't use @available won't have to be linked to CoreFoundation. The Clang frontend IRGen library will need to emit a CoreFoundation symbol when @available is used to ensure that programs that actually use @available are linked to CoreFoundation. rdar://31039554 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297760 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/os_version_check.c | 85 +++++++++++++++++----- .../os_version_check_test_no_core_foundation.c | 12 +++ 2 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c index b36ae546e..fd8a96ae2 100644 --- a/lib/builtins/os_version_check.c +++ b/lib/builtins/os_version_check.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,55 @@ static dispatch_once_t DispatchOnceCounter; /* Find and parse the SystemVersion.plist file. */ static void parseSystemVersionPList(void *Unused) { (void)Unused; + /* Load CoreFoundation dynamically */ + const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull"); + if (!NullAllocator) + return; + const CFAllocatorRef kCFAllocatorNull = + *(const CFAllocatorRef *)NullAllocator; + typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc = + (typeof(CFDataCreateWithBytesNoCopy) *)dlsym( + RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy"); + if (!CFDataCreateWithBytesNoCopyFunc) + return; + typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc = + (typeof(CFPropertyListCreateWithData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateWithData"); + /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it + * will be NULL on earlier OS versions. */ + typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc = + (typeof(CFPropertyListCreateFromXMLData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateFromXMLData"); + /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it + * might be NULL in future OS versions. */ + if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc) + return; + typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc = + (typeof(CFStringCreateWithCStringNoCopy) *)dlsym( + RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy"); + if (!CFStringCreateWithCStringNoCopyFunc) + return; + typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc = + (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT, + "CFDictionaryGetValue"); + if (!CFDictionaryGetValueFunc) + return; + typeof(CFGetTypeID) *CFGetTypeIDFunc = + (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID"); + if (!CFGetTypeIDFunc) + return; + typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc = + (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); + if (!CFStringGetTypeIDFunc) + return; + typeof(CFStringGetCString) *CFStringGetCStringFunc = + (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString"); + if (!CFStringGetCStringFunc) + return; + typeof(CFRelease) *CFReleaseFunc = + (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease"); + if (!CFReleaseFunc) + return; char *PListPath = "/System/Library/CoreServices/SystemVersion.plist"; @@ -67,40 +117,41 @@ static void parseSystemVersionPList(void *Unused) { /* Get the file buffer into CF's format. We pass in a null allocator here * * because we free PListBuf ourselves */ - FileContentsRef = CFDataCreateWithBytesNoCopy( + FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)( NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull); if (!FileContentsRef) goto Fail; - if (&CFPropertyListCreateWithData) - PListRef = CFPropertyListCreateWithData( + if (CFPropertyListCreateWithDataFunc) + PListRef = (*CFPropertyListCreateWithDataFunc)( NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL); - else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - PListRef = CFPropertyListCreateFromXMLData(NULL, FileContentsRef, - kCFPropertyListImmutable, NULL); -#pragma clang diagnostic pop - } + else + PListRef = (*CFPropertyListCreateFromXMLDataFunc)( + NULL, FileContentsRef, kCFPropertyListImmutable, NULL); if (!PListRef) goto Fail; - CFTypeRef OpaqueValue = - CFDictionaryGetValue(PListRef, CFSTR("ProductVersion")); - if (!OpaqueValue || CFGetTypeID(OpaqueValue) != CFStringGetTypeID()) + CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)( + NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull); + if (!ProductVersion) + goto Fail; + CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion); + (*CFReleaseFunc)(ProductVersion); + if (!OpaqueValue || + (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)()) goto Fail; char VersionStr[32]; - if (!CFStringGetCString((CFStringRef)OpaqueValue, VersionStr, - sizeof(VersionStr), kCFStringEncodingUTF8)) + if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr, + sizeof(VersionStr), kCFStringEncodingUTF8)) goto Fail; sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor); Fail: if (PListRef) - CFRelease(PListRef); + (*CFReleaseFunc)(PListRef); if (FileContentsRef) - CFRelease(FileContentsRef); + (*CFReleaseFunc)(FileContentsRef); free(PListBuf); fclose(PropertyList); } diff --git a/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c new file mode 100644 index 000000000..4e0da35cd --- /dev/null +++ b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c @@ -0,0 +1,12 @@ +// RUN: %clang %s -o %t -mmacosx-version-min=10.5 +// RUN: %run %t + +int __isOSVersionAtLeast(int Major, int Minor, int Subminor); + +int main() { + // When CoreFoundation isn't linked, we expect the system version to be 0, 0, + // 0. + if (__isOSVersionAtLeast(1, 0, 0)) + return 1; + return 0; +} -- cgit v1.2.1 From 622ea83a03926ee1f33810b7b3ec32f5a27554da Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 14 Mar 2017 18:18:14 +0000 Subject: After rL297370 and rL297383, instead of a platform check, explicitly check for the existence of RTLD_DEEPBIND, since this constant is only supported for glibc >= 2.3.4. This fixes builds for FreeBSD and other platforms that do not have RTLD_DEEPBIND. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297763 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 46dd0858a..24707c74d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1463,7 +1463,7 @@ void MaybeReexec() { void PrintModuleMap() { } void CheckNoDeepBind(const char *filename, int flag) { -#if !SANITIZER_ANDROID +#ifdef RTLD_DEEPBIND if (flag & RTLD_DEEPBIND) { Report( "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" -- cgit v1.2.1 From 625d95f037d24b12f4d4e626a329d27cf10c0f1c Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 14 Mar 2017 19:33:44 +0000 Subject: [cfi] Add test for type metadata split issue. https://reviews.llvm.org/D30716 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297771 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/bad-split.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/cfi/bad-split.cpp diff --git a/test/cfi/bad-split.cpp b/test/cfi/bad-split.cpp new file mode 100644 index 000000000..2f3bef948 --- /dev/null +++ b/test/cfi/bad-split.cpp @@ -0,0 +1,19 @@ +// GlobalSplit used to lose type metadata for classes with virtual bases but no virtual methods. +// RUN: %clangxx_cfi -o %t1 %s && %t1 + +struct Z { +}; + +struct ZZ : public virtual Z { +}; + +struct A : public ZZ { +}; + +struct B : public A { +}; + +int main() { + A* a = new B(); + B *b = (B*)a; +} -- cgit v1.2.1 From 69dc77e9e5a42155b462ec0393f235b9cd9157e2 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 14 Mar 2017 20:02:42 +0000 Subject: [cfi] Disable bad-split test on win32. It appears that the fix only helped Itanium ABI. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297775 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/bad-split.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cfi/bad-split.cpp b/test/cfi/bad-split.cpp index 2f3bef948..53504bd27 100644 --- a/test/cfi/bad-split.cpp +++ b/test/cfi/bad-split.cpp @@ -1,6 +1,8 @@ // GlobalSplit used to lose type metadata for classes with virtual bases but no virtual methods. // RUN: %clangxx_cfi -o %t1 %s && %t1 +// UNSUPPORTED: win32 + struct Z { }; -- cgit v1.2.1 From 13cc5fb606cbe7a2303307ccb8b0e5865179c5a3 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 14 Mar 2017 23:48:37 +0000 Subject: [msan] Intercept wcsncpy, wcsnlen. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297793 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 21 +++++++++++++++++++++ test/msan/wcsncpy.cc | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/msan/wcsncpy.cc diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 6447bb1b2..f3d5f4a09 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -580,6 +580,13 @@ INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { return res; } +INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { + ENSURE_MSAN_INITED(); + SIZE_T res = REAL(wcsnlen)(s, n); + CHECK_UNPOISONED(s, sizeof(wchar_t) * Min(res + 1, n)); + return res; +} + // wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { ENSURE_MSAN_INITED(); @@ -597,6 +604,18 @@ INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { return res; } +INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, + SIZE_T n) { // NOLINT + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = REAL(wcsnlen)(src, n); + if (copy_size < n) copy_size++; // trailing \0 + wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT + CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack); + __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t)); + return res; +} + // wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n); INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { ENSURE_MSAN_INITED(); @@ -1565,8 +1584,10 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(mbtowc); INTERCEPT_FUNCTION(mbrtowc); INTERCEPT_FUNCTION(wcslen); + INTERCEPT_FUNCTION(wcsnlen); INTERCEPT_FUNCTION(wcschr); INTERCEPT_FUNCTION(wcscpy); + INTERCEPT_FUNCTION(wcsncpy); INTERCEPT_FUNCTION(wcscmp); INTERCEPT_FUNCTION(getenv); INTERCEPT_FUNCTION(setenv); diff --git a/test/msan/wcsncpy.cc b/test/msan/wcsncpy.cc new file mode 100644 index 000000000..8f809697e --- /dev/null +++ b/test/msan/wcsncpy.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out + +#include +#include + +#include + +int main() { + const wchar_t *s = L"abc"; + assert(wcslen(s) == 3); + + wchar_t s2[5]; + assert(wcsncpy(s2, s, 3) == s2); + assert(__msan_test_shadow(&s2, 5 * sizeof(wchar_t)) == 3 * sizeof(wchar_t)); + assert(wcsncpy(s2, s, 5) == s2); + assert(__msan_test_shadow(&s2, 5 * sizeof(wchar_t)) == -1); + + wchar_t s3[5]; + assert(wcsncpy(s3, s, 2) == s3); + assert(__msan_test_shadow(&s3, 5 * sizeof(wchar_t)) == 2 * sizeof(wchar_t)); + + __msan_allocated_memory(&s2[1], sizeof(wchar_t)); + wchar_t s4[5]; + assert(wcsncpy(s4, s2, 3) == s4); + __msan_check_mem_is_initialized(&s4, sizeof(s4)); +} +// CHECK: Uninitialized bytes in __msan_check_mem_is_initialized +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +// CHECK: in main {{.*}}wcsncpy.cc:26 + +// CHECK: Uninitialized value was stored to memory at +// CHECK: in wcsncpy +// CHECK: in main {{.*}}wcsncpy.cc:25 + +// CHECK: Memory was marked as uninitialized +// CHECK: in __msan_allocated_memory +// CHECK: in main {{.*}}wcsncpy.cc:23 -- cgit v1.2.1 From 56deed03935538bc30e82aadd3f185ae2024343d Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 14 Mar 2017 23:49:12 +0000 Subject: Fix a build break with xray Summary: Building compiler-rt with clang 3.7 broken, could not find mkstemp Reviewers: dberris, bkramer Reviewed By: dberris Differential Revision: https://reviews.llvm.org/D30389 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297794 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_utils.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/xray_utils.cc b/lib/xray/xray_utils.cc index 69e7b98fe..5d6390c80 100644 --- a/lib/xray/xray_utils.cc +++ b/lib/xray/xray_utils.cc @@ -15,6 +15,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "xray_defs.h" #include "xray_flags.h" +#include #include #include #include -- cgit v1.2.1 From 438d9c8805b50d38e0a0f5dda42d30fe286dde70 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 15 Mar 2017 02:28:00 +0000 Subject: [XRay][compiler-rt] Support TSC emulation even for x86_64 Summary: Use TSC emulation in cases where RDTSCP isn't available on the host running an XRay instrumented binary. We can then fall back into emulation instead of not even installing XRay's runtime functionality. We only do this for now in the naive/basic logging implementation, but should be useful in even FDR mode. Should fix http://llvm.org/PR32148. Reviewers: pelikan, rnk, sdardis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D30677 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297800 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_inmemory_log.cc | 43 ++++++++++++++++++++++++++++++++----------- lib/xray/xray_tsc.h | 8 +++++--- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc index fd4f54931..cdaa6d1b5 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_inmemory_log.cc @@ -77,7 +77,6 @@ using namespace __xray; static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { int F = getLogFD(); - auto TSCFrequency = getTSCFrequency(); if (F == -1) return -1; // Since we're here, we get to write the header. We set it up so that the @@ -86,7 +85,9 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { XRayFileHeader Header; Header.Version = 1; Header.Type = FileTypes::NAIVE_LOG; - Header.CycleFrequency = TSCFrequency; + Header.CycleFrequency = probeRequiredCPUFeatures() + ? getTSCFrequency() + : __xray::NanosecondsPerSecond; // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc' // before setting the values in the header. @@ -97,8 +98,9 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { return F; } -void __xray_InMemoryRawLog(int32_t FuncId, - XRayEntryType Type) XRAY_NEVER_INSTRUMENT { +template +void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, + RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT { using Buffer = std::aligned_storage::type; static constexpr size_t BuffLen = 1024; @@ -115,7 +117,7 @@ void __xray_InMemoryRawLog(int32_t FuncId, // through a pointer offset. auto &R = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer)[Offset]; R.RecordType = RecordTypes::NORMAL; - R.TSC = __xray::readTSC(R.CPU); + R.TSC = ReadTSC(R.CPU); R.TId = TId; R.Type = Type; R.FuncId = FuncId; @@ -129,13 +131,32 @@ void __xray_InMemoryRawLog(int32_t FuncId, } } +void __xray_InMemoryRawLogRealTSC(int32_t FuncId, + XRayEntryType Type) XRAY_NEVER_INSTRUMENT { + __xray_InMemoryRawLog(FuncId, Type, __xray::readTSC); +} + +void __xray_InMemoryEmulateTSC(int32_t FuncId, + XRayEntryType Type) XRAY_NEVER_INSTRUMENT { + __xray_InMemoryRawLog(FuncId, Type, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT { + timespec TS; + int result = clock_gettime(CLOCK_REALTIME, &TS); + if (result != 0) { + Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno)); + TS = {0, 0}; + } + CPU = 0; + return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; + }); +} + static auto UNUSED Unused = [] { - if (!probeRequiredCPUFeatures()) { - Report("Required CPU features missing for XRay instrumentation, not " - "installing instrumentation hooks.\n"); - return false; - } + auto UseRealTSC = probeRequiredCPUFeatures(); + if (!UseRealTSC) + Report("WARNING: Required CPU features missing for XRay instrumentation, " + "using emulation instead.\n"); if (flags()->xray_naive_log) - __xray_set_handler(__xray_InMemoryRawLog); + __xray_set_handler(UseRealTSC ? __xray_InMemoryRawLogRealTSC + : __xray_InMemoryEmulateTSC); return true; }(); diff --git a/lib/xray/xray_tsc.h b/lib/xray/xray_tsc.h index e9ed7c735..4507564e7 100644 --- a/lib/xray/xray_tsc.h +++ b/lib/xray/xray_tsc.h @@ -13,6 +13,10 @@ #ifndef XRAY_EMULATE_TSC_H #define XRAY_EMULATE_TSC_H +namespace __xray { +static constexpr uint64_t NanosecondsPerSecond = 1000ULL * 1000 * 1000; +} + #if defined(__x86_64__) #include "xray_x86_64.inc" #elif defined(__powerpc64__) @@ -37,8 +41,6 @@ namespace __xray { -static constexpr uint64_t NanosecondsPerSecond = 1000ULL * 1000 * 1000; - inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT { @@ -60,7 +62,7 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { } // namespace __xray #else -"Unsupported CPU Architecture" +#error Target architecture is not supported. #endif // CPU architecture #endif // XRAY_EMULATE_TSC_H -- cgit v1.2.1 From ed26f06729828d91fd3d92677a35aadeb6af0a36 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 15 Mar 2017 03:12:01 +0000 Subject: [XRay] [compiler-rt] Refactor logic for xray fdr logging. NFC. Summary: Separated the IO and the thread local storage state machine of logging from the writing of log records once the contents are deterministic. Finer granularity functions are provided as inline functions in the same header such that stack does not grow due to the functions being separated. An executable utility xray_fdr_log_printer is also implemented to use the finest granularity functions to produce binary test data in the FDR format with a relatively convenient text input. For example, one can take a file with textual contents layed out in rows and feed it to the binary to generate data that llvm-xray convert can then read. This is a convenient way to build a test suite for llvm-xray convert to ensure it's robust to the fdr format. Example: $cat myFile.txt NewBuffer : { time = 2 , Tid=5} NewCPU : { CPU =1 , TSC = 123} Function : { FuncId = 5, TSCDelta = 3, EntryType = Entry } Function : { FuncId = 5, TSCDelta = 5, EntryType = Exit} TSCWrap : { TSC = 678 } Function : { FuncId = 6, TSCDelta = 0, EntryType = Entry } Function : { FuncId = 6, TSCDelta = 50, EntryType = Exit } EOB : { } $cat myFile.txt | ./bin/xray_fdr_log_printer > /tmp/binarydata.bin $./bin/llvm-xray convert -output-format=yaml -output=- /tmp/binarydata.bin yaml format comes out as expected. Reviewers: dberris, pelikan Reviewed By: dberris Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D30850 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297801 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/unit/CMakeLists.txt | 2 + lib/xray/tests/unit/xray_fdr_log_printer_tool.cc | 329 +++++++++++++++ lib/xray/xray_fdr_log_records.h | 65 +++ lib/xray/xray_fdr_logging.cc | 349 +--------------- lib/xray/xray_fdr_logging.h | 54 +-- lib/xray/xray_fdr_logging_impl.h | 486 +++++++++++++++++++++++ 6 files changed, 891 insertions(+), 394 deletions(-) create mode 100644 lib/xray/tests/unit/xray_fdr_log_printer_tool.cc create mode 100644 lib/xray/xray_fdr_log_records.h create mode 100644 lib/xray/xray_fdr_logging_impl.h diff --git a/lib/xray/tests/unit/CMakeLists.txt b/lib/xray/tests/unit/CMakeLists.txt index 62d01f239..4ed919518 100644 --- a/lib/xray/tests/unit/CMakeLists.txt +++ b/lib/xray/tests/unit/CMakeLists.txt @@ -2,3 +2,5 @@ add_xray_unittest(XRayBufferQueueTest SOURCES buffer_queue_test.cc xray_unit_test_main.cc) add_xray_unittest(XRayFDRLoggingTest SOURCES fdr_logging_test.cc xray_unit_test_main.cc) + +add_executable(xray_fdr_log_printer xray_fdr_log_printer_tool.cc) diff --git a/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc b/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc new file mode 100644 index 000000000..a4d05f200 --- /dev/null +++ b/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc @@ -0,0 +1,329 @@ +//===-- xray_fdr_log_printer_tool.cc --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// + +#include "xray_fdr_logging.h" +#include "xray_fdr_logging_impl.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "xray/xray_records.h" + +// Writes out xray fdr mode log records to stdout based on a sequence of +// formatted data read from stdin. +// +// Interprets an adhoc format of Top Level Types and parameter maps of the form: +// +// RecordType : { Parameter1 = Value, Parameter2 = value , Parameter3 = value} +// OtherRecordType : { ParameterOne = Value } +// +// Each line corresponds to a type of record written by the Xray Flight Data +// Recorder mode to a buffer. This program synthesizes records in the FDR binary +// format and writes them to std::cout. + +namespace { + +/// A crude lexer to read tokens and skip over whitespace. +class TokenReader { +public: + TokenReader() : LastDelimPresent(false), FoundEof(false), LastDelim(0) {} + std::string readToken(std::istream &Stream); + bool hasLastDelim() const { return LastDelimPresent; } + char getLastDelim() const { return LastDelim; } + void setLastDelim(char Delim) { + LastDelimPresent = true; + LastDelim = Delim; + } + void clearLastDelim() { + LastDelimPresent = false; + LastDelim = 0; + } + bool isEof() { return FoundEof; } + void setFoundEof(bool eof) { FoundEof = eof; } + +private: + bool LastDelimPresent; + bool FoundEof; + char LastDelim; +}; + +// Globally tracks whether we reached EOF and caches delimiters that qualify as +// tokens. +static TokenReader TokenReader{}; + +bool isWhitespace(char c) { + // Hardcode the whitespace characters we will not return as tokens even though + // they are token delimiters. + static const std::vector Whitespace{' ', '\n', '\t'}; + return std::find(Whitespace.begin(), Whitespace.end(), c) != Whitespace.end(); +} + +bool isDelimiter(char c) { + // Hardcode a set of token delimiters. + static const std::vector Delimiters{' ', ':', ',', '\n', + '\t', '{', '}', '='}; + return std::find(Delimiters.begin(), Delimiters.end(), c) != Delimiters.end(); +} + +std::string TokenReader::readToken(std::istream &Stream) { + // If on the last call we read a trailing delimiter that also qualifies as a + // token, return it now. + if (hasLastDelim()) { + char Token = getLastDelim(); + clearLastDelim(); + return std::string{Token}; + } + + std::stringstream Builder{}; + char c; + c = Stream.get(); + while (!isDelimiter(c) && !Stream.eof()) { + Builder << c; + c = Stream.get(); + } + + setFoundEof(Stream.eof()); + + std::string Token = Builder.str(); + + if (Token.empty()) { + // We read a whitespace delimiter only. Skip over it. + if (!isEof() && isWhitespace(c)) { + return readToken(Stream); + } else if (isWhitespace(c)) { + // We only read a whitespace delimiter. + return ""; + } else { + // We read a delimiter that matters as a token. + return std::string{c}; + } + } + + // If we found a delimiter that's a valid token. Store it to return as the + // next token. + if (!isWhitespace(c)) + setLastDelim(c); + + return Token; +} + +// Reads an expected token or dies a gruesome death. +void eatExpectedToken(std::istream &Stream, const std::string &Expected) { + std::string Token = TokenReader.readToken(Stream); + if (Token.compare(Expected) != 0) { + std::cerr << "Expecting token '" << Expected << "'. Found '" << Token + << "'.\n"; + std::exit(1); + } +} + +// Constructs a map of key value pairs from a token stream. +// Expects to read an expression of the form: +// +// { a = b, c = d, e = f} +// +// If not, the driver will crash. +std::map readMap(std::istream &Stream) { + using StrMap = std::map; + using StrVector = std::vector; + + eatExpectedToken(Stream, "{"); + StrVector TokenList{}; + + while (!TokenReader.isEof()) { + std::string CurrentToken = TokenReader.readToken(Stream); + if (CurrentToken.compare("}") == 0) { + break; + } + TokenList.push_back(CurrentToken); + if (TokenReader.isEof()) { + std::cerr << "Got EOF while building a param map.\n"; + std::exit(1); + } + } + + if (TokenList.size() == 0) { + StrMap EmptyMap{}; + return EmptyMap; + } + if (TokenList.size() % 4 != 3) { + std::cerr << "Error while building token map. Expected triples of tokens " + "in the form 'a = b' separated by commas.\n"; + std::exit(1); + } + + StrMap TokenMap{}; + std::size_t ElementIndex = 0; + for (; ElementIndex < TokenList.size(); ElementIndex += 4) { + if (TokenList[ElementIndex + 1].compare("=") != 0) { + std::cerr << "Expected an assignment when building a param map.\n"; + std::exit(1); + } + TokenMap[TokenList[ElementIndex]] = TokenList[ElementIndex + 2]; + if (ElementIndex + 3 < TokenList.size()) { + if (TokenList[ElementIndex + 3].compare(",") != 0) { + std::cerr << "Expected assignment statements to be separated by commas." + << "\n"; + std::exit(1); + } + } + } + return TokenMap; +} + +std::string getOrDie(const std::map &Lookup, + const std::string &Key) { + auto MapIter = Lookup.find(Key); + if (MapIter == Lookup.end()) { + std::cerr << "Expected key '" << Key << "'. Was not found.\n"; + std::exit(1); + } + return MapIter->second; +} + +// Reads a numeric type from a string token through the magic of +// std::stringstream. +template struct NumberParser { + static NT parse(const std::string &Input) { + NT Number = 0; + std::stringstream Stream(Input); + Stream >> Number; + return Number; + } +}; + +void writeNewBufferOrDie(std::istream &Input) { + auto TokenMap = readMap(Input); + pid_t Tid = NumberParser::parse(getOrDie(TokenMap, "Tid")); + time_t Time = NumberParser::parse(getOrDie(TokenMap, "time")); + timespec TimeSpec = {Time, 0}; + constexpr const size_t OutputSize = 32; + std::array Buffer{}; + char *MemPtr = Buffer.data(); + __xray::__xray_fdr_internal::writeNewBufferPreamble(Tid, TimeSpec, MemPtr); + std::cout.write(Buffer.data(), OutputSize); +} + +void writeNewCPUIdOrDie(std::istream &Input) { + auto TokenMap = readMap(Input); + uint16_t CPU = NumberParser::parse(getOrDie(TokenMap, "CPU")); + uint64_t TSC = NumberParser::parse(getOrDie(TokenMap, "TSC")); + constexpr const size_t OutputSize = 16; + std::array Buffer{}; + char *MemPtr = Buffer.data(); + __xray::__xray_fdr_internal::writeNewCPUIdMetadata(CPU, TSC, MemPtr); + std::cout.write(Buffer.data(), OutputSize); +} + +void writeEOBOrDie(std::istream &Input) { + auto TokenMap = readMap(Input); + constexpr const size_t OutputSize = 16; + std::array Buffer{}; + char *MemPtr = Buffer.data(); + __xray::__xray_fdr_internal::writeEOBMetadata(MemPtr); + std::cout.write(Buffer.data(), OutputSize); +} + +void writeTSCWrapOrDie(std::istream &Input) { + auto TokenMap = readMap(Input); + uint64_t TSC = NumberParser::parse(getOrDie(TokenMap, "TSC")); + constexpr const size_t OutputSize = 16; + std::array Buffer{}; + char *MemPtr = Buffer.data(); + __xray::__xray_fdr_internal::writeTSCWrapMetadata(TSC, MemPtr); + std::cout.write(Buffer.data(), OutputSize); +} + +XRayEntryType decodeEntryType(const std::string &EntryTypeStr) { + if (EntryTypeStr.compare("Entry") == 0) { + return XRayEntryType::ENTRY; + } else if (EntryTypeStr.compare("LogArgsEntry") == 0) { + return XRayEntryType::LOG_ARGS_ENTRY; + } else if (EntryTypeStr.compare("Exit") == 0) { + return XRayEntryType::EXIT; + } else if (EntryTypeStr.compare("Tail") == 0) { + return XRayEntryType::TAIL; + } + std::cerr << "Illegal entry type " << EntryTypeStr << ".\n"; + std::exit(1); +} + +void writeFunctionOrDie(std::istream &Input) { + auto TokenMap = readMap(std::cin); + int FuncId = NumberParser::parse(getOrDie(TokenMap, "FuncId")); + uint32_t TSCDelta = + NumberParser::parse(getOrDie(TokenMap, "TSCDelta")); + std::string EntryType = getOrDie(TokenMap, "EntryType"); + XRayEntryType XrayEntryType = decodeEntryType(EntryType); + constexpr const size_t OutputSize = 8; + std::array Buffer{}; + char *MemPtr = Buffer.data(); + __xray::__xray_fdr_internal::writeFunctionRecord(FuncId, TSCDelta, + XrayEntryType, MemPtr); + std::cout.write(Buffer.data(), OutputSize); +} + +} // namespace + +int main(int argc, char **argv) { + std::map> TopLevelRecordMap; + TopLevelRecordMap["NewBuffer"] = writeNewBufferOrDie; + TopLevelRecordMap["NewCPU"] = writeNewCPUIdOrDie; + TopLevelRecordMap["EOB"] = writeEOBOrDie; + TopLevelRecordMap["TSCWrap"] = writeTSCWrapOrDie; + TopLevelRecordMap["Function"] = writeFunctionOrDie; + + // Write file header + // + // (2) uint16 : version + // (2) uint16 : type + // (4) uint32 : bitfield + // (8) uint64 : cycle frequency + // (16) - : padding + uint16_t HeaderVersion = 1; + uint16_t HeaderType = 1; + uint32_t Bitfield = 3; + uint64_t CycleFreq = 42; + constexpr const size_t HeaderSize = 32; + std::array Header{}; + std::memcpy(Header.data(), &HeaderVersion, sizeof(HeaderVersion)); + std::memcpy(Header.data() + 2, &HeaderType, sizeof(HeaderType)); + std::memcpy(Header.data() + 4, &Bitfield, sizeof(Bitfield)); + std::memcpy(Header.data() + 8, &CycleFreq, sizeof(CycleFreq)); + std::cout.write(Header.data(), HeaderSize); + + std::string CurrentToken; + while (true) { + CurrentToken = TokenReader.readToken(std::cin); + if (TokenReader.isEof()) + break; + auto MapIter = TopLevelRecordMap.find(CurrentToken); + if (MapIter != TopLevelRecordMap.end()) { + eatExpectedToken(std::cin, ":"); + if (TokenReader.isEof()) { + std::cerr << "Got eof when expecting to read a map.\n"; + std::exit(1); + } + MapIter->second(std::cin); + } else { + std::cerr << "Got bad top level instruction '" << CurrentToken << "'.\n"; + std::exit(1); + } + } + return 0; +} diff --git a/lib/xray/xray_fdr_log_records.h b/lib/xray/xray_fdr_log_records.h new file mode 100644 index 000000000..36d9410d1 --- /dev/null +++ b/lib/xray/xray_fdr_log_records.h @@ -0,0 +1,65 @@ +//===-- xray_fdr_log_records.h -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a function call tracing system. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_FDR_LOG_RECORDS_H +#define XRAY_XRAY_FDR_LOG_RECORDS_H + +enum class RecordType : uint8_t { Function, Metadata }; + +// A MetadataRecord encodes the kind of record in its first byte, and have 15 +// additional bytes in the end to hold free-form data. +struct alignas(16) MetadataRecord { + // A MetadataRecord must always have a type of 1. + /* RecordType */ uint8_t Type : 1; + + // Each kind of record is represented as a 7-bit value (even though we use an + // unsigned 8-bit enum class to do so). + enum class RecordKinds : uint8_t { + NewBuffer, + EndOfBuffer, + NewCPUId, + TSCWrap, + WalltimeMarker, + }; + // Use 7 bits to identify this record type. + /* RecordKinds */ uint8_t RecordKind : 7; + char Data[15]; +} __attribute__((packed)); + +static_assert(sizeof(MetadataRecord) == 16, "Wrong size for MetadataRecord."); + +struct alignas(8) FunctionRecord { + // A FunctionRecord must always have a type of 0. + /* RecordType */ uint8_t Type : 1; + enum class RecordKinds { + FunctionEnter = 0x00, + FunctionExit = 0x01, + FunctionTailExit = 0x02, + }; + /* RecordKinds */ uint8_t RecordKind : 3; + + // We only use 28 bits of the function ID, so that we can use as few bytes as + // possible. This means we only support 2^28 (268,435,456) unique function ids + // in a single binary. + int FuncId : 28; + + // We use another 4 bytes to hold the delta between the previous entry's TSC. + // In case we've found that the distance is greater than the allowable 32 bits + // (either because we are running in a different CPU and the TSC might be + // different then), we should use a MetadataRecord before this FunctionRecord + // that will contain the full TSC for that CPU, and keep this to 0. + uint32_t TSCDelta; +} __attribute__((packed)); + +static_assert(sizeof(FunctionRecord) == 8, "Wrong size for FunctionRecord."); + +#endif // XRAY_XRAY_FDR_LOG_RECORDS_H diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index bae7d4c4d..0a1fb19f0 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file is a part of XRay, a dynamic runtime instruementation system. +// This file is a part of XRay, a dynamic runtime instrumentation system. // // Here we implement the Flight Data Recorder mode for XRay, where we use // compact structures to store records in memory as well as when writing out the @@ -31,6 +31,7 @@ #include "xray/xray_records.h" #include "xray_buffer_queue.h" #include "xray_defs.h" +#include "xray_fdr_logging_impl.h" #include "xray_flags.h" #include "xray_tsc.h" #include "xray_utils.h" @@ -49,8 +50,8 @@ std::atomic LogFlushStatus{ std::unique_ptr FDROptions; XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, - void *Options, - size_t OptionsSize) XRAY_NEVER_INSTRUMENT { + void *Options, + size_t OptionsSize) XRAY_NEVER_INSTRUMENT { assert(OptionsSize == sizeof(FDRLoggingOptions)); XRayLogInitStatus CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; if (!LoggingStatus.compare_exchange_strong( @@ -174,352 +175,16 @@ XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; } -namespace { -thread_local BufferQueue::Buffer Buffer; -thread_local char *RecordPtr = nullptr; - -void setupNewBuffer(const BufferQueue::Buffer &Buffer) XRAY_NEVER_INSTRUMENT { - RecordPtr = static_cast(Buffer.Buffer); - - static constexpr int InitRecordsCount = 2; - std::aligned_storage::type Records[InitRecordsCount]; - { - // Write out a MetadataRecord to signify that this is the start of a new - // buffer, associated with a particular thread, with a new CPU. For the - // data, we have 15 bytes to squeeze as much information as we can. At this - // point we only write down the following bytes: - // - Thread ID (pid_t, 4 bytes) - auto &NewBuffer = *reinterpret_cast(&Records[0]); - NewBuffer.Type = uint8_t(RecordType::Metadata); - NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer); - pid_t Tid = syscall(SYS_gettid); - std::memcpy(&NewBuffer.Data, &Tid, sizeof(pid_t)); - } - - // Also write the WalltimeMarker record. - { - static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes"); - auto &WalltimeMarker = *reinterpret_cast(&Records[1]); - WalltimeMarker.Type = uint8_t(RecordType::Metadata); - WalltimeMarker.RecordKind = - uint8_t(MetadataRecord::RecordKinds::WalltimeMarker); - timespec TS{0, 0}; - clock_gettime(CLOCK_MONOTONIC, &TS); - - // We only really need microsecond precision here, and enforce across - // platforms that we need 64-bit seconds and 32-bit microseconds encoded in - // the Metadata record. - int32_t Micros = TS.tv_nsec / 1000; - int64_t Seconds = TS.tv_sec; - std::memcpy(WalltimeMarker.Data, &Seconds, sizeof(Seconds)); - std::memcpy(WalltimeMarker.Data + sizeof(Seconds), &Micros, sizeof(Micros)); - } - std::memcpy(RecordPtr, Records, sizeof(MetadataRecord) * InitRecordsCount); - RecordPtr += sizeof(MetadataRecord) * InitRecordsCount; -} - -void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC) XRAY_NEVER_INSTRUMENT { - MetadataRecord NewCPUId; - NewCPUId.Type = uint8_t(RecordType::Metadata); - NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); - - // The data for the New CPU will contain the following bytes: - // - CPU ID (uint16_t, 2 bytes) - // - Full TSC (uint64_t, 8 bytes) - // Total = 12 bytes. - std::memcpy(&NewCPUId.Data, &CPU, sizeof(CPU)); - std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); - std::memcpy(RecordPtr, &NewCPUId, sizeof(MetadataRecord)); - RecordPtr += sizeof(MetadataRecord); -} - -void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { - MetadataRecord EOBMeta; - EOBMeta.Type = uint8_t(RecordType::Metadata); - EOBMeta.RecordKind = uint8_t(MetadataRecord::RecordKinds::EndOfBuffer); - // For now we don't write any bytes into the Data field. - std::memcpy(RecordPtr, &EOBMeta, sizeof(MetadataRecord)); - RecordPtr += sizeof(MetadataRecord); -} - -void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { - MetadataRecord TSCWrap; - TSCWrap.Type = uint8_t(RecordType::Metadata); - TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); - - // The data for the TSCWrap record contains the following bytes: - // - Full TSC (uint64_t, 8 bytes) - // Total = 8 bytes. - std::memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); - std::memcpy(RecordPtr, &TSCWrap, sizeof(MetadataRecord)); - RecordPtr += sizeof(MetadataRecord); -} - -constexpr auto MetadataRecSize = sizeof(MetadataRecord); -constexpr auto FunctionRecSize = sizeof(FunctionRecord); - -class ThreadExitBufferCleanup { - std::weak_ptr Buffers; - BufferQueue::Buffer &Buffer; - -public: - explicit ThreadExitBufferCleanup(std::weak_ptr BQ, - BufferQueue::Buffer &Buffer) - XRAY_NEVER_INSTRUMENT : Buffers(BQ), - Buffer(Buffer) {} - - ~ThreadExitBufferCleanup() noexcept XRAY_NEVER_INSTRUMENT { - if (RecordPtr == nullptr) - return; - - // We make sure that upon exit, a thread will write out the EOB - // MetadataRecord in the thread-local log, and also release the buffer to - // the queue. - assert((RecordPtr + MetadataRecSize) - static_cast(Buffer.Buffer) >= - static_cast(MetadataRecSize)); - if (auto BQ = Buffers.lock()) { - writeEOBMetadata(); - if (auto EC = BQ->releaseBuffer(Buffer)) - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); - return; - } - } -}; - -class RecursionGuard { - bool &Running; - const bool Valid; - -public: - explicit RecursionGuard(bool &R) : Running(R), Valid(!R) { - if (Valid) - Running = true; - } - - RecursionGuard(const RecursionGuard &) = delete; - RecursionGuard(RecursionGuard &&) = delete; - RecursionGuard &operator=(const RecursionGuard &) = delete; - RecursionGuard &operator=(RecursionGuard &&) = delete; - - explicit operator bool() const { return Valid; } - - ~RecursionGuard() noexcept { - if (Valid) - Running = false; - } -}; - -inline bool loggingInitialized() { - return LoggingStatus.load(std::memory_order_acquire) == - XRayLogInitStatus::XRAY_LOG_INITIALIZED; -} - -} // namespace - void fdrLoggingHandleArg0(int32_t FuncId, - XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { + XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { // We want to get the TSC as early as possible, so that we can check whether // we've seen this CPU before. We also do it before we load anything else, to // allow for forward progress with the scheduling. unsigned char CPU; uint64_t TSC = __xray::readTSC(CPU); - // Bail out right away if logging is not initialized yet. - if (LoggingStatus.load(std::memory_order_acquire) != - XRayLogInitStatus::XRAY_LOG_INITIALIZED) - return; - - // We use a thread_local variable to keep track of which CPUs we've already - // run, and the TSC times for these CPUs. This allows us to stop repeating the - // CPU field in the function records. - // - // We assume that we'll support only 65536 CPUs for x86_64. - thread_local uint16_t CurrentCPU = std::numeric_limits::max(); - thread_local uint64_t LastTSC = 0; - - // Make sure a thread that's ever called handleArg0 has a thread-local - // live reference to the buffer queue for this particular instance of - // FDRLogging, and that we're going to clean it up when the thread exits. - thread_local auto LocalBQ = BQ; - thread_local ThreadExitBufferCleanup Cleanup(LocalBQ, Buffer); - - // Prevent signal handler recursion, so in case we're already in a log writing - // mode and the signal handler comes in (and is also instrumented) then we - // don't want to be clobbering potentially partial writes already happening in - // the thread. We use a simple thread_local latch to only allow one on-going - // handleArg0 to happen at any given time. - thread_local bool Running = false; - RecursionGuard Guard{Running}; - if (!Guard) { - assert(Running == true && "RecursionGuard is buggy!"); - return; - } - - if (!loggingInitialized() || LocalBQ->finalizing()) { - writeEOBMetadata(); - if (auto EC = BQ->releaseBuffer(Buffer)) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); - return; - } - RecordPtr = nullptr; - } - - if (Buffer.Buffer == nullptr) { - if (auto EC = LocalBQ->getBuffer(Buffer)) { - auto LS = LoggingStatus.load(std::memory_order_acquire); - if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && - LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) - Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); - return; - } - - setupNewBuffer(Buffer); - } - - if (CurrentCPU == std::numeric_limits::max()) { - // This means this is the first CPU this thread has ever run on. We set the - // current CPU and record this as the first TSC we've seen. - CurrentCPU = CPU; - writeNewCPUIdMetadata(CPU, TSC); - } - - // Before we go setting up writing new function entries, we need to be really - // careful about the pointer math we're doing. This means we need to ensure - // that the record we are about to write is going to fit into the buffer, - // without overflowing the buffer. - // - // To do this properly, we use the following assumptions: - // - // - The least number of bytes we will ever write is 8 - // (sizeof(FunctionRecord)) only if the delta between the previous entry - // and this entry is within 32 bits. - // - The most number of bytes we will ever write is 8 + 16 = 24. This is - // computed by: - // - // sizeof(FunctionRecord) + sizeof(MetadataRecord) - // - // These arise in the following cases: - // - // 1. When the delta between the TSC we get and the previous TSC for the - // same CPU is outside of the uint32_t range, we end up having to - // write a MetadataRecord to indicate a "tsc wrap" before the actual - // FunctionRecord. - // 2. When we learn that we've moved CPUs, we need to write a - // MetadataRecord to indicate a "cpu change", and thus write out the - // current TSC for that CPU before writing out the actual - // FunctionRecord. - // 3. When we learn about a new CPU ID, we need to write down a "new cpu - // id" MetadataRecord before writing out the actual FunctionRecord. - // - // - An End-of-Buffer (EOB) MetadataRecord is 16 bytes. - // - // So the math we need to do is to determine whether writing 24 bytes past the - // current pointer leaves us with enough bytes to write the EOB - // MetadataRecord. If we don't have enough space after writing as much as 24 - // bytes in the end of the buffer, we need to write out the EOB, get a new - // Buffer, set it up properly before doing any further writing. - // - char *BufferStart = static_cast(Buffer.Buffer); - if ((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart < - static_cast(MetadataRecSize)) { - writeEOBMetadata(); - if (auto EC = LocalBQ->releaseBuffer(Buffer)) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); - return; - } - if (auto EC = LocalBQ->getBuffer(Buffer)) { - Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); - return; - } - setupNewBuffer(Buffer); - } - - // By this point, we are now ready to write at most 24 bytes (one metadata - // record and one function record). - BufferStart = static_cast(Buffer.Buffer); - assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart >= - static_cast(MetadataRecSize) && - "Misconfigured BufferQueue provided; Buffer size not large enough."); - - std::aligned_storage::type - AlignedFuncRecordBuffer; - auto &FuncRecord = - *reinterpret_cast(&AlignedFuncRecordBuffer); - FuncRecord.Type = uint8_t(RecordType::Function); - - // Only get the lower 28 bits of the function id. - FuncRecord.FuncId = FuncId & ~(0x0F << 28); - - // Here we compute the TSC Delta. There are a few interesting situations we - // need to account for: - // - // - The thread has migrated to a different CPU. If this is the case, then - // we write down the following records: - // - // 1. A 'NewCPUId' Metadata record. - // 2. A FunctionRecord with a 0 for the TSCDelta field. - // - // - The TSC delta is greater than the 32 bits we can store in a - // FunctionRecord. In this case we write down the following records: - // - // 1. A 'TSCWrap' Metadata record. - // 2. A FunctionRecord with a 0 for the TSCDelta field. - // - // - The TSC delta is representable within the 32 bits we can store in a - // FunctionRecord. In this case we write down just a FunctionRecord with - // the correct TSC delta. - // - FuncRecord.TSCDelta = 0; - if (CPU != CurrentCPU) { - // We've moved to a new CPU. - writeNewCPUIdMetadata(CPU, TSC); - } else { - // If the delta is greater than the range for a uint32_t, then we write out - // the TSC wrap metadata entry with the full TSC, and the TSC for the - // function record be 0. - auto Delta = LastTSC - TSC; - if (Delta > (1ULL << 32) - 1) - writeTSCWrapMetadata(TSC); - else - FuncRecord.TSCDelta = Delta; - } - - // We then update our "LastTSC" and "CurrentCPU" thread-local variables to aid - // us in future computations of this TSC delta value. - LastTSC = TSC; - CurrentCPU = CPU; - - switch (Entry) { - case XRayEntryType::ENTRY: - case XRayEntryType::LOG_ARGS_ENTRY: - FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); - break; - case XRayEntryType::EXIT: - FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); - break; - case XRayEntryType::TAIL: - FuncRecord.RecordKind = - uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); - break; - } - - std::memcpy(RecordPtr, &AlignedFuncRecordBuffer, sizeof(FunctionRecord)); - RecordPtr += sizeof(FunctionRecord); - - // If we've exhausted the buffer by this time, we then release the buffer to - // make sure that other threads may start using this buffer. - if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { - writeEOBMetadata(); - if (auto EC = LocalBQ->releaseBuffer(Buffer)) { - Report("Failed releasing buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); - return; - } - RecordPtr = nullptr; - } + __xray_fdr_internal::processFunctionHook(FuncId, Entry, TSC, CPU, + clock_gettime, LoggingStatus, BQ); } } // namespace __xray diff --git a/lib/xray/xray_fdr_logging.h b/lib/xray/xray_fdr_logging.h index 28c829625..93c33b417 100644 --- a/lib/xray/xray_fdr_logging.h +++ b/lib/xray/xray_fdr_logging.h @@ -14,6 +14,7 @@ #define XRAY_XRAY_FDR_LOGGING_H #include "xray/xray_log_interface.h" +#include "xray_fdr_log_records.h" // FDR (Flight Data Recorder) Mode // =============================== @@ -26,57 +27,6 @@ namespace __xray { -enum class RecordType : uint8_t { - Function, Metadata -}; - -// A MetadataRecord encodes the kind of record in its first byte, and have 15 -// additional bytes in the end to hold free-form data. -struct alignas(16) MetadataRecord { - // A MetadataRecord must always have a type of 1. - /* RecordType */ uint8_t Type : 1; - - // Each kind of record is represented as a 7-bit value (even though we use an - // unsigned 8-bit enum class to do so). - enum class RecordKinds : uint8_t { - NewBuffer, - EndOfBuffer, - NewCPUId, - TSCWrap, - WalltimeMarker, - }; - // Use 7 bits to identify this record type. - /* RecordKinds */ uint8_t RecordKind : 7; - char Data[15]; -} __attribute__((packed)); - -static_assert(sizeof(MetadataRecord) == 16, "Wrong size for MetadataRecord."); - -struct alignas(8) FunctionRecord { - // A FunctionRecord must always have a type of 0. - /* RecordType */ uint8_t Type : 1; - enum class RecordKinds { - FunctionEnter = 0x00, - FunctionExit = 0x01, - FunctionTailExit = 0x02, - }; - /* RecordKinds */ uint8_t RecordKind : 3; - - // We only use 28 bits of the function ID, so that we can use as few bytes as - // possible. This means we only support 2^28 (268,435,456) unique function ids - // in a single binary. - int FuncId : 28; - - // We use another 4 bytes to hold the delta between the previous entry's TSC. - // In case we've found that the distance is greater than the allowable 32 bits - // (either because we are running in a different CPU and the TSC might be - // different then), we should use a MetadataRecord before this FunctionRecord - // that will contain the full TSC for that CPU, and keep this to 0. - uint32_t TSCDelta; -} __attribute__((packed)); - -static_assert(sizeof(FunctionRecord) == 8, "Wrong size for FunctionRecord."); - // Options used by the FDR implementation. struct FDRLoggingOptions { bool ReportErrors = false; @@ -85,7 +35,7 @@ struct FDRLoggingOptions { // Flight Data Recorder mode implementation interfaces. XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax, - void *Options, size_t OptionsSize); + void *Options, size_t OptionsSize); XRayLogInitStatus fdrLoggingFinalize(); void fdrLoggingHandleArg0(int32_t FuncId, XRayEntryType Entry); XRayLogFlushStatus fdrLoggingFlush(); diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h new file mode 100644 index 000000000..a06b22df9 --- /dev/null +++ b/lib/xray/xray_fdr_logging_impl.h @@ -0,0 +1,486 @@ +//===-- xray_fdr_logging_impl.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Here we implement the thread local state management and record i/o for Flight +// Data Recorder mode for XRay, where we use compact structures to store records +// in memory as well as when writing out the data to files. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_FDR_LOGGING_IMPL_H +#define XRAY_XRAY_FDR_LOGGING_IMPL_H + +#include +#include +#include +#include +#include +#include + +#include "sanitizer_common/sanitizer_common.h" +#include "xray/xray_log_interface.h" +#include "xray_buffer_queue.h" +#include "xray_defs.h" +#include "xray_fdr_log_records.h" + +namespace __xray { + +/// We expose some of the state transitions when FDR logging mode is operating +/// such that we can simulate a series of log events that may occur without +/// and test with determinism without worrying about the real CPU time. +/// +/// Because the code uses thread_local allocation extensively as part of its +/// design, callers that wish to test events occuring on different threads +/// will actually have to run them on different threads. +/// +/// This also means that it is possible to break invariants maintained by +/// cooperation with xray_fdr_logging class, so be careful and think twice. +namespace __xray_fdr_internal { + +/// Writes the new buffer record and wallclock time that begin a buffer for a +/// thread to MemPtr and increments MemPtr. Bypasses the thread local state +// machine and writes directly to memory without checks. +static void writeNewBufferPreamble(pid_t Tid, timespec TS, char *&MemPtr); + +/// Write a metadata record to switch to a new CPU to MemPtr and increments +/// MemPtr. Bypasses the thread local state machine and writes directly to +/// memory without checks. +static void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, char *&MemPtr); + +/// Writes an EOB metadata record to MemPtr and increments MemPtr. Bypasses the +/// thread local state machine and writes directly to memory without checks. +static void writeEOBMetadata(char *&MemPtr); + +/// Writes a TSC Wrap metadata record to MemPtr and increments MemPtr. Bypasses +/// the thread local state machine and directly writes to memory without checks. +static void writeTSCWrapMetadata(uint64_t TSC, char *&MemPtr); + +/// Writes a Function Record to MemPtr and increments MemPtr. Bypasses the +/// thread local state machine and writes the function record directly to +/// memory. +static void writeFunctionRecord(int FuncId, uint32_t TSCDelta, + XRayEntryType EntryType, char *&MemPtr); + +/// Sets up a new buffer in thread_local storage and writes a preamble. The +/// wall_clock_reader function is used to populate the WallTimeRecord entry. +static void setupNewBuffer(const BufferQueue::Buffer &Buffer, + int (*wall_clock_reader)(clockid_t, + struct timespec *)); + +/// Called to record CPU time for a new CPU within the current thread. +static void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC); + +/// Called to close the buffer when the thread exhausts the buffer or when the +/// thread exits (via a thread local variable destructor). +static void writeEOBMetadata(); + +/// TSC Wrap records are written when a TSC delta encoding scheme overflows. +static void writeTSCWrapMetadata(uint64_t TSC); + +/// Here's where the meat of the processing happens. The writer captures +/// function entry, exit and tail exit points with a time and will create +/// TSCWrap, NewCPUId and Function records as necessary. The writer might +/// walk backward through its buffer and erase trivial functions to avoid +/// polluting the log and may use the buffer queue to obtain or release a +/// buffer. +static void +processFunctionHook(int32_t FuncId, XRayEntryType Entry, uint64_t TSC, + unsigned char CPU, + int (*wall_clock_reader)(clockid_t, struct timespec *), + const std::atomic &LoggingStatus, + const std::shared_ptr &BQ); + +//-----------------------------------------------------------------------------| +// The rest of the file is implementation. | +//-----------------------------------------------------------------------------| +// Functions are implemented in the header for inlining since we don't want | +// to grow the stack when we've hijacked the binary for logging. | +//-----------------------------------------------------------------------------| + +namespace { +thread_local BufferQueue::Buffer Buffer; +thread_local char *RecordPtr = nullptr; + +constexpr auto MetadataRecSize = sizeof(MetadataRecord); +constexpr auto FunctionRecSize = sizeof(FunctionRecord); + +class ThreadExitBufferCleanup { + std::weak_ptr Buffers; + BufferQueue::Buffer &Buffer; + +public: + explicit ThreadExitBufferCleanup(std::weak_ptr BQ, + BufferQueue::Buffer &Buffer) + XRAY_NEVER_INSTRUMENT : Buffers(BQ), + Buffer(Buffer) {} + + ~ThreadExitBufferCleanup() noexcept XRAY_NEVER_INSTRUMENT { + if (RecordPtr == nullptr) + return; + + // We make sure that upon exit, a thread will write out the EOB + // MetadataRecord in the thread-local log, and also release the buffer to + // the queue. + assert((RecordPtr + MetadataRecSize) - static_cast(Buffer.Buffer) >= + static_cast(MetadataRecSize)); + if (auto BQ = Buffers.lock()) { + writeEOBMetadata(); + if (auto EC = BQ->releaseBuffer(Buffer)) + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + EC.message().c_str()); + return; + } + } +}; + +class RecursionGuard { + bool &Running; + const bool Valid; + +public: + explicit RecursionGuard(bool &R) : Running(R), Valid(!R) { + if (Valid) + Running = true; + } + + RecursionGuard(const RecursionGuard &) = delete; + RecursionGuard(RecursionGuard &&) = delete; + RecursionGuard &operator=(const RecursionGuard &) = delete; + RecursionGuard &operator=(RecursionGuard &&) = delete; + + explicit operator bool() const { return Valid; } + + ~RecursionGuard() noexcept { + if (Valid) + Running = false; + } +}; + +static inline bool loggingInitialized( + const std::atomic &LoggingStatus) XRAY_NEVER_INSTRUMENT { + return LoggingStatus.load(std::memory_order_acquire) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED; +} + +} // namespace anonymous + +static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { + static constexpr int InitRecordsCount = 2; + std::aligned_storage::type Records[InitRecordsCount]; + { + // Write out a MetadataRecord to signify that this is the start of a new + // buffer, associated with a particular thread, with a new CPU. For the + // data, we have 15 bytes to squeeze as much information as we can. At this + // point we only write down the following bytes: + // - Thread ID (pid_t, 4 bytes) + auto &NewBuffer = *reinterpret_cast(&Records[0]); + NewBuffer.Type = uint8_t(RecordType::Metadata); + NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer); + std::memcpy(&NewBuffer.Data, &Tid, sizeof(pid_t)); + } + // Also write the WalltimeMarker record. + { + static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes"); + auto &WalltimeMarker = *reinterpret_cast(&Records[1]); + WalltimeMarker.Type = uint8_t(RecordType::Metadata); + WalltimeMarker.RecordKind = + uint8_t(MetadataRecord::RecordKinds::WalltimeMarker); + + // We only really need microsecond precision here, and enforce across + // platforms that we need 64-bit seconds and 32-bit microseconds encoded in + // the Metadata record. + int32_t Micros = TS.tv_nsec / 1000; + int64_t Seconds = TS.tv_sec; + std::memcpy(WalltimeMarker.Data, &Seconds, sizeof(Seconds)); + std::memcpy(WalltimeMarker.Data + sizeof(Seconds), &Micros, sizeof(Micros)); + } + std::memcpy(MemPtr, Records, sizeof(MetadataRecord) * InitRecordsCount); + MemPtr += sizeof(MetadataRecord) * InitRecordsCount; +} + +static inline void setupNewBuffer(const BufferQueue::Buffer &Buffer, + int (*wall_clock_reader)(clockid_t, + struct timespec *)) + XRAY_NEVER_INSTRUMENT { + RecordPtr = static_cast(Buffer.Buffer); + pid_t Tid = syscall(SYS_gettid); + timespec TS{0, 0}; + // This is typically clock_gettime, but callers have injection ability. + wall_clock_reader(CLOCK_MONOTONIC, &TS); + writeNewBufferPreamble(Tid, TS, RecordPtr); +} + +static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { + MetadataRecord NewCPUId; + NewCPUId.Type = uint8_t(RecordType::Metadata); + NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); + + // The data for the New CPU will contain the following bytes: + // - CPU ID (uint16_t, 2 bytes) + // - Full TSC (uint64_t, 8 bytes) + // Total = 12 bytes. + std::memcpy(&NewCPUId.Data, &CPU, sizeof(CPU)); + std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); + std::memcpy(MemPtr, &NewCPUId, sizeof(MetadataRecord)); + MemPtr += sizeof(MetadataRecord); +} + +static inline void writeNewCPUIdMetadata(uint16_t CPU, + uint64_t TSC) XRAY_NEVER_INSTRUMENT { + writeNewCPUIdMetadata(CPU, TSC, RecordPtr); +} + +static inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { + MetadataRecord EOBMeta; + EOBMeta.Type = uint8_t(RecordType::Metadata); + EOBMeta.RecordKind = uint8_t(MetadataRecord::RecordKinds::EndOfBuffer); + // For now we don't write any bytes into the Data field. + std::memcpy(MemPtr, &EOBMeta, sizeof(MetadataRecord)); + MemPtr += sizeof(MetadataRecord); +} + +static inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { + writeEOBMetadata(RecordPtr); +} + +static inline void writeTSCWrapMetadata(uint64_t TSC, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { + MetadataRecord TSCWrap; + TSCWrap.Type = uint8_t(RecordType::Metadata); + TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); + + // The data for the TSCWrap record contains the following bytes: + // - Full TSC (uint64_t, 8 bytes) + // Total = 8 bytes. + std::memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); + std::memcpy(MemPtr, &TSCWrap, sizeof(MetadataRecord)); + MemPtr += sizeof(MetadataRecord); +} + +static inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { + writeTSCWrapMetadata(TSC, RecordPtr); +} + +static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, + XRayEntryType EntryType, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { + std::aligned_storage::type + AlignedFuncRecordBuffer; + auto &FuncRecord = + *reinterpret_cast(&AlignedFuncRecordBuffer); + FuncRecord.Type = uint8_t(RecordType::Function); + // Only take 28 bits of the function id. + FuncRecord.FuncId = FuncId & ~(0x0F << 28); + FuncRecord.TSCDelta = TSCDelta; + + switch (EntryType) { + case XRayEntryType::ENTRY: + case XRayEntryType::LOG_ARGS_ENTRY: + FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); + break; + case XRayEntryType::EXIT: + FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); + break; + case XRayEntryType::TAIL: + FuncRecord.RecordKind = + uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); + break; + } + + std::memcpy(MemPtr, &AlignedFuncRecordBuffer, sizeof(FunctionRecord)); + MemPtr += sizeof(FunctionRecord); +} + +static inline void processFunctionHook( + int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, + int (*wall_clock_reader)(clockid_t, struct timespec *), + const std::atomic &LoggingStatus, + const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { + // Bail out right away if logging is not initialized yet. + if (LoggingStatus.load(std::memory_order_acquire) != + XRayLogInitStatus::XRAY_LOG_INITIALIZED) + return; + + // We use a thread_local variable to keep track of which CPUs we've already + // run, and the TSC times for these CPUs. This allows us to stop repeating the + // CPU field in the function records. + // + // We assume that we'll support only 65536 CPUs for x86_64. + thread_local uint16_t CurrentCPU = std::numeric_limits::max(); + thread_local uint64_t LastTSC = 0; + + // Make sure a thread that's ever called handleArg0 has a thread-local + // live reference to the buffer queue for this particular instance of + // FDRLogging, and that we're going to clean it up when the thread exits. + thread_local auto LocalBQ = BQ; + thread_local ThreadExitBufferCleanup Cleanup(LocalBQ, Buffer); + + // Prevent signal handler recursion, so in case we're already in a log writing + // mode and the signal handler comes in (and is also instrumented) then we + // don't want to be clobbering potentially partial writes already happening in + // the thread. We use a simple thread_local latch to only allow one on-going + // handleArg0 to happen at any given time. + thread_local bool Running = false; + RecursionGuard Guard{Running}; + if (!Guard) { + assert(Running == true && "RecursionGuard is buggy!"); + return; + } + + if (!loggingInitialized(LoggingStatus) || LocalBQ->finalizing()) { + writeEOBMetadata(); + if (auto EC = BQ->releaseBuffer(Buffer)) { + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + EC.message().c_str()); + return; + } + RecordPtr = nullptr; + } + + if (Buffer.Buffer == nullptr) { + if (auto EC = LocalBQ->getBuffer(Buffer)) { + auto LS = LoggingStatus.load(std::memory_order_acquire); + if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && + LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) + Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); + return; + } + + setupNewBuffer(Buffer, wall_clock_reader); + } + + if (CurrentCPU == std::numeric_limits::max()) { + // This means this is the first CPU this thread has ever run on. We set the + // current CPU and record this as the first TSC we've seen. + CurrentCPU = CPU; + writeNewCPUIdMetadata(CPU, TSC); + } + + // Before we go setting up writing new function entries, we need to be really + // careful about the pointer math we're doing. This means we need to ensure + // that the record we are about to write is going to fit into the buffer, + // without overflowing the buffer. + // + // To do this properly, we use the following assumptions: + // + // - The least number of bytes we will ever write is 8 + // (sizeof(FunctionRecord)) only if the delta between the previous entry + // and this entry is within 32 bits. + // - The most number of bytes we will ever write is 8 + 16 = 24. This is + // computed by: + // + // sizeof(FunctionRecord) + sizeof(MetadataRecord) + // + // These arise in the following cases: + // + // 1. When the delta between the TSC we get and the previous TSC for the + // same CPU is outside of the uint32_t range, we end up having to + // write a MetadataRecord to indicate a "tsc wrap" before the actual + // FunctionRecord. + // 2. When we learn that we've moved CPUs, we need to write a + // MetadataRecord to indicate a "cpu change", and thus write out the + // current TSC for that CPU before writing out the actual + // FunctionRecord. + // 3. When we learn about a new CPU ID, we need to write down a "new cpu + // id" MetadataRecord before writing out the actual FunctionRecord. + // + // - An End-of-Buffer (EOB) MetadataRecord is 16 bytes. + // + // So the math we need to do is to determine whether writing 24 bytes past the + // current pointer leaves us with enough bytes to write the EOB + // MetadataRecord. If we don't have enough space after writing as much as 24 + // bytes in the end of the buffer, we need to write out the EOB, get a new + // Buffer, set it up properly before doing any further writing. + // + char *BufferStart = static_cast(Buffer.Buffer); + if ((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart < + static_cast(MetadataRecSize)) { + writeEOBMetadata(); + if (auto EC = LocalBQ->releaseBuffer(Buffer)) { + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + EC.message().c_str()); + return; + } + if (auto EC = LocalBQ->getBuffer(Buffer)) { + Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); + return; + } + setupNewBuffer(Buffer, wall_clock_reader); + } + + // By this point, we are now ready to write at most 24 bytes (one metadata + // record and one function record). + BufferStart = static_cast(Buffer.Buffer); + assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart >= + static_cast(MetadataRecSize) && + "Misconfigured BufferQueue provided; Buffer size not large enough."); + + // Here we compute the TSC Delta. There are a few interesting situations we + // need to account for: + // + // - The thread has migrated to a different CPU. If this is the case, then + // we write down the following records: + // + // 1. A 'NewCPUId' Metadata record. + // 2. A FunctionRecord with a 0 for the TSCDelta field. + // + // - The TSC delta is greater than the 32 bits we can store in a + // FunctionRecord. In this case we write down the following records: + // + // 1. A 'TSCWrap' Metadata record. + // 2. A FunctionRecord with a 0 for the TSCDelta field. + // + // - The TSC delta is representable within the 32 bits we can store in a + // FunctionRecord. In this case we write down just a FunctionRecord with + // the correct TSC delta. + // + + uint32_t RecordTSCDelta = 0; + if (CPU != CurrentCPU) { + // We've moved to a new CPU. + writeNewCPUIdMetadata(CPU, TSC); + } else { + // If the delta is greater than the range for a uint32_t, then we write out + // the TSC wrap metadata entry with the full TSC, and the TSC for the + // function record be 0. + auto Delta = TSC - LastTSC; + if (Delta > (1ULL << 32) - 1) + writeTSCWrapMetadata(TSC); + else + RecordTSCDelta = Delta; + } + + // We then update our "LastTSC" and "CurrentCPU" thread-local variables to aid + // us in future computations of this TSC delta value. + LastTSC = TSC; + CurrentCPU = CPU; + + writeFunctionRecord(FuncId, RecordTSCDelta, Entry, RecordPtr); + + // If we've exhausted the buffer by this time, we then release the buffer to + // make sure that other threads may start using this buffer. + if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { + writeEOBMetadata(); + if (auto EC = LocalBQ->releaseBuffer(Buffer)) { + Report("Failed releasing buffer at %p; error=%s\n", Buffer.Buffer, + EC.message().c_str()); + return; + } + RecordPtr = nullptr; + } +} + +} // namespace __xray_fdr_internal + +} // namespace __xray + +#endif // XRAY_XRAY_FDR_LOGGING_IMPL_H -- cgit v1.2.1 From 54929415e103b05e680b9c0370ad433198eef358 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 15 Mar 2017 12:13:20 +0000 Subject: [compiler-rt][builtins] Ignore the deprecated warning for CFPropertyListCreateFromXMLData that's used in __isOSVersionAtLeast I forgot to add the pragmas in r297760. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297827 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/os_version_check.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c index fd8a96ae2..74ade2f5b 100644 --- a/lib/builtins/os_version_check.c +++ b/lib/builtins/os_version_check.c @@ -47,9 +47,12 @@ static void parseSystemVersionPList(void *Unused) { RTLD_DEFAULT, "CFPropertyListCreateWithData"); /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it * will be NULL on earlier OS versions. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc = (typeof(CFPropertyListCreateFromXMLData) *)dlsym( RTLD_DEFAULT, "CFPropertyListCreateFromXMLData"); +#pragma clang diagnostic pop /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it * might be NULL in future OS versions. */ if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc) -- cgit v1.2.1 From ca1faf3b60b7624d97ebf5ce385745bb1bea5d88 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Wed, 15 Mar 2017 12:14:32 +0000 Subject: [msan] Relax lit check in wcsncpy.cc Summary: The CHECK failed when the name is __interceptor_wcsncpy Reviewers: bkramer, eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D30975 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297828 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/wcsncpy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/msan/wcsncpy.cc b/test/msan/wcsncpy.cc index 8f809697e..f582c37b7 100644 --- a/test/msan/wcsncpy.cc +++ b/test/msan/wcsncpy.cc @@ -30,7 +30,7 @@ int main() { // CHECK: in main {{.*}}wcsncpy.cc:26 // CHECK: Uninitialized value was stored to memory at -// CHECK: in wcsncpy +// CHECK: in {{[^\s]*}}wcsncpy // CHECK: in main {{.*}}wcsncpy.cc:25 // CHECK: Memory was marked as uninitialized -- cgit v1.2.1 From 53923f58bacda14fff951ffeb9bf66fbfa544a95 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 15 Mar 2017 19:50:02 +0000 Subject: Fix -Wstring-conversion instance git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297879 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_win.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc index 5163c04f7..efa058243 100644 --- a/lib/asan/asan_malloc_win.cc +++ b/lib/asan/asan_malloc_win.cc @@ -100,7 +100,7 @@ void *realloc(void *ptr, size_t size) { ALLOCATION_FUNCTION_ATTRIBUTE void *_realloc_dbg(void *ptr, size_t size, int) { - CHECK(!"_realloc_dbg should not exist!"); + UNREACHABLE("_realloc_dbg should not exist!"); return 0; } -- cgit v1.2.1 From 9f44a79edd75644e5578158a1a933cf734edd3f3 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 15 Mar 2017 21:18:47 +0000 Subject: Add NO_EXEC_STACK_DIRECTIVE to xray assembly files. Summary: Add NO_EXEC_STACK_DIRECTIVE to xray assembly files Reviewers: dberris, javed.absar Reviewed By: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D30953 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297894 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_trampoline_AArch64.S | 4 ++++ lib/xray/xray_trampoline_arm.S | 4 ++++ lib/xray/xray_trampoline_x86_64.S | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/lib/xray/xray_trampoline_AArch64.S b/lib/xray/xray_trampoline_AArch64.S index b8c89e4bc..4d1b04fb7 100644 --- a/lib/xray/xray_trampoline_AArch64.S +++ b/lib/xray/xray_trampoline_AArch64.S @@ -1,3 +1,5 @@ +#include "../builtins/assembly.h" + .text /* The variable containing the handler function pointer */ .global _ZN6__xray19XRayPatchedFunctionE @@ -138,3 +140,5 @@ FunctionTailExit_restore: LDP X3, X4, [SP], #16 LDP X1, X2, [SP], #16 RET + +NO_EXEC_STACK_DIRECTIVE diff --git a/lib/xray/xray_trampoline_arm.S b/lib/xray/xray_trampoline_arm.S index ee6763e0e..71dbee65d 100644 --- a/lib/xray/xray_trampoline_arm.S +++ b/lib/xray/xray_trampoline_arm.S @@ -1,3 +1,5 @@ +#include "../builtins/assembly.h" + .syntax unified .arch armv6t2 .fpu vfpv2 @@ -96,3 +98,5 @@ FunctionTailExit_restore: @ Restore floating-point parameters of the instrumented function VPOP {d0-d7} POP {r1-r3,pc} + +NO_EXEC_STACK_DIRECTIVE diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index b9fef6dad..da0aae326 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -13,6 +13,8 @@ // //===----------------------------------------------------------------------===// +#include "../builtins/assembly.h" + .macro SAVE_REGISTERS subq $200, %rsp movupd %xmm0, 184(%rsp) @@ -188,3 +190,5 @@ __xray_ArgLoggerEntry: .Larg1entryEnd: .size __xray_ArgLoggerEntry, .Larg1entryEnd-__xray_ArgLoggerEntry .cfi_endproc + +NO_EXEC_STACK_DIRECTIVE -- cgit v1.2.1 From 17eb0acd661cd9f371fe9599213e8d7848cc7690 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Wed, 15 Mar 2017 21:46:31 +0000 Subject: [PGO] Value profile support for value ranges This patch adds profile run time support to profile a range of values. This interface will be used in profiling the size of memory intrinsic calls. Differential Revision: http://reviews.llvm.org/D28964 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297895 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 17 ++++++++++++++++- lib/profile/InstrProfilingValue.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index f7c22d107..6ef1625d8 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -153,7 +153,17 @@ INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \ INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA +#ifndef VALUE_RANGE_PROF VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) +#else /* VALUE_RANGE_PROF */ +VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeStart, Type::getInt64Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeLast, Type::getInt64Ty(Ctx)) \ + INSTR_PROF_COMMA +VALUE_PROF_FUNC_PARAM(uint64_t, LargeValue, Type::getInt64Ty(Ctx)) +#endif /*VALUE_RANGE_PROF */ #undef VALUE_PROF_FUNC_PARAM #undef INSTR_PROF_COMMA /* VALUE_PROF_FUNC_PARAM end */ @@ -174,13 +184,15 @@ VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) * name hash and the function address. */ VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) +/* For memory intrinsic functions size profiling. */ +VALUE_PROF_KIND(IPVK_MemOPSize, 1) /* These two kinds must be the last to be * declared. This is to make sure the string * array created with the template can be * indexed with the kind value. */ VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget) -VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) +VALUE_PROF_KIND(IPVK_Last, IPVK_MemOPSize) #undef VALUE_PROF_KIND /* VALUE_PROF_KIND end */ @@ -649,6 +661,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, #define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target #define INSTR_PROF_VALUE_PROF_FUNC_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC) +#define INSTR_PROF_VALUE_RANGE_PROF_FUNC __llvm_profile_instrument_range +#define INSTR_PROF_VALUE_RANGE_PROF_FUNC_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VALUE_RANGE_PROF_FUNC) /* InstrProfile per-function control data alignment. */ #define INSTR_PROF_DATA_ALIGNMENT 8 diff --git a/lib/profile/InstrProfilingValue.c b/lib/profile/InstrProfilingValue.c index 6648f8923..44263da80 100644 --- a/lib/profile/InstrProfilingValue.c +++ b/lib/profile/InstrProfilingValue.c @@ -219,6 +219,35 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, } } +/* + * The target values are partitioned into multiple regions/ranges. There is one + * contiguous region which is precise -- every value in the range is tracked + * individually. A value outside the precise region will be collapsed into one + * value depending on the region it falls in. + * + * There are three regions: + * 1. (-inf, PreciseRangeStart) and (PreciseRangeLast, LargeRangeValue) belong + * to one region -- all values here should be mapped to one value of + * "PreciseRangeLast + 1". + * 2. [PreciseRangeStart, PreciseRangeLast] + * 3. Large values: [LargeValue, +inf) maps to one value of LargeValue. + * + * The range for large values is optional. The default value of INT64_MIN + * indicates it is not specified. + */ +COMPILER_RT_VISIBILITY void __llvm_profile_instrument_range( + uint64_t TargetValue, void *Data, uint32_t CounterIndex, + int64_t PreciseRangeStart, int64_t PreciseRangeLast, int64_t LargeValue) { + + if (LargeValue != INT64_MIN && (int64_t)TargetValue >= LargeValue) + TargetValue = LargeValue; + else if ((int64_t)TargetValue < PreciseRangeStart || + (int64_t)TargetValue > PreciseRangeLast) + TargetValue = PreciseRangeLast + 1; + + __llvm_profile_instrument_target(TargetValue, Data, CounterIndex); +} + /* * A wrapper struct that represents value profile runtime data. * Like InstrProfRecord class which is used by profiling host tools, -- cgit v1.2.1 From ae48dbe3d85b92abbaf4e3c2fb35f47298c5d70c Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 15 Mar 2017 23:27:14 +0000 Subject: [asan] add one more argument to __sanitizer_print_memory_profile, remove a redundant weak definition. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297914 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/common_interface_defs.h | 4 +++- lib/asan/asan_memory_profile.cc | 21 +++++++++++------ .../sanitizer_allocator_interface.h | 5 ++--- lib/sanitizer_common/sanitizer_common.cc | 7 ------ .../sanitizer_common_interface.inc | 2 +- lib/sanitizer_common/sanitizer_common_libcdep.cc | 2 +- .../TestCases/Linux/print_memory_profile_test.cc | 26 +++++++++++++--------- 7 files changed, 37 insertions(+), 30 deletions(-) diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h index f9f930223..4a1de968b 100644 --- a/include/sanitizer/common_interface_defs.h +++ b/include/sanitizer/common_interface_defs.h @@ -158,8 +158,10 @@ extern "C" { // Prints stack traces for all live heap allocations ordered by total // allocation size until `top_percent` of total live heap is shown. // `top_percent` should be between 1 and 100. + // At most `max_number_of_contexts` contexts (stack traces) is printed. // Experimental feature currently available only with asan on Linux/x86_64. - void __sanitizer_print_memory_profile(size_t top_percent); + void __sanitizer_print_memory_profile(size_t top_percent, + size_t max_number_of_contexts); // Fiber annotation interface. // Before switching to a different stack, one must call diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc index c2678b974..e07f45144 100644 --- a/lib/asan/asan_memory_profile.cc +++ b/lib/asan/asan_memory_profile.cc @@ -48,7 +48,7 @@ class HeapProfile { } } - void Print(uptr top_percent) { + void Print(uptr top_percent, uptr max_number_of_contexts) { InternalSort(&allocations_, allocations_.size(), [](const AllocationSite &a, const AllocationSite &b) { return a.total_size > b.total_size; @@ -57,12 +57,14 @@ class HeapProfile { uptr total_shown = 0; Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: " "%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; " - "showing top %zd%%\n", + "showing top %zd%% (at most %zd unique contexts)\n", total_allocated_user_size_, total_allocated_count_, total_quarantined_user_size_, total_quarantined_count_, total_other_count_, total_allocated_count_ + - total_quarantined_count_ + total_other_count_, top_percent); - for (uptr i = 0; i < allocations_.size(); i++) { + total_quarantined_count_ + total_other_count_, top_percent, + max_number_of_contexts); + for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts); + i++) { auto &a = allocations_[i]; Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, a.total_size * 100 / total_allocated_user_size_, a.count); @@ -103,15 +105,20 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, void *argument) { HeapProfile hp; __lsan::ForEachChunk(ChunkCallback, &hp); - hp.Print(reinterpret_cast(argument)); + uptr *Arg = reinterpret_cast(argument); + hp.Print(Arg[0], Arg[1]); } } // namespace __asan extern "C" { SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_print_memory_profile(uptr top_percent) { - __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent); +void __sanitizer_print_memory_profile(uptr top_percent, + uptr max_number_of_contexts) { + uptr Arg[2]; + Arg[0] = top_percent; + Arg[1] = max_number_of_contexts; + __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg); } } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_allocator_interface.h b/lib/sanitizer_common/sanitizer_allocator_interface.h index 74ee903c3..13910e719 100644 --- a/lib/sanitizer_common/sanitizer_allocator_interface.h +++ b/lib/sanitizer_common/sanitizer_allocator_interface.h @@ -38,9 +38,8 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_free_hook(void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - void __sanitizer_print_memory_profile(int top_percent); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void +__sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts); } // extern "C" #endif // SANITIZER_ALLOCATOR_INTERFACE_H diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 9078a900b..36f391118 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -505,11 +505,4 @@ int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, void (*free_hook)(const void *)) { return InstallMallocFreeHooks(malloc_hook, free_hook); } - -#if !SANITIZER_GO -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_print_memory_profile, - int top_percent) { - (void)top_percent; -} -#endif } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_common_interface.inc b/lib/sanitizer_common/sanitizer_common_interface.inc index 4f0e940a1..550427c90 100644 --- a/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/lib/sanitizer_common/sanitizer_common_interface.inc @@ -34,6 +34,6 @@ INTERFACE_FUNCTION(__sanitizer_get_heap_size) INTERFACE_FUNCTION(__sanitizer_get_ownership) INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) +INTERFACE_FUNCTION(__sanitizer_print_memory_profile) INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook) INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook) -INTERFACE_WEAK_FUNCTION(__sanitizer_print_memory_profile) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index e96db6dd6..430318863 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -123,7 +123,7 @@ void BackgroundThread(void *arg) { if (heap_profile && current_rss_mb > rss_during_last_reported_profile * 1.1) { Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); - __sanitizer_print_memory_profile(90); + __sanitizer_print_memory_profile(90, 20); rss_during_last_reported_profile = current_rss_mb; } } diff --git a/test/asan/TestCases/Linux/print_memory_profile_test.cc b/test/asan/TestCases/Linux/print_memory_profile_test.cc index 8909ccad0..e7896be40 100644 --- a/test/asan/TestCases/Linux/print_memory_profile_test.cc +++ b/test/asan/TestCases/Linux/print_memory_profile_test.cc @@ -3,8 +3,9 @@ // REQUIRES: leak-detection // // RUN: %clangxx_asan %s -o %t -// RUN: %run %t 100 2>&1 | FileCheck %s --check-prefix=CHECK-100 -// RUN: %run %t 50 2>&1 | FileCheck %s --check-prefix=CHECK-50 +// RUN: %run %t 100 10 2>&1 | FileCheck %s --check-prefix=CHECK-100-10 +// RUN: %run %t 100 1 2>&1 | FileCheck %s --check-prefix=CHECK-100-1 +// RUN: %run %t 50 10 2>&1 | FileCheck %s --check-prefix=CHECK-50-10 #include #include @@ -13,7 +14,7 @@ char *sink[1000]; int main(int argc, char **argv) { - if (argc < 2) + if (argc < 3) return 1; int idx = 0; @@ -22,12 +23,17 @@ int main(int argc, char **argv) { for (int i = 0; i < 28; i++) sink[idx++] = new char[24000]; - __sanitizer_print_memory_profile(atoi(argv[1])); + __sanitizer_print_memory_profile(atoi(argv[1]), atoi(argv[2])); } -// CHECK-100: Live Heap Allocations: {{.*}}; showing top 100% -// CHECK-100: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) -// CHECK-100: 672000 byte(s) ({{.*}}%) in 28 allocation(s) -// CHECK-50: Live Heap Allocations: {{.*}}; showing top 50% -// CHECK-50: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) -// CHECK-50-NOT: allocation +// CHECK-100-10: Live Heap Allocations: {{.*}}; showing top 100% (at most 10 unique contexts) +// CHECK-100-10: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) +// CHECK-100-10: 672000 byte(s) ({{.*}}%) in 28 allocation(s) + +// CHECK-100-1: Live Heap Allocations: {{.*}}; showing top 100% (at most 1 unique contexts) +// CHECK-100-1: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) +// CHECK-100-1-NOT: allocation + +// CHECK-50-10: Live Heap Allocations: {{.*}}; showing top 50% (at most 10 unique contexts) +// CHECK-50-10: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) +// CHECK-50-10-NOT: allocation -- cgit v1.2.1 From 201864e5cd5f172bd3c86aa09415d8a5c5157f45 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 15 Mar 2017 23:53:12 +0000 Subject: [asan] trying to fix the windows build git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297918 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_memory_profile.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc index e07f45144..05846c37c 100644 --- a/lib/asan/asan_memory_profile.cc +++ b/lib/asan/asan_memory_profile.cc @@ -111,15 +111,17 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, } // namespace __asan +#endif // CAN_SANITIZE_LEAKS + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts) { +#if CAN_SANITIZE_LEAKS uptr Arg[2]; Arg[0] = top_percent; Arg[1] = max_number_of_contexts; __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg); +#endif // CAN_SANITIZE_LEAKS } } // extern "C" - -#endif // CAN_SANITIZE_LEAKS -- cgit v1.2.1 From fe89b8c7dfbb711898fd23dede37edcd2ea46ca0 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 16 Mar 2017 01:06:22 +0000 Subject: [msan] Intercept getloadavg. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297923 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_interceptors.inc | 16 ++++++++++++++++ lib/sanitizer_common/sanitizer_platform_interceptors.h | 3 +++ test/msan/getloadavg.cc | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 test/msan/getloadavg.cc diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index fbffb56db..75026e0e4 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6047,6 +6047,21 @@ INTERCEPTOR(void *, getutxline, void *ut) { #define INIT_UTMPX #endif +#if SANITIZER_INTERCEPT_GETLOADAVG +INTERCEPTOR(int, getloadavg, double *loadavg, int nelem) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getloadavg, loadavg, nelem); + int res = REAL(getloadavg)(loadavg, nelem); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, loadavg, res * sizeof(*loadavg)); + return res; +} +#define INIT_GETLOADAVG \ + COMMON_INTERCEPT_FUNCTION(getloadavg); +#else +#define INIT_GETLOADAVG +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -6245,4 +6260,5 @@ static void InitializeCommonInterceptors() { // FIXME: add other *stat interceptors. INIT_UTMP; INIT_UTMPX; + INIT_GETLOADAVG; } diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 480e63a14..43ec55830 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -326,6 +326,9 @@ #define SANITIZER_INTERCEPT_UTMP SI_NOT_WINDOWS && !SI_MAC && !SI_FREEBSD #define SANITIZER_INTERCEPT_UTMPX SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD +#define SANITIZER_INTERCEPT_GETLOADAVG \ + SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD + #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (!SI_FREEBSD && !SI_MAC) #define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC) #define SANITIZER_INTERCEPT_PVALLOC (!SI_FREEBSD && !SI_MAC) diff --git a/test/msan/getloadavg.cc b/test/msan/getloadavg.cc new file mode 100644 index 000000000..7facd580d --- /dev/null +++ b/test/msan/getloadavg.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t + +#define _BSD_SOURCE +#include +#include + +#include + +int main(void) { + double x[4]; + int ret = getloadavg(x, 3); + assert(ret > 0); + assert(ret <= 3); + assert(__msan_test_shadow(x, sizeof(double) * ret) == -1); + assert(__msan_test_shadow(&x[ret], sizeof(double)) == 0); +} -- cgit v1.2.1 From ad103a52c3545020187b9334188af5e863561c76 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 16 Mar 2017 01:17:31 +0000 Subject: [compiler-rt] Add undefined "dup" symbol into internal symbolizer white-list. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297924 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/symbolizer/scripts/global_symbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt index 033acf7f2..737f9459d 100644 --- a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt +++ b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt @@ -37,6 +37,7 @@ clock_gettime U cfgetospeed U dl_iterate_phdr U dlsym U +dup U dup2 U environ U execv U -- cgit v1.2.1 From 539aa9b498ef52319ec22f7341d13e860635ee19 Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Thu, 16 Mar 2017 21:14:13 +0000 Subject: [PowerPC] Fix sanitizer frame unwind on 32-bit ABIs This fixes many sanitizer problems with -m32. It is really intended for gcc but patches to the sanitizers make their way through llvm first. ref: https://gcc.gnu.org/ml/gcc-patches/2017-02/msg00855.html git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@297995 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stacktrace.cc | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc index 2741dde7a..3453b8bad 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -79,15 +79,22 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, while (IsValidFrame((uptr)frame, stack_top, bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { + // PowerPC ABIs specify that the return address is saved on the + // *caller's* stack frame. Thus we must dereference the back chain + // to find the caller frame before extracting it. + uhwptr *caller_frame = (uhwptr*)frame[0]; + if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || + !IsAligned((uptr)caller_frame, sizeof(uhwptr))) + break; #ifdef __powerpc__ - // PowerPC ABIs specify that the return address is saved at offset - // 16 of the *caller's* stack frame. Thus we must dereference the - // back chain to find the caller frame before extracting it. - uhwptr *caller_frame = (uhwptr*)frame[0]; - if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || - !IsAligned((uptr)caller_frame, sizeof(uhwptr))) - break; + // For most ABIs the offset where the return address is saved is two + // register sizes. The exception is the SVR4 ABI, which uses an + // offset of only one register size. +#ifdef _CALL_SYSV + uhwptr pc1 = caller_frame[1]; +#else uhwptr pc1 = caller_frame[2]; +#endif #elif defined(__s390__) uhwptr pc1 = frame[14]; #else -- cgit v1.2.1 From a9c608446e5bf5e35e50e9a77751b773cc28e722 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 16 Mar 2017 22:35:34 +0000 Subject: Fix macOS version detection to also allow missing 3rd part of the version number. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298008 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index bffdc4331..741ce87c1 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -126,10 +126,11 @@ if config.can_symbolize: lit.util.usePlatformSdkOnDarwin(config, lit_config) if config.host_os == 'Darwin': + osx_version = (10, 0, 0) try: osx_version = subprocess.check_output(["sw_vers", "-productVersion"]) osx_version = tuple(int(x) for x in osx_version.split('.')) - config.darwin_osx_version = osx_version + if len(osx_version) == 2: osx_version = (osx_version[0], osx_version[1], 0) if osx_version >= (10, 11): config.available_features.add('osx-autointerception') config.available_features.add('osx-ld64-live_support') @@ -142,6 +143,8 @@ if config.host_os == 'Darwin': except: pass + config.darwin_osx_version = osx_version + # Detect x86_64h try: output = subprocess.check_output(["sysctl", "hw.cpusubtype"]) -- cgit v1.2.1 From 0dc7254c899cea943b53be0b267711685b95a8b6 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Fri, 17 Mar 2017 01:15:39 +0000 Subject: Revert "[PowerPC] Fix sanitizer frame unwind on 32-bit ABIs" This broke GreenDragon: http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/29210/ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298029 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stacktrace.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc index 3453b8bad..2741dde7a 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -79,22 +79,15 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, while (IsValidFrame((uptr)frame, stack_top, bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { - // PowerPC ABIs specify that the return address is saved on the - // *caller's* stack frame. Thus we must dereference the back chain - // to find the caller frame before extracting it. - uhwptr *caller_frame = (uhwptr*)frame[0]; - if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || - !IsAligned((uptr)caller_frame, sizeof(uhwptr))) - break; #ifdef __powerpc__ - // For most ABIs the offset where the return address is saved is two - // register sizes. The exception is the SVR4 ABI, which uses an - // offset of only one register size. -#ifdef _CALL_SYSV - uhwptr pc1 = caller_frame[1]; -#else + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. + uhwptr *caller_frame = (uhwptr*)frame[0]; + if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || + !IsAligned((uptr)caller_frame, sizeof(uhwptr))) + break; uhwptr pc1 = caller_frame[2]; -#endif #elif defined(__s390__) uhwptr pc1 = frame[14]; #else -- cgit v1.2.1 From 44a02421423d61f95d22eeaa70761fb042047483 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 17 Mar 2017 02:36:17 +0000 Subject: [XRay][compiler-rt] Add missing include for Fixes http://llvm.org/PR32313 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298037 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/unit/xray_fdr_log_printer_tool.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc b/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc index a4d05f200..6e209809e 100644 --- a/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc +++ b/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.1 From 7e119a30d6b3f35ee22db8a8d7d6839c4c481a29 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 17 Mar 2017 03:38:12 +0000 Subject: [XRay][compiler-rt] Add missing include to Fixes a build break when using clang-3.9.1 (reported upstream, post-commit review of D30850). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298039 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index a06b22df9..94e446bfc 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include -- cgit v1.2.1 From 4fdab5b726a155dd3da614734caa6ba69f2ee80c Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Fri, 17 Mar 2017 18:41:33 +0000 Subject: Resubmit r295469 [PGO] Suspend SIGKILL for PR_SET_PDEATHSIG in profile-write And also r295364 [PGO] remove unintended debug trace. NFC I removed the test case: it's hard to write synchronized test b/w processes in this framework. I will revisit the test-case later. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298113 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingFile.c | 9 +++++++++ lib/profile/InstrProfilingUtil.c | 23 +++++++++++++++++++++++ lib/profile/InstrProfilingUtil.h | 8 ++++++++ 3 files changed, 40 insertions(+) diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index cd3590e12..dfcbe52d7 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -530,6 +530,7 @@ int __llvm_profile_write_file(void) { int rc, Length; const char *Filename; char *FilenameBuf; + int PDeathSig = 0; if (lprofProfileDumped()) { PROF_NOTE("Profile data not written to file: %s.\n", @@ -556,10 +557,18 @@ int __llvm_profile_write_file(void) { return -1; } + // Temporarily suspend getting SIGKILL when the parent exits. + PDeathSig = lprofSuspendSigKill(); + /* Write profile data to the file. */ rc = writeFile(Filename); if (rc) PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); + + // Restore SIGKILL. + if (PDeathSig == 1) + lprofRestoreSigKill(); + return rc; } diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index 321c7192c..fb68f30a5 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -29,6 +29,11 @@ #include #include +#if defined(__linux__) +#include +#include +#endif + COMPILER_RT_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; @@ -219,3 +224,21 @@ COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) { #endif return Sep; } + +COMPILER_RT_VISIBILITY int lprofSuspendSigKill() { +#if defined(__linux__) + int PDeachSig = 0; + /* Temporarily suspend getting SIGKILL upon exit of the parent process. */ + if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL) + prctl(PR_SET_PDEATHSIG, 0); + return (PDeachSig == SIGKILL); +#else + return 0; +#endif +} + +COMPILER_RT_VISIBILITY void lprofRestoreSigKill() { +#if defined(__linux__) + prctl(PR_SET_PDEATHSIG, SIGKILL); +#endif +} diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h index a80fde77e..969859960 100644 --- a/lib/profile/InstrProfilingUtil.h +++ b/lib/profile/InstrProfilingUtil.h @@ -51,4 +51,12 @@ int lprofGetHostName(char *Name, int Len); unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV); void *lprofPtrFetchAdd(void **Mem, long ByteIncr); +/* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed. + * Other return values mean no restore is needed. + */ +int lprofSuspendSigKill(); + +/* Restore previously suspended SIGKILL. */ +void lprofRestoreSigKill(); + #endif /* PROFILE_INSTRPROFILINGUTIL_H */ -- cgit v1.2.1 From b0440701995f9d09ff87b210856b5e426ad073eb Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 17 Mar 2017 20:27:33 +0000 Subject: [ubsan] Add e2e test for -fsanitize=nullability git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298117 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/Misc/nullability.c | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/ubsan/TestCases/Misc/nullability.c diff --git a/test/ubsan/TestCases/Misc/nullability.c b/test/ubsan/TestCases/Misc/nullability.c new file mode 100644 index 000000000..37b8ddc8d --- /dev/null +++ b/test/ubsan/TestCases/Misc/nullability.c @@ -0,0 +1,64 @@ +// RUN: %clang -w -fsanitize=nullability-arg,nullability-assign,nullability-return %s -O3 -o %t +// RUN: %run %t foo 2>&1 | count 0 +// RUN: %run %t 2>&1 | FileCheck %s + +// CHECK: nullability.c:[[@LINE+2]]:51: runtime error: null pointer returned from function declared to never return null +// CHECK-NEXT: nullability.c:[[@LINE+1]]:6: note: _Nonnull return type annotation specified here +int *_Nonnull nonnull_retval1(int *p) { return p; } + +// CHECK: nullability.c:1001:19: runtime error: null pointer passed as argument 1, which is declared to never be null +// CHECK-NEXT: nullability.c:[[@LINE+3]]:36: note: _Nonnull type annotation specified here +// CHECK: nullability.c:1001:22: runtime error: null pointer passed as argument 2, which is declared to never be null +// CHECK-NEXT: nullability.c:[[@LINE+1]]:56: note: _Nonnull type annotation specified here +int *_Nonnull nonnull_retval2(int *_Nonnull arg1, int *_Nonnull arg2, + int *_Nullable arg3, int *arg4, int arg5, ...) { + return arg1; +} + +// CHECK: nullability.c:1002:15: runtime error: null pointer passed as argument 1, which is declared to never be null +// CHECK-NEXT: nullability.c:[[@LINE+1]]:23: note: _Nonnull type annotation specified here +void nonnull_arg(int *_Nonnull p) {} + +void nonnull_assign1(int *p) { + int *_Nonnull local; +// CHECK: nullability.c:[[@LINE+1]]:9: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' + local = p; +} + +void nonnull_assign2(int *p) { + int *_Nonnull arr[1]; + // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' + arr[0] = p; +} + +struct S1 { + int *_Nonnull mptr; +}; + +void nonnull_assign3(int *p) { + struct S1 s; + // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' + s.mptr = p; +} + +// CHECK: nullability.c:[[@LINE+1]]:52: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' +void nonnull_init1(int *p) { int *_Nonnull local = p; } + +// CHECK: nullability.c:[[@LINE+2]]:53: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' +// CHECK: nullability.c:[[@LINE+1]]:56: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull' +void nonnull_init2(int *p) { int *_Nonnull arr[] = {p, p}; } + +int main(int argc, char **argv) { + int *p = (argc > 1) ? &argc : ((int *)0); + +#line 1000 + nonnull_retval1(p); + nonnull_retval2(p, p, p, p, 0, 0, 0, 0); + nonnull_arg(p); + nonnull_assign1(p); + nonnull_assign2(p); + nonnull_assign3(p); + nonnull_init1(p); + nonnull_init2(p); + return 0; +} -- cgit v1.2.1 From 93b8798339095958569c28edad564b077adeecbe Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 17 Mar 2017 22:17:38 +0000 Subject: [asan] Fix dead stripping of globals on Linux (compiler-rt) Runtime support for the new instrumentation of globals based on !associated, and a bunch of tests. Differential Revision: https://reviews.llvm.org/D30120 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298159 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 20 ++++++++++++++++++++ lib/asan/asan_interface.inc | 2 ++ lib/asan/asan_interface_internal.h | 5 +++++ test/asan/CMakeLists.txt | 2 +- test/asan/TestCases/Linux/global-overflow-bfd.cc | 18 ++++++++++++++++++ test/asan/TestCases/Linux/global-overflow-lld.cc | 19 +++++++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections-lld.cc | 15 +++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections.cc | 14 ++++++++++---- 8 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 test/asan/TestCases/Linux/global-overflow-bfd.cc create mode 100644 test/asan/TestCases/Linux/global-overflow-lld.cc create mode 100644 test/asan/TestCases/Linux/globals-gc-sections-lld.cc diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index b72330673..eebada804 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -332,6 +332,26 @@ void __asan_unregister_image_globals(uptr *flag) { *flag = 0; } +void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { + if (*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_register_globals(globals_start, globals_stop - globals_start); + *flag = 1; +} + +void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { + if (!*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_unregister_globals(globals_start, globals_stop - globals_start); + *flag = 0; +} + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc index 351be4da5..e65f61722 100644 --- a/lib/asan/asan_interface.inc +++ b/lib/asan/asan_interface.inc @@ -64,6 +64,7 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_print_accumulated_stats) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_register_globals) +INTERFACE_FUNCTION(__asan_register_elf_globals) INTERFACE_FUNCTION(__asan_register_image_globals) INTERFACE_FUNCTION(__asan_report_error) INTERFACE_FUNCTION(__asan_report_exp_load1) @@ -149,6 +150,7 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) +INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index b18c31548..b974c0cc4 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -67,6 +67,11 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_elf_globals(uptr *flag, void *start, void *stop); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop); + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 893276767..a0b9cf98f 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -16,7 +16,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) + if(NOT APPLE AND COMPILER_RT_HAS_LLD_SOURCES) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc new file mode 100644 index 000000000..117a761af --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-bfd.cc @@ -0,0 +1,18 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the BFD linker. +// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc new file mode 100644 index 000000000..f4d0bc977 --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-lld.cc @@ -0,0 +1,19 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the LLD linker. +// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: lld + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc new file mode 100644 index 000000000..0d8bcdd1c --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// REQUIRES: lld + +int undefined(); + +// On i386 clang adds --export-dynamic when linking with ASan, which adds all +// non-hidden globals to GC roots. +__attribute__((visibility("hidden"))) int (*unused)() = undefined; + +int main() { + return 0; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc index 72a9e9498..ad60f33d8 100644 --- a/test/asan/TestCases/Linux/globals-gc-sections.cc +++ b/test/asan/TestCases/Linux/globals-gc-sections.cc @@ -1,12 +1,18 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=bfd -ffunction-sections -fdata-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=bfd -ffunction-sections -fdata-sections -mllvm -asan-globals=1 // https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// XFAIL: * int undefined(); -int (*unused)() = undefined; +// bug in ld.bfd: with multiple "asan_globals" sections, __start_asan_globals is +// treated as a strong GC reference to the first such section. As a result, the +// first (for some definition of the word) global is never gc-ed. +int first_unused = 42; + +// On i386 clang adds --export-dynamic when linking with ASan, which adds all +// non-hidden globals to GC roots. +__attribute__((visibility("hidden"))) int (*unused)() = undefined; int main() { return 0; -- cgit v1.2.1 From 209c570aa5636346d80288dc5a6f0fcd5e6ba858 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 17 Mar 2017 23:40:50 +0000 Subject: [asan] Disable globals-gc test with ld.bfd. Fails on clang-cmake-armv7-a15-full. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298169 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/globals-gc-sections.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc index ad60f33d8..e95db2f6c 100644 --- a/test/asan/TestCases/Linux/globals-gc-sections.cc +++ b/test/asan/TestCases/Linux/globals-gc-sections.cc @@ -2,6 +2,7 @@ // RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=bfd -ffunction-sections -fdata-sections -mllvm -asan-globals=1 // https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// UNSUPPORTED: * int undefined(); -- cgit v1.2.1 From a938e22d24ce7d7af81469bb06bb417d28f8a65f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 18 Mar 2017 00:25:40 +0000 Subject: [asan] Remove gc-sections test with bfd. It used to be XFAIL: *, but with the new implementation it passes in some cases and fails in other. There are similar tests for gold and lld that are not flaky, and a positive test for bfd that makes sure that were are not breaking existing functionality. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298173 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/globals-gc-sections.cc | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 test/asan/TestCases/Linux/globals-gc-sections.cc diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc deleted file mode 100644 index e95db2f6c..000000000 --- a/test/asan/TestCases/Linux/globals-gc-sections.cc +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=bfd -ffunction-sections -fdata-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=bfd -ffunction-sections -fdata-sections -mllvm -asan-globals=1 - -// https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// UNSUPPORTED: * - -int undefined(); - -// bug in ld.bfd: with multiple "asan_globals" sections, __start_asan_globals is -// treated as a strong GC reference to the first such section. As a result, the -// first (for some definition of the word) global is never gc-ed. -int first_unused = 42; - -// On i386 clang adds --export-dynamic when linking with ASan, which adds all -// non-hidden globals to GC roots. -__attribute__((visibility("hidden"))) int (*unused)() = undefined; - -int main() { - return 0; -} -- cgit v1.2.1 From 3cdb20b8a006082faaff2585a6be214ebbd92772 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 18 Mar 2017 00:25:43 +0000 Subject: Fix sanitizer tests with LLVM_TOOL_LLD_BUILD=OFF. Only depend on LLD if it is going to be built. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298174 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 8 ++++---- test/asan/CMakeLists.txt | 2 +- test/cfi/CMakeLists.txt | 2 +- test/lit.common.configured.in | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbde83113..14e493d3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,12 +253,12 @@ else() endif() set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) -if(EXISTS ${COMPILER_RT_LLD_PATH}/) - set(COMPILER_RT_HAS_LLD_SOURCES TRUE) +if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) + set(COMPILER_RT_HAS_LLD TRUE) else() - set(COMPILER_RT_HAS_LLD_SOURCES FALSE) + set(COMPILER_RT_HAS_LLD FALSE) endif() -pythonize_bool(COMPILER_RT_HAS_LLD_SOURCES) +pythonize_bool(COMPILER_RT_HAS_LLD) add_subdirectory(lib) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index a0b9cf98f..b253742f0 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -16,7 +16,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(NOT APPLE AND COMPILER_RT_HAS_LLD_SOURCES) + if(NOT APPLE AND COMPILER_RT_HAS_LLD) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index bd51eacb6..c3123a820 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -34,7 +34,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LTO ) endif() - if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) + if(WIN32 AND COMPILER_RT_HAS_LLD) list(APPEND CFI_TEST_DEPS lld ) diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 862d06bf2..387f4d4a7 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -26,7 +26,7 @@ set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@) set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@") set_default("emulator", "@COMPILER_RT_EMULATOR@") set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) -set_default("has_lld", @COMPILER_RT_HAS_LLD_SOURCES_PYBOOL@) +set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) config.available_features.add('target-is-%s' % config.target_arch) -- cgit v1.2.1 From e656508ca1054fb635916b74b0246f23b8b27d22 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sat, 18 Mar 2017 20:39:31 +0000 Subject: Add extra return value checks into stack-use-after-return.cc to help diagnose AArch64 test failures for . NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298193 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../asan/TestCases/Posix/stack-use-after-return.cc | 25 +++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index cf114be97..8ba3c9a90 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -14,8 +14,9 @@ // RUN: %env_asan_opts=detect_stack_use_after_return=1:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s // RUN: %env_asan_opts=detect_stack_use_after_return=1:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s -#include #include +#include +#include #ifndef kSize # define kSize 1 @@ -66,8 +67,26 @@ int main(int argc, char **argv) { #if UseThread pthread_attr_t attr; pthread_attr_init(&attr); - if (kStackSize > 0) - pthread_attr_setstacksize(&attr, kStackSize); + if (kStackSize > 0) { + int ret = pthread_attr_setstacksize(&attr, kStackSize); + if (ret != 0) { + fprintf(stderr, "pthread_attr_setstacksize returned %d\n", ret); + abort(); + } + + size_t stacksize_check; + ret = pthread_attr_getstacksize(&attr, &stacksize_check); + if (ret != 0) { + fprintf(stderr, "pthread_attr_getstacksize returned %d\n", ret); + abort(); + } + + if (stacksize_check != kStackSize) { + fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n", + kStackSize, stacksize_check); + abort(); + } + } pthread_t t; pthread_create(&t, &attr, Thread, 0); pthread_attr_destroy(&attr); -- cgit v1.2.1 From 257bbc4c194f6faff95d4c0cdb0b1ef14d93295a Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sat, 18 Mar 2017 21:35:12 +0000 Subject: Change stack-use-after-return.cc to respect PTHREAD_STACK_MIN before calling pthread_attr_setstacksize. To investigate . NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298195 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/stack-use-after-return.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index 8ba3c9a90..a0f74712a 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -68,7 +68,12 @@ int main(int argc, char **argv) { pthread_attr_t attr; pthread_attr_init(&attr); if (kStackSize > 0) { - int ret = pthread_attr_setstacksize(&attr, kStackSize); + size_t desired_stack_size = kStackSize; + if (desired_stack_size < PTHREAD_STACK_MIN) { + desired_stack_size = PTHREAD_STACK_MIN; + } + + int ret = pthread_attr_setstacksize(&attr, desired_stack_size); if (ret != 0) { fprintf(stderr, "pthread_attr_setstacksize returned %d\n", ret); abort(); @@ -81,9 +86,9 @@ int main(int argc, char **argv) { abort(); } - if (stacksize_check != kStackSize) { + if (stacksize_check != desired_stack_size) { fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n", - kStackSize, stacksize_check); + desired_stack_size, stacksize_check); abort(); } } -- cgit v1.2.1 From acee824759b9244934a946ab72d87fd5bcf97741 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sat, 18 Mar 2017 22:01:33 +0000 Subject: Apparently, PTHREAD_STACK_MIN can be in limits.h on some systems... git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298196 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/stack-use-after-return.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index a0f74712a..b67707aaf 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -14,6 +14,7 @@ // RUN: %env_asan_opts=detect_stack_use_after_return=1:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s // RUN: %env_asan_opts=detect_stack_use_after_return=1:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s +#include #include #include #include -- cgit v1.2.1 From da9f41bddc1a6e410dd46e038f7aeb416f32c351 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 19 Mar 2017 00:59:08 +0000 Subject: Re-commit of r296706 ("Increase stack size for stack-use-after-return test"). Hopefully the recent changes in the test will make it not flaky anymore. Differential Revision: https://reviews.llvm.org/D30267 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298200 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/stack-use-after-return.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index b67707aaf..c8bebfc25 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -4,7 +4,7 @@ // RUN: %clangxx_asan -O3 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t // Regression test for a CHECK failure with small stack size and large frame. -// RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=65536 && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s +// RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s // // Test that we can find UAR in a thread other than main: // RUN: %clangxx_asan -DUseThread -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s -- cgit v1.2.1 From 5b350130fc4bf6f70c078a5d97096df98a17a057 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Sun, 19 Mar 2017 15:02:43 +0000 Subject: Use pthreads for thread-local lsan allocator cache on darwin Summary: This patch allows us to move away from using __thread on darwin, which is requiring for building lsan for darwin on ios version 7 and on iossim i386. Reviewers: kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29994 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298214 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 51 +++++++------------------------------------ lib/lsan/lsan_allocator.h | 37 +++++++++++++++++++++++++++++++ lib/lsan/lsan_common_linux.cc | 4 ++++ lib/lsan/lsan_common_mac.cc | 8 ++++++- 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 428485796..640497d40 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,53 +24,18 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { - -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; -#if SANITIZER_WORDSIZE == 64 - uptr requested_size : 54; -#else - uptr requested_size : 32; - uptr padding : 22; -#endif - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) #if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; -#else +#elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; -#endif -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; #else static const uptr kMaxAllowedMallocSize = 8UL << 30; - -struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. - static const uptr kMetadataSize = sizeof(ChunkMetadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; -}; - -typedef SizeClassAllocator64 PrimaryAllocator; #endif -typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; -static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized( @@ -79,7 +44,7 @@ void InitializeAllocator() { } void AllocatorThreadFinish() { - allocator.SwallowCache(&cache); + allocator.SwallowCache(GetAllocatorCache()); } static ChunkMetadata *Metadata(const void *p) { @@ -111,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(&cache, size, alignment, false); + void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -125,7 +90,7 @@ void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -133,17 +98,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); return nullptr; } - p = allocator.Reallocate(&cache, p, new_size, alignment); + p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)&cache; - *end = *begin + sizeof(cache); + *begin = (uptr)GetAllocatorCache(); + *end = *begin + sizeof(AllocatorCache); } uptr GetMallocUsableSize(const void *p) { diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index f56460119..9c3dce97a 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -15,8 +15,10 @@ #ifndef LSAN_ALLOCATOR_H #define LSAN_ALLOCATOR_H +#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" +#include "lsan_common.h" namespace __lsan { @@ -34,6 +36,41 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; +#if SANITIZER_WORDSIZE == 64 + uptr requested_size : 54; +#else + uptr requested_size : 32; + uptr padding : 22; +#endif + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; +#elif defined(__x86_64__) +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; + +AllocatorCache *GetAllocatorCache(); } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 0e10d4191..e73768e58 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,6 +22,7 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "lsan_allocator.h" namespace __lsan { @@ -38,6 +39,9 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } + __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 7f5e0550d..f70ebdd0e 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -12,12 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" #if CAN_SANITIZE_LEAKS && SANITIZER_MAC +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "lsan_allocator.h" + #include namespace __lsan { @@ -25,6 +27,7 @@ namespace __lsan { typedef struct { int disable_counter; u32 current_thread_id; + AllocatorCache cache; } thread_local_data_t; static pthread_key_t key; @@ -40,6 +43,7 @@ static thread_local_data_t *get_tls_val() { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; + ptr->cache = AllocatorCache(); pthread_setspecific(key, ptr); } @@ -62,6 +66,8 @@ u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } +AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } + void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); } -- cgit v1.2.1 From 101784fa617fcaca1e75b1719a0827dd7a86cab5 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 20 Mar 2017 13:45:29 +0000 Subject: Revert "Use pthreads for thread-local lsan allocator cache on darwin" This is still failing stack-use-after-return on linux-aarch64. This reverts commit 5b350130fc4bf6f70c078a5d97096df98a17a057. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298246 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 51 ++++++++++++++++++++++++++++++++++++------- lib/lsan/lsan_allocator.h | 37 ------------------------------- lib/lsan/lsan_common_linux.cc | 4 ---- lib/lsan/lsan_common_mac.cc | 8 +------ 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 640497d40..428485796 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,18 +24,53 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { + +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; +#if SANITIZER_WORDSIZE == 64 + uptr requested_size : 54; +#else + uptr requested_size : 32; + uptr padding : 22; +#endif + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) #if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; -#elif defined(__mips64) || defined(__aarch64__) +#else static const uptr kMaxAllowedMallocSize = 4UL << 30; +#endif +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; #else static const uptr kMaxAllowedMallocSize = 8UL << 30; + +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; #endif +typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; +static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized( @@ -44,7 +79,7 @@ void InitializeAllocator() { } void AllocatorThreadFinish() { - allocator.SwallowCache(GetAllocatorCache()); + allocator.SwallowCache(&cache); } static ChunkMetadata *Metadata(const void *p) { @@ -76,7 +111,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); + void *p = allocator.Allocate(&cache, size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -90,7 +125,7 @@ void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(GetAllocatorCache(), p); + allocator.Deallocate(&cache, p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -98,17 +133,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(GetAllocatorCache(), p); + allocator.Deallocate(&cache, p); return nullptr; } - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); + p = allocator.Reallocate(&cache, p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)GetAllocatorCache(); - *end = *begin + sizeof(AllocatorCache); + *begin = (uptr)&cache; + *end = *begin + sizeof(cache); } uptr GetMallocUsableSize(const void *p) { diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 9c3dce97a..f56460119 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -15,10 +15,8 @@ #ifndef LSAN_ALLOCATOR_H #define LSAN_ALLOCATOR_H -#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" -#include "lsan_common.h" namespace __lsan { @@ -36,41 +34,6 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; -#if SANITIZER_WORDSIZE == 64 - uptr requested_size : 54; -#else - uptr requested_size : 32; - uptr padding : 22; -#endif - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; -#elif defined(__x86_64__) -struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. - static const uptr kMetadataSize = sizeof(ChunkMetadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; -}; - -typedef SizeClassAllocator64 PrimaryAllocator; -#endif -typedef SizeClassAllocatorLocalCache AllocatorCache; - -AllocatorCache *GetAllocatorCache(); } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index e73768e58..0e10d4191 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,7 +22,6 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#include "lsan_allocator.h" namespace __lsan { @@ -39,9 +38,6 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } -static THREADLOCAL AllocatorCache allocator_cache; -AllocatorCache *GetAllocatorCache() { return &allocator_cache; } - __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index f70ebdd0e..7f5e0550d 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -12,14 +12,12 @@ // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" #if CAN_SANITIZE_LEAKS && SANITIZER_MAC -#include "sanitizer_common/sanitizer_allocator_internal.h" -#include "lsan_allocator.h" - #include namespace __lsan { @@ -27,7 +25,6 @@ namespace __lsan { typedef struct { int disable_counter; u32 current_thread_id; - AllocatorCache cache; } thread_local_data_t; static pthread_key_t key; @@ -43,7 +40,6 @@ static thread_local_data_t *get_tls_val() { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; - ptr->cache = AllocatorCache(); pthread_setspecific(key, ptr); } @@ -66,8 +62,6 @@ u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } -AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } - void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); } -- cgit v1.2.1 From c8bc492389096fb3f7a24485c950ad43a772f1e9 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 20 Mar 2017 16:36:34 +0000 Subject: Disable stack-use-after-return.cc on AArch64. The test was not testing the right thing before (the call to pthread_attr_setstacksize wasn't doing anything) anyway, and now it's running out of stack due to an unrelated change. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298267 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/stack-use-after-return.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index c8bebfc25..232f93f89 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -14,6 +14,9 @@ // RUN: %env_asan_opts=detect_stack_use_after_return=1:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s // RUN: %env_asan_opts=detect_stack_use_after_return=1:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s +// This test runs out of stack on AArch64. +// UNSUPPORTED: aarch64 + #include #include #include -- cgit v1.2.1 From a36125098f2fec54690d0d20965a6010dc5d3e38 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 20 Mar 2017 17:06:42 +0000 Subject: Use pthreads for thread-local lsan allocator cache on darwin Summary: This patch allows us to move away from using __thread on darwin, which is requiring for building lsan for darwin on ios version 7 and on iossim i386. Reviewers: kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29994 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298274 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 51 +++++++------------------------------------ lib/lsan/lsan_allocator.h | 37 +++++++++++++++++++++++++++++++ lib/lsan/lsan_common_linux.cc | 4 ++++ lib/lsan/lsan_common_mac.cc | 8 ++++++- 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 428485796..640497d40 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,53 +24,18 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { - -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; -#if SANITIZER_WORDSIZE == 64 - uptr requested_size : 54; -#else - uptr requested_size : 32; - uptr padding : 22; -#endif - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) #if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; -#else +#elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; -#endif -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; #else static const uptr kMaxAllowedMallocSize = 8UL << 30; - -struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. - static const uptr kMetadataSize = sizeof(ChunkMetadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; -}; - -typedef SizeClassAllocator64 PrimaryAllocator; #endif -typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; -static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized( @@ -79,7 +44,7 @@ void InitializeAllocator() { } void AllocatorThreadFinish() { - allocator.SwallowCache(&cache); + allocator.SwallowCache(GetAllocatorCache()); } static ChunkMetadata *Metadata(const void *p) { @@ -111,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(&cache, size, alignment, false); + void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -125,7 +90,7 @@ void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -133,17 +98,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); return nullptr; } - p = allocator.Reallocate(&cache, p, new_size, alignment); + p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)&cache; - *end = *begin + sizeof(cache); + *begin = (uptr)GetAllocatorCache(); + *end = *begin + sizeof(AllocatorCache); } uptr GetMallocUsableSize(const void *p) { diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index f56460119..9c3dce97a 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -15,8 +15,10 @@ #ifndef LSAN_ALLOCATOR_H #define LSAN_ALLOCATOR_H +#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" +#include "lsan_common.h" namespace __lsan { @@ -34,6 +36,41 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; +#if SANITIZER_WORDSIZE == 64 + uptr requested_size : 54; +#else + uptr requested_size : 32; + uptr padding : 22; +#endif + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; +#elif defined(__x86_64__) +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; + +AllocatorCache *GetAllocatorCache(); } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 0e10d4191..e73768e58 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,6 +22,7 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "lsan_allocator.h" namespace __lsan { @@ -38,6 +39,9 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } + __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 7f5e0550d..f70ebdd0e 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -12,12 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" #if CAN_SANITIZE_LEAKS && SANITIZER_MAC +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "lsan_allocator.h" + #include namespace __lsan { @@ -25,6 +27,7 @@ namespace __lsan { typedef struct { int disable_counter; u32 current_thread_id; + AllocatorCache cache; } thread_local_data_t; static pthread_key_t key; @@ -40,6 +43,7 @@ static thread_local_data_t *get_tls_val() { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; + ptr->cache = AllocatorCache(); pthread_setspecific(key, ptr); } @@ -62,6 +66,8 @@ u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } +AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } + void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); } -- cgit v1.2.1 From dc8b945decb8d19208975f9c90c0037cbb408d80 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 20 Mar 2017 18:45:27 +0000 Subject: Revert r298174, r298173, r298169, r298159. Revert "Fix sanitizer tests with LLVM_TOOL_LLD_BUILD=OFF." Revert "[asan] Remove gc-sections test with bfd." Revert "[asan] Disable globals-gc test with ld.bfd." Revert "[asan] Fix dead stripping of globals on Linux (compiler-rt)" OOM in gold linker. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298287 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 8 ++++---- lib/asan/asan_globals.cc | 20 -------------------- lib/asan/asan_interface.inc | 2 -- lib/asan/asan_interface_internal.h | 5 ----- test/asan/CMakeLists.txt | 2 +- test/asan/TestCases/Linux/global-overflow-bfd.cc | 18 ------------------ test/asan/TestCases/Linux/global-overflow-lld.cc | 19 ------------------- test/asan/TestCases/Linux/globals-gc-sections-lld.cc | 15 --------------- test/asan/TestCases/Linux/globals-gc-sections.cc | 13 +++++++++++++ test/cfi/CMakeLists.txt | 2 +- test/lit.common.configured.in | 2 +- 11 files changed, 20 insertions(+), 86 deletions(-) delete mode 100644 test/asan/TestCases/Linux/global-overflow-bfd.cc delete mode 100644 test/asan/TestCases/Linux/global-overflow-lld.cc delete mode 100644 test/asan/TestCases/Linux/globals-gc-sections-lld.cc create mode 100644 test/asan/TestCases/Linux/globals-gc-sections.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 14e493d3b..cbde83113 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,12 +253,12 @@ else() endif() set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) -if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) - set(COMPILER_RT_HAS_LLD TRUE) +if(EXISTS ${COMPILER_RT_LLD_PATH}/) + set(COMPILER_RT_HAS_LLD_SOURCES TRUE) else() - set(COMPILER_RT_HAS_LLD FALSE) + set(COMPILER_RT_HAS_LLD_SOURCES FALSE) endif() -pythonize_bool(COMPILER_RT_HAS_LLD) +pythonize_bool(COMPILER_RT_HAS_LLD_SOURCES) add_subdirectory(lib) diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index eebada804..b72330673 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -332,26 +332,6 @@ void __asan_unregister_image_globals(uptr *flag) { *flag = 0; } -void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { - if (*flag) return; - if (!start) return; - CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); - __asan_global *globals_start = (__asan_global*)start; - __asan_global *globals_stop = (__asan_global*)stop; - __asan_register_globals(globals_start, globals_stop - globals_start); - *flag = 1; -} - -void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { - if (!*flag) return; - if (!start) return; - CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); - __asan_global *globals_start = (__asan_global*)start; - __asan_global *globals_stop = (__asan_global*)stop; - __asan_unregister_globals(globals_start, globals_stop - globals_start); - *flag = 0; -} - // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc index e65f61722..351be4da5 100644 --- a/lib/asan/asan_interface.inc +++ b/lib/asan/asan_interface.inc @@ -64,7 +64,6 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_print_accumulated_stats) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_register_globals) -INTERFACE_FUNCTION(__asan_register_elf_globals) INTERFACE_FUNCTION(__asan_register_image_globals) INTERFACE_FUNCTION(__asan_report_error) INTERFACE_FUNCTION(__asan_report_exp_load1) @@ -150,7 +149,6 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) -INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index b974c0cc4..b18c31548 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -67,11 +67,6 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); - SANITIZER_INTERFACE_ATTRIBUTE - void __asan_register_elf_globals(uptr *flag, void *start, void *stop); - SANITIZER_INTERFACE_ATTRIBUTE - void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop); - // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index b253742f0..893276767 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -16,7 +16,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(NOT APPLE AND COMPILER_RT_HAS_LLD) + if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc deleted file mode 100644 index 117a761af..000000000 --- a/test/asan/TestCases/Linux/global-overflow-bfd.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Test that gc-sections-friendly instrumentation of globals does not introduce -// false negatives with the BFD linker. -// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s - -#include -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at}} - // CHECK: {{located 0 bytes to the right of global variable}} - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc deleted file mode 100644 index f4d0bc977..000000000 --- a/test/asan/TestCases/Linux/global-overflow-lld.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Test that gc-sections-friendly instrumentation of globals does not introduce -// false negatives with the LLD linker. -// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: lld - -#include -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at}} - // CHECK: {{located 0 bytes to the right of global variable}} - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc deleted file mode 100644 index 0d8bcdd1c..000000000 --- a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1 - -// https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// REQUIRES: lld - -int undefined(); - -// On i386 clang adds --export-dynamic when linking with ASan, which adds all -// non-hidden globals to GC roots. -__attribute__((visibility("hidden"))) int (*unused)() = undefined; - -int main() { - return 0; -} diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc new file mode 100644 index 000000000..72a9e9498 --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// XFAIL: * + +int undefined(); + +int (*unused)() = undefined; + +int main() { + return 0; +} diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index c3123a820..bd51eacb6 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -34,7 +34,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LTO ) endif() - if(WIN32 AND COMPILER_RT_HAS_LLD) + if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) list(APPEND CFI_TEST_DEPS lld ) diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 387f4d4a7..862d06bf2 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -26,7 +26,7 @@ set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@) set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@") set_default("emulator", "@COMPILER_RT_EMULATOR@") set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) -set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) +set_default("has_lld", @COMPILER_RT_HAS_LLD_SOURCES_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) config.available_features.add('target-is-%s' % config.target_arch) -- cgit v1.2.1 From 2435d1fad8853b2beea8b8eae0fa6c52feda56c3 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 20 Mar 2017 21:03:28 +0000 Subject: Bypass potential libc's sysconf wrappers for sysconf(_SC_PAGESIZE) call Summary: sysconf(_SC_PAGESIZE) is called very early, during sanitizer init and any instrumented code (a wrapper/interceptor will likely be instrumented) calling back to sanitizer before init is done will most surely crash. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31092 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298305 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 3 +++ .../Linux/sysconf_interceptor_bypass_test.cc | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 24707c74d..6b2952308 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -78,6 +78,7 @@ extern char **environ; // provided by crt1 #endif #if SANITIZER_LINUX +#include // struct kernel_timeval { long tv_sec; @@ -805,6 +806,8 @@ uptr GetPageSize() { return 4096; #elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; +#elif SANITIZER_LINUX + return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif diff --git a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc new file mode 100644 index 000000000..97b6132e2 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s + +#include + +extern "C" long sysconf(int name) { + fprintf(stderr, "sysconf wrapper called\n"); + return 0; +} + +int main() { + // All we need to check is that the sysconf() interceptor defined above was + // not called. Should it get called, it will crash right there, any + // instrumented code executed before sanitizer init is finished will crash + // accessing non-initialized sanitizer internals. Even if it will not crash + // in some configuration, it should never be called anyway. + fprintf(stderr, "Passed\n"); + // CHECK-NOT: sysconf wrapper called + // CHECK: Passed + // CHECK-NOT: sysconf wrapper called + return 0; +} -- cgit v1.2.1 From 43d584fba6ecb04daa4851e8529a90c8b79fc538 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Tue, 21 Mar 2017 05:32:51 +0000 Subject: [Builtin] Implement lit-test support (part 1 of 2: test cases update) Original r297566 is splitted into two parts. This is part one, which adds "RUN" command for test cases. Unit/arm/call_apsr.S is updated to support thumb1. It also fixes a bug in arm/aeabi_uldivmod_test.c gcc_personality_test is XFAILED as the framework cannot handle it so far. cpu_model_test is also XFAILED for now as it is expected to return non-zero. TODO: A few tests are XFAILed for armhf and aarch64. We need further investigating. [1,2] Tracks the issue. [1] https://bugs.llvm.org//show_bug.cgi?id=32260 [2] https://bugs.llvm.org//show_bug.cgi?id=32261 Reviewers: rengolin, compnerd, jroelofs, erik.pilkington, arphaman Reviewed By: jroelofs Subscribers: jroelofs, aemerson, srhines, nemanjai, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D30802 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298339 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/absvdi2_test.c | 1 + test/builtins/Unit/absvsi2_test.c | 1 + test/builtins/Unit/absvti2_test.c | 1 + test/builtins/Unit/adddf3vfp_test.c | 1 + test/builtins/Unit/addsf3vfp_test.c | 1 + test/builtins/Unit/addtf3_test.c | 1 + test/builtins/Unit/addvdi3_test.c | 1 + test/builtins/Unit/addvsi3_test.c | 1 + test/builtins/Unit/addvti3_test.c | 1 + test/builtins/Unit/arm/aeabi_cdcmpeq_test.c | 3 +++ test/builtins/Unit/arm/aeabi_cdcmple_test.c | 4 ++++ test/builtins/Unit/arm/aeabi_cfcmpeq_test.c | 3 +++ test/builtins/Unit/arm/aeabi_cfcmple_test.c | 4 ++++ test/builtins/Unit/arm/aeabi_drsub_test.c | 2 ++ test/builtins/Unit/arm/aeabi_frsub_test.c | 2 ++ test/builtins/Unit/arm/aeabi_idivmod_test.c | 2 ++ test/builtins/Unit/arm/aeabi_uidivmod_test.c | 2 ++ test/builtins/Unit/arm/aeabi_uldivmod_test.c | 2 ++ test/builtins/Unit/arm/call_apsr.S | 8 ++++---- test/builtins/Unit/ashldi3_test.c | 1 + test/builtins/Unit/ashlti3_test.c | 1 + test/builtins/Unit/ashrdi3_test.c | 1 + test/builtins/Unit/ashrti3_test.c | 1 + test/builtins/Unit/bswapdi2_test.c | 2 ++ test/builtins/Unit/bswapsi2_test.c | 2 ++ test/builtins/Unit/clear_cache_test.c | 3 +++ test/builtins/Unit/clzdi2_test.c | 1 + test/builtins/Unit/clzsi2_test.c | 1 + test/builtins/Unit/clzti2_test.c | 1 + test/builtins/Unit/cmpdi2_test.c | 1 + test/builtins/Unit/cmpti2_test.c | 1 + test/builtins/Unit/comparedf2_test.c | 4 ++++ test/builtins/Unit/comparesf2_test.c | 4 ++++ test/builtins/Unit/cpu_model_test.c | 8 +++++--- test/builtins/Unit/ctzdi2_test.c | 1 + test/builtins/Unit/ctzsi2_test.c | 1 + test/builtins/Unit/ctzti2_test.c | 1 + test/builtins/Unit/divdc3_test.c | 1 + test/builtins/Unit/divdf3vfp_test.c | 1 + test/builtins/Unit/divdi3_test.c | 1 + test/builtins/Unit/divmodsi4_test.c | 1 + test/builtins/Unit/divsc3_test.c | 1 + test/builtins/Unit/divsf3vfp_test.c | 1 + test/builtins/Unit/divsi3_test.c | 1 + test/builtins/Unit/divtc3_test.c | 1 + test/builtins/Unit/divtf3_test.c | 1 + test/builtins/Unit/divti3_test.c | 1 + test/builtins/Unit/divxc3_test.c | 1 + test/builtins/Unit/enable_execute_stack_test.c | 2 ++ test/builtins/Unit/eqdf2vfp_test.c | 4 ++++ test/builtins/Unit/eqsf2vfp_test.c | 4 ++++ test/builtins/Unit/eqtf2_test.c | 1 + test/builtins/Unit/extebdsfdf2vfp_test.c | 1 + test/builtins/Unit/extenddftf2_test.c | 1 + test/builtins/Unit/extendhfsf2_test.c | 1 + test/builtins/Unit/extendsftf2_test.c | 1 + test/builtins/Unit/ffsdi2_test.c | 1 + test/builtins/Unit/ffsti2_test.c | 1 + test/builtins/Unit/fixdfdi_test.c | 1 + test/builtins/Unit/fixdfsivfp_test.c | 4 ++++ test/builtins/Unit/fixdfti_test.c | 1 + test/builtins/Unit/fixsfdi_test.c | 1 + test/builtins/Unit/fixsfsivfp_test.c | 4 ++++ test/builtins/Unit/fixsfti_test.c | 1 + test/builtins/Unit/fixtfdi_test.c | 1 + test/builtins/Unit/fixtfsi_test.c | 1 + test/builtins/Unit/fixtfti_test.c | 1 + test/builtins/Unit/fixunsdfdi_test.c | 1 + test/builtins/Unit/fixunsdfsi_test.c | 1 + test/builtins/Unit/fixunsdfsivfp_test.c | 1 + test/builtins/Unit/fixunsdfti_test.c | 1 + test/builtins/Unit/fixunssfdi_test.c | 1 + test/builtins/Unit/fixunssfsi_test.c | 1 + test/builtins/Unit/fixunssfsivfp_test.c | 4 ++++ test/builtins/Unit/fixunssfti_test.c | 1 + test/builtins/Unit/fixunstfdi_test.c | 1 + test/builtins/Unit/fixunstfsi_test.c | 1 + test/builtins/Unit/fixunstfti_test.c | 1 + test/builtins/Unit/fixunsxfdi_test.c | 1 + test/builtins/Unit/fixunsxfsi_test.c | 1 + test/builtins/Unit/fixunsxfti_test.c | 4 ++++ test/builtins/Unit/fixxfdi_test.c | 1 + test/builtins/Unit/fixxfti_test.c | 4 ++++ test/builtins/Unit/floatdidf_test.c | 1 + test/builtins/Unit/floatdisf_test.c | 1 + test/builtins/Unit/floatditf_test.c | 1 + test/builtins/Unit/floatdixf_test.c | 1 + test/builtins/Unit/floatsidfvfp_test.c | 1 + test/builtins/Unit/floatsisfvfp_test.c | 1 + test/builtins/Unit/floatsitf_test.c | 1 + test/builtins/Unit/floattidf_test.c | 1 + test/builtins/Unit/floattisf_test.c | 1 + test/builtins/Unit/floattitf_test.c | 1 + test/builtins/Unit/floattixf_test.c | 4 ++++ test/builtins/Unit/floatundidf_test.c | 1 + test/builtins/Unit/floatundisf_test.c | 1 + test/builtins/Unit/floatunditf_test.c | 1 + test/builtins/Unit/floatundixf_test.c | 1 + test/builtins/Unit/floatunsitf_test.c | 1 + test/builtins/Unit/floatunssidfvfp_test.c | 1 + test/builtins/Unit/floatunssisfvfp_test.c | 1 + test/builtins/Unit/floatuntidf_test.c | 1 + test/builtins/Unit/floatuntisf_test.c | 1 + test/builtins/Unit/floatuntitf_test.c | 1 + test/builtins/Unit/floatuntixf_test.c | 4 ++++ test/builtins/Unit/gcc_personality_test.c | 3 +++ test/builtins/Unit/gedf2vfp_test.c | 4 ++++ test/builtins/Unit/gesf2vfp_test.c | 4 ++++ test/builtins/Unit/getf2_test.c | 1 + test/builtins/Unit/gtdf2vfp_test.c | 4 ++++ test/builtins/Unit/gtsf2vfp_test.c | 4 ++++ test/builtins/Unit/gttf2_test.c | 1 + test/builtins/Unit/ledf2vfp_test.c | 4 ++++ test/builtins/Unit/lesf2vfp_test.c | 4 ++++ test/builtins/Unit/letf2_test.c | 1 + test/builtins/Unit/lshrdi3_test.c | 1 + test/builtins/Unit/lshrti3_test.c | 1 + test/builtins/Unit/ltdf2vfp_test.c | 4 ++++ test/builtins/Unit/ltsf2vfp_test.c | 4 ++++ test/builtins/Unit/lttf2_test.c | 1 + test/builtins/Unit/moddi3_test.c | 1 + test/builtins/Unit/modsi3_test.c | 1 + test/builtins/Unit/modti3_test.c | 1 + test/builtins/Unit/muldc3_test.c | 1 + test/builtins/Unit/muldf3vfp_test.c | 1 + test/builtins/Unit/muldi3_test.c | 1 + test/builtins/Unit/mulodi4_test.c | 1 + test/builtins/Unit/mulosi4_test.c | 1 + test/builtins/Unit/muloti4_test.c | 1 + test/builtins/Unit/mulsc3_test.c | 1 + test/builtins/Unit/mulsf3vfp_test.c | 1 + test/builtins/Unit/multc3_test.c | 1 + test/builtins/Unit/multf3_test.c | 1 + test/builtins/Unit/multi3_test.c | 1 + test/builtins/Unit/mulvdi3_test.c | 1 + test/builtins/Unit/mulvsi3_test.c | 1 + test/builtins/Unit/mulvti3_test.c | 1 + test/builtins/Unit/mulxc3_test.c | 1 + test/builtins/Unit/nedf2vfp_test.c | 4 ++++ test/builtins/Unit/negdf2vfp_test.c | 1 + test/builtins/Unit/negdi2_test.c | 1 + test/builtins/Unit/negsf2vfp_test.c | 1 + test/builtins/Unit/negti2_test.c | 1 + test/builtins/Unit/negvdi2_test.c | 1 + test/builtins/Unit/negvsi2_test.c | 1 + test/builtins/Unit/negvti2_test.c | 1 + test/builtins/Unit/nesf2vfp_test.c | 4 ++++ test/builtins/Unit/netf2_test.c | 1 + test/builtins/Unit/paritydi2_test.c | 1 + test/builtins/Unit/paritysi2_test.c | 1 + test/builtins/Unit/parityti2_test.c | 1 + test/builtins/Unit/popcountdi2_test.c | 1 + test/builtins/Unit/popcountsi2_test.c | 1 + test/builtins/Unit/popcountti2_test.c | 1 + test/builtins/Unit/powidf2_test.c | 1 + test/builtins/Unit/powisf2_test.c | 1 + test/builtins/Unit/powitf2_test.c | 1 + test/builtins/Unit/powixf2_test.c | 1 + test/builtins/Unit/ppc/fixtfdi_test.c | 2 ++ test/builtins/Unit/ppc/floatditf_test.c | 2 ++ test/builtins/Unit/ppc/floatunditf_test.c | 2 ++ test/builtins/Unit/ppc/qadd_test.c | 2 ++ test/builtins/Unit/ppc/qdiv_test.c | 2 ++ test/builtins/Unit/ppc/qmul_test.c | 2 ++ test/builtins/Unit/ppc/qsub_test.c | 2 ++ test/builtins/Unit/subdf3vfp_test.c | 1 + test/builtins/Unit/subsf3vfp_test.c | 1 + test/builtins/Unit/subtf3_test.c | 1 + test/builtins/Unit/subvdi3_test.c | 1 + test/builtins/Unit/subvsi3_test.c | 1 + test/builtins/Unit/subvti3_test.c | 1 + test/builtins/Unit/trampoline_setup_test.c | 1 + test/builtins/Unit/truncdfhf2_test.c | 4 ++++ test/builtins/Unit/truncdfsf2_test.c | 4 ++++ test/builtins/Unit/truncdfsf2vfp_test.c | 1 + test/builtins/Unit/truncsfhf2_test.c | 4 ++++ test/builtins/Unit/trunctfdf2_test.c | 1 + test/builtins/Unit/trunctfsf2_test.c | 1 + test/builtins/Unit/ucmpdi2_test.c | 1 + test/builtins/Unit/ucmpti2_test.c | 1 + test/builtins/Unit/udivdi3_test.c | 1 + test/builtins/Unit/udivmoddi4_test.c | 1 + test/builtins/Unit/udivmodsi4_test.c | 1 + test/builtins/Unit/udivmodti4_test.c | 1 + test/builtins/Unit/udivsi3_test.c | 1 + test/builtins/Unit/udivti3_test.c | 1 + test/builtins/Unit/umoddi3_test.c | 1 + test/builtins/Unit/umodsi3_test.c | 1 + test/builtins/Unit/umodti3_test.c | 1 + test/builtins/Unit/unorddf2vfp_test.c | 4 ++++ test/builtins/Unit/unordsf2vfp_test.c | 4 ++++ test/builtins/Unit/unordtf2_test.c | 1 + 192 files changed, 306 insertions(+), 7 deletions(-) diff --git a/test/builtins/Unit/absvdi2_test.c b/test/builtins/Unit/absvdi2_test.c index f69ae4151..dd9dfd17e 100644 --- a/test/builtins/Unit/absvdi2_test.c +++ b/test/builtins/Unit/absvdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- absvdi2_test.c - Test __absvdi2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/absvsi2_test.c b/test/builtins/Unit/absvsi2_test.c index c395cca7a..bae306b2c 100644 --- a/test/builtins/Unit/absvsi2_test.c +++ b/test/builtins/Unit/absvsi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- absvsi2_test.c - Test __absvsi2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/absvti2_test.c b/test/builtins/Unit/absvti2_test.c index 6c626e97d..0c0117dfe 100644 --- a/test/builtins/Unit/absvti2_test.c +++ b/test/builtins/Unit/absvti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- absvti2_test.c - Test __absvti2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/adddf3vfp_test.c b/test/builtins/Unit/adddf3vfp_test.c index c1b988419..e0da08bc0 100644 --- a/test/builtins/Unit/adddf3vfp_test.c +++ b/test/builtins/Unit/adddf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- adddf3vfp_test.c - Test __adddf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/addsf3vfp_test.c b/test/builtins/Unit/addsf3vfp_test.c index 958865d68..ed18de3b6 100644 --- a/test/builtins/Unit/addsf3vfp_test.c +++ b/test/builtins/Unit/addsf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- addsf3vfp_test.c - Test __addsf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/addtf3_test.c b/test/builtins/Unit/addtf3_test.c index 7b92ccee1..57a4729f4 100644 --- a/test/builtins/Unit/addtf3_test.c +++ b/test/builtins/Unit/addtf3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- addtf3_test.c - Test __addtf3 ------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/addvdi3_test.c b/test/builtins/Unit/addvdi3_test.c index 5f8729a61..99e70403e 100644 --- a/test/builtins/Unit/addvdi3_test.c +++ b/test/builtins/Unit/addvdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- addvdi3_test.c - Test __addvdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/addvsi3_test.c b/test/builtins/Unit/addvsi3_test.c index b5358d0f5..11fdbc3c1 100644 --- a/test/builtins/Unit/addvsi3_test.c +++ b/test/builtins/Unit/addvsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- addvsi3_test.c - Test __addvsi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/addvti3_test.c b/test/builtins/Unit/addvti3_test.c index e2f75cf86..3ffcf4b2d 100644 --- a/test/builtins/Unit/addvti3_test.c +++ b/test/builtins/Unit/addvti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- addvti3_test.c - Test __addvti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c b/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c index ce8b0a431..0d9e006f0 100644 --- a/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c +++ b/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c @@ -1,3 +1,6 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %arm_call_apsr -o %t.aspr.o +// RUN: %clang_builtins %s %t.aspr.o %librt -o %t && %run %t //===-- aeabi_cdcmpeq.c - Test __aeabi_cdcmpeq ----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_cdcmple_test.c b/test/builtins/Unit/arm/aeabi_cdcmple_test.c index afc701493..e499bf85a 100644 --- a/test/builtins/Unit/arm/aeabi_cdcmple_test.c +++ b/test/builtins/Unit/arm/aeabi_cdcmple_test.c @@ -1,3 +1,7 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %arm_call_apsr -o %t.aspr.o +// RUN: %clang_builtins %s %t.aspr.o %librt -o %t && %run %t + //===-- aeabi_cdcmple.c - Test __aeabi_cdcmple and __aeabi_cdrcmple -------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_cfcmpeq_test.c b/test/builtins/Unit/arm/aeabi_cfcmpeq_test.c index fe0166485..72a556ca7 100644 --- a/test/builtins/Unit/arm/aeabi_cfcmpeq_test.c +++ b/test/builtins/Unit/arm/aeabi_cfcmpeq_test.c @@ -1,3 +1,6 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %arm_call_apsr -o %t.aspr.o +// RUN: %clang_builtins %s %t.aspr.o %librt -o %t && %run %t //===-- aeabi_cfcmpeq.c - Test __aeabi_cfcmpeq ----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_cfcmple_test.c b/test/builtins/Unit/arm/aeabi_cfcmple_test.c index aebe4257e..a09aead6b 100644 --- a/test/builtins/Unit/arm/aeabi_cfcmple_test.c +++ b/test/builtins/Unit/arm/aeabi_cfcmple_test.c @@ -1,3 +1,7 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %arm_call_apsr -o %t.aspr.o +// RUN: %clang_builtins %s %t.aspr.o %librt -o %t && %run %t + //===-- aeabi_cfcmple.c - Test __aeabi_cfcmple and __aeabi_cfrcmple -------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_drsub_test.c b/test/builtins/Unit/arm/aeabi_drsub_test.c index 7d867ef2c..8bd04a989 100644 --- a/test/builtins/Unit/arm/aeabi_drsub_test.c +++ b/test/builtins/Unit/arm/aeabi_drsub_test.c @@ -1,3 +1,5 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- aeabi_drsub.c - Test __aeabi_drsub --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_frsub_test.c b/test/builtins/Unit/arm/aeabi_frsub_test.c index b8b21b96e..3d301616a 100644 --- a/test/builtins/Unit/arm/aeabi_frsub_test.c +++ b/test/builtins/Unit/arm/aeabi_frsub_test.c @@ -1,3 +1,5 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- aeabi_frsub.c - Test __aeabi_frsub --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_idivmod_test.c b/test/builtins/Unit/arm/aeabi_idivmod_test.c index c732e4ba4..ac1804694 100644 --- a/test/builtins/Unit/arm/aeabi_idivmod_test.c +++ b/test/builtins/Unit/arm/aeabi_idivmod_test.c @@ -1,3 +1,5 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- aeabi_idivmod_test.c - Test __aeabi_idivmod -----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_uidivmod_test.c b/test/builtins/Unit/arm/aeabi_uidivmod_test.c index 81d5e0e1f..9ac51da59 100644 --- a/test/builtins/Unit/arm/aeabi_uidivmod_test.c +++ b/test/builtins/Unit/arm/aeabi_uidivmod_test.c @@ -1,3 +1,5 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- aeabi_uidivmod_test.c - Test __aeabi_uidivmod ---------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/aeabi_uldivmod_test.c b/test/builtins/Unit/arm/aeabi_uldivmod_test.c index f629d6b4d..a40f006fa 100644 --- a/test/builtins/Unit/arm/aeabi_uldivmod_test.c +++ b/test/builtins/Unit/arm/aeabi_uldivmod_test.c @@ -1,3 +1,5 @@ +// REQUIRES-ANY: arm-target-arch,armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- aeabi_uldivmod_test.c - Test aeabi_uldivmod -----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/arm/call_apsr.S b/test/builtins/Unit/arm/call_apsr.S index b5e154cff..2656f8de6 100644 --- a/test/builtins/Unit/arm/call_apsr.S +++ b/test/builtins/Unit/arm/call_apsr.S @@ -22,11 +22,11 @@ // } DEFINE_COMPILERRT_PRIVATE_FUNCTION(call_apsr_d) - push {lr} - ldr ip, [sp, #4] - blx ip + push {r7, lr} + ldr r7, [sp, #8] + blx r7 mrs r0, apsr - pop {pc} + pop {r7, pc} END_COMPILERRT_FUNCTION(call_apsr_d) // __attribute__((pcs("aapcs"))) diff --git a/test/builtins/Unit/ashldi3_test.c b/test/builtins/Unit/ashldi3_test.c index 398fb69be..f0984e06d 100644 --- a/test/builtins/Unit/ashldi3_test.c +++ b/test/builtins/Unit/ashldi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ashldi3_test.c - Test __ashldi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ashlti3_test.c b/test/builtins/Unit/ashlti3_test.c index 595e35306..06186614f 100644 --- a/test/builtins/Unit/ashlti3_test.c +++ b/test/builtins/Unit/ashlti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ashlti3_test.c - Test __ashlti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ashrdi3_test.c b/test/builtins/Unit/ashrdi3_test.c index ee6409c87..a987c9530 100644 --- a/test/builtins/Unit/ashrdi3_test.c +++ b/test/builtins/Unit/ashrdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ashrdi3_test.c - Test __ashrdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ashrti3_test.c b/test/builtins/Unit/ashrti3_test.c index 201582d4e..1f0865352 100644 --- a/test/builtins/Unit/ashrti3_test.c +++ b/test/builtins/Unit/ashrti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ashrti3_test.c - Test __ashrti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/bswapdi2_test.c b/test/builtins/Unit/bswapdi2_test.c index 2d830cf5e..6881c8092 100644 --- a/test/builtins/Unit/bswapdi2_test.c +++ b/test/builtins/Unit/bswapdi2_test.c @@ -1,3 +1,5 @@ +// UNSUPPORTED: armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- bswapdi2_test.c - Test __bswapdi2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/bswapsi2_test.c b/test/builtins/Unit/bswapsi2_test.c index 4488a888e..c32cbb442 100644 --- a/test/builtins/Unit/bswapsi2_test.c +++ b/test/builtins/Unit/bswapsi2_test.c @@ -1,3 +1,5 @@ +// UNSUPPORTED: armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- bswapsi2_test.c - Test __bswapsi2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/clear_cache_test.c b/test/builtins/Unit/clear_cache_test.c index 0ef704fcd..590be7eb2 100644 --- a/test/builtins/Unit/clear_cache_test.c +++ b/test/builtins/Unit/clear_cache_test.c @@ -1,3 +1,6 @@ +// REQUIRES: native-run +// UNSUPPORTED: arm, aarch64 +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- clear_cache_test.c - Test clear_cache -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/clzdi2_test.c b/test/builtins/Unit/clzdi2_test.c index 41e120932..a8c0e1b35 100644 --- a/test/builtins/Unit/clzdi2_test.c +++ b/test/builtins/Unit/clzdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- clzdi2_test.c - Test __clzdi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/clzsi2_test.c b/test/builtins/Unit/clzsi2_test.c index 80b300fee..f86e8885e 100644 --- a/test/builtins/Unit/clzsi2_test.c +++ b/test/builtins/Unit/clzsi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- clzsi2_test.c - Test __clzsi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/clzti2_test.c b/test/builtins/Unit/clzti2_test.c index 3a2c6fabb..157838b6b 100644 --- a/test/builtins/Unit/clzti2_test.c +++ b/test/builtins/Unit/clzti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- clzti2_test.c - Test __clzti2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/cmpdi2_test.c b/test/builtins/Unit/cmpdi2_test.c index 33a12a042..1420dc773 100644 --- a/test/builtins/Unit/cmpdi2_test.c +++ b/test/builtins/Unit/cmpdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- cmpdi2_test.c - Test __cmpdi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/cmpti2_test.c b/test/builtins/Unit/cmpti2_test.c index d951923b2..a2215f3c1 100644 --- a/test/builtins/Unit/cmpti2_test.c +++ b/test/builtins/Unit/cmpti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- cmpti2_test.c - Test __cmpti2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/comparedf2_test.c b/test/builtins/Unit/comparedf2_test.c index 662372290..a7db7a433 100644 --- a/test/builtins/Unit/comparedf2_test.c +++ b/test/builtins/Unit/comparedf2_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- cmpdf2_test.c - Test __cmpdf2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/comparesf2_test.c b/test/builtins/Unit/comparesf2_test.c index 026e90053..9f42d9784 100644 --- a/test/builtins/Unit/comparesf2_test.c +++ b/test/builtins/Unit/comparesf2_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- cmpsf2_test.c - Test __cmpsf2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/cpu_model_test.c b/test/builtins/Unit/cpu_model_test.c index ed484cdd4..6b47d143f 100644 --- a/test/builtins/Unit/cpu_model_test.c +++ b/test/builtins/Unit/cpu_model_test.c @@ -1,4 +1,8 @@ -//===-- cpu_model_test.c - Test __builtin_cpu_supports -------------------------------===// +// FIXME: XFAIL the test because it is expected to return non-zero value. +// XFAIL: * +// REQUIRES: x86-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t +//===-- cpu_model_test.c - Test __builtin_cpu_supports --------------------===// // // The LLVM Compiler Infrastructure // @@ -11,8 +15,6 @@ // //===----------------------------------------------------------------------===// -// REQUIRES: x86-target-arch - #include int main (void) { diff --git a/test/builtins/Unit/ctzdi2_test.c b/test/builtins/Unit/ctzdi2_test.c index bde66b1e5..0515e2072 100644 --- a/test/builtins/Unit/ctzdi2_test.c +++ b/test/builtins/Unit/ctzdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ctzdi2_test.c - Test __ctzdi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ctzsi2_test.c b/test/builtins/Unit/ctzsi2_test.c index cbc101fca..bf8982bf0 100644 --- a/test/builtins/Unit/ctzsi2_test.c +++ b/test/builtins/Unit/ctzsi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ctzsi2_test.c - Test __ctzsi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ctzti2_test.c b/test/builtins/Unit/ctzti2_test.c index 0ca1920bd..bef79b6f8 100644 --- a/test/builtins/Unit/ctzti2_test.c +++ b/test/builtins/Unit/ctzti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ctzti2_test.c - Test __ctzti2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divdc3_test.c b/test/builtins/Unit/divdc3_test.c index 80b9e86e1..3c69cf3d0 100644 --- a/test/builtins/Unit/divdc3_test.c +++ b/test/builtins/Unit/divdc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divdc3_test.c - Test __divdc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divdf3vfp_test.c b/test/builtins/Unit/divdf3vfp_test.c index 8735f6378..4f18409a2 100644 --- a/test/builtins/Unit/divdf3vfp_test.c +++ b/test/builtins/Unit/divdf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divdf3vfp_test.c - Test __divdf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divdi3_test.c b/test/builtins/Unit/divdi3_test.c index 1d459803e..4c8c92226 100644 --- a/test/builtins/Unit/divdi3_test.c +++ b/test/builtins/Unit/divdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divdi3_test.c - Test __divdi3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divmodsi4_test.c b/test/builtins/Unit/divmodsi4_test.c index 6fb1c985a..e766aaee1 100644 --- a/test/builtins/Unit/divmodsi4_test.c +++ b/test/builtins/Unit/divmodsi4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divmodsi4_test.c - Test __divmodsi4 -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divsc3_test.c b/test/builtins/Unit/divsc3_test.c index 2d7c65937..42430151f 100644 --- a/test/builtins/Unit/divsc3_test.c +++ b/test/builtins/Unit/divsc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- divsc3_test.c - Test __divsc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divsf3vfp_test.c b/test/builtins/Unit/divsf3vfp_test.c index 039fa7f01..75b7eba7a 100644 --- a/test/builtins/Unit/divsf3vfp_test.c +++ b/test/builtins/Unit/divsf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divsf3vfp_test.c - Test __divsf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divsi3_test.c b/test/builtins/Unit/divsi3_test.c index c52336745..4c5d0fba5 100644 --- a/test/builtins/Unit/divsi3_test.c +++ b/test/builtins/Unit/divsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divsi3_test.c - Test __divsi3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divtc3_test.c b/test/builtins/Unit/divtc3_test.c index a1f061344..f561a9644 100644 --- a/test/builtins/Unit/divtc3_test.c +++ b/test/builtins/Unit/divtc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- divtc3_test.c - Test __divtc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divtf3_test.c b/test/builtins/Unit/divtf3_test.c index e0def45ff..12cb94a26 100644 --- a/test/builtins/Unit/divtf3_test.c +++ b/test/builtins/Unit/divtf3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- divtf3_test.c - Test __divtf3 ------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divti3_test.c b/test/builtins/Unit/divti3_test.c index 3a94dab8c..9a6bf178b 100644 --- a/test/builtins/Unit/divti3_test.c +++ b/test/builtins/Unit/divti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- divti3_test.c - Test __divti3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c index 509b4b18e..d71660bfe 100644 --- a/test/builtins/Unit/divxc3_test.c +++ b/test/builtins/Unit/divxc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- divxc3_test.c - Test __divxc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/enable_execute_stack_test.c b/test/builtins/Unit/enable_execute_stack_test.c index 38a142afb..24165ed9f 100644 --- a/test/builtins/Unit/enable_execute_stack_test.c +++ b/test/builtins/Unit/enable_execute_stack_test.c @@ -1,3 +1,5 @@ +// REQUIRES: native-run +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- enable_execute_stack_test.c - Test __enable_execute_stack ----------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/eqdf2vfp_test.c b/test/builtins/Unit/eqdf2vfp_test.c index 4780d87ea..549c37e1a 100644 --- a/test/builtins/Unit/eqdf2vfp_test.c +++ b/test/builtins/Unit/eqdf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- eqdf2vfp_test.c - Test __eqdf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/eqsf2vfp_test.c b/test/builtins/Unit/eqsf2vfp_test.c index 7d6f581ce..628b0fd75 100644 --- a/test/builtins/Unit/eqsf2vfp_test.c +++ b/test/builtins/Unit/eqsf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- eqsf2vfp_test.c - Test __eqsf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/eqtf2_test.c b/test/builtins/Unit/eqtf2_test.c index 038583503..91b35cff2 100644 --- a/test/builtins/Unit/eqtf2_test.c +++ b/test/builtins/Unit/eqtf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ eqtf2_test.c - Test __eqtf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/extebdsfdf2vfp_test.c b/test/builtins/Unit/extebdsfdf2vfp_test.c index ec27c4c69..c350d933d 100644 --- a/test/builtins/Unit/extebdsfdf2vfp_test.c +++ b/test/builtins/Unit/extebdsfdf2vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- extendsfdf2vfp_test.c - Test __extendsfdf2vfp ---------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/extenddftf2_test.c b/test/builtins/Unit/extenddftf2_test.c index 2cfb32b26..7254141a2 100644 --- a/test/builtins/Unit/extenddftf2_test.c +++ b/test/builtins/Unit/extenddftf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- extenddftf2_test.c - Test __extenddftf2 --------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/extendhfsf2_test.c b/test/builtins/Unit/extendhfsf2_test.c index 5dd994cae..d423e7b4e 100644 --- a/test/builtins/Unit/extendhfsf2_test.c +++ b/test/builtins/Unit/extendhfsf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- extendhfsf2_test.c - Test __extendhfsf2 --------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/extendsftf2_test.c b/test/builtins/Unit/extendsftf2_test.c index 7dff5b6be..4fad9060f 100644 --- a/test/builtins/Unit/extendsftf2_test.c +++ b/test/builtins/Unit/extendsftf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- extendsftf2_test.c - Test __extendsftf2 --------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ffsdi2_test.c b/test/builtins/Unit/ffsdi2_test.c index a27d154fd..80c0c08cb 100644 --- a/test/builtins/Unit/ffsdi2_test.c +++ b/test/builtins/Unit/ffsdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ffsdi2_test.c - Test __ffsdi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ffsti2_test.c b/test/builtins/Unit/ffsti2_test.c index 396269d51..3b312c430 100644 --- a/test/builtins/Unit/ffsti2_test.c +++ b/test/builtins/Unit/ffsti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ffsti2_test.c - Test __ffsti2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixdfdi_test.c b/test/builtins/Unit/fixdfdi_test.c index 4a7cfa31c..d2ba7b19f 100644 --- a/test/builtins/Unit/fixdfdi_test.c +++ b/test/builtins/Unit/fixdfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixdfdi_test.c - Test __fixdfdi -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixdfsivfp_test.c b/test/builtins/Unit/fixdfsivfp_test.c index 73e4e58ed..3cd420aa6 100644 --- a/test/builtins/Unit/fixdfsivfp_test.c +++ b/test/builtins/Unit/fixdfsivfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- fixdfsivfp_test.c - Test __fixdfsivfp -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixdfti_test.c b/test/builtins/Unit/fixdfti_test.c index b5da456fc..0abe187ae 100644 --- a/test/builtins/Unit/fixdfti_test.c +++ b/test/builtins/Unit/fixdfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixdfti_test.c - Test __fixdfti -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixsfdi_test.c b/test/builtins/Unit/fixsfdi_test.c index f37ecef04..468299f9b 100644 --- a/test/builtins/Unit/fixsfdi_test.c +++ b/test/builtins/Unit/fixsfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixsfdi_test.c - Test __fixsfdi -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixsfsivfp_test.c b/test/builtins/Unit/fixsfsivfp_test.c index 0ded952d1..0e233a5f8 100644 --- a/test/builtins/Unit/fixsfsivfp_test.c +++ b/test/builtins/Unit/fixsfsivfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- fixsfsivfp_test.c - Test __fixsfsivfp -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixsfti_test.c b/test/builtins/Unit/fixsfti_test.c index 38748aabc..ec4e8ddb0 100644 --- a/test/builtins/Unit/fixsfti_test.c +++ b/test/builtins/Unit/fixsfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixsfti_test.c - Test __fixsfti -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixtfdi_test.c b/test/builtins/Unit/fixtfdi_test.c index cc25becb2..3cd1ebf78 100644 --- a/test/builtins/Unit/fixtfdi_test.c +++ b/test/builtins/Unit/fixtfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- fixtfdi_test.c - Test __fixtfdi ----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixtfsi_test.c b/test/builtins/Unit/fixtfsi_test.c index 1da516bd0..59e43520a 100644 --- a/test/builtins/Unit/fixtfsi_test.c +++ b/test/builtins/Unit/fixtfsi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- fixtfsi_test.c - Test __fixtfsi ----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixtfti_test.c b/test/builtins/Unit/fixtfti_test.c index 52184ca62..4d3b56c78 100644 --- a/test/builtins/Unit/fixtfti_test.c +++ b/test/builtins/Unit/fixtfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- fixtfti_test.c - Test __fixtfti ----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsdfdi_test.c b/test/builtins/Unit/fixunsdfdi_test.c index 399848287..ab09bd0f3 100644 --- a/test/builtins/Unit/fixunsdfdi_test.c +++ b/test/builtins/Unit/fixunsdfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsdfdi_test.c - Test __fixunsdfdi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsdfsi_test.c b/test/builtins/Unit/fixunsdfsi_test.c index 8d3d6304f..7fbd9ee11 100644 --- a/test/builtins/Unit/fixunsdfsi_test.c +++ b/test/builtins/Unit/fixunsdfsi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsdfsi_test.c - Test __fixunsdfsi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsdfsivfp_test.c b/test/builtins/Unit/fixunsdfsivfp_test.c index 33cec81da..b70799247 100644 --- a/test/builtins/Unit/fixunsdfsivfp_test.c +++ b/test/builtins/Unit/fixunsdfsivfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsdfsivfp_test.c - Test __fixunsdfsivfp -----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsdfti_test.c b/test/builtins/Unit/fixunsdfti_test.c index 0298fb9e9..249d8f886 100644 --- a/test/builtins/Unit/fixunsdfti_test.c +++ b/test/builtins/Unit/fixunsdfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsdfti_test.c - Test __fixunsdfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunssfdi_test.c b/test/builtins/Unit/fixunssfdi_test.c index 812457a00..2d693eb9c 100644 --- a/test/builtins/Unit/fixunssfdi_test.c +++ b/test/builtins/Unit/fixunssfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunssfdi_test.c - Test __fixunssfdi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunssfsi_test.c b/test/builtins/Unit/fixunssfsi_test.c index 17293e438..3974b5329 100644 --- a/test/builtins/Unit/fixunssfsi_test.c +++ b/test/builtins/Unit/fixunssfsi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunssfsi_test.c - Test __fixunssfsi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunssfsivfp_test.c b/test/builtins/Unit/fixunssfsivfp_test.c index 9c8194ff0..f745d6f55 100644 --- a/test/builtins/Unit/fixunssfsivfp_test.c +++ b/test/builtins/Unit/fixunssfsivfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- fixunssfsivfp_test.c - Test __fixunssfsivfp -----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunssfti_test.c b/test/builtins/Unit/fixunssfti_test.c index 979d66191..fd2d108f2 100644 --- a/test/builtins/Unit/fixunssfti_test.c +++ b/test/builtins/Unit/fixunssfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunssfti_test.c - Test __fixunssfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunstfdi_test.c b/test/builtins/Unit/fixunstfdi_test.c index 817c59b2d..67fcc2fde 100644 --- a/test/builtins/Unit/fixunstfdi_test.c +++ b/test/builtins/Unit/fixunstfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunstfdi_test.c - Test __fixunstfdi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunstfsi_test.c b/test/builtins/Unit/fixunstfsi_test.c index 13ed77952..edf5422a8 100644 --- a/test/builtins/Unit/fixunstfsi_test.c +++ b/test/builtins/Unit/fixunstfsi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- fixunstfsi_test.c - Test __fixunstfsi ----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunstfti_test.c b/test/builtins/Unit/fixunstfti_test.c index 60a0982b6..019b72049 100644 --- a/test/builtins/Unit/fixunstfti_test.c +++ b/test/builtins/Unit/fixunstfti_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunstfti_test.c - Test __fixunstfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsxfdi_test.c b/test/builtins/Unit/fixunsxfdi_test.c index 6f4207969..c5c27d359 100644 --- a/test/builtins/Unit/fixunsxfdi_test.c +++ b/test/builtins/Unit/fixunsxfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsxfdi_test.c - Test __fixunsxfdi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsxfsi_test.c b/test/builtins/Unit/fixunsxfsi_test.c index 0d78dcb53..e0bed7ec8 100644 --- a/test/builtins/Unit/fixunsxfsi_test.c +++ b/test/builtins/Unit/fixunsxfsi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixunsxfsi_test.c - Test __fixunsxfsi -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixunsxfti_test.c b/test/builtins/Unit/fixunsxfti_test.c index 94b5aebe4..28a7e9783 100644 --- a/test/builtins/Unit/fixunsxfti_test.c +++ b/test/builtins/Unit/fixunsxfti_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: aarch64 +// test fails for aarch64 (see pr32260) + //===-- fixunsxfti_test.c - Test __fixunsxfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixxfdi_test.c b/test/builtins/Unit/fixxfdi_test.c index 0a90a56e6..40ad2b04f 100644 --- a/test/builtins/Unit/fixxfdi_test.c +++ b/test/builtins/Unit/fixxfdi_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- fixxfdi_test.c - Test __fixxfdi -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixxfti_test.c b/test/builtins/Unit/fixxfti_test.c index b8573cc14..c6d42c6e1 100644 --- a/test/builtins/Unit/fixxfti_test.c +++ b/test/builtins/Unit/fixxfti_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: aarch64 +// test fails for aarch64 (see pr32260) + //===-- fixxfti_test.c - Test __fixxfti -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatdidf_test.c b/test/builtins/Unit/floatdidf_test.c index 9bf2be97c..77429173d 100644 --- a/test/builtins/Unit/floatdidf_test.c +++ b/test/builtins/Unit/floatdidf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatdidf.c - Test __floatdidf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatdisf_test.c b/test/builtins/Unit/floatdisf_test.c index a55c6a961..8299bb171 100644 --- a/test/builtins/Unit/floatdisf_test.c +++ b/test/builtins/Unit/floatdisf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatdisf_test.c - Test __floatdisf -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatditf_test.c b/test/builtins/Unit/floatditf_test.c index 8cf8a0859..bdfb7f948 100644 --- a/test/builtins/Unit/floatditf_test.c +++ b/test/builtins/Unit/floatditf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatditf_test.c - Test __floatditf -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatdixf_test.c b/test/builtins/Unit/floatdixf_test.c index f6ab5a466..0a4ca3a57 100644 --- a/test/builtins/Unit/floatdixf_test.c +++ b/test/builtins/Unit/floatdixf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatdixf_test.c - Test __floatdixf -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatsidfvfp_test.c b/test/builtins/Unit/floatsidfvfp_test.c index 8404a7ec6..8a3c7fb4e 100644 --- a/test/builtins/Unit/floatsidfvfp_test.c +++ b/test/builtins/Unit/floatsidfvfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatsidfvfp_test.c - Test __floatsidfvfp -------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatsisfvfp_test.c b/test/builtins/Unit/floatsisfvfp_test.c index c41cf9d51..7c044b2f3 100644 --- a/test/builtins/Unit/floatsisfvfp_test.c +++ b/test/builtins/Unit/floatsisfvfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatsisfvfp_test.c - Test __floatsisfvfp -------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatsitf_test.c b/test/builtins/Unit/floatsitf_test.c index 6f98721b0..f8d700b3b 100644 --- a/test/builtins/Unit/floatsitf_test.c +++ b/test/builtins/Unit/floatsitf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- floatsitf_test.c - Test __floatsitf ------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattidf_test.c b/test/builtins/Unit/floattidf_test.c index 3af382ac0..9da8c5dc6 100644 --- a/test/builtins/Unit/floattidf_test.c +++ b/test/builtins/Unit/floattidf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floattidf.c - Test __floattidf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattisf_test.c b/test/builtins/Unit/floattisf_test.c index 0f5dc544d..9d7282cde 100644 --- a/test/builtins/Unit/floattisf_test.c +++ b/test/builtins/Unit/floattisf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floattisf_test.c - Test __floattisf -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattitf_test.c b/test/builtins/Unit/floattitf_test.c index 928b2e881..5aeb76057 100644 --- a/test/builtins/Unit/floattitf_test.c +++ b/test/builtins/Unit/floattitf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floattitf.c - Test __floattitf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattixf_test.c b/test/builtins/Unit/floattixf_test.c index d281debdc..00644fae1 100644 --- a/test/builtins/Unit/floattixf_test.c +++ b/test/builtins/Unit/floattixf_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: aarch64 +// test fails for aarch64 (see pr32260) + //===-- floattixf.c - Test __floattixf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatundidf_test.c b/test/builtins/Unit/floatundidf_test.c index 97fb1e5ec..d5d74195c 100644 --- a/test/builtins/Unit/floatundidf_test.c +++ b/test/builtins/Unit/floatundidf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatundidf_test.c - Test __floatundidf ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatundisf_test.c b/test/builtins/Unit/floatundisf_test.c index 40b6bcc45..898d8863f 100644 --- a/test/builtins/Unit/floatundisf_test.c +++ b/test/builtins/Unit/floatundisf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatundisf_test.c - Test __floatundisf ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatunditf_test.c b/test/builtins/Unit/floatunditf_test.c index b66a174a3..342dc278f 100644 --- a/test/builtins/Unit/floatunditf_test.c +++ b/test/builtins/Unit/floatunditf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatunditf_test.c - Test __floatunditf ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatundixf_test.c b/test/builtins/Unit/floatundixf_test.c index 690dce199..47b431697 100644 --- a/test/builtins/Unit/floatundixf_test.c +++ b/test/builtins/Unit/floatundixf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatundixf_test.c - Test __floatundixf ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatunsitf_test.c b/test/builtins/Unit/floatunsitf_test.c index c3d3fe949..966a4fd7b 100644 --- a/test/builtins/Unit/floatunsitf_test.c +++ b/test/builtins/Unit/floatunsitf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- floatunsitf_test.c - Test __floatunsitf --------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatunssidfvfp_test.c b/test/builtins/Unit/floatunssidfvfp_test.c index 1671c74bb..733755719 100644 --- a/test/builtins/Unit/floatunssidfvfp_test.c +++ b/test/builtins/Unit/floatunssidfvfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatunssidfvfp_test.c - Test __floatunssidfvfp -------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatunssisfvfp_test.c b/test/builtins/Unit/floatunssisfvfp_test.c index 506f3be51..9d7fb654f 100644 --- a/test/builtins/Unit/floatunssisfvfp_test.c +++ b/test/builtins/Unit/floatunssisfvfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatunssisfvfp_test.c - Test __floatunssisfvfp -------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntidf_test.c b/test/builtins/Unit/floatuntidf_test.c index 9855ff797..1bf19ba14 100644 --- a/test/builtins/Unit/floatuntidf_test.c +++ b/test/builtins/Unit/floatuntidf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatuntidf.c - Test __floatuntidf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntisf_test.c b/test/builtins/Unit/floatuntisf_test.c index 9b5ff790a..c7c11ba48 100644 --- a/test/builtins/Unit/floatuntisf_test.c +++ b/test/builtins/Unit/floatuntisf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatuntisf.c - Test __floatuntisf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntitf_test.c b/test/builtins/Unit/floatuntitf_test.c index 495adcfa9..e81c30e32 100644 --- a/test/builtins/Unit/floatuntitf_test.c +++ b/test/builtins/Unit/floatuntitf_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- floatuntitf.c - Test __floatuntitf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntixf_test.c b/test/builtins/Unit/floatuntixf_test.c index c58b55d3e..70ad5f36f 100644 --- a/test/builtins/Unit/floatuntixf_test.c +++ b/test/builtins/Unit/floatuntixf_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: aarch64 +// test fails for aarch64 (see pr32260) + //===-- floatuntixf.c - Test __floatuntixf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gcc_personality_test.c b/test/builtins/Unit/gcc_personality_test.c index f9598c697..b3345dd73 100644 --- a/test/builtins/Unit/gcc_personality_test.c +++ b/test/builtins/Unit/gcc_personality_test.c @@ -1,3 +1,6 @@ +// FIXME: XFAIL as currently it cannot be built by lit properly. +// XFAIL: * +// RUN: %clangxx_builtins %s %librt -o %t && %run %t /* ===-- gcc_personality_test.c - Tests __gcc_personality_v0 -------------=== * * The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gedf2vfp_test.c b/test/builtins/Unit/gedf2vfp_test.c index 341fd65d2..17cca9f22 100644 --- a/test/builtins/Unit/gedf2vfp_test.c +++ b/test/builtins/Unit/gedf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- gedf2vfp_test.c - Test __gedf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gesf2vfp_test.c b/test/builtins/Unit/gesf2vfp_test.c index 607d9880e..240880acb 100644 --- a/test/builtins/Unit/gesf2vfp_test.c +++ b/test/builtins/Unit/gesf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- gesf2vfp_test.c - Test __gesf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/getf2_test.c b/test/builtins/Unit/getf2_test.c index 9796b8ab8..115b630b4 100644 --- a/test/builtins/Unit/getf2_test.c +++ b/test/builtins/Unit/getf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ getf2_test.c - Test __getf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gtdf2vfp_test.c b/test/builtins/Unit/gtdf2vfp_test.c index 1bf68bf1a..9180ec248 100644 --- a/test/builtins/Unit/gtdf2vfp_test.c +++ b/test/builtins/Unit/gtdf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- gtdf2vfp_test.c - Test __gtdf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gtsf2vfp_test.c b/test/builtins/Unit/gtsf2vfp_test.c index 8209647ce..52e77fee2 100644 --- a/test/builtins/Unit/gtsf2vfp_test.c +++ b/test/builtins/Unit/gtsf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- gtsf2vfp_test.c - Test __gtsf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/gttf2_test.c b/test/builtins/Unit/gttf2_test.c index 6508d4b97..81d68cbf1 100644 --- a/test/builtins/Unit/gttf2_test.c +++ b/test/builtins/Unit/gttf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ gttf2_test.c - Test __gttf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ledf2vfp_test.c b/test/builtins/Unit/ledf2vfp_test.c index 2e1daf044..b24832377 100644 --- a/test/builtins/Unit/ledf2vfp_test.c +++ b/test/builtins/Unit/ledf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- ledf2vfp_test.c - Test __ledf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/lesf2vfp_test.c b/test/builtins/Unit/lesf2vfp_test.c index 0f8939366..c8ca59045 100644 --- a/test/builtins/Unit/lesf2vfp_test.c +++ b/test/builtins/Unit/lesf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- lesf2vfp_test.c - Test __lesf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/letf2_test.c b/test/builtins/Unit/letf2_test.c index 1842e3c55..bb8452567 100644 --- a/test/builtins/Unit/letf2_test.c +++ b/test/builtins/Unit/letf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ letf2_test.c - Test __letf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/lshrdi3_test.c b/test/builtins/Unit/lshrdi3_test.c index d48ae4dd7..c5faa98ee 100644 --- a/test/builtins/Unit/lshrdi3_test.c +++ b/test/builtins/Unit/lshrdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- lshrdi3_test.c - Test __lshrdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/lshrti3_test.c b/test/builtins/Unit/lshrti3_test.c index f5a0dd616..91356c8bf 100644 --- a/test/builtins/Unit/lshrti3_test.c +++ b/test/builtins/Unit/lshrti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- lshrti3_test.c - Test __lshrti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ltdf2vfp_test.c b/test/builtins/Unit/ltdf2vfp_test.c index fdbe9a17b..238a6f07c 100644 --- a/test/builtins/Unit/ltdf2vfp_test.c +++ b/test/builtins/Unit/ltdf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- ltdf2vfp_test.c - Test __ltdf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ltsf2vfp_test.c b/test/builtins/Unit/ltsf2vfp_test.c index d4d65ba92..837e0a800 100644 --- a/test/builtins/Unit/ltsf2vfp_test.c +++ b/test/builtins/Unit/ltsf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- ltsf2vfp_test.c - Test __ltsf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/lttf2_test.c b/test/builtins/Unit/lttf2_test.c index e8f9dc17c..cfe1906d2 100644 --- a/test/builtins/Unit/lttf2_test.c +++ b/test/builtins/Unit/lttf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ lttf2_test.c - Test __lttf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/moddi3_test.c b/test/builtins/Unit/moddi3_test.c index 62e8f227b..8325ad75b 100644 --- a/test/builtins/Unit/moddi3_test.c +++ b/test/builtins/Unit/moddi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- moddi3_test.c - Test __moddi3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/modsi3_test.c b/test/builtins/Unit/modsi3_test.c index 8c9f58832..8075f5160 100644 --- a/test/builtins/Unit/modsi3_test.c +++ b/test/builtins/Unit/modsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t /* ===-- modsi3_test.c - Test __modsi3 -------------------------------------=== * * The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/modti3_test.c b/test/builtins/Unit/modti3_test.c index 99413aaa2..53fbf5bba 100644 --- a/test/builtins/Unit/modti3_test.c +++ b/test/builtins/Unit/modti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- modti3_test.c - Test __modti3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/muldc3_test.c b/test/builtins/Unit/muldc3_test.c index 6902ef322..add09f4e8 100644 --- a/test/builtins/Unit/muldc3_test.c +++ b/test/builtins/Unit/muldc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- muldc3_test.c - Test __muldc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/muldf3vfp_test.c b/test/builtins/Unit/muldf3vfp_test.c index 024c9a8a8..36a22625c 100644 --- a/test/builtins/Unit/muldf3vfp_test.c +++ b/test/builtins/Unit/muldf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- muldf3vfp_test.c - Test __muldf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/muldi3_test.c b/test/builtins/Unit/muldi3_test.c index 651dd0177..d09e74d1a 100644 --- a/test/builtins/Unit/muldi3_test.c +++ b/test/builtins/Unit/muldi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- muldi3_test.c - Test __muldi3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulodi4_test.c b/test/builtins/Unit/mulodi4_test.c index 4546609fb..f03b8fecf 100644 --- a/test/builtins/Unit/mulodi4_test.c +++ b/test/builtins/Unit/mulodi4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulodi4_test.c - Test __mulodi4 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulosi4_test.c b/test/builtins/Unit/mulosi4_test.c index 6a27d69bd..12913f1d7 100644 --- a/test/builtins/Unit/mulosi4_test.c +++ b/test/builtins/Unit/mulosi4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulosi4_test.c - Test __mulosi4 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/muloti4_test.c b/test/builtins/Unit/muloti4_test.c index d00e7bb6b..e7c78cf16 100644 --- a/test/builtins/Unit/muloti4_test.c +++ b/test/builtins/Unit/muloti4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- muloti4_test.c - Test __muloti4 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c index eeb537ac1..4eac07e8d 100644 --- a/test/builtins/Unit/mulsc3_test.c +++ b/test/builtins/Unit/mulsc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- mulsc3_test.c - Test __mulsc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulsf3vfp_test.c b/test/builtins/Unit/mulsf3vfp_test.c index 9fe88f29b..8ee05510b 100644 --- a/test/builtins/Unit/mulsf3vfp_test.c +++ b/test/builtins/Unit/mulsf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulsf3vfp_test.c - Test __mulsf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/multc3_test.c b/test/builtins/Unit/multc3_test.c index f6cf4ca87..5ef84670e 100644 --- a/test/builtins/Unit/multc3_test.c +++ b/test/builtins/Unit/multc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- multc3_test.c - Test __multc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/multf3_test.c b/test/builtins/Unit/multf3_test.c index 994486552..2bce70793 100644 --- a/test/builtins/Unit/multf3_test.c +++ b/test/builtins/Unit/multf3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- multf3_test.c - Test __multf3 ------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/multi3_test.c b/test/builtins/Unit/multi3_test.c index 04b1b8aa8..8227f2426 100644 --- a/test/builtins/Unit/multi3_test.c +++ b/test/builtins/Unit/multi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- multi3_test.c - Test __multi3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulvdi3_test.c b/test/builtins/Unit/mulvdi3_test.c index 7f16c4c4f..0e10bbef1 100644 --- a/test/builtins/Unit/mulvdi3_test.c +++ b/test/builtins/Unit/mulvdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulvdi3_test.c - Test __mulvdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulvsi3_test.c b/test/builtins/Unit/mulvsi3_test.c index 64df4fe24..f62a5aa42 100644 --- a/test/builtins/Unit/mulvsi3_test.c +++ b/test/builtins/Unit/mulvsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulvsi3_test.c - Test __mulvsi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulvti3_test.c b/test/builtins/Unit/mulvti3_test.c index bf2f7316b..36e96ad60 100644 --- a/test/builtins/Unit/mulvti3_test.c +++ b/test/builtins/Unit/mulvti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- mulvti3_test.c - Test __mulvti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c index e77e94fa9..384c6ee11 100644 --- a/test/builtins/Unit/mulxc3_test.c +++ b/test/builtins/Unit/mulxc3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -lm -o %t && %run %t //===-- mulxc3_test.c - Test __mulxc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/nedf2vfp_test.c b/test/builtins/Unit/nedf2vfp_test.c index 69587d468..46bca5ae9 100644 --- a/test/builtins/Unit/nedf2vfp_test.c +++ b/test/builtins/Unit/nedf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- nedf2vfp_test.c - Test __nedf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negdf2vfp_test.c b/test/builtins/Unit/negdf2vfp_test.c index 72bde7c01..776dca618 100644 --- a/test/builtins/Unit/negdf2vfp_test.c +++ b/test/builtins/Unit/negdf2vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negdf2vfp_test.c - Test __negdf2vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negdi2_test.c b/test/builtins/Unit/negdi2_test.c index beccd71ee..c85e91581 100644 --- a/test/builtins/Unit/negdi2_test.c +++ b/test/builtins/Unit/negdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negdi2_test.c - Test __negdi2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negsf2vfp_test.c b/test/builtins/Unit/negsf2vfp_test.c index 1c9ba5292..e15e43c80 100644 --- a/test/builtins/Unit/negsf2vfp_test.c +++ b/test/builtins/Unit/negsf2vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negsf2vfp_test.c - Test __negsf2vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negti2_test.c b/test/builtins/Unit/negti2_test.c index b07597868..bb7379cae 100644 --- a/test/builtins/Unit/negti2_test.c +++ b/test/builtins/Unit/negti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negti2_test.c - Test __negti2 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negvdi2_test.c b/test/builtins/Unit/negvdi2_test.c index 5c202e55c..4e17c3089 100644 --- a/test/builtins/Unit/negvdi2_test.c +++ b/test/builtins/Unit/negvdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negvdi2_test.c - Test __negvdi2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negvsi2_test.c b/test/builtins/Unit/negvsi2_test.c index 6330803d5..3deb4235b 100644 --- a/test/builtins/Unit/negvsi2_test.c +++ b/test/builtins/Unit/negvsi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negvsi2_test.c - Test __negvsi2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/negvti2_test.c b/test/builtins/Unit/negvti2_test.c index 005f8a8ac..980f44869 100644 --- a/test/builtins/Unit/negvti2_test.c +++ b/test/builtins/Unit/negvti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- negvti2_test.c - Test __negvti2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/nesf2vfp_test.c b/test/builtins/Unit/nesf2vfp_test.c index 0ebcd6721..b6491700a 100644 --- a/test/builtins/Unit/nesf2vfp_test.c +++ b/test/builtins/Unit/nesf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- nesf2vfp_test.c - Test __nesf2vfp ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/netf2_test.c b/test/builtins/Unit/netf2_test.c index bbd953ab5..c0b839d64 100644 --- a/test/builtins/Unit/netf2_test.c +++ b/test/builtins/Unit/netf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ netf2_test.c - Test __netf2------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/paritydi2_test.c b/test/builtins/Unit/paritydi2_test.c index 98220bd8c..cc56eda57 100644 --- a/test/builtins/Unit/paritydi2_test.c +++ b/test/builtins/Unit/paritydi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- paritydi2_test.c - Test __paritydi2 -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/paritysi2_test.c b/test/builtins/Unit/paritysi2_test.c index 175aeb2c9..42d687f17 100644 --- a/test/builtins/Unit/paritysi2_test.c +++ b/test/builtins/Unit/paritysi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- paritysi2_test.c - Test __paritysi2 -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/parityti2_test.c b/test/builtins/Unit/parityti2_test.c index cc1e999f2..bcd26d0af 100644 --- a/test/builtins/Unit/parityti2_test.c +++ b/test/builtins/Unit/parityti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- parityti2_test.c - Test __parityti2 -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/popcountdi2_test.c b/test/builtins/Unit/popcountdi2_test.c index bfd4977b4..1d52fb8db 100644 --- a/test/builtins/Unit/popcountdi2_test.c +++ b/test/builtins/Unit/popcountdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- popcountdi2_test.c - Test __popcountdi2 ----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/popcountsi2_test.c b/test/builtins/Unit/popcountsi2_test.c index 10b757d81..5eb88ac62 100644 --- a/test/builtins/Unit/popcountsi2_test.c +++ b/test/builtins/Unit/popcountsi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- popcountsi2_test.c - Test __popcountsi2 ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/popcountti2_test.c b/test/builtins/Unit/popcountti2_test.c index 3a3c3cb4f..ef8b2c383 100644 --- a/test/builtins/Unit/popcountti2_test.c +++ b/test/builtins/Unit/popcountti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- popcountti2_test.c - Test __popcountti2 ----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/powidf2_test.c b/test/builtins/Unit/powidf2_test.c index c499d9aba..210e3c3c7 100644 --- a/test/builtins/Unit/powidf2_test.c +++ b/test/builtins/Unit/powidf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- powidf2_test.cpp - Test __powidf2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/powisf2_test.c b/test/builtins/Unit/powisf2_test.c index 1186ef4af..add4be43f 100644 --- a/test/builtins/Unit/powisf2_test.c +++ b/test/builtins/Unit/powisf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- powisf2_test.cpp - Test __powisf2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/powitf2_test.c b/test/builtins/Unit/powitf2_test.c index 13c890a0d..9d11b76cb 100644 --- a/test/builtins/Unit/powitf2_test.c +++ b/test/builtins/Unit/powitf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- powitf2_test.cpp - Test __powitf2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/powixf2_test.c b/test/builtins/Unit/powixf2_test.c index a28f1f969..bf5a812fa 100644 --- a/test/builtins/Unit/powixf2_test.c +++ b/test/builtins/Unit/powixf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- powixf2_test.cpp - Test __powixf2 ---------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ppc/fixtfdi_test.c b/test/builtins/Unit/ppc/fixtfdi_test.c index b4865fb8e..ea6c40563 100644 --- a/test/builtins/Unit/ppc/fixtfdi_test.c +++ b/test/builtins/Unit/ppc/fixtfdi_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include #include diff --git a/test/builtins/Unit/ppc/floatditf_test.c b/test/builtins/Unit/ppc/floatditf_test.c index 71ecf7c4b..5c08ade4b 100644 --- a/test/builtins/Unit/ppc/floatditf_test.c +++ b/test/builtins/Unit/ppc/floatditf_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include diff --git a/test/builtins/Unit/ppc/floatunditf_test.c b/test/builtins/Unit/ppc/floatunditf_test.c index 4d1ce0884..3e5012857 100644 --- a/test/builtins/Unit/ppc/floatunditf_test.c +++ b/test/builtins/Unit/ppc/floatunditf_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include diff --git a/test/builtins/Unit/ppc/qadd_test.c b/test/builtins/Unit/ppc/qadd_test.c index 6d4ca93c2..327fd21e8 100644 --- a/test/builtins/Unit/ppc/qadd_test.c +++ b/test/builtins/Unit/ppc/qadd_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include "DD.h" diff --git a/test/builtins/Unit/ppc/qdiv_test.c b/test/builtins/Unit/ppc/qdiv_test.c index 8e4e75a50..7530e428f 100644 --- a/test/builtins/Unit/ppc/qdiv_test.c +++ b/test/builtins/Unit/ppc/qdiv_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include "DD.h" diff --git a/test/builtins/Unit/ppc/qmul_test.c b/test/builtins/Unit/ppc/qmul_test.c index fc5b46d33..dbe3536f3 100644 --- a/test/builtins/Unit/ppc/qmul_test.c +++ b/test/builtins/Unit/ppc/qmul_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include "DD.h" diff --git a/test/builtins/Unit/ppc/qsub_test.c b/test/builtins/Unit/ppc/qsub_test.c index 43bc7f4a8..e21224096 100644 --- a/test/builtins/Unit/ppc/qsub_test.c +++ b/test/builtins/Unit/ppc/qsub_test.c @@ -1,3 +1,5 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_builtins %s -o %t && %run %t #include #include "DD.h" diff --git a/test/builtins/Unit/subdf3vfp_test.c b/test/builtins/Unit/subdf3vfp_test.c index 398494e1d..75bfe4542 100644 --- a/test/builtins/Unit/subdf3vfp_test.c +++ b/test/builtins/Unit/subdf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- subdf3vfp_test.c - Test __subdf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/subsf3vfp_test.c b/test/builtins/Unit/subsf3vfp_test.c index 8d529e525..fb3839f23 100644 --- a/test/builtins/Unit/subsf3vfp_test.c +++ b/test/builtins/Unit/subsf3vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- subsf3vfp_test.c - Test __subsf3vfp -------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/subtf3_test.c b/test/builtins/Unit/subtf3_test.c index 32c30bd23..771242ba4 100644 --- a/test/builtins/Unit/subtf3_test.c +++ b/test/builtins/Unit/subtf3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- subtf3_test.c - Test __subtf3 ------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/subvdi3_test.c b/test/builtins/Unit/subvdi3_test.c index 96e825caf..7606e27d1 100644 --- a/test/builtins/Unit/subvdi3_test.c +++ b/test/builtins/Unit/subvdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- subvdi3_test.c - Test __subvdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/subvsi3_test.c b/test/builtins/Unit/subvsi3_test.c index 03ef5045d..f52a12b60 100644 --- a/test/builtins/Unit/subvsi3_test.c +++ b/test/builtins/Unit/subvsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- subvsi3_test.c - Test __subvsi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/subvti3_test.c b/test/builtins/Unit/subvti3_test.c index 40eb51869..66806ba0b 100644 --- a/test/builtins/Unit/subvti3_test.c +++ b/test/builtins/Unit/subvti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- subvti3_test.c - Test __subvti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/trampoline_setup_test.c b/test/builtins/Unit/trampoline_setup_test.c index dc30fb6df..5a75724f4 100644 --- a/test/builtins/Unit/trampoline_setup_test.c +++ b/test/builtins/Unit/trampoline_setup_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -fnested-functions -o %t && %run %t /* ===-- trampoline_setup_test.c - Test __trampoline_setup -----------------=== * * The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/truncdfhf2_test.c b/test/builtins/Unit/truncdfhf2_test.c index 6627a001e..94595fc97 100644 --- a/test/builtins/Unit/truncdfhf2_test.c +++ b/test/builtins/Unit/truncdfhf2_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===--------------- truncdfhf2_test.c - Test __truncdfhf2 ----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/truncdfsf2_test.c b/test/builtins/Unit/truncdfsf2_test.c index a208a3a56..a692edee8 100644 --- a/test/builtins/Unit/truncdfsf2_test.c +++ b/test/builtins/Unit/truncdfsf2_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===--------------- truncdfsf2_test.c - Test __truncdfsf2 ----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/truncdfsf2vfp_test.c b/test/builtins/Unit/truncdfsf2vfp_test.c index efe6f97ab..f034dd2da 100644 --- a/test/builtins/Unit/truncdfsf2vfp_test.c +++ b/test/builtins/Unit/truncdfsf2vfp_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- truncdfsf2vfp_test.c - Test __truncdfsf2vfp -----------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/truncsfhf2_test.c b/test/builtins/Unit/truncsfhf2_test.c index 5bc3c8e22..b83d8fd8a 100644 --- a/test/builtins/Unit/truncsfhf2_test.c +++ b/test/builtins/Unit/truncsfhf2_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===--------------- truncsfhf2_test.c - Test __truncsfhf2 ----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/trunctfdf2_test.c b/test/builtins/Unit/trunctfdf2_test.c index 0366a8ce9..1d8c2bf05 100644 --- a/test/builtins/Unit/trunctfdf2_test.c +++ b/test/builtins/Unit/trunctfdf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-------------- trunctfdf2_test.c - Test __trunctfdf2 -----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/trunctfsf2_test.c b/test/builtins/Unit/trunctfsf2_test.c index a6b922ce1..177508319 100644 --- a/test/builtins/Unit/trunctfsf2_test.c +++ b/test/builtins/Unit/trunctfsf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===--------------- trunctfsf2_test.c - Test __trunctfsf2 ----------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ucmpdi2_test.c b/test/builtins/Unit/ucmpdi2_test.c index 65ae4fce0..ee815454a 100644 --- a/test/builtins/Unit/ucmpdi2_test.c +++ b/test/builtins/Unit/ucmpdi2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ucmpdi2_test.c - Test __ucmpdi2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/ucmpti2_test.c b/test/builtins/Unit/ucmpti2_test.c index 826cd6439..17a857fb5 100644 --- a/test/builtins/Unit/ucmpti2_test.c +++ b/test/builtins/Unit/ucmpti2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- ucmpti2_test.c - Test __ucmpti2 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivdi3_test.c b/test/builtins/Unit/udivdi3_test.c index 48c99e309..5858bc7f9 100644 --- a/test/builtins/Unit/udivdi3_test.c +++ b/test/builtins/Unit/udivdi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivdi3_test.c - Test __udivdi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivmoddi4_test.c b/test/builtins/Unit/udivmoddi4_test.c index 79af1eeff..a5024bae0 100644 --- a/test/builtins/Unit/udivmoddi4_test.c +++ b/test/builtins/Unit/udivmoddi4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivmoddi4_test.c - Test __udivmoddi4 -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivmodsi4_test.c b/test/builtins/Unit/udivmodsi4_test.c index 4c14e297d..320018cba 100644 --- a/test/builtins/Unit/udivmodsi4_test.c +++ b/test/builtins/Unit/udivmodsi4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivmodsi4_test.c - Test __udivmodsi4 -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivmodti4_test.c b/test/builtins/Unit/udivmodti4_test.c index c4246613d..b07ce8c24 100644 --- a/test/builtins/Unit/udivmodti4_test.c +++ b/test/builtins/Unit/udivmodti4_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivmodti4_test.c - Test __udivmodti4 -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivsi3_test.c b/test/builtins/Unit/udivsi3_test.c index 49053865b..7adf30a15 100644 --- a/test/builtins/Unit/udivsi3_test.c +++ b/test/builtins/Unit/udivsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivsi3_test.c - Test __udivsi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/udivti3_test.c b/test/builtins/Unit/udivti3_test.c index f24ff03b2..81cedadff 100644 --- a/test/builtins/Unit/udivti3_test.c +++ b/test/builtins/Unit/udivti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- udivti3_test.c - Test __udivti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/umoddi3_test.c b/test/builtins/Unit/umoddi3_test.c index b46fb4022..b1382b621 100644 --- a/test/builtins/Unit/umoddi3_test.c +++ b/test/builtins/Unit/umoddi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- umoddi3_test.c - Test __umoddi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/umodsi3_test.c b/test/builtins/Unit/umodsi3_test.c index 3655da139..c43053874 100644 --- a/test/builtins/Unit/umodsi3_test.c +++ b/test/builtins/Unit/umodsi3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- umodsi3_test.c - Test __umodsi3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/umodti3_test.c b/test/builtins/Unit/umodti3_test.c index 21e82a4a2..5bce0258a 100644 --- a/test/builtins/Unit/umodti3_test.c +++ b/test/builtins/Unit/umodti3_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===-- umodti3_test.c - Test __umodti3 -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/unorddf2vfp_test.c b/test/builtins/Unit/unorddf2vfp_test.c index be17e4113..7fe3894bc 100644 --- a/test/builtins/Unit/unorddf2vfp_test.c +++ b/test/builtins/Unit/unorddf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- unorddf2vfp_test.c - Test __unorddf2vfp ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/unordsf2vfp_test.c b/test/builtins/Unit/unordsf2vfp_test.c index e40d71f77..670d3351b 100644 --- a/test/builtins/Unit/unordsf2vfp_test.c +++ b/test/builtins/Unit/unordsf2vfp_test.c @@ -1,3 +1,7 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// XFAIL: armhf-target-arch +// This test fails for armhf (see pr32261) + //===-- unordsf2vfp_test.c - Test __unordsf2vfp ---------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/unordtf2_test.c b/test/builtins/Unit/unordtf2_test.c index 114cd8cb3..22907ce76 100644 --- a/test/builtins/Unit/unordtf2_test.c +++ b/test/builtins/Unit/unordtf2_test.c @@ -1,3 +1,4 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t //===------------ unordtf2_test.c - Test __unordtf2------------------------===// // // The LLVM Compiler Infrastructure -- cgit v1.2.1 From afa3b5b092dd73ad360916cd05113cb6e07c51c5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 21 Mar 2017 06:55:32 +0000 Subject: Revert "Bypass potential libc's sysconf wrappers for sysconf(_SC_PAGESIZE) call" Bot can't find This reverts commit r298305. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298343 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 3 --- .../Linux/sysconf_interceptor_bypass_test.cc | 21 --------------------- 2 files changed, 24 deletions(-) delete mode 100644 test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 6b2952308..24707c74d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -78,7 +78,6 @@ extern char **environ; // provided by crt1 #endif #if SANITIZER_LINUX -#include // struct kernel_timeval { long tv_sec; @@ -806,8 +805,6 @@ uptr GetPageSize() { return 4096; #elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; -#elif SANITIZER_LINUX - return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif diff --git a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc deleted file mode 100644 index 97b6132e2..000000000 --- a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc +++ /dev/null @@ -1,21 +0,0 @@ -// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s - -#include - -extern "C" long sysconf(int name) { - fprintf(stderr, "sysconf wrapper called\n"); - return 0; -} - -int main() { - // All we need to check is that the sysconf() interceptor defined above was - // not called. Should it get called, it will crash right there, any - // instrumented code executed before sanitizer init is finished will crash - // accessing non-initialized sanitizer internals. Even if it will not crash - // in some configuration, it should never be called anyway. - fprintf(stderr, "Passed\n"); - // CHECK-NOT: sysconf wrapper called - // CHECK: Passed - // CHECK-NOT: sysconf wrapper called - return 0; -} -- cgit v1.2.1 From 1698c9fe645e6d001bf8a9a7c115edb8098e73a1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 21 Mar 2017 13:44:01 +0000 Subject: tsan: add test for pie/no aslr Just ensure that such combination works. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298372 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Linux/pie_no_aslr.cc | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/tsan/Linux/pie_no_aslr.cc diff --git a/test/tsan/Linux/pie_no_aslr.cc b/test/tsan/Linux/pie_no_aslr.cc new file mode 100644 index 000000000..a30b6b488 --- /dev/null +++ b/test/tsan/Linux/pie_no_aslr.cc @@ -0,0 +1,5 @@ +// RUN: %clang_tsan %s -pie -fPIE -o %t && %run setarch x86_64 -R %t + +int main() { + return 0; +} -- cgit v1.2.1 From 8f117382b967d5e5c4f27a10477de1ea65b76be1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 21 Mar 2017 14:28:55 +0000 Subject: tsan: support __ATOMIC_HLE_ACQUIRE/RELEASE flags HLE flags can be combined with memory order in atomic operations. Currently tsan runtime crashes on e.g. IsStoreOrder(mo) in atomic store if any of these additional flags are specified. Filter these flags out. See the comment as to why it is safe. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298378 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interface_atomic.cc | 19 ++++++++++++++++++- test/tsan/atomic_hle.cc | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 test/tsan/atomic_hle.cc diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc index 5238b66a2..e49e1d2c5 100644 --- a/lib/tsan/rtl/tsan_interface_atomic.cc +++ b/lib/tsan/rtl/tsan_interface_atomic.cc @@ -450,10 +450,27 @@ static void AtomicFence(ThreadState *thr, uptr pc, morder mo) { // C/C++ +static morder covert_morder(morder mo) { + if (flags()->force_seq_cst_atomics) + return (morder)mo_seq_cst; + + // Filter out additional memory order flags: + // MEMMODEL_SYNC = 1 << 15 + // __ATOMIC_HLE_ACQUIRE = 1 << 16 + // __ATOMIC_HLE_RELEASE = 1 << 17 + // + // HLE is an optimization, and we pretend that elision always fails. + // MEMMODEL_SYNC is used when lowering __sync_ atomics, + // since we use __sync_ atomics for actual atomic operations, + // we can safely ignore it as well. It also subtly affects semantics, + // but we don't model the difference. + return (morder)(mo & 0x7fff); +} + #define SCOPED_ATOMIC(func, ...) \ const uptr callpc = (uptr)__builtin_return_address(0); \ uptr pc = StackTrace::GetCurrentPc(); \ - mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \ + mo = covert_morder(mo); \ ThreadState *const thr = cur_thread(); \ if (thr->ignore_interceptors) \ return NoTsanAtomic##func(__VA_ARGS__); \ diff --git a/test/tsan/atomic_hle.cc b/test/tsan/atomic_hle.cc new file mode 100644 index 000000000..345e363c2 --- /dev/null +++ b/test/tsan/atomic_hle.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "test.h" +#include + +#ifndef __ATOMIC_HLE_ACQUIRE +#define __ATOMIC_HLE_ACQUIRE (1 << 16) +#endif +#ifndef __ATOMIC_HLE_RELEASE +#define __ATOMIC_HLE_RELEASE (1 << 17) +#endif + +int main() { + volatile int x = 0; + //__atomic_fetch_add(&x, 1, __ATOMIC_ACQUIRE | __ATOMIC_HLE_ACQUIRE); + //__atomic_store_n(&x, 0, __ATOMIC_RELEASE | __ATOMIC_HLE_RELEASE); + __tsan_atomic32_fetch_add(&x, 1, + (__tsan_memory_order)(__ATOMIC_ACQUIRE | __ATOMIC_HLE_ACQUIRE)); + __tsan_atomic32_store(&x, 0, + (__tsan_memory_order)(__ATOMIC_RELEASE | __ATOMIC_HLE_RELEASE)); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: DONE + -- cgit v1.2.1 From 9ede2ebf28902cdeadca20a5ff279082b8ba4cd7 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 21 Mar 2017 15:31:15 +0000 Subject: Revert r298274: "Use pthreads for thread-local lsan allocator cache on darwin" This fixes a failure currently present on the upstream linux boxes (and reproduces for me as well): http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux/builds/1130/steps/64-bit%20check-asan-dynamic/logs/stdio git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298382 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 51 ++++++++++++++++++++++++++++++++++++------- lib/lsan/lsan_allocator.h | 37 ------------------------------- lib/lsan/lsan_common_linux.cc | 4 ---- lib/lsan/lsan_common_mac.cc | 8 +------ 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 640497d40..428485796 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,18 +24,53 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { + +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; +#if SANITIZER_WORDSIZE == 64 + uptr requested_size : 54; +#else + uptr requested_size : 32; + uptr padding : 22; +#endif + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) #if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; -#elif defined(__mips64) || defined(__aarch64__) +#else static const uptr kMaxAllowedMallocSize = 4UL << 30; +#endif +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; #else static const uptr kMaxAllowedMallocSize = 8UL << 30; + +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; #endif +typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; +static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized( @@ -44,7 +79,7 @@ void InitializeAllocator() { } void AllocatorThreadFinish() { - allocator.SwallowCache(GetAllocatorCache()); + allocator.SwallowCache(&cache); } static ChunkMetadata *Metadata(const void *p) { @@ -76,7 +111,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); + void *p = allocator.Allocate(&cache, size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -90,7 +125,7 @@ void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(GetAllocatorCache(), p); + allocator.Deallocate(&cache, p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -98,17 +133,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(GetAllocatorCache(), p); + allocator.Deallocate(&cache, p); return nullptr; } - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); + p = allocator.Reallocate(&cache, p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)GetAllocatorCache(); - *end = *begin + sizeof(AllocatorCache); + *begin = (uptr)&cache; + *end = *begin + sizeof(cache); } uptr GetMallocUsableSize(const void *p) { diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 9c3dce97a..f56460119 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -15,10 +15,8 @@ #ifndef LSAN_ALLOCATOR_H #define LSAN_ALLOCATOR_H -#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" -#include "lsan_common.h" namespace __lsan { @@ -36,41 +34,6 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; -#if SANITIZER_WORDSIZE == 64 - uptr requested_size : 54; -#else - uptr requested_size : 32; - uptr padding : 22; -#endif - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; -#elif defined(__x86_64__) -struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. - static const uptr kMetadataSize = sizeof(ChunkMetadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; -}; - -typedef SizeClassAllocator64 PrimaryAllocator; -#endif -typedef SizeClassAllocatorLocalCache AllocatorCache; - -AllocatorCache *GetAllocatorCache(); } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index e73768e58..0e10d4191 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,7 +22,6 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#include "lsan_allocator.h" namespace __lsan { @@ -39,9 +38,6 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } -static THREADLOCAL AllocatorCache allocator_cache; -AllocatorCache *GetAllocatorCache() { return &allocator_cache; } - __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index f70ebdd0e..7f5e0550d 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -12,14 +12,12 @@ // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" #if CAN_SANITIZE_LEAKS && SANITIZER_MAC -#include "sanitizer_common/sanitizer_allocator_internal.h" -#include "lsan_allocator.h" - #include namespace __lsan { @@ -27,7 +25,6 @@ namespace __lsan { typedef struct { int disable_counter; u32 current_thread_id; - AllocatorCache cache; } thread_local_data_t; static pthread_key_t key; @@ -43,7 +40,6 @@ static thread_local_data_t *get_tls_val() { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; - ptr->cache = AllocatorCache(); pthread_setspecific(key, ptr); } @@ -66,8 +62,6 @@ u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } -AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } - void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); } -- cgit v1.2.1 From 7ea40255820c1b7fbc45e05e99351c9c667e6624 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 21 Mar 2017 15:37:48 +0000 Subject: tsan: fix pie_no_aslr test It failed on clang-cmake-aarch64-39vma. Restrict it to x86_64 only. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298383 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Linux/pie_no_aslr.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tsan/Linux/pie_no_aslr.cc b/test/tsan/Linux/pie_no_aslr.cc index a30b6b488..b99342da0 100644 --- a/test/tsan/Linux/pie_no_aslr.cc +++ b/test/tsan/Linux/pie_no_aslr.cc @@ -1,4 +1,5 @@ // RUN: %clang_tsan %s -pie -fPIE -o %t && %run setarch x86_64 -R %t +// REQUIRES: x86_64-target-arch int main() { return 0; -- cgit v1.2.1 From ba802a4235ecdadc45278718b861d54efc07c626 Mon Sep 17 00:00:00 2001 From: Bob Haarman Date: Tue, 21 Mar 2017 18:25:35 +0000 Subject: [compiler-rt] respect CMAKE_EXE_LINKER_FLAGS in compiler and library tests Summary: check_cxx_compiler_flag and check_library_exists could fail because they ignored CMAKE_EXE_LINKER_FLAGS and therefore would always fail to produce executables. Cmake policy CMP0056 fixes this, but was explicitly set to OLD in our CMakeLists because it caused problems with test_target_arch. This change sets the policy to NEW to fix the problem with the compiler and library tests, and temporarily clears CMAKE_EXE_LINKER_FLAGS inside test_target_arch to emulate the old behavior there. This allows, for example, LTO builds that require lld to succeed. Reviewers: davidxl, beanz Reviewed By: beanz Subscribers: fjricci, dberris, mgorny, mehdi_amini, tejohnson, rnk, llvm-commits Differential Revision: https://reviews.llvm.org/D31098 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298413 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 10 ---------- cmake/Modules/CompilerRTDarwinUtils.cmake | 4 +++- cmake/Modules/CompilerRTUtils.cmake | 7 ++++--- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbde83113..9714340dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,16 +14,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE endif() cmake_minimum_required(VERSION 3.4.3) -# FIXME: -# The OLD behavior (pre 3.2) for this policy is to not set the value of the -# CMAKE_EXE_LINKER_FLAGS variable in the generated test project. The NEW behavior -# for this policy is to set the value of the CMAKE_EXE_LINKER_FLAGS variable -# in the test project to the same as it is in the calling project. The new -# behavior cause the compiler_rt test to fail during try_compile: see -# projects/compiler-rt/cmake/Modules/CompilerRTUtils.cmake:121 such that -# CAN_TARGET_${arch} is not set properly. This results in COMPILER_RT_SUPPORTED_ARCH -# not being updated properly leading to poblems. -cmake_policy(SET CMP0056 OLD) # Add path for custom compiler-rt modules. list(INSERT CMAKE_MODULE_PATH 0 diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index 3c89381f9..baea4a067 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -85,10 +85,12 @@ function(darwin_test_archs os valid_archs) if(TEST_COMPILE_ONLY) try_compile_only(CAN_TARGET_${os}_${arch} -v -arch ${arch} ${DARWIN_${os}_CFLAGS}) else() + set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${arch_linker_flags}") try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_C} COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS} - CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${arch_linker_flags}" OUTPUT_VARIABLE TEST_OUTPUT) + set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS}) endif() if(${CAN_TARGET_${os}_${arch}}) list(APPEND working_archs ${arch}) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index ed946d88f..3b3a0c153 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -138,15 +138,16 @@ macro(test_target_arch arch def) elseif(TEST_COMPILE_ONLY) try_compile_only(CAN_TARGET_${arch} ${TARGET_${arch}_CFLAGS}) else() - set(argstring "${CMAKE_EXE_LINKER_FLAGS} ${argstring}") set(FLAG_NO_EXCEPTIONS "") if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG) set(FLAG_NO_EXCEPTIONS " -fno-exceptions ") endif() + set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${argstring}") try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE} COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS} ${FLAG_NO_EXCEPTIONS}" - OUTPUT_VARIABLE TARGET_${arch}_OUTPUT - CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${argstring}") + OUTPUT_VARIABLE TARGET_${arch}_OUTPUT) + set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS}) endif() endif() if(${CAN_TARGET_${arch}}) -- cgit v1.2.1 From 101bbf41368b6cd4f054e85cad84fe5271e92a80 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 21 Mar 2017 22:07:06 +0000 Subject: Revert "[compiler-rt][asan] Turn on ASAN unittests for win64." This reverts commit r296878. These test still require too much swap to pass reliably. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298450 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 893276767..fb1478e7a 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -3,6 +3,12 @@ set(ASAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(ASAN_TESTSUITES) set(ASAN_DYNAMIC_TESTSUITES) +# FIXME: Shadow memory for 64-bit asan easily exhausts swap on most machines. +# Find a way to make these tests pass reliably, and re-enable them. +if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8) + set(EXCLUDE_FROM_ALL TRUE) +endif() + macro(get_bits_for_arch arch bits) if (${arch} MATCHES "i386|i686|arm|mips|mipsel") set(${bits} 32) @@ -108,3 +114,9 @@ if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) set(EXCLUDE_FROM_ALL FALSE) endif() endif() + +# Reset EXCLUDE_FROM_ALL to its initial value. +# FIXME: Remove when we run Win64 asan tests. +if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8) + set(EXCLUDE_FROM_ALL FALSE) +endif() -- cgit v1.2.1 From 42738308e809b9007368dd59d590e4fb61a866f7 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 22 Mar 2017 01:45:08 +0000 Subject: XFAIL CFI stats test while LLD produces corrupt PDBs that confuse DIA git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298476 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/stats.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cfi/stats.cpp b/test/cfi/stats.cpp index 566fcfbc2..8d96b5db0 100644 --- a/test/cfi/stats.cpp +++ b/test/cfi/stats.cpp @@ -2,6 +2,8 @@ // RUN: env SANITIZER_STATS_PATH=%t.stats %t // RUN: sanstats %t.stats | FileCheck %s +// XFAIL: win32 + // FIXME: We currently emit the wrong debug info under devirtualization. // UNSUPPORTED: devirt -- cgit v1.2.1 From 6a332346c1699549886caebcfdf634f5f46915a0 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 22 Mar 2017 04:40:32 +0000 Subject: [XRay][compiler-rt] Remove dependency on Summary: Depending on C++11 introduces a link-time requirement to C++11 symbols. Removing it allows us to depend on header-only C++11 and up libraries. Partially fixes http://llvm.org/PR32274 -- we know there's more invasive work to be done, but we're doing it incrementally. Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31233 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298480 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/unit/buffer_queue_test.cc | 35 +++++++++++++++--------------- lib/xray/xray_buffer_queue.cc | 26 ++++++++++++---------- lib/xray/xray_buffer_queue.h | 37 ++++++++++++++++++++++++++------ lib/xray/xray_fdr_logging_impl.h | 34 ++++++++++++++++++----------- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/lib/xray/tests/unit/buffer_queue_test.cc b/lib/xray/tests/unit/buffer_queue_test.cc index 4db762dc7..ac89a8dbc 100644 --- a/lib/xray/tests/unit/buffer_queue_test.cc +++ b/lib/xray/tests/unit/buffer_queue_test.cc @@ -14,7 +14,6 @@ #include "gtest/gtest.h" #include -#include #include namespace __xray { @@ -32,9 +31,9 @@ TEST(BufferQueueTest, GetAndRelease) { BufferQueue Buffers(kSize, 1, Success); ASSERT_TRUE(Success); BufferQueue::Buffer Buf; - ASSERT_EQ(Buffers.getBuffer(Buf), std::error_code()); + ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok); ASSERT_NE(nullptr, Buf.Buffer); - ASSERT_EQ(Buffers.releaseBuffer(Buf), std::error_code()); + ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok); ASSERT_EQ(nullptr, Buf.Buffer); } @@ -43,11 +42,10 @@ TEST(BufferQueueTest, GetUntilFailed) { BufferQueue Buffers(kSize, 1, Success); ASSERT_TRUE(Success); BufferQueue::Buffer Buf0; - EXPECT_EQ(Buffers.getBuffer(Buf0), std::error_code()); + EXPECT_EQ(Buffers.getBuffer(Buf0), BufferQueue::ErrorCode::Ok); BufferQueue::Buffer Buf1; - EXPECT_EQ(std::make_error_code(std::errc::not_enough_memory), - Buffers.getBuffer(Buf1)); - EXPECT_EQ(Buffers.releaseBuffer(Buf0), std::error_code()); + EXPECT_EQ(BufferQueue::ErrorCode::NotEnoughMemory, Buffers.getBuffer(Buf1)); + EXPECT_EQ(Buffers.releaseBuffer(Buf0), BufferQueue::ErrorCode::Ok); } TEST(BufferQueueTest, ReleaseUnknown) { @@ -57,7 +55,7 @@ TEST(BufferQueueTest, ReleaseUnknown) { BufferQueue::Buffer Buf; Buf.Buffer = reinterpret_cast(0xdeadbeef); Buf.Size = kSize; - EXPECT_EQ(std::make_error_code(std::errc::argument_out_of_domain), + EXPECT_EQ(BufferQueue::ErrorCode::UnrecognizedBuffer, Buffers.releaseBuffer(Buf)); } @@ -66,15 +64,15 @@ TEST(BufferQueueTest, ErrorsWhenFinalising) { BufferQueue Buffers(kSize, 2, Success); ASSERT_TRUE(Success); BufferQueue::Buffer Buf; - ASSERT_EQ(Buffers.getBuffer(Buf), std::error_code()); + ASSERT_EQ(Buffers.getBuffer(Buf), BufferQueue::ErrorCode::Ok); ASSERT_NE(nullptr, Buf.Buffer); - ASSERT_EQ(Buffers.finalize(), std::error_code()); + ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok); BufferQueue::Buffer OtherBuf; - ASSERT_EQ(std::make_error_code(std::errc::state_not_recoverable), + ASSERT_EQ(BufferQueue::ErrorCode::AlreadyFinalized, Buffers.getBuffer(OtherBuf)); - ASSERT_EQ(std::make_error_code(std::errc::state_not_recoverable), + ASSERT_EQ(BufferQueue::ErrorCode::AlreadyFinalized, Buffers.finalize()); - ASSERT_EQ(Buffers.releaseBuffer(Buf), std::error_code()); + ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok); } TEST(BufferQueueTest, MultiThreaded) { @@ -83,14 +81,17 @@ TEST(BufferQueueTest, MultiThreaded) { ASSERT_TRUE(Success); auto F = [&] { BufferQueue::Buffer B; - while (!Buffers.getBuffer(B)) { + while (true) { + auto EC = Buffers.getBuffer(B); + if (EC != BufferQueue::ErrorCode::Ok) + return; Buffers.releaseBuffer(B); } }; auto T0 = std::async(std::launch::async, F); auto T1 = std::async(std::launch::async, F); auto T2 = std::async(std::launch::async, [&] { - while (!Buffers.finalize()) + while (Buffers.finalize() != BufferQueue::ErrorCode::Ok) ; }); F(); @@ -103,8 +104,8 @@ TEST(BufferQueueTest, Apply) { auto Count = 0; BufferQueue::Buffer B; for (int I = 0; I < 10; ++I) { - ASSERT_FALSE(Buffers.getBuffer(B)); - ASSERT_FALSE(Buffers.releaseBuffer(B)); + ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok); + ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok); } Buffers.apply([&](const BufferQueue::Buffer &B) { ++Count; }); ASSERT_EQ(Count, 10); diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index bd8f4961e..13d17537e 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -13,10 +13,14 @@ // //===----------------------------------------------------------------------===// #include "xray_buffer_queue.h" -#include +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" + #include +#include using namespace __xray; +using namespace __sanitizer; BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing(false) { @@ -35,37 +39,37 @@ BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) Success = true; } -std::error_code BufferQueue::getBuffer(Buffer &Buf) { +BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (Finalizing.load(std::memory_order_acquire)) - return std::make_error_code(std::errc::state_not_recoverable); + return ErrorCode::QueueFinalizing; std::lock_guard Guard(Mutex); if (Buffers.empty()) - return std::make_error_code(std::errc::not_enough_memory); + return ErrorCode::NotEnoughMemory; auto &T = Buffers.front(); auto &B = std::get<0>(T); Buf = B; B.Buffer = nullptr; B.Size = 0; Buffers.pop_front(); - return {}; + return ErrorCode::Ok; } -std::error_code BufferQueue::releaseBuffer(Buffer &Buf) { +BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { if (OwnedBuffers.count(Buf.Buffer) == 0) - return std::make_error_code(std::errc::argument_out_of_domain); + return ErrorCode::UnrecognizedBuffer; std::lock_guard Guard(Mutex); // Now that the buffer has been released, we mark it as "used". Buffers.emplace(Buffers.end(), Buf, true /* used */); Buf.Buffer = nullptr; Buf.Size = 0; - return {}; + return ErrorCode::Ok; } -std::error_code BufferQueue::finalize() { +BufferQueue::ErrorCode BufferQueue::finalize() { if (Finalizing.exchange(true, std::memory_order_acq_rel)) - return std::make_error_code(std::errc::state_not_recoverable); - return {}; + return ErrorCode::QueueFinalizing; + return ErrorCode::Ok; } BufferQueue::~BufferQueue() { diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 3898437e4..32f7ae967 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -34,11 +33,11 @@ class BufferQueue { public: struct Buffer { void *Buffer = nullptr; - std::size_t Size = 0; + size_t Size = 0; }; private: - std::size_t BufferSize; + size_t BufferSize; // We use a bool to indicate whether the Buffer has been used in this // freelist implementation. @@ -48,9 +47,33 @@ private: std::atomic Finalizing; public: + enum class ErrorCode : unsigned { + Ok, + NotEnoughMemory, + QueueFinalizing, + UnrecognizedBuffer, + AlreadyFinalized, + }; + + static const char *getErrorString(ErrorCode E) { + switch (E) { + case ErrorCode::Ok: + return "(none)"; + case ErrorCode::NotEnoughMemory: + return "no available buffers in the queue"; + case ErrorCode::QueueFinalizing: + return "queue already finalizing"; + case ErrorCode::UnrecognizedBuffer: + return "buffer being returned not owned by buffer queue"; + case ErrorCode::AlreadyFinalized: + return "queue already finalized"; + } + return "unknown error"; + } + /// Initialise a queue of size |N| with buffers of size |B|. We report success /// through |Success|. - BufferQueue(std::size_t B, std::size_t N, bool &Success); + BufferQueue(size_t B, size_t N, bool &Success); /// Updates |Buf| to contain the pointer to an appropriate buffer. Returns an /// error in case there are no available buffers to return when we will run @@ -63,13 +86,13 @@ public: /// - std::errc::not_enough_memory on exceeding MaxSize. /// - no error when we find a Buffer. /// - std::errc::state_not_recoverable on finalising BufferQueue. - std::error_code getBuffer(Buffer &Buf); + ErrorCode getBuffer(Buffer &Buf); /// Updates |Buf| to point to nullptr, with size 0. /// /// Returns: /// - ... - std::error_code releaseBuffer(Buffer &Buf); + ErrorCode releaseBuffer(Buffer &Buf); bool finalizing() const { return Finalizing.load(std::memory_order_acquire); } @@ -80,7 +103,7 @@ public: /// /// After a call to finalize succeeds, all subsequent calls to finalize will /// fail with std::errc::state_not_recoverable. - std::error_code finalize(); + ErrorCode finalize(); /// Applies the provided function F to each Buffer in the queue, only if the /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 94e446bfc..d65c0f4f4 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -133,9 +133,10 @@ public: static_cast(MetadataRecSize)); if (auto BQ = Buffers.lock()) { writeEOBMetadata(); - if (auto EC = BQ->releaseBuffer(Buffer)) + auto EC = BQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); + BufferQueue::getErrorString(EC)); return; } } @@ -170,7 +171,7 @@ static inline bool loggingInitialized( XRayLogInitStatus::XRAY_LOG_INITIALIZED; } -} // namespace anonymous +} // namespace static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, char *&MemPtr) XRAY_NEVER_INSTRUMENT { @@ -339,20 +340,23 @@ static inline void processFunctionHook( if (!loggingInitialized(LoggingStatus) || LocalBQ->finalizing()) { writeEOBMetadata(); - if (auto EC = BQ->releaseBuffer(Buffer)) { + auto EC = BQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); + BufferQueue::getErrorString(EC)); return; } RecordPtr = nullptr; } if (Buffer.Buffer == nullptr) { - if (auto EC = LocalBQ->getBuffer(Buffer)) { + auto EC = LocalBQ->getBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { auto LS = LoggingStatus.load(std::memory_order_acquire); if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) - Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); + Report("Failed to acquire a buffer; error=%s\n", + BufferQueue::getErrorString(EC)); return; } @@ -406,13 +410,16 @@ static inline void processFunctionHook( if ((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart < static_cast(MetadataRecSize)) { writeEOBMetadata(); - if (auto EC = LocalBQ->releaseBuffer(Buffer)) { + auto EC = LocalBQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); + BufferQueue::getErrorString(EC)); return; } - if (auto EC = LocalBQ->getBuffer(Buffer)) { - Report("Failed to acquire a buffer; error=%s\n", EC.message().c_str()); + EC = LocalBQ->getBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { + Report("Failed to acquire a buffer; error=%s\n", + BufferQueue::getErrorString(EC)); return; } setupNewBuffer(Buffer, wall_clock_reader); @@ -471,9 +478,10 @@ static inline void processFunctionHook( // make sure that other threads may start using this buffer. if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { writeEOBMetadata(); - if (auto EC = LocalBQ->releaseBuffer(Buffer)) { + auto EC = LocalBQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed releasing buffer at %p; error=%s\n", Buffer.Buffer, - EC.message().c_str()); + BufferQueue::getErrorString(EC)); return; } RecordPtr = nullptr; -- cgit v1.2.1 From ec69c0c9fdfcdf8a4cd5f8c00892ae58d9bb39ec Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 22 Mar 2017 09:31:17 +0000 Subject: tsan: fix a typo s/covert_morder/convert_morder/ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298492 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interface_atomic.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc index e49e1d2c5..0e3dbaedf 100644 --- a/lib/tsan/rtl/tsan_interface_atomic.cc +++ b/lib/tsan/rtl/tsan_interface_atomic.cc @@ -450,7 +450,7 @@ static void AtomicFence(ThreadState *thr, uptr pc, morder mo) { // C/C++ -static morder covert_morder(morder mo) { +static morder convert_morder(morder mo) { if (flags()->force_seq_cst_atomics) return (morder)mo_seq_cst; @@ -470,7 +470,7 @@ static morder covert_morder(morder mo) { #define SCOPED_ATOMIC(func, ...) \ const uptr callpc = (uptr)__builtin_return_address(0); \ uptr pc = StackTrace::GetCurrentPc(); \ - mo = covert_morder(mo); \ + mo = convert_morder(mo); \ ThreadState *const thr = cur_thread(); \ if (thr->ignore_interceptors) \ return NoTsanAtomic##func(__VA_ARGS__); \ -- cgit v1.2.1 From 955475ab45db24c49adad12618dfb0a25c5e3e74 Mon Sep 17 00:00:00 2001 From: Bob Haarman Date: Wed, 22 Mar 2017 17:25:49 +0000 Subject: [compiler-rt] build compiler-rt runtimes without LTO Summary: Currently, we build the compiler-rt runtimes with link-time optimization if LTO is configured for the LLVM project. This will break external programs that don't invoke the linker in such a way that it supports LLVM's LTO. To avoid this, this change causes the compiler-rt runtimes to be compiled with -fno-lto. This also makes the check-profile tests work on systems when doing a lld LTO build on a system where the system linker does not support LLVM LTO. Reviewers: rnk, davidxl Reviewed By: davidxl Subscribers: dberris, mgorny, llvm-commits, mehdi_amini Differential Revision: https://reviews.llvm.org/D31218 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298525 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index d4533e631..b64eb4246 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -110,6 +110,13 @@ function(add_compiler_rt_runtime name type) "OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;LINK_LIBS;OBJECT_LIBS" ${ARGN}) set(libnames) + # Until we support this some other way, build compiler-rt runtime without LTO + # to allow non-LTO projects to link with it. + if(COMPILER_RT_HAS_FNO_LTO_FLAG) + set(NO_LTO_FLAGS "-fno-lto") + else() + set(NO_LTO_FLAGS "") + endif() if(APPLE) foreach(os ${LIB_OS}) if(type STREQUAL "STATIC") @@ -121,7 +128,7 @@ function(add_compiler_rt_runtime name type) list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS) if(LIB_ARCHS_${libname}) list(APPEND libnames ${libname}) - set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${LIB_CFLAGS}) + set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS}) set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX}) set(sources_${libname} ${LIB_SOURCES}) format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS}) @@ -149,7 +156,7 @@ function(add_compiler_rt_runtime name type) set(sources_${libname} ${LIB_SOURCES}) format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS}) set(libnames ${libnames} ${libname}) - set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS}) + set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS}) endforeach() endif() -- cgit v1.2.1 From 65ede46c9b256dd0276361730dbac8b64de259a5 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 22 Mar 2017 18:42:43 +0000 Subject: Factor lsan allocator cache accesses into a function Summary: This patch is the first step towards allows us to move away from using __thread for the allocator cache on darwin, which is requiring for building lsan for darwin on ios version 7 and on iossim i386. This will be followed by patches to move the function into OS-specific files. Reviewers: kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29994 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298537 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 428485796..a08dcf286 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -70,7 +70,8 @@ typedef CombinedAllocator Allocator; static Allocator allocator; -static THREADLOCAL AllocatorCache cache; +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } void InitializeAllocator() { allocator.InitLinkerInitialized( @@ -79,7 +80,7 @@ void InitializeAllocator() { } void AllocatorThreadFinish() { - allocator.SwallowCache(&cache); + allocator.SwallowCache(GetAllocatorCache()); } static ChunkMetadata *Metadata(const void *p) { @@ -111,7 +112,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(&cache, size, alignment, false); + void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); @@ -125,7 +126,7 @@ void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); RegisterDeallocation(p); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, @@ -133,17 +134,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); - allocator.Deallocate(&cache, p); + allocator.Deallocate(GetAllocatorCache(), p); return nullptr; } - p = allocator.Reallocate(&cache, p, new_size, alignment); + p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { - *begin = (uptr)&cache; - *end = *begin + sizeof(cache); + *begin = (uptr)GetAllocatorCache(); + *end = *begin + sizeof(AllocatorCache); } uptr GetMallocUsableSize(const void *p) { -- cgit v1.2.1 From 5d7bda47b5326f934ed14e83743461f995c2d229 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 22 Mar 2017 19:15:24 +0000 Subject: Make nullability test pass on Windows, which evaluates parameters right-to-left. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298539 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/Misc/nullability.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/ubsan/TestCases/Misc/nullability.c b/test/ubsan/TestCases/Misc/nullability.c index 37b8ddc8d..583b8ec12 100644 --- a/test/ubsan/TestCases/Misc/nullability.c +++ b/test/ubsan/TestCases/Misc/nullability.c @@ -6,8 +6,6 @@ // CHECK-NEXT: nullability.c:[[@LINE+1]]:6: note: _Nonnull return type annotation specified here int *_Nonnull nonnull_retval1(int *p) { return p; } -// CHECK: nullability.c:1001:19: runtime error: null pointer passed as argument 1, which is declared to never be null -// CHECK-NEXT: nullability.c:[[@LINE+3]]:36: note: _Nonnull type annotation specified here // CHECK: nullability.c:1001:22: runtime error: null pointer passed as argument 2, which is declared to never be null // CHECK-NEXT: nullability.c:[[@LINE+1]]:56: note: _Nonnull type annotation specified here int *_Nonnull nonnull_retval2(int *_Nonnull arg1, int *_Nonnull arg2, -- cgit v1.2.1 From 94401629f27f34b5bebf69ce866a5aa413139549 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 22 Mar 2017 19:49:29 +0000 Subject: Use lld-link /nopdb to suppress PDB generation when DWARF is required Fixes cfi/stats.cpp and asan/fuse-lld.cc on Windows. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298545 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/fuse-lld.cc | 4 ++-- test/cfi/stats.cpp | 2 -- test/lit.common.cfg | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Windows/fuse-lld.cc b/test/asan/TestCases/Windows/fuse-lld.cc index 76c36d828..7fa5d4e8a 100644 --- a/test/asan/TestCases/Windows/fuse-lld.cc +++ b/test/asan/TestCases/Windows/fuse-lld.cc @@ -5,8 +5,8 @@ // FIXME: Use -fuse-ld=lld after the old COFF linker is removed. // FIXME: Test will fail until we add flags for requesting dwarf or cv. // RUNX: %clangxx_asan -O2 %s -o %t.exe -fuse-ld=lld -Wl,-debug -// RUN: %clangxx_asan -c -O2 %s -o %t.o -gdwarf -// RUN: lld-link %t.o -out:%t.exe -debug -defaultlib:libcmt %asan_lib %asan_cxx_lib +// RUN: %clangxx_asan -c -O2 %s -o %t.o -g -gdwarf +// RUN: lld-link %t.o -out:%t.exe -debug -nopdb -defaultlib:libcmt %asan_lib %asan_cxx_lib // RUN: not %run %t.exe 2>&1 | FileCheck %s #include diff --git a/test/cfi/stats.cpp b/test/cfi/stats.cpp index 8d96b5db0..566fcfbc2 100644 --- a/test/cfi/stats.cpp +++ b/test/cfi/stats.cpp @@ -2,8 +2,6 @@ // RUN: env SANITIZER_STATS_PATH=%t.stats %t // RUN: sanstats %t.stats | FileCheck %s -// XFAIL: win32 - // FIXME: We currently emit the wrong debug info under devirtualization. // UNSUPPORTED: devirt diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 741ce87c1..648c7fa3c 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -195,7 +195,8 @@ elif config.host_os == 'Linux' and is_linux_lto_supported(): elif config.host_os == 'Windows' and is_windows_lto_supported(): config.lto_supported = True config.lto_launch = [] - config.lto_flags = ["-fuse-ld=lld"] + # FIXME: Remove -nopdb when PDB writing is ready. + config.lto_flags = ["-fuse-ld=lld -Wl,-nopdb"] else: config.lto_supported = False -- cgit v1.2.1 From aaa8f43ba26653f9d0dd7da3a4bc8fe4bf717993 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 23 Mar 2017 15:57:58 +0000 Subject: Bypass potential libc's sysconf interceptors Summary: sysconf(_SC_PAGESIZE) is called very early during sanitizer init and any instrumented code (sysconf() wrapper/interceptor will likely be instrumented) calling back to sanitizer before init is done will most surely crash. 2nd attempt, now with glibc version checks (D31092 was reverted). Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D31221 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298613 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 16 ++++++++++++++ .../Linux/sysconf_interceptor_bypass_test.cc | 25 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 24707c74d..ab65e2db5 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -77,6 +77,20 @@ extern char **environ; // provided by crt1 #include #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif + +#if SANITIZER_USE_GETAUXVAL +#include +#endif + #if SANITIZER_LINUX // struct kernel_timeval { @@ -805,6 +819,8 @@ uptr GetPageSize() { return 4096; #elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; +#elif SANITIZER_USE_GETAUXVAL + return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif diff --git a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc new file mode 100644 index 000000000..eb4deace0 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s + +#include + +// getauxval() used instead of sysconf() in GetPageSize() is defined starting +// glbc version 2.16. +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 16) +extern "C" long sysconf(int name) { + fprintf(stderr, "sysconf wrapper called\n"); + return 0; +} +#endif // defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 16) + +int main() { + // All we need to check is that the sysconf() interceptor defined above was + // not called. Should it get called, it will crash right there, any + // instrumented code executed before sanitizer init is finished will crash + // accessing non-initialized sanitizer internals. Even if it will not crash + // in some configuration, it should never be called anyway. + fprintf(stderr, "Passed\n"); + // CHECK-NOT: sysconf wrapper called + // CHECK: Passed + // CHECK-NOT: sysconf wrapper called + return 0; +} -- cgit v1.2.1 From 16ed7295a5e6619e28c4bf93dba7b3b87e7ca2e3 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 23 Mar 2017 19:21:10 +0000 Subject: [scudo] Add test exercising pthreads Summary: Scudo didn't have any test using multiple threads. Add one, borrowed from lsan. Reviewers: kcc, alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31297 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298636 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/scudo/threads.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 test/scudo/threads.cpp diff --git a/test/scudo/threads.cpp b/test/scudo/threads.cpp new file mode 100644 index 000000000..d9f4a86c1 --- /dev/null +++ b/test/scudo/threads.cpp @@ -0,0 +1,65 @@ +// RUN: %clang_scudo %s -o %t +// RUN: SCUDO_OPTIONS="QuarantineSizeMb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 +// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 + +// Tests parallel allocations and deallocations of memory chunks from a number +// of concurrent threads, with and without quarantine. +// This test passes if everything executes properly without crashing. + +#include +#include +#include +#include + +#include + +int num_threads; +int total_num_alloc; +const int kMaxNumThreads = 500; +pthread_t tid[kMaxNumThreads]; + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +bool go = false; + +void *thread_fun(void *arg) { + pthread_mutex_lock(&mutex); + while (!go) pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < total_num_alloc / num_threads; i++) { + void *p = malloc(10); + __asm__ __volatile__("" : : "r"(p) : "memory"); + free(p); + } + return 0; +} + +int main(int argc, char** argv) { + assert(argc == 3); + num_threads = atoi(argv[1]); + assert(num_threads > 0); + assert(num_threads <= kMaxNumThreads); + total_num_alloc = atoi(argv[2]); + assert(total_num_alloc > 0); + + printf("%d threads, %d allocations in each\n", num_threads, + total_num_alloc / num_threads); + fprintf(stderr, "Heap size before: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes before: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + for (int i = 0; i < num_threads; i++) + pthread_create(&tid[i], 0, thread_fun, 0); + pthread_mutex_lock(&mutex); + go = true; + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < num_threads; i++) + pthread_join(tid[i], 0); + + fprintf(stderr, "Heap size after: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes after: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + return 0; +} -- cgit v1.2.1 From 8db84b52513a00e1151e8a6561dc014656fd15d7 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 23 Mar 2017 21:39:52 +0000 Subject: [asan] Add an interceptor for strtok Summary: This change addresses https://github.com/google/sanitizers/issues/766. I tested the change with make check-asan and the newly added test case. Reviewers: ygribov, kcc, alekseyshl Subscribers: kubamracek, llvm-commits Patch by mrigger Differential Revision: https://reviews.llvm.org/D30384 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298650 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 47 +++++++++ lib/sanitizer_common/sanitizer_flags.inc | 3 + .../sanitizer_platform_interceptors.h | 1 + test/asan/TestCases/strtok.c | 108 +++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 test/asan/TestCases/strtok.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 75026e0e4..8e5734273 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -495,6 +495,52 @@ INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { #define INIT_STRCASESTR #endif +#if SANITIZER_INTERCEPT_STRTOK + +INTERCEPTOR(char*, strtok, char *str, const char *delimiters) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtok, str, delimiters); + if (!common_flags()->intercept_strtok) { + return REAL(strtok)(str, delimiters); + } + if (common_flags()->strict_string_checks) { + // If strict_string_checks is enabled, we check the whole first argument + // string on the first call (strtok saves this string in a static buffer + // for subsequent calls). We do not need to check strtok's result. + // As the delimiters can change, we check them every call. + if (str != nullptr) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1); + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, + REAL(strlen)(delimiters) + 1); + return REAL(strtok)(str, delimiters); + } else { + // However, when strict_string_checks is disabled we cannot check the + // whole string on the first call. Instead, we check the result string + // which is guaranteed to be a NULL-terminated substring of the first + // argument. We also conservatively check one character of str and the + // delimiters. + if (str != nullptr) { + COMMON_INTERCEPTOR_READ_STRING(ctx, str, 1); + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, 1); + char *result = REAL(strtok)(str, delimiters); + if (result != nullptr) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, result, REAL(strlen)(result) + 1); + } else if (str != nullptr) { + // No delimiter were found, it's safe to assume that the entire str was + // scanned. + COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1); + } + return result; + } +} + +#define INIT_STRTOK COMMON_INTERCEPT_FUNCTION(strtok) +#else +#define INIT_STRTOK +#endif + #if SANITIZER_INTERCEPT_MEMMEM DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc, const void *s1, SIZE_T len1, const void *s2, @@ -6079,6 +6125,7 @@ static void InitializeCommonInterceptors() { INIT_STRCHRNUL; INIT_STRRCHR; INIT_STRSPN; + INIT_STRTOK; INIT_STRPBRK; INIT_MEMSET; INIT_MEMMOVE; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 1306c721b..f1113698d 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -193,6 +193,9 @@ COMMON_FLAG(bool, intercept_strstr, true, COMMON_FLAG(bool, intercept_strspn, true, "If set, uses custom wrappers for strspn and strcspn function " "to find more errors.") +COMMON_FLAG(bool, intercept_strtok, true, + "If set, uses a custom wrapper for the strtok function " + "to find more errors.") COMMON_FLAG(bool, intercept_strpbrk, true, "If set, uses custom wrappers for strpbrk function " "to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 43ec55830..e56557530 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -74,6 +74,7 @@ #define SANITIZER_INTERCEPT_STRCMP 1 #define SANITIZER_INTERCEPT_STRSTR 1 #define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRTOK 1 #define SANITIZER_INTERCEPT_STRCHR 1 #define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC #define SANITIZER_INTERCEPT_STRRCHR 1 diff --git a/test/asan/TestCases/strtok.c b/test/asan/TestCases/strtok.c new file mode 100644 index 000000000..7aa263add --- /dev/null +++ b/test/asan/TestCases/strtok.c @@ -0,0 +1,108 @@ +// RUN: %clang_asan %s -o %t + +// Test overflows with strict_string_checks + +// RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK1 +// RUN: %env_asan_opts=intercept_strtok=false%run %t test1 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK2 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test2 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t test3 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK3 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test3 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true %run %t test4 2>&1 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test4 2>&1 + +// Test overflows with !strict_string_checks +// RUN: %env_asan_opts=strict_string_checks=false not %run %t test5 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK5 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test5 2>&1 +// RUN: %env_asan_opts=strict_string_checks=false not %run %t test6 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK6 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test6 2>&1 + + +#include +#include +#include + +// Check that we find overflows in the delimiters on the first call +// with strict_string_checks. +void test1() { + char *token; + char s[4] = "abc"; + char token_delimiter[2] = "b"; + __asan_poison_memory_region ((char *)&token_delimiter[1], 2); + token = strtok(s, token_delimiter); + // CHECK1:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable + assert(strcmp(token, "a") == 0); +} + +// Check that we find overflows in the delimiters on the second call (str == NULL) +// with strict_string_checks. +void test2() { + char *token; + char s[4] = "abc"; + char token_delimiter[2] = "b"; + token = strtok(s, token_delimiter); + assert(strcmp(token, "a") == 0); + __asan_poison_memory_region ((char *)&token_delimiter[1], 2); + token = strtok(NULL, token_delimiter); + // CHECK2:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable + assert(strcmp(token, "c") == 0); +} + +// Check that we find overflows in the string (only on the first call) with strict_string_checks. +void test3() { + char *token; + char s[4] = "abc"; + char token_delimiter[2] = "b"; + __asan_poison_memory_region ((char *)&s[3], 2); + token = strtok(s, token_delimiter); + // CHECK3:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable + assert(token == s); +} + +// Check that we do not crash when strtok returns NULL with strict_string_checks. +void test4() { + char *token; + char s[] = ""; + char token_delimiter[] = "a"; + token = strtok(s, token_delimiter); + assert(token == NULL); +} + +// Check that we find overflows in the string (only on the first call) with !strict_string_checks. +void test5() { + char *token; + char s[4] = "abc"; + char token_delimiter[2] = "d"; + __asan_poison_memory_region ((char *)&s[2], 2); + __asan_poison_memory_region ((char *)&token_delimiter[1], 2); + token = strtok(s, token_delimiter); + // CHECK5:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable + assert(token == s); +} + +// Check that we find overflows in the delimiters (only on the first call) with !strict_string_checks. +void test6() { + char *token; + char s[4] = "abc"; + char token_delimiter[1] = {'d'}; + __asan_poison_memory_region ((char *)&token_delimiter[1], 2); + token = strtok(s, &token_delimiter[1]); + // CHECK6:'token_delimiter' <== Memory access at offset {{[0-9]+}} overflows this variable + assert(strcmp(token, "abc") == 0); +} + +int main(int argc, char **argv) { + if (argc != 2) return 1; + if (!strcmp(argv[1], "test1")) test1(); + if (!strcmp(argv[1], "test2")) test2(); + if (!strcmp(argv[1], "test3")) test3(); + if (!strcmp(argv[1], "test4")) test4(); + if (!strcmp(argv[1], "test5")) test5(); + if (!strcmp(argv[1], "test6")) test6(); + return 0; +} -- cgit v1.2.1 From d218b6eb8a64b34c3d958827daac5cddfc55ab64 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 23 Mar 2017 23:20:47 +0000 Subject: Add strtok interceptor for ASAN for Windows. Summary: Fixes test broken by D30384 Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D31312 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298658 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_win_dll_thunk.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index 651886c91..189b4b141 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -82,6 +82,7 @@ INTERCEPT_LIBRARY_FUNCTION(strpbrk); INTERCEPT_LIBRARY_FUNCTION(strrchr); INTERCEPT_LIBRARY_FUNCTION(strspn); INTERCEPT_LIBRARY_FUNCTION(strstr); +INTERCEPT_LIBRARY_FUNCTION(strtok); INTERCEPT_LIBRARY_FUNCTION(strtol); INTERCEPT_LIBRARY_FUNCTION(wcslen); -- cgit v1.2.1 From 5788957d2ee938cb79af3d4560ec0ef49335502d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 24 Mar 2017 03:53:44 +0000 Subject: Update the Darwin/external.cc testcase to use rpath. This means we can move the test output executables and still be able to run them. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298682 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/external.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc index 3c5e71a0f..2605480d7 100644 --- a/test/tsan/Darwin/external.cc +++ b/test/tsan/Darwin/external.cc @@ -1,6 +1,15 @@ -// RUN: %clangxx_tsan %s -o %t-lib-instrumented.dylib -shared -DSHARED_LIB -// RUN: %clangxx_tsan %s -o %t-lib-noninstrumented.dylib -shared -DSHARED_LIB -fno-sanitize=thread -// RUN: %clangxx_tsan %s -o %t-lib-noninstrumented-callbacks.dylib -shared -DSHARED_LIB -fno-sanitize=thread -DUSE_TSAN_CALLBACKS +// RUN: %clangxx_tsan %s -shared -DSHARED_LIB \ +// RUN: -o %t-lib-instrumented.dylib \ +// RUN: -install_name @rpath/`basename %t-lib-instrumented.dylib` + +// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread \ +// RUN: -o %t-lib-noninstrumented.dylib \ +// RUN: -install_name @rpath/`basename %t-lib-noninstrumented.dylib` + +// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \ +// RUN: -o %t-lib-noninstrumented-callbacks.dylib \ +// RUN: -install_name @rpath/`basename %t-lib-noninstrumented-callbacks.dylib` + // RUN: %clangxx_tsan %s %t-lib-instrumented.dylib -o %t-lib-instrumented // RUN: %clangxx_tsan %s %t-lib-noninstrumented.dylib -o %t-lib-noninstrumented // RUN: %clangxx_tsan %s %t-lib-noninstrumented-callbacks.dylib -o %t-lib-noninstrumented-callbacks -- cgit v1.2.1 From 4980e83ed000103f30705b7d34c8ab4cf727e0d3 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 24 Mar 2017 03:57:27 +0000 Subject: Fix a warning when running the GotsanRuntimeCheck test on Darwin. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298684 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 7e85505a6..34af4e918 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -102,12 +102,12 @@ extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, u64 offset) { if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL); - if (__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); + if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); return (uptr)mmap(addr, length, prot, flags, fd, offset); } uptr internal_munmap(void *addr, uptr length) { - if (__munmap) return __munmap(addr, length); + if (&__munmap) return __munmap(addr, length); return munmap(addr, length); } @@ -198,7 +198,7 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; int internal_fork() { - if (__fork) + if (&__fork) return __fork(); return fork(); } -- cgit v1.2.1 From 4bb8e9c39f9a23b3ed9a430beefbb5df8923f69f Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Fri, 24 Mar 2017 05:02:51 +0000 Subject: [XRay] [compiler-rt] Plug a file descriptor leak in a failure case. Summary: Fd needs to be closed before the number gets out of scope. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31278 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298685 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_x86_64.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index 1b9131316..8c2a4e313 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -44,9 +44,9 @@ static bool readValueFromFile(const char *Filename, ssize_t BytesRead; bool Success; std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize); + close(Fd); if (!Success) return false; - close(Fd); char *End = nullptr; long long Tmp = internal_simple_strtoll(Line, &End, 10); bool Result = false; -- cgit v1.2.1 From b80243e5db3482b79da471ec578b35d6afbe8791 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 24 Mar 2017 16:37:02 +0000 Subject: Update debug_external.cc testcase to use TSan-invisible barriers to reduce flakiness. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298707 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/debug_external.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/tsan/Darwin/debug_external.cc b/test/tsan/Darwin/debug_external.cc index ac05a01c4..217690fc5 100644 --- a/test/tsan/Darwin/debug_external.cc +++ b/test/tsan/Darwin/debug_external.cc @@ -6,6 +6,8 @@ #include #include +#include "../test.h" + extern "C" { void __tsan_on_report(void *report); int __tsan_get_report_loc(void *report, unsigned long idx, const char **type, @@ -20,11 +22,13 @@ void __tsan_external_assign_tag(void *addr, void *tag); } void *Thread(void *arg) { + barrier_wait(&barrier); *((long *)arg) = 42; return NULL; } int main() { + barrier_init(&barrier, 2); void *tag = __tsan_external_register_tag("MyObject"); long *obj = (long *)malloc(sizeof(long)); fprintf(stderr, "obj = %p\n", obj); @@ -34,6 +38,7 @@ int main() { pthread_t t; pthread_create(&t, 0, Thread, obj); *obj = 41; + barrier_wait(&barrier); pthread_join(t, 0); fprintf(stderr, "Done.\n"); return 0; -- cgit v1.2.1 From c3709191b6d36c4c936173f4a9a29a734b12cb15 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Fri, 24 Mar 2017 17:06:00 +0000 Subject: builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA. Summary: Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation mode (-mthumb, -marm), it reflect's capability of given CPU. Due to this: - use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB - use '.thumb' directive consistently in all affected files - decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION() --------- Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 ! Reviewers: weimingz, rengolin, compnerd Subscribers: aemerson, dim Differential Revision: https://reviews.llvm.org/D30938 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298713 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_idivmod.S | 15 ++++++++++++--- lib/builtins/arm/aeabi_uidivmod.S | 8 ++++++++ lib/builtins/arm/bswapdi2.S | 4 ++-- lib/builtins/arm/bswapsi2.S | 4 ++-- lib/builtins/arm/clzdi2.S | 4 ++-- lib/builtins/arm/clzsi2.S | 4 ++-- lib/builtins/arm/comparesf2.S | 38 ++++++++++++++++++++++++++------------ lib/builtins/arm/divmodsi4.S | 4 ++-- lib/builtins/arm/divsi3.S | 12 ++++++------ lib/builtins/arm/modsi3.S | 4 ++-- lib/builtins/arm/udivmodsi4.S | 9 ++++----- lib/builtins/arm/udivsi3.S | 29 ++++++++++++++--------------- lib/builtins/arm/umodsi3.S | 8 ++++---- lib/builtins/assembly.h | 29 ++++++++++++++++++++++------- 14 files changed, 108 insertions(+), 64 deletions(-) diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S index 0164b15dc..4419929f6 100644 --- a/lib/builtins/arm/aeabi_idivmod.S +++ b/lib/builtins/arm/aeabi_idivmod.S @@ -20,16 +20,25 @@ #endif .syntax unified + .syntax unified + .text +#if defined(USE_THUMB_PROLOGUE) + .thumb +#endif .p2align 2 +#if defined(USE_THUMB_PROLOGUE) +DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_idivmod) +#else DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) -#if __ARM_ARCH_ISA_THUMB == 1 +#endif +#if defined(USE_THUMB_1) push {r0, r1, lr} bl SYMBOL_NAME(__divsi3) pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom muls r2, r0, r2 // r2 = quot * denom subs r1, r1, r2 JMP (r3) -#else +#else // defined(USE_THUMB_1) push { lr } sub sp, sp, #4 mov r2, sp @@ -42,7 +51,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) ldr r1, [sp] add sp, sp, #4 pop { pc } -#endif // __ARM_ARCH_ISA_THUMB == 1 +#endif // defined(USE_THUMB_1) END_COMPILERRT_FUNCTION(__aeabi_idivmod) NO_EXEC_STACK_DIRECTIVE diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S index a627fc740..37dae4a10 100644 --- a/lib/builtins/arm/aeabi_uidivmod.S +++ b/lib/builtins/arm/aeabi_uidivmod.S @@ -21,8 +21,16 @@ #endif .syntax unified + .text +#if defined(USE_THUMB_PROLOGUE) + .thumb +#endif .p2align 2 +#if defined(USE_THUMB_PROLOGUE) +DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_uidivmod) +#else DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) +#endif #if __ARM_ARCH_ISA_THUMB == 1 cmp r0, r1 bcc LOCAL_LABEL(case_denom_larger) diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S index fb226cea2..4e5a579cf 100644 --- a/lib/builtins/arm/bswapdi2.S +++ b/lib/builtins/arm/bswapdi2.S @@ -11,7 +11,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -21,7 +21,7 @@ // Reverse all the bytes in a 64-bit integer. // .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2) #else DEFINE_COMPILERRT_FUNCTION(__bswapdi2) diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S index 553c3c2e3..60342ae0f 100644 --- a/lib/builtins/arm/bswapsi2.S +++ b/lib/builtins/arm/bswapsi2.S @@ -11,7 +11,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -21,7 +21,7 @@ // Reverse all the bytes in a 32-bit integer. // .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2) #else DEFINE_COMPILERRT_FUNCTION(__bswapsi2) diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S index 6068c176f..fe56a183f 100644 --- a/lib/builtins/arm/clzdi2.S +++ b/lib/builtins/arm/clzdi2.S @@ -15,13 +15,13 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2) #else DEFINE_COMPILERRT_FUNCTION(__clzdi2) diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S index c2ba3a8cf..28d43041e 100644 --- a/lib/builtins/arm/clzsi2.S +++ b/lib/builtins/arm/clzsi2.S @@ -15,12 +15,12 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2) #else DEFINE_COMPILERRT_FUNCTION(__clzsi2) diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S index ef7091bf3..1f7031cbf 100644 --- a/lib/builtins/arm/comparesf2.S +++ b/lib/builtins/arm/comparesf2.S @@ -38,15 +38,20 @@ //===----------------------------------------------------------------------===// #include "../assembly.h" -.syntax unified -#if __ARM_ARCH_ISA_THUMB == 2 -.thumb + .syntax unified + .text +#if defined(USE_THUMB_PROLOGUE) + .thumb #endif @ int __eqsf2(float a, float b) .p2align 2 +#if defined(USE_THUMB_PROLOGUE) +DEFINE_COMPILERRT_THUMB_FUNCTION(__eqsf2) +#else DEFINE_COMPILERRT_FUNCTION(__eqsf2) +#endif #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 @@ -67,7 +72,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // flag if both a and b are zero (of either sign). The shift of r3 doesn't // effect this at all, but it *does* make sure that the C flag is clear for // the subsequent operations. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) lsrs r6, r3, #1 orrs r6, r2 #else @@ -75,7 +80,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) #endif // Next, we check if a and b have the same or different signs. If they have // opposite signs, this eor will set the N flag. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) beq 1f movs r6, r0 eors r6, r1 @@ -89,7 +94,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // ignoring NaNs for now), this subtract will zero out r0. If they have the // same sign, the flags are updated as they would be for a comparison of the // absolute values of a and b. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bmi 1f subs r0, r2, r3 1: @@ -108,7 +113,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // still clear from the shift argument in orrs; if a is positive and b // negative, this places 0 in r0; if a is negative and b positive, -1 is // placed in r0. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bhs 1f // Here if a and b have the same sign and absA < absB, the result is thus // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan). @@ -127,7 +132,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed // in r0, which is the desired result. Conversely, if both are positive // and a > b, zero is placed in r0. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bls 1f // Here both have the same sign and absA > absB. movs r0, #1 @@ -145,14 +150,14 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // If a == b, then the Z flag is set, so we can get the correct final value // into r0 by simply or'ing with 1 if Z is clear. // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b. -#if __ARM_ARCH_ISA_THUMB != 1 +#if defined(USE_THUMB_1) it ne orrne r0, r0, #1 #endif // Finally, we need to deal with NaNs. If either argument is NaN, replace // the value in r0 with 1. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) LOCAL_LABEL(CHECK_NAN): movs r6, #0xff lsls r6, #24 @@ -180,7 +185,11 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) @ int __gtsf2(float a, float b) .p2align 2 +#if defined(USE_THUMB) +DEFINE_COMPILERRT_THUMB_FUNCTION(__gtsf2) +#else DEFINE_COMPILERRT_FUNCTION(__gtsf2) +#endif // Identical to the preceding except in that we return -1 for NaN values. // Given that the two paths share so much code, one might be tempted to // unify them; however, the extra code needed to do so makes the code size @@ -189,7 +198,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2) vmov r0, s0 vmov r1, s1 #endif -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 @@ -254,7 +263,12 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) @ int __unordsf2(float a, float b) .p2align 2 +#if defined(USE_THUMB) +DEFINE_COMPILERRT_THUMB_FUNCTION(__unordsf2) +#else DEFINE_COMPILERRT_FUNCTION(__unordsf2) +#endif + #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 @@ -263,7 +277,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2) lsls r2, r0, #1 lsls r3, r1, #1 movs r0, #0 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) movs r1, #0xff lsls r1, #24 cmp r2, r1 diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S index 999c310ec..3c8359852 100644 --- a/lib/builtins/arm/divmodsi4.S +++ b/lib/builtins/arm/divmodsi4.S @@ -23,7 +23,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -32,7 +32,7 @@ @ value is the quotient, the remainder is placed in the variable. .p2align 3 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4) #else DEFINE_COMPILERRT_FUNCTION(__divmodsi4) diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S index f066f60ad..ad96c9e5b 100644 --- a/lib/builtins/arm/divsi3.S +++ b/lib/builtins/arm/divsi3.S @@ -20,10 +20,10 @@ #define CLEAR_FRAME_AND_RETURN \ pop {r4, r7, pc} - .syntax unified - .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb + .syntax unified + .text +#if defined(USE_THUMB_PROLOGUE) + .thumb #endif .p2align 3 @@ -33,7 +33,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3) @ int __divsi3(int divident, int divisor) @ Calculate and return the quotient of the (signed) division. -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3) #else DEFINE_COMPILERRT_FUNCTION(__divsi3) @@ -72,7 +72,7 @@ ESTABLISH_FRAME // abs(a) / abs(b) bl SYMBOL_NAME(__udivsi3) // Apply sign of quotient to result and return. -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) asrs r4, #31 eors r0, r4 subs r0, r0, r4 diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S index 1d302edc6..0986d8494 100644 --- a/lib/builtins/arm/modsi3.S +++ b/lib/builtins/arm/modsi3.S @@ -22,7 +22,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -30,7 +30,7 @@ @ Calculate and return the remainder of the (signed) division. .p2align 3 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3) #else DEFINE_COMPILERRT_FUNCTION(__modsi3) diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S index 1ad8ee34b..860fced63 100644 --- a/lib/builtins/arm/udivmodsi4.S +++ b/lib/builtins/arm/udivmodsi4.S @@ -16,8 +16,7 @@ .syntax unified .text - -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -27,7 +26,7 @@ @ value is the quotient, the remainder is placed in the variable. .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4) #else DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) @@ -67,7 +66,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -78,7 +77,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) mov r3, #0 bx ip # else -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif str r4, [sp, #-8]! diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S index fcc472b4f..2a0209927 100644 --- a/lib/builtins/arm/udivsi3.S +++ b/lib/builtins/arm/udivsi3.S @@ -16,8 +16,7 @@ .syntax unified .text - -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -27,7 +26,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) @ unsigned int __udivsi3(unsigned int divident, unsigned int divisor) @ Calculate and return the quotient of the (unsigned) division. -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3) #else DEFINE_COMPILERRT_FUNCTION(__udivsi3) @@ -40,7 +39,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivsi3) #else cmp r1, #1 bcc LOCAL_LABEL(divby0) -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bne LOCAL_LABEL(num_neq_denom) JMP(lr) LOCAL_LABEL(num_neq_denom): @@ -49,7 +48,7 @@ LOCAL_LABEL(num_neq_denom): JMPc(lr, eq) #endif cmp r0, r1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bhs LOCAL_LABEL(num_ge_denom) movs r0, #0 JMP(lr) @@ -81,7 +80,7 @@ LOCAL_LABEL(num_ge_denom): clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -92,17 +91,17 @@ LOCAL_LABEL(num_ge_denom): mov r3, #0 bx ip # else /* No CLZ Feature */ -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) # define BLOCK_SIZE 10 # else # define BLOCK_SIZE 12 # endif mov r2, r0 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) mov ip, r0 adr r0, LOCAL_LABEL(div0block) adds r0, #1 @@ -111,7 +110,7 @@ LOCAL_LABEL(num_ge_denom): # endif lsrs r3, r2, #16 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_16) movs r2, r3 subs r0, r0, #(16 * BLOCK_SIZE) @@ -123,7 +122,7 @@ LOCAL_LABEL(skip_16): lsrs r3, r2, #8 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_8) movs r2, r3 subs r0, r0, #(8 * BLOCK_SIZE) @@ -135,7 +134,7 @@ LOCAL_LABEL(skip_8): lsrs r3, r2, #4 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_4) movs r2, r3 subs r0, r0, #(4 * BLOCK_SIZE) @@ -147,7 +146,7 @@ LOCAL_LABEL(skip_4): lsrs r3, r2, #2 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_2) movs r2, r3 subs r0, r0, #(2 * BLOCK_SIZE) @@ -158,7 +157,7 @@ LOCAL_LABEL(skip_2): # endif /* Last block, no need to update r2 or r3. */ -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) lsrs r3, r2, #1 cmp r3, r1 blo LOCAL_LABEL(skip_1) @@ -191,7 +190,7 @@ LOCAL_LABEL(divby0): JMP(lr) -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) #define block(shift) \ lsls r2, r1, IMM shift; \ cmp r0, r2; \ diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S index 672487e81..90f3e8575 100644 --- a/lib/builtins/arm/umodsi3.S +++ b/lib/builtins/arm/umodsi3.S @@ -16,7 +16,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) .thumb #endif @@ -24,7 +24,7 @@ @ Calculate and return the remainder of the (unsigned) division. .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 +#if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3) #else DEFINE_COMPILERRT_FUNCTION(__umodsi3) @@ -65,7 +65,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -74,7 +74,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) sub ip, ip, r3, lsl #3 bx ip # else -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif mov r2, r0 diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 29d9f8844..af959b24b 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -92,20 +92,35 @@ JMP(ip) #endif -#if __ARM_ARCH_ISA_THUMB == 2 +/* + * Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros: + * - for '-mthumb -march=armv6' compiler defines '__thumb__' + * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' + */ +#if defined(__thumb2__) +#define USE_THUMB_2 1 +#elif defined(__thumb__) +#define USE_THUMB_1 1 +#endif + +#if defined(USE_THUMB_1) && defined(USE_THUMB_2) +#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together." +#endif + +#if defined(USE_THUMB_1) || defined(USE_THUMB_1) +#define USE_THUMB_PROLOGUE 1 +#endif + +#if defined(USE_THUMB_2) #define IT(cond) it cond #define ITT(cond) itt cond +#define WIDE(op) op.w #else #define IT(cond) #define ITT(cond) -#endif - -#if __ARM_ARCH_ISA_THUMB == 2 -#define WIDE(op) op.w -#else #define WIDE(op) op #endif -#endif +#endif /* defined(__arm__) */ #define GLUE2(a, b) a##b #define GLUE(a, b) GLUE2(a, b) -- cgit v1.2.1 From c651b5d41839aae2711af96c24b19949a1f38014 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Fri, 24 Mar 2017 17:06:05 +0000 Subject: [Compiler-rt][Builtins] Implement lit-test support (part 2 of 2) Summary: Original r297566 (https://reviews.llvm.org/D30802) is splitted into two parts. This part adds CMakefile/lit.cfg support. Reviewers: rengolin, compnerd, jroelofs, erik.pilkington Subscribers: srhines, dberris, mgorny Differential Revision: https://reviews.llvm.org/D31259 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298714 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/CMakeLists.txt | 17 ++++++++ test/builtins/Unit/lit.cfg | 80 ++++++++++++++++++++++++++++++++++++++ test/builtins/Unit/lit.site.cfg.in | 12 ++++++ 3 files changed, 109 insertions(+) create mode 100644 test/builtins/Unit/lit.cfg create mode 100644 test/builtins/Unit/lit.site.cfg.in diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index 443e552f8..8b5479d83 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -9,6 +9,23 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg ) +#Unit tests. + +include(builtin-config-ix) + +foreach(arch ${BUILTIN_SUPPORTED_ARCH}) + set(BUILTINS_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}-${OS_NAME}" BUILTINS_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} BUILTINS_TEST_TARGET_CC BUILTINS_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg + ) + list(APPEND BUILTINS_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) +endforeach() + add_lit_testsuite(check-builtins "Running the Builtins tests" ${BUILTINS_TESTSUITES} DEPENDS ${BUILTINS_TEST_DEPS}) diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg new file mode 100644 index 000000000..f29f7e00d --- /dev/null +++ b/test/builtins/Unit/lit.cfg @@ -0,0 +1,80 @@ +# -*- Python -*- + +import os +import platform + +import lit.formats + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +# Setup config name. +config.name = 'Builtins' + config.name_suffix + +# Platform-specific default Builtins_OPTIONS for lit tests. +default_builtins_opts = '' + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Path to the static library +base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a " + % config.target_arch) + +builtins_source_dir = os.path.join( + get_required_attr(config, "compiler_rt_src_root"), "lib", "builtins") +builtins_lit_source_dir = get_required_attr(config, "builtins_lit_source_dir") + +extra_link_flags = ["-nodefaultlibs"] +config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') ) + +target_cflags = [get_required_attr(config, "target_cflags")] +target_cflags += ['-fno-builtin', '-I', builtins_source_dir] +target_cflags += extra_link_flags +target_cxxflags = config.cxx_mode_flags + target_cflags +clang_builtins_static_cflags = ([""] + + config.debug_info_flags + target_cflags) +clang_builtins_static_cxxflags = config.cxx_mode_flags + \ + clang_builtins_static_cflags + +clang_builtins_cflags = clang_builtins_static_cflags +clang_builtins_cxxflags = clang_builtins_static_cxxflags + + +config.available_features.add('not-android') +clang_wrapper = "" + +def build_invocation(compile_flags): + return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " " + + +target_arch = config.target_arch +if (target_arch == "arm"): + target_arch = "armv7" + +config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) +config.substitutions.append( ("%clang_builtins ", \ + build_invocation(clang_builtins_cflags))) +config.substitutions.append( ("%clangxx_builtins ", \ + build_invocation(clang_builtins_cxxflags))) + +# FIXME: move the call_apsr.s into call_apsr.h as inline-asm. +# some ARM tests needs call_apsr.s +call_apsr_source = os.path.join(builtins_lit_source_dir, 'arm', 'call_apsr.S') +march_flag = '-march=' + target_arch +call_apsr_flags = ['-c', march_flag, call_apsr_source] +config.substitutions.append( ("%arm_call_apsr ", \ + build_invocation(call_apsr_flags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +if not config.emulator: + config.available_features.add('native-run') diff --git a/test/builtins/Unit/lit.site.cfg.in b/test/builtins/Unit/lit.site.cfg.in new file mode 100644 index 000000000..4b4009d1e --- /dev/null +++ b/test/builtins/Unit/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +config.name_suffix = "@BUILTINS_TEST_CONFIG_SUFFIX@" +config.builtins_lit_source_dir = "@BUILTINS_LIT_SOURCE_DIR@/Unit" +config.target_cflags = "@BUILTINS_TEST_TARGET_CFLAGS@" +config.target_arch = "@BUILTINS_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@BUILTINS_LIT_SOURCE_DIR@/Unit/lit.cfg") -- cgit v1.2.1 From 9736f90434cf210271d30af6972075ac4b36694f Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Fri, 24 Mar 2017 17:08:35 +0000 Subject: Revert "builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA." This reverts commit c3709191b6d36c4c936173f4a9a29a734b12cb15. (commit by mistake) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298715 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_idivmod.S | 15 +++------------ lib/builtins/arm/aeabi_uidivmod.S | 8 -------- lib/builtins/arm/bswapdi2.S | 4 ++-- lib/builtins/arm/bswapsi2.S | 4 ++-- lib/builtins/arm/clzdi2.S | 4 ++-- lib/builtins/arm/clzsi2.S | 4 ++-- lib/builtins/arm/comparesf2.S | 38 ++++++++++++-------------------------- lib/builtins/arm/divmodsi4.S | 4 ++-- lib/builtins/arm/divsi3.S | 12 ++++++------ lib/builtins/arm/modsi3.S | 4 ++-- lib/builtins/arm/udivmodsi4.S | 9 +++++---- lib/builtins/arm/udivsi3.S | 29 +++++++++++++++-------------- lib/builtins/arm/umodsi3.S | 8 ++++---- lib/builtins/assembly.h | 29 +++++++---------------------- 14 files changed, 64 insertions(+), 108 deletions(-) diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S index 4419929f6..0164b15dc 100644 --- a/lib/builtins/arm/aeabi_idivmod.S +++ b/lib/builtins/arm/aeabi_idivmod.S @@ -20,25 +20,16 @@ #endif .syntax unified - .syntax unified - .text -#if defined(USE_THUMB_PROLOGUE) - .thumb -#endif .p2align 2 -#if defined(USE_THUMB_PROLOGUE) -DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_idivmod) -#else DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) -#endif -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 push {r0, r1, lr} bl SYMBOL_NAME(__divsi3) pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom muls r2, r0, r2 // r2 = quot * denom subs r1, r1, r2 JMP (r3) -#else // defined(USE_THUMB_1) +#else push { lr } sub sp, sp, #4 mov r2, sp @@ -51,7 +42,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) ldr r1, [sp] add sp, sp, #4 pop { pc } -#endif // defined(USE_THUMB_1) +#endif // __ARM_ARCH_ISA_THUMB == 1 END_COMPILERRT_FUNCTION(__aeabi_idivmod) NO_EXEC_STACK_DIRECTIVE diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S index 37dae4a10..a627fc740 100644 --- a/lib/builtins/arm/aeabi_uidivmod.S +++ b/lib/builtins/arm/aeabi_uidivmod.S @@ -21,16 +21,8 @@ #endif .syntax unified - .text -#if defined(USE_THUMB_PROLOGUE) - .thumb -#endif .p2align 2 -#if defined(USE_THUMB_PROLOGUE) -DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_uidivmod) -#else DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) -#endif #if __ARM_ARCH_ISA_THUMB == 1 cmp r0, r1 bcc LOCAL_LABEL(case_denom_larger) diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S index 4e5a579cf..fb226cea2 100644 --- a/lib/builtins/arm/bswapdi2.S +++ b/lib/builtins/arm/bswapdi2.S @@ -11,7 +11,7 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -21,7 +21,7 @@ // Reverse all the bytes in a 64-bit integer. // .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2) #else DEFINE_COMPILERRT_FUNCTION(__bswapdi2) diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S index 60342ae0f..553c3c2e3 100644 --- a/lib/builtins/arm/bswapsi2.S +++ b/lib/builtins/arm/bswapsi2.S @@ -11,7 +11,7 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -21,7 +21,7 @@ // Reverse all the bytes in a 32-bit integer. // .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2) #else DEFINE_COMPILERRT_FUNCTION(__bswapsi2) diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S index fe56a183f..6068c176f 100644 --- a/lib/builtins/arm/clzdi2.S +++ b/lib/builtins/arm/clzdi2.S @@ -15,13 +15,13 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2) #else DEFINE_COMPILERRT_FUNCTION(__clzdi2) diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S index 28d43041e..c2ba3a8cf 100644 --- a/lib/builtins/arm/clzsi2.S +++ b/lib/builtins/arm/clzsi2.S @@ -15,12 +15,12 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2) #else DEFINE_COMPILERRT_FUNCTION(__clzsi2) diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S index 1f7031cbf..ef7091bf3 100644 --- a/lib/builtins/arm/comparesf2.S +++ b/lib/builtins/arm/comparesf2.S @@ -38,20 +38,15 @@ //===----------------------------------------------------------------------===// #include "../assembly.h" - .syntax unified - .text -#if defined(USE_THUMB_PROLOGUE) - .thumb +.syntax unified +#if __ARM_ARCH_ISA_THUMB == 2 +.thumb #endif @ int __eqsf2(float a, float b) .p2align 2 -#if defined(USE_THUMB_PROLOGUE) -DEFINE_COMPILERRT_THUMB_FUNCTION(__eqsf2) -#else DEFINE_COMPILERRT_FUNCTION(__eqsf2) -#endif #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 @@ -72,7 +67,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // flag if both a and b are zero (of either sign). The shift of r3 doesn't // effect this at all, but it *does* make sure that the C flag is clear for // the subsequent operations. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 lsrs r6, r3, #1 orrs r6, r2 #else @@ -80,7 +75,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) #endif // Next, we check if a and b have the same or different signs. If they have // opposite signs, this eor will set the N flag. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 beq 1f movs r6, r0 eors r6, r1 @@ -94,7 +89,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // ignoring NaNs for now), this subtract will zero out r0. If they have the // same sign, the flags are updated as they would be for a comparison of the // absolute values of a and b. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 bmi 1f subs r0, r2, r3 1: @@ -113,7 +108,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // still clear from the shift argument in orrs; if a is positive and b // negative, this places 0 in r0; if a is negative and b positive, -1 is // placed in r0. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 bhs 1f // Here if a and b have the same sign and absA < absB, the result is thus // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan). @@ -132,7 +127,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed // in r0, which is the desired result. Conversely, if both are positive // and a > b, zero is placed in r0. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 bls 1f // Here both have the same sign and absA > absB. movs r0, #1 @@ -150,14 +145,14 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // If a == b, then the Z flag is set, so we can get the correct final value // into r0 by simply or'ing with 1 if Z is clear. // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB != 1 it ne orrne r0, r0, #1 #endif // Finally, we need to deal with NaNs. If either argument is NaN, replace // the value in r0 with 1. -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 LOCAL_LABEL(CHECK_NAN): movs r6, #0xff lsls r6, #24 @@ -185,11 +180,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) @ int __gtsf2(float a, float b) .p2align 2 -#if defined(USE_THUMB) -DEFINE_COMPILERRT_THUMB_FUNCTION(__gtsf2) -#else DEFINE_COMPILERRT_FUNCTION(__gtsf2) -#endif // Identical to the preceding except in that we return -1 for NaN values. // Given that the two paths share so much code, one might be tempted to // unify them; however, the extra code needed to do so makes the code size @@ -198,7 +189,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2) vmov r0, s0 vmov r1, s1 #endif -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 @@ -263,12 +254,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) @ int __unordsf2(float a, float b) .p2align 2 -#if defined(USE_THUMB) -DEFINE_COMPILERRT_THUMB_FUNCTION(__unordsf2) -#else DEFINE_COMPILERRT_FUNCTION(__unordsf2) -#endif - #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 @@ -277,7 +263,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2) lsls r2, r0, #1 lsls r3, r1, #1 movs r0, #0 -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 movs r1, #0xff lsls r1, #24 cmp r2, r1 diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S index 3c8359852..999c310ec 100644 --- a/lib/builtins/arm/divmodsi4.S +++ b/lib/builtins/arm/divmodsi4.S @@ -23,7 +23,7 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -32,7 +32,7 @@ @ value is the quotient, the remainder is placed in the variable. .p2align 3 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4) #else DEFINE_COMPILERRT_FUNCTION(__divmodsi4) diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S index ad96c9e5b..f066f60ad 100644 --- a/lib/builtins/arm/divsi3.S +++ b/lib/builtins/arm/divsi3.S @@ -20,10 +20,10 @@ #define CLEAR_FRAME_AND_RETURN \ pop {r4, r7, pc} - .syntax unified - .text -#if defined(USE_THUMB_PROLOGUE) - .thumb + .syntax unified + .text +#if __ARM_ARCH_ISA_THUMB == 2 + .thumb #endif .p2align 3 @@ -33,7 +33,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3) @ int __divsi3(int divident, int divisor) @ Calculate and return the quotient of the (signed) division. -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3) #else DEFINE_COMPILERRT_FUNCTION(__divsi3) @@ -72,7 +72,7 @@ ESTABLISH_FRAME // abs(a) / abs(b) bl SYMBOL_NAME(__udivsi3) // Apply sign of quotient to result and return. -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 asrs r4, #31 eors r0, r4 subs r0, r0, r4 diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S index 0986d8494..1d302edc6 100644 --- a/lib/builtins/arm/modsi3.S +++ b/lib/builtins/arm/modsi3.S @@ -22,7 +22,7 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -30,7 +30,7 @@ @ Calculate and return the remainder of the (signed) division. .p2align 3 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3) #else DEFINE_COMPILERRT_FUNCTION(__modsi3) diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S index 860fced63..1ad8ee34b 100644 --- a/lib/builtins/arm/udivmodsi4.S +++ b/lib/builtins/arm/udivmodsi4.S @@ -16,7 +16,8 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) + +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -26,7 +27,7 @@ @ value is the quotient, the remainder is placed in the variable. .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4) #else DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) @@ -66,7 +67,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -77,7 +78,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) mov r3, #0 bx ip # else -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 # error THUMB mode requires CLZ or UDIV # endif str r4, [sp, #-8]! diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S index 2a0209927..fcc472b4f 100644 --- a/lib/builtins/arm/udivsi3.S +++ b/lib/builtins/arm/udivsi3.S @@ -16,7 +16,8 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) + +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -26,7 +27,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) @ unsigned int __udivsi3(unsigned int divident, unsigned int divisor) @ Calculate and return the quotient of the (unsigned) division. -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3) #else DEFINE_COMPILERRT_FUNCTION(__udivsi3) @@ -39,7 +40,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivsi3) #else cmp r1, #1 bcc LOCAL_LABEL(divby0) -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 bne LOCAL_LABEL(num_neq_denom) JMP(lr) LOCAL_LABEL(num_neq_denom): @@ -48,7 +49,7 @@ LOCAL_LABEL(num_neq_denom): JMPc(lr, eq) #endif cmp r0, r1 -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 bhs LOCAL_LABEL(num_ge_denom) movs r0, #0 JMP(lr) @@ -80,7 +81,7 @@ LOCAL_LABEL(num_ge_denom): clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -91,17 +92,17 @@ LOCAL_LABEL(num_ge_denom): mov r3, #0 bx ip # else /* No CLZ Feature */ -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 # error THUMB mode requires CLZ or UDIV # endif -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 # define BLOCK_SIZE 10 # else # define BLOCK_SIZE 12 # endif mov r2, r0 -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 mov ip, r0 adr r0, LOCAL_LABEL(div0block) adds r0, #1 @@ -110,7 +111,7 @@ LOCAL_LABEL(num_ge_denom): # endif lsrs r3, r2, #16 cmp r3, r1 -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 blo LOCAL_LABEL(skip_16) movs r2, r3 subs r0, r0, #(16 * BLOCK_SIZE) @@ -122,7 +123,7 @@ LOCAL_LABEL(skip_16): lsrs r3, r2, #8 cmp r3, r1 -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 blo LOCAL_LABEL(skip_8) movs r2, r3 subs r0, r0, #(8 * BLOCK_SIZE) @@ -134,7 +135,7 @@ LOCAL_LABEL(skip_8): lsrs r3, r2, #4 cmp r3, r1 -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 blo LOCAL_LABEL(skip_4) movs r2, r3 subs r0, r0, #(4 * BLOCK_SIZE) @@ -146,7 +147,7 @@ LOCAL_LABEL(skip_4): lsrs r3, r2, #2 cmp r3, r1 -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 blo LOCAL_LABEL(skip_2) movs r2, r3 subs r0, r0, #(2 * BLOCK_SIZE) @@ -157,7 +158,7 @@ LOCAL_LABEL(skip_2): # endif /* Last block, no need to update r2 or r3. */ -# if defined(USE_THUMB_1) +# if __ARM_ARCH_ISA_THUMB == 1 lsrs r3, r2, #1 cmp r3, r1 blo LOCAL_LABEL(skip_1) @@ -190,7 +191,7 @@ LOCAL_LABEL(divby0): JMP(lr) -#if defined(USE_THUMB_1) +#if __ARM_ARCH_ISA_THUMB == 1 #define block(shift) \ lsls r2, r1, IMM shift; \ cmp r0, r2; \ diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S index 90f3e8575..672487e81 100644 --- a/lib/builtins/arm/umodsi3.S +++ b/lib/builtins/arm/umodsi3.S @@ -16,7 +16,7 @@ .syntax unified .text -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif @@ -24,7 +24,7 @@ @ Calculate and return the remainder of the (unsigned) division. .p2align 2 -#if defined(USE_THUMB_PROLOGUE) +#if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3) #else DEFINE_COMPILERRT_FUNCTION(__umodsi3) @@ -65,7 +65,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -74,7 +74,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) sub ip, ip, r3, lsl #3 bx ip # else -# if defined(USE_THUMB_2) +# if __ARM_ARCH_ISA_THUMB == 2 # error THUMB mode requires CLZ or UDIV # endif mov r2, r0 diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index af959b24b..29d9f8844 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -92,35 +92,20 @@ JMP(ip) #endif -/* - * Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros: - * - for '-mthumb -march=armv6' compiler defines '__thumb__' - * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' - */ -#if defined(__thumb2__) -#define USE_THUMB_2 1 -#elif defined(__thumb__) -#define USE_THUMB_1 1 -#endif - -#if defined(USE_THUMB_1) && defined(USE_THUMB_2) -#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together." -#endif - -#if defined(USE_THUMB_1) || defined(USE_THUMB_1) -#define USE_THUMB_PROLOGUE 1 -#endif - -#if defined(USE_THUMB_2) +#if __ARM_ARCH_ISA_THUMB == 2 #define IT(cond) it cond #define ITT(cond) itt cond -#define WIDE(op) op.w #else #define IT(cond) #define ITT(cond) +#endif + +#if __ARM_ARCH_ISA_THUMB == 2 +#define WIDE(op) op.w +#else #define WIDE(op) op #endif -#endif /* defined(__arm__) */ +#endif #define GLUE2(a, b) a##b #define GLUE(a, b) GLUE2(a, b) -- cgit v1.2.1 From 9ef4ca6aa20823c9023ce017a49bbd7ec255f0af Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 24 Mar 2017 20:57:33 +0000 Subject: Fix an uninitialized field in tsan_block_context_t/AllocContext in tsan_libdispatch_mac.cc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298738 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_libdispatch_mac.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc index d8c689ebb..bf08c7450 100644 --- a/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -93,6 +93,7 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc, new_context->free_context_in_callback = true; new_context->submitted_synchronously = false; new_context->is_barrier_block = false; + new_context->non_queue_sync_object = false; return new_context; } -- cgit v1.2.1 From 50bdaed4bba31101ef3b5a94fd12c8f6694e5faa Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 24 Mar 2017 21:12:24 +0000 Subject: Follow-up for r298738: Use "0" instead of "false" because the variable is uptr. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298741 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_libdispatch_mac.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc index bf08c7450..48351e80a 100644 --- a/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -93,7 +93,7 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc, new_context->free_context_in_callback = true; new_context->submitted_synchronously = false; new_context->is_barrier_block = false; - new_context->non_queue_sync_object = false; + new_context->non_queue_sync_object = 0; return new_context; } -- cgit v1.2.1 From a2065a768c13a5c30a5b7058f4c315bfdc9eeba4 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 24 Mar 2017 21:43:56 +0000 Subject: Fix flaky strtok.c test. Asserting the result of strtok when we expect delimiter overflow is flaky, the result depends on the random state of memory right after the delimiters. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298743 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/strtok.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/asan/TestCases/strtok.c b/test/asan/TestCases/strtok.c index 7aa263add..37c23ea2d 100644 --- a/test/asan/TestCases/strtok.c +++ b/test/asan/TestCases/strtok.c @@ -27,7 +27,7 @@ #include #include -// Check that we find overflows in the delimiters on the first call +// Check that we find overflows in the delimiters on the first call // with strict_string_checks. void test1() { char *token; @@ -36,7 +36,6 @@ void test1() { __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, token_delimiter); // CHECK1:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable - assert(strcmp(token, "a") == 0); } // Check that we find overflows in the delimiters on the second call (str == NULL) @@ -50,7 +49,6 @@ void test2() { __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(NULL, token_delimiter); // CHECK2:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable - assert(strcmp(token, "c") == 0); } // Check that we find overflows in the string (only on the first call) with strict_string_checks. @@ -61,7 +59,6 @@ void test3() { __asan_poison_memory_region ((char *)&s[3], 2); token = strtok(s, token_delimiter); // CHECK3:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable - assert(token == s); } // Check that we do not crash when strtok returns NULL with strict_string_checks. @@ -82,7 +79,6 @@ void test5() { __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, token_delimiter); // CHECK5:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable - assert(token == s); } // Check that we find overflows in the delimiters (only on the first call) with !strict_string_checks. @@ -93,7 +89,6 @@ void test6() { __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, &token_delimiter[1]); // CHECK6:'token_delimiter' <== Memory access at offset {{[0-9]+}} overflows this variable - assert(strcmp(token, "abc") == 0); } int main(int argc, char **argv) { -- cgit v1.2.1 From 7218fa55e35c76ef0947cb0e9261696dc11e168d Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 25 Mar 2017 00:42:25 +0000 Subject: Fix sanitizer tests with LLVM_TOOL_LLD_BUILD=OFF. Only depend on LLD if it is going to be built. Re-land of r298174 which got reverted in r298287. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298753 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 8 ++++---- test/asan/CMakeLists.txt | 2 +- test/cfi/CMakeLists.txt | 2 +- test/lit.common.configured.in | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9714340dd..db083491f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,12 +243,12 @@ else() endif() set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) -if(EXISTS ${COMPILER_RT_LLD_PATH}/) - set(COMPILER_RT_HAS_LLD_SOURCES TRUE) +if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) + set(COMPILER_RT_HAS_LLD TRUE) else() - set(COMPILER_RT_HAS_LLD_SOURCES FALSE) + set(COMPILER_RT_HAS_LLD FALSE) endif() -pythonize_bool(COMPILER_RT_HAS_LLD_SOURCES) +pythonize_bool(COMPILER_RT_HAS_LLD) add_subdirectory(lib) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index fb1478e7a..4b4fdf19d 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -22,7 +22,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) + if(WIN32 AND COMPILER_RT_HAS_LLD) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index bd51eacb6..c3123a820 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -34,7 +34,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LTO ) endif() - if(WIN32 AND COMPILER_RT_HAS_LLD_SOURCES) + if(WIN32 AND COMPILER_RT_HAS_LLD) list(APPEND CFI_TEST_DEPS lld ) diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 862d06bf2..387f4d4a7 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -26,7 +26,7 @@ set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@) set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@") set_default("emulator", "@COMPILER_RT_EMULATOR@") set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) -set_default("has_lld", @COMPILER_RT_HAS_LLD_SOURCES_PYBOOL@) +set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) config.available_features.add('target-is-%s' % config.target_arch) -- cgit v1.2.1 From 96ccf181c8c1bf446bae8fc738b3dc8da5a65cfe Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sun, 26 Mar 2017 15:27:04 +0000 Subject: tsan: add new mutex annotations There are several problems with the current annotations (AnnotateRWLockCreate and friends): - they don't fully support deadlock detection (we need a hook _before_ mutex lock) - they don't support insertion of random artificial delays to perturb execution (again we need a hook _before_ mutex lock) - they don't support setting extended mutex attributes like read/write reentrancy (only "linker init" was bolted on) - they don't support setting mutex attributes if a mutex don't have a "constructor" (e.g. static, Java, Go mutexes) - they don't ignore synchronization inside of lock/unlock operations which leads to slowdown and false negatives The new annotations solve of the above problems. See tsan_interface.h for the interface specification and comments. Reviewed in https://reviews.llvm.org/D31093 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298809 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/CMakeLists.txt | 1 + include/sanitizer/tsan_interface.h | 121 +++++++++++++++++++++ .../sanitizer_common_interceptors.inc | 14 ++- lib/tsan/go/tsan_go.cc | 8 +- lib/tsan/rtl/tsan.syms.extra | 10 ++ lib/tsan/rtl/tsan_flags.cc | 4 - lib/tsan/rtl/tsan_flags.h | 1 - lib/tsan/rtl/tsan_interceptors.cc | 50 +++++---- lib/tsan/rtl/tsan_interface_ann.cc | 112 +++++++++++++++++-- lib/tsan/rtl/tsan_interface_atomic.cc | 8 +- lib/tsan/rtl/tsan_interface_java.cc | 14 +-- lib/tsan/rtl/tsan_rtl.cc | 12 +- lib/tsan/rtl/tsan_rtl.h | 23 ++-- lib/tsan/rtl/tsan_rtl_mutex.cc | 118 +++++++++++++------- lib/tsan/rtl/tsan_stat.cc | 10 ++ lib/tsan/rtl/tsan_stat.h | 10 ++ lib/tsan/rtl/tsan_sync.cc | 5 +- lib/tsan/rtl/tsan_sync.h | 48 +++++++- test/tsan/custom_mutex.h | 91 ++++++++++++++++ test/tsan/custom_mutex0.cc | 31 ++++++ test/tsan/custom_mutex1.cc | 39 +++++++ test/tsan/custom_mutex2.cc | 34 ++++++ 22 files changed, 651 insertions(+), 113 deletions(-) create mode 100644 include/sanitizer/tsan_interface.h create mode 100644 test/tsan/custom_mutex.h create mode 100644 test/tsan/custom_mutex0.cc create mode 100644 test/tsan/custom_mutex1.cc create mode 100644 test/tsan/custom_mutex2.cc diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 1f8b481e7..6104aded2 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -8,6 +8,7 @@ set(SANITIZER_HEADERS sanitizer/linux_syscall_hooks.h sanitizer/lsan_interface.h sanitizer/msan_interface.h + sanitizer/tsan_interface.h sanitizer/tsan_interface_atomic.h) set(XRAY_HEADERS diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h new file mode 100644 index 000000000..34b74d537 --- /dev/null +++ b/include/sanitizer/tsan_interface.h @@ -0,0 +1,121 @@ +//===-- tsan_interface.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// Public interface header for TSan. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_TSAN_INTERFACE_H +#define SANITIZER_TSAN_INTERFACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// __tsan_release establishes a happens-before relation with a preceding +// __tsan_acquire on the same address. +void __tsan_acquire(void *addr); +void __tsan_release(void *addr); + +// Annotations for custom mutexes. +// The annotations allow to get better reports (with sets of locked mutexes), +// detect more types of bugs (e.g. mutex misuses, races between lock/unlock and +// destruction and potential deadlocks) and improve precision and performance +// (by ignoring individual atomic operations in mutex code). However, the +// downside is that annotated mutex code itself is not checked for correctness. + +// Mutex creation flags are passed to __tsan_mutex_create annotation. +// If mutex has no constructor and __tsan_mutex_create is not called, +// the flags may be passed to __tsan_mutex_pre_lock/__tsan_mutex_post_lock +// annotations. + +// Mutex has static storage duration and no-op constructor and destructor. +// This effectively makes tsan ignore destroy annotation. +const unsigned __tsan_mutex_linker_init = 1 << 0; +// Mutex is write reentrant. +const unsigned __tsan_mutex_write_reentrant = 1 << 1; +// Mutex is read reentrant. +const unsigned __tsan_mutex_read_reentrant = 1 << 2; + +// Mutex operation flags: + +// Denotes read lock operation. +const unsigned __tsan_mutex_read_lock = 1 << 3; +// Denotes try lock operation. +const unsigned __tsan_mutex_try_lock = 1 << 4; +// Denotes that a try lock operation has failed to acquire the mutex. +const unsigned __tsan_mutex_try_lock_failed = 1 << 5; +// Denotes that the lock operation acquires multiple recursion levels. +// Number of levels is passed in recursion parameter. +// This is useful for annotation of e.g. Java builtin monitors, +// for which wait operation releases all recursive acquisitions of the mutex. +const unsigned __tsan_mutex_recursive_lock = 1 << 6; +// Denotes that the unlock operation releases all recursion levels. +// Number of released levels is returned and later must be passed to +// the corresponding __tsan_mutex_post_lock annotation. +const unsigned __tsan_mutex_recursive_unlock = 1 << 7; + +// Annotate creation of a mutex. +// Supported flags: mutex creation flags. +void __tsan_mutex_create(void *addr, unsigned flags); + +// Annotate destruction of a mutex. +// Supported flags: none. +void __tsan_mutex_destroy(void *addr, unsigned flags); + +// Annotate start of lock operation. +// Supported flags: +// - __tsan_mutex_read_lock +// - __tsan_mutex_try_lock +// - all mutex creation flags +void __tsan_mutex_pre_lock(void *addr, unsigned flags); + +// Annotate end of lock operation. +// Supported flags: +// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock) +// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock) +// - __tsan_mutex_try_lock_failed +// - __tsan_mutex_recursive_lock +// - all mutex creation flags +void __tsan_mutex_post_lock(void *addr, unsigned flags, int recursion); + +// Annotate start of unlock operation. +// Supported flags: +// - __tsan_mutex_read_lock +// - __tsan_mutex_recursive_unlock +int __tsan_mutex_pre_unlock(void *addr, unsigned flags); + +// Annotate end of unlock operation. +// Supported flags: +// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock) +void __tsan_mutex_post_unlock(void *addr, unsigned flags); + +// Annotate start/end of notify/signal/broadcast operation. +// Supported flags: none. +void __tsan_mutex_pre_signal(void *addr, unsigned flags); +void __tsan_mutex_post_signal(void *addr, unsigned flags); + +// Annotate start/end of a region of code where lock/unlock/signal operation +// diverts to do something else unrelated to the mutex. This can be used to +// annotate, for example, calls into cooperative scheduler or contention +// profiling code. +// These annotations must be called only from within +// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock, +// __tsan_mutex_pre/post_signal regions. +// Supported flags: none. +void __tsan_mutex_pre_divert(void *addr, unsigned flags); +void __tsan_mutex_post_divert(void *addr, unsigned flags); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_TSAN_INTERFACE_H diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 8e5734273..4f4cd43ab 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -24,7 +24,8 @@ // COMMON_INTERCEPTOR_SET_THREAD_NAME // COMMON_INTERCEPTOR_ON_DLOPEN // COMMON_INTERCEPTOR_ON_EXIT -// COMMON_INTERCEPTOR_MUTEX_LOCK +// COMMON_INTERCEPTOR_MUTEX_PRE_LOCK +// COMMON_INTERCEPTOR_MUTEX_POST_LOCK // COMMON_INTERCEPTOR_MUTEX_UNLOCK // COMMON_INTERCEPTOR_MUTEX_REPAIR // COMMON_INTERCEPTOR_SET_PTHREAD_NAME @@ -89,8 +90,12 @@ bool PlatformHasDifferentMemcpyAndMemmove(); #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {} #endif -#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK -#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {} +#ifndef COMMON_INTERCEPTOR_MUTEX_PRE_LOCK +#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_POST_LOCK +#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) {} #endif #ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK @@ -3721,11 +3726,12 @@ INTERCEPTOR(void, _exit, int status) { INTERCEPTOR(int, pthread_mutex_lock, void *m) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m); + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); int res = REAL(pthread_mutex_lock)(m); if (res == errno_EOWNERDEAD) COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); if (res == 0 || res == errno_EOWNERDEAD) - COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m); + COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); if (res == errno_EINVAL) COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); return res; diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc index 7fb4eb2a5..d7a9e0b67 100644 --- a/lib/tsan/go/tsan_go.cc +++ b/lib/tsan/go/tsan_go.cc @@ -247,13 +247,17 @@ void __tsan_finalizer_goroutine(ThreadState *thr) { } void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) { + if (write) + MutexPreLock(thr, 0, addr); + else + MutexPreReadLock(thr, 0, addr); } void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) { if (write) - MutexLock(thr, 0, addr); + MutexPostLock(thr, 0, addr); else - MutexReadLock(thr, 0, addr); + MutexPostReadLock(thr, 0, addr); } void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) { diff --git a/lib/tsan/rtl/tsan.syms.extra b/lib/tsan/rtl/tsan.syms.extra index 22dfde914..ab5b5a4fc 100644 --- a/lib/tsan/rtl/tsan.syms.extra +++ b/lib/tsan/rtl/tsan.syms.extra @@ -9,6 +9,16 @@ __tsan_java* __tsan_unaligned* __tsan_release __tsan_acquire +__tsan_mutex_create +__tsan_mutex_destroy +__tsan_mutex_pre_lock +__tsan_mutex_post_lock +__tsan_mutex_pre_unlock +__tsan_mutex_post_unlock +__tsan_mutex_pre_signal +__tsan_mutex_post_signal +__tsan_mutex_pre_divert +__tsan_mutex_post_divert __ubsan_* Annotate* WTFAnnotate* diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc index d8d4746ab..89e22a132 100644 --- a/lib/tsan/rtl/tsan_flags.cc +++ b/lib/tsan/rtl/tsan_flags.cc @@ -21,10 +21,6 @@ namespace __tsan { -Flags *flags() { - return &ctx->flags; -} - // Can be overriden in frontend. #ifdef TSAN_EXTERNAL_HOOKS extern "C" const char* __tsan_default_options(); diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h index e2f6b3c9f..66740def5 100644 --- a/lib/tsan/rtl/tsan_flags.h +++ b/lib/tsan/rtl/tsan_flags.h @@ -28,7 +28,6 @@ struct Flags : DDFlags { void ParseFromString(const char *str); }; -Flags *flags(); void InitializeFlags(Flags *flags, const char *env); } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 9bf1b28b9..17a914371 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -277,7 +277,7 @@ ScopedInterceptor::~ScopedInterceptor() { void ScopedInterceptor::EnableIgnores() { if (ignoring_) { - ThreadIgnoreBegin(thr_, pc_); + ThreadIgnoreBegin(thr_, pc_, false); if (in_ignored_lib_) { DCHECK(!thr_->in_ignored_lib); thr_->in_ignored_lib = true; @@ -1025,7 +1025,7 @@ static void cond_mutex_unlock(CondMutexUnlockCtx *arg) { ThreadSignalContext *ctx = SigCtx(arg->thr); CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1); atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); - MutexLock(arg->thr, arg->pc, (uptr)arg->m); + MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock); // Undo BlockingCall ctor effects. arg->thr->ignore_interceptors--; arg->si->~ScopedInterceptor(); @@ -1054,7 +1054,7 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg); } if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); - MutexLock(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock); return res; } @@ -1114,14 +1114,15 @@ TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a); int res = REAL(pthread_mutex_init)(m, a); if (res == 0) { - bool recursive = false; + u32 flagz = 0; if (a) { int type = 0; if (REAL(pthread_mutexattr_gettype)(a, &type) == 0) - recursive = (type == PTHREAD_MUTEX_RECURSIVE - || type == PTHREAD_MUTEX_RECURSIVE_NP); + if (type == PTHREAD_MUTEX_RECURSIVE || + type == PTHREAD_MUTEX_RECURSIVE_NP) + flagz |= MutexFlagWriteReentrant; } - MutexCreate(thr, pc, (uptr)m, false, recursive, false); + MutexCreate(thr, pc, (uptr)m, flagz); } return res; } @@ -1141,7 +1142,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { if (res == EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); if (res == 0 || res == EOWNERDEAD) - MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); return res; } @@ -1150,7 +1151,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime); int res = REAL(pthread_mutex_timedlock)(m, abstime); if (res == 0) { - MutexLock(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); } return res; } @@ -1161,7 +1162,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared); int res = REAL(pthread_spin_init)(m, pshared); if (res == 0) { - MutexCreate(thr, pc, (uptr)m, false, false, false); + MutexCreate(thr, pc, (uptr)m); } return res; } @@ -1177,9 +1178,10 @@ TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) { TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m); + MutexPreLock(thr, pc, (uptr)m); int res = REAL(pthread_spin_lock)(m); if (res == 0) { - MutexLock(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m); } return res; } @@ -1188,7 +1190,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m); int res = REAL(pthread_spin_trylock)(m); if (res == 0) { - MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); } return res; } @@ -1205,7 +1207,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a); int res = REAL(pthread_rwlock_init)(m, a); if (res == 0) { - MutexCreate(thr, pc, (uptr)m, true, false, false); + MutexCreate(thr, pc, (uptr)m); } return res; } @@ -1221,9 +1223,10 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) { TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m); + MutexPreReadLock(thr, pc, (uptr)m); int res = REAL(pthread_rwlock_rdlock)(m); if (res == 0) { - MutexReadLock(thr, pc, (uptr)m); + MutexPostReadLock(thr, pc, (uptr)m); } return res; } @@ -1232,7 +1235,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m); int res = REAL(pthread_rwlock_tryrdlock)(m); if (res == 0) { - MutexReadLock(thr, pc, (uptr)m, /*try_lock=*/true); + MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock); } return res; } @@ -1242,7 +1245,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime); int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); if (res == 0) { - MutexReadLock(thr, pc, (uptr)m); + MutexPostReadLock(thr, pc, (uptr)m); } return res; } @@ -1250,9 +1253,10 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m); + MutexPreLock(thr, pc, (uptr)m); int res = REAL(pthread_rwlock_wrlock)(m); if (res == 0) { - MutexLock(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m); } return res; } @@ -1261,7 +1265,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m); int res = REAL(pthread_rwlock_trywrlock)(m); if (res == 0) { - MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); } return res; } @@ -1271,7 +1275,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime); int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); if (res == 0) { - MutexLock(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); } return res; } @@ -2251,8 +2255,12 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, #define COMMON_INTERCEPTOR_ON_EXIT(ctx) \ OnExit(((TsanInterceptorContext *) ctx)->thr) -#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ - MutexLock(((TsanInterceptorContext *)ctx)->thr, \ +#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \ + MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \ + MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc index 62db79661..810c84025 100644 --- a/lib/tsan/rtl/tsan_interface_ann.cc +++ b/lib/tsan/rtl/tsan_interface_ann.cc @@ -31,11 +31,10 @@ namespace __tsan { class ScopedAnnotation { public: - ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l, - uptr pc) + ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc) : thr_(thr) { FuncEntry(thr_, pc); - DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l); + DPrintf("#%d: annotation %s()\n", thr_->tid, aname); } ~ScopedAnnotation() { @@ -46,18 +45,20 @@ class ScopedAnnotation { ThreadState *const thr_; }; -#define SCOPED_ANNOTATION(typ) \ +#define SCOPED_ANNOTATION_RET(typ, ret) \ if (!flags()->enable_annotations) \ - return; \ + return ret; \ ThreadState *thr = cur_thread(); \ const uptr caller_pc = (uptr)__builtin_return_address(0); \ StatInc(thr, StatAnnotation); \ StatInc(thr, Stat##typ); \ - ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \ + ScopedAnnotation sa(thr, __func__, caller_pc); \ const uptr pc = StackTrace::GetCurrentPc(); \ (void)pc; \ /**/ +#define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, ) + static const int kMaxDescLen = 128; struct ExpectRace { @@ -252,12 +253,12 @@ void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv, void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) { SCOPED_ANNOTATION(AnnotateRWLockCreate); - MutexCreate(thr, pc, m, true, true, false); + MutexCreate(thr, pc, m, MutexFlagWriteReentrant); } void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) { SCOPED_ANNOTATION(AnnotateRWLockCreateStatic); - MutexCreate(thr, pc, m, true, true, true); + MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit); } void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) { @@ -269,9 +270,9 @@ void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m, uptr is_w) { SCOPED_ANNOTATION(AnnotateRWLockAcquired); if (is_w) - MutexLock(thr, pc, m); + MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock); else - MutexReadLock(thr, pc, m); + MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock); } void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m, @@ -458,4 +459,95 @@ void INTERFACE_ATTRIBUTE AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {} void INTERFACE_ATTRIBUTE AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {} + +// Note: the parameter is called flagz, because flags is already taken +// by the global function that returns flags. +INTERFACE_ATTRIBUTE +void __tsan_mutex_create(void *m, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_create); + MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_destroy(void *m, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_destroy); + MutexDestroy(thr, pc, (uptr)m); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_pre_lock(void *m, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_pre_lock); + if (!(flagz & MutexFlagTryLock)) { + if (flagz & MutexFlagReadLock) + MutexPreReadLock(thr, pc, (uptr)m); + else + MutexPreLock(thr, pc, (uptr)m); + } + ThreadIgnoreBegin(thr, pc, false); + ThreadIgnoreSyncBegin(thr, pc, false); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) { + SCOPED_ANNOTATION(__tsan_mutex_post_lock); + ThreadIgnoreSyncEnd(thr, pc); + ThreadIgnoreEnd(thr, pc); + if (!(flagz & MutexFlagTryLockFailed)) { + if (flagz & MutexFlagReadLock) + MutexPostReadLock(thr, pc, (uptr)m, flagz); + else + MutexPostLock(thr, pc, (uptr)m, flagz, rec); + } +} + +INTERFACE_ATTRIBUTE +int __tsan_mutex_pre_unlock(void *m, unsigned flagz) { + SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0); + int ret = 0; + if (flagz & MutexFlagReadLock) { + CHECK(!(flagz & MutexFlagRecursiveUnlock)); + MutexReadUnlock(thr, pc, (uptr)m); + } else { + ret = MutexUnlock(thr, pc, (uptr)m, flagz); + } + ThreadIgnoreBegin(thr, pc, false); + ThreadIgnoreSyncBegin(thr, pc, false); + return ret; +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_post_unlock(void *m, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_post_unlock); + ThreadIgnoreSyncEnd(thr, pc); + ThreadIgnoreEnd(thr, pc); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_pre_signal(void *addr, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_pre_signal); + ThreadIgnoreBegin(thr, pc, false); + ThreadIgnoreSyncBegin(thr, pc, false); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_post_signal(void *addr, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_post_signal); + ThreadIgnoreSyncEnd(thr, pc); + ThreadIgnoreEnd(thr, pc); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_pre_divert(void *addr, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_pre_divert); + // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal. + ThreadIgnoreSyncEnd(thr, pc); + ThreadIgnoreEnd(thr, pc); +} + +INTERFACE_ATTRIBUTE +void __tsan_mutex_post_divert(void *addr, unsigned flagz) { + SCOPED_ANNOTATION(__tsan_mutex_post_divert); + ThreadIgnoreBegin(thr, pc, false); + ThreadIgnoreSyncBegin(thr, pc, false); +} } // extern "C" diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc index 0e3dbaedf..b22d5c1ec 100644 --- a/lib/tsan/rtl/tsan_interface_atomic.cc +++ b/lib/tsan/rtl/tsan_interface_atomic.cc @@ -468,12 +468,14 @@ static morder convert_morder(morder mo) { } #define SCOPED_ATOMIC(func, ...) \ + ThreadState *const thr = cur_thread(); \ + if (thr->ignore_sync || thr->ignore_interceptors) { \ + ProcessPendingSignals(thr); \ + return NoTsanAtomic##func(__VA_ARGS__); \ + } \ const uptr callpc = (uptr)__builtin_return_address(0); \ uptr pc = StackTrace::GetCurrentPc(); \ mo = convert_morder(mo); \ - ThreadState *const thr = cur_thread(); \ - if (thr->ignore_interceptors) \ - return NoTsanAtomic##func(__VA_ARGS__); \ AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \ ScopedAtomic sa(thr, callpc, a, mo, __func__); \ return Atomic##func(thr, pc, __VA_ARGS__); \ diff --git a/lib/tsan/rtl/tsan_interface_java.cc b/lib/tsan/rtl/tsan_interface_java.cc index 5bdc04f07..75e960e62 100644 --- a/lib/tsan/rtl/tsan_interface_java.cc +++ b/lib/tsan/rtl/tsan_interface_java.cc @@ -180,8 +180,8 @@ void __tsan_java_mutex_lock(jptr addr) { CHECK_GE(addr, jctx->heap_begin); CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); - MutexCreate(thr, pc, addr, true, true, true); - MutexLock(thr, pc, addr); + MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | + MutexFlagDoPreLockOnPostLock); } void __tsan_java_mutex_unlock(jptr addr) { @@ -201,8 +201,8 @@ void __tsan_java_mutex_read_lock(jptr addr) { CHECK_GE(addr, jctx->heap_begin); CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); - MutexCreate(thr, pc, addr, true, true, true); - MutexReadLock(thr, pc, addr); + MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit | + MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock); } void __tsan_java_mutex_read_unlock(jptr addr) { @@ -223,8 +223,8 @@ void __tsan_java_mutex_lock_rec(jptr addr, int rec) { CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); CHECK_GT(rec, 0); - MutexCreate(thr, pc, addr, true, true, true); - MutexLock(thr, pc, addr, rec); + MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | + MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec); } int __tsan_java_mutex_unlock_rec(jptr addr) { @@ -234,7 +234,7 @@ int __tsan_java_mutex_unlock_rec(jptr addr) { CHECK_GE(addr, jctx->heap_begin); CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); - return MutexUnlock(thr, pc, addr, true); + return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock); } void __tsan_java_acquire(jptr addr) { diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index bc5991c6e..70393037e 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -980,21 +980,21 @@ void FuncExit(ThreadState *thr) { thr->shadow_stack_pos--; } -void ThreadIgnoreBegin(ThreadState *thr, uptr pc) { +void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack) { DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid); thr->ignore_reads_and_writes++; CHECK_GT(thr->ignore_reads_and_writes, 0); thr->fast_state.SetIgnoreBit(); #if !SANITIZER_GO - if (!ctx->after_multithreaded_fork) + if (save_stack && !ctx->after_multithreaded_fork) thr->mop_ignore_set.Add(CurrentStackId(thr, pc)); #endif } void ThreadIgnoreEnd(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid); + CHECK_GT(thr->ignore_reads_and_writes, 0); thr->ignore_reads_and_writes--; - CHECK_GE(thr->ignore_reads_and_writes, 0); if (thr->ignore_reads_and_writes == 0) { thr->fast_state.ClearIgnoreBit(); #if !SANITIZER_GO @@ -1011,20 +1011,20 @@ uptr __tsan_testonly_shadow_stack_current_size() { } #endif -void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) { +void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack) { DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid); thr->ignore_sync++; CHECK_GT(thr->ignore_sync, 0); #if !SANITIZER_GO - if (!ctx->after_multithreaded_fork) + if (save_stack && !ctx->after_multithreaded_fork) thr->sync_ignore_set.Add(CurrentStackId(thr, pc)); #endif } void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid); + CHECK_GT(thr->ignore_sync, 0); thr->ignore_sync--; - CHECK_GE(thr->ignore_sync, 0); #if !SANITIZER_GO if (thr->ignore_sync == 0) thr->sync_ignore_set.Reset(); diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 88539414c..0d62af00a 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -546,6 +546,10 @@ struct Context { extern Context *ctx; // The one and the only global runtime context. +ALWAYS_INLINE Flags *flags() { + return &ctx->flags; +} + struct ScopedIgnoreInterceptors { ScopedIgnoreInterceptors() { #if !SANITIZER_GO @@ -707,9 +711,9 @@ void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size); -void ThreadIgnoreBegin(ThreadState *thr, uptr pc); +void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true); void ThreadIgnoreEnd(ThreadState *thr, uptr pc); -void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc); +void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack = true); void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc); void FuncEntry(ThreadState *thr, uptr pc); @@ -731,13 +735,16 @@ void ProcDestroy(Processor *proc); void ProcWire(Processor *proc, ThreadState *thr); void ProcUnwire(Processor *proc, ThreadState *thr); -void MutexCreate(ThreadState *thr, uptr pc, uptr addr, - bool rw, bool recursive, bool linker_init); +// Note: the parameter is called flagz, because flags is already taken +// by the global function that returns flags. +void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); void MutexDestroy(ThreadState *thr, uptr pc, uptr addr); -void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1, - bool try_lock = false); -int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false); -void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false); +void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); +void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0, + int rec = 1); +int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); +void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); +void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr); void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr); void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index f3b51c30f..086b28927 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -62,20 +62,17 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, OutputReport(thr, rep); } -void MutexCreate(ThreadState *thr, uptr pc, uptr addr, - bool rw, bool recursive, bool linker_init) { - DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr); +void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { + DPrintf("#%d: MutexCreate %zx flagz=0x%x\n", thr->tid, addr, flagz); StatInc(thr, StatMutexCreate); - if (!linker_init && IsAppMem(addr)) { + if (!(flagz & MutexFlagLinkerInit) && IsAppMem(addr)) { CHECK(!thr->is_freeing); thr->is_freeing = true; MemoryWrite(thr, pc, addr, kSizeLog1); thr->is_freeing = false; } SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); - s->is_rw = rw; - s->is_recursive = recursive; - s->is_linker_init = linker_init; + s->SetFlags(flagz & MutexCreationFlagMask); if (!SANITIZER_GO && s->creation_stack_id == 0) s->creation_stack_id = CurrentStackId(thr, pc); s->mtx.Unlock(); @@ -87,7 +84,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); if (s == 0) return; - if (s->is_linker_init) { + if (s->IsFlagSet(MutexFlagLinkerInit)) { // Destroy is no-op for linker-initialized mutexes. s->mtx.Unlock(); return; @@ -100,8 +97,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { bool unlock_locked = false; if (flags()->report_destroy_locked && s->owner_tid != SyncVar::kInvalidTid - && !s->is_broken) { - s->is_broken = true; + && !s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); unlock_locked = true; } u64 mid = s->GetId(); @@ -141,12 +138,33 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { // s will be destroyed and freed in MetaMap::FreeBlock. } -void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { - DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec); - CHECK_GT(rec, 0); +void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { + DPrintf("#%d: MutexPreLock %zx flagz=0x%x\n", thr->tid, addr, flagz); + if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); + s->UpdateFlags(flagz); + if (s->owner_tid != thr->tid) { + Callback cb(thr, pc); + ctx->dd->MutexBeforeLock(&cb, &s->dd, true); + s->mtx.ReadUnlock(); + ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); + } else { + s->mtx.ReadUnlock(); + } + } +} + +void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) { + DPrintf("#%d: MutexPostLock %zx flag=0x%x rec=%d\n", + thr->tid, addr, flagz, rec); + if (flagz & MutexFlagRecursiveLock) + CHECK_GT(rec, 0); + else + rec = 1; if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); + s->UpdateFlags(flagz); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); bool report_double_lock = false; @@ -156,38 +174,43 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { s->last_lock = thr->fast_state.raw(); } else if (s->owner_tid == thr->tid) { CHECK_GT(s->recursion, 0); - } else if (flags()->report_mutex_bugs && !s->is_broken) { - s->is_broken = true; + } else if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); report_double_lock = true; } - if (s->recursion == 0) { + const bool first = s->recursion == 0; + s->recursion += rec; + if (first) { StatInc(thr, StatMutexLock); AcquireImpl(thr, pc, &s->clock); AcquireImpl(thr, pc, &s->read_clock); - } else if (!s->is_recursive) { + } else if (!s->IsFlagSet(MutexFlagWriteReentrant)) { StatInc(thr, StatMutexRecLock); } - s->recursion += rec; thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); - if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) { + bool pre_lock = false; + if (first && common_flags()->detect_deadlocks) { + pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && + !(flagz & MutexFlagTryLock); Callback cb(thr, pc); - if (!try_lock) + if (pre_lock) ctx->dd->MutexBeforeLock(&cb, &s->dd, true); - ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock); + ctx->dd->MutexAfterLock(&cb, &s->dd, true, flagz & MutexFlagTryLock); } u64 mid = s->GetId(); s->mtx.Unlock(); // Can't touch s after this point. + s = 0; if (report_double_lock) ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); - if (common_flags()->detect_deadlocks) { + if (first && pre_lock && common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } } -int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { - DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); +int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { + DPrintf("#%d: MutexUnlock %zx flagz=0x%x\n", thr->tid, addr, flagz); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); @@ -196,12 +219,12 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { int rec = 0; bool report_bad_unlock = false; if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) { - if (flags()->report_mutex_bugs && !s->is_broken) { - s->is_broken = true; + if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); report_bad_unlock = true; } } else { - rec = all ? s->recursion : 1; + rec = (flagz & MutexFlagRecursiveUnlock) ? s->recursion : 1; s->recursion -= rec; if (s->recursion == 0) { StatInc(thr, StatMutexUnlock); @@ -229,36 +252,53 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { return rec; } -void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { - DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr); +void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { + DPrintf("#%d: MutexPreReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); + if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); + s->UpdateFlags(flagz); + Callback cb(thr, pc); + ctx->dd->MutexBeforeLock(&cb, &s->dd, false); + s->mtx.ReadUnlock(); + ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); + } +} + +void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { + DPrintf("#%d: MutexPostReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); StatInc(thr, StatMutexReadLock); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); + s->UpdateFlags(flagz); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); bool report_bad_lock = false; if (s->owner_tid != SyncVar::kInvalidTid) { - if (flags()->report_mutex_bugs && !s->is_broken) { - s->is_broken = true; + if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); report_bad_lock = true; } } AcquireImpl(thr, pc, &s->clock); s->last_lock = thr->fast_state.raw(); thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); - if (common_flags()->detect_deadlocks && s->recursion == 0) { + bool pre_lock = false; + if (common_flags()->detect_deadlocks) { + pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && + !(flagz & MutexFlagTryLock); Callback cb(thr, pc); - if (!trylock) + if (pre_lock) ctx->dd->MutexBeforeLock(&cb, &s->dd, false); - ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock); + ctx->dd->MutexAfterLock(&cb, &s->dd, false, flagz & MutexFlagTryLock); } u64 mid = s->GetId(); s->mtx.ReadUnlock(); // Can't touch s after this point. + s = 0; if (report_bad_lock) ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); - if (common_flags()->detect_deadlocks) { + if (pre_lock && common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -274,8 +314,8 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); bool report_bad_unlock = false; if (s->owner_tid != SyncVar::kInvalidTid) { - if (flags()->report_mutex_bugs && !s->is_broken) { - s->is_broken = true; + if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); report_bad_unlock = true; } } @@ -323,8 +363,8 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { } else { StatInc(thr, StatMutexRecUnlock); } - } else if (!s->is_broken) { - s->is_broken = true; + } else if (!s->IsFlagSet(MutexFlagBroken)) { + s->SetFlags(MutexFlagBroken); report_bad_unlock = true; } thr->mset.Del(s->GetId(), write); diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc index d1d6ed24d..2ee688bf5 100644 --- a/lib/tsan/rtl/tsan_stat.cc +++ b/lib/tsan/rtl/tsan_stat.cc @@ -153,6 +153,16 @@ void StatOutput(u64 *stat) { name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange "; name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange "; name[StatAnnotateThreadName] = " ThreadName "; + name[Stat__tsan_mutex_create] = " __tsan_mutex_create "; + name[Stat__tsan_mutex_destroy] = " __tsan_mutex_destroy "; + name[Stat__tsan_mutex_pre_lock] = " __tsan_mutex_pre_lock "; + name[Stat__tsan_mutex_post_lock] = " __tsan_mutex_post_lock "; + name[Stat__tsan_mutex_pre_unlock] = " __tsan_mutex_pre_unlock "; + name[Stat__tsan_mutex_post_unlock] = " __tsan_mutex_post_unlock "; + name[Stat__tsan_mutex_pre_signal] = " __tsan_mutex_pre_signal "; + name[Stat__tsan_mutex_post_signal] = " __tsan_mutex_post_signal "; + name[Stat__tsan_mutex_pre_divert] = " __tsan_mutex_pre_divert "; + name[Stat__tsan_mutex_post_divert] = " __tsan_mutex_post_divert "; name[StatMtxTotal] = "Contentionz "; name[StatMtxTrace] = " Trace "; diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h index 8447dd84f..7d2791ebb 100644 --- a/lib/tsan/rtl/tsan_stat.h +++ b/lib/tsan/rtl/tsan_stat.h @@ -157,6 +157,16 @@ enum StatType { StatAnnotatePublishMemoryRange, StatAnnotateUnpublishMemoryRange, StatAnnotateThreadName, + Stat__tsan_mutex_create, + Stat__tsan_mutex_destroy, + Stat__tsan_mutex_pre_lock, + Stat__tsan_mutex_post_lock, + Stat__tsan_mutex_pre_unlock, + Stat__tsan_mutex_post_unlock, + Stat__tsan_mutex_pre_signal, + Stat__tsan_mutex_post_signal, + Stat__tsan_mutex_pre_divert, + Stat__tsan_mutex_post_divert, // Internal mutex contentionz. StatMtxTotal, diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc index 2be047462..4cc3cb89c 100644 --- a/lib/tsan/rtl/tsan_sync.cc +++ b/lib/tsan/rtl/tsan_sync.cc @@ -42,10 +42,7 @@ void SyncVar::Reset(Processor *proc) { owner_tid = kInvalidTid; last_lock = 0; recursion = 0; - is_rw = 0; - is_recursive = 0; - is_broken = 0; - is_linker_init = 0; + atomic_store_relaxed(&flags, 0); if (proc == 0) { CHECK_EQ(clock.size(), 0); diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h index 86e6bbd55..d24d69762 100644 --- a/lib/tsan/rtl/tsan_sync.h +++ b/lib/tsan/rtl/tsan_sync.h @@ -23,6 +23,29 @@ namespace __tsan { +// These need to match __tsan_mutex_* flags defined in tsan_interface.h. +// See documentation there as well. +enum MutexFlags { + MutexFlagLinkerInit = 1 << 0, // __tsan_mutex_linker_init + MutexFlagWriteReentrant = 1 << 1, // __tsan_mutex_write_reentrant + MutexFlagReadReentrant = 1 << 2, // __tsan_mutex_read_reentrant + MutexFlagReadLock = 1 << 3, // __tsan_mutex_read_lock + MutexFlagTryLock = 1 << 4, // __tsan_mutex_try_lock + MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed + MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock + MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock + + // The following flags are runtime private. + // Mutex API misuse was detected, so don't report any more. + MutexFlagBroken = 1 << 30, + // We did not intercept pre lock event, so handle it on post lock. + MutexFlagDoPreLockOnPostLock = 1 << 29, + // Must list all mutex creation flags. + MutexCreationFlagMask = MutexFlagLinkerInit | + MutexFlagWriteReentrant | + MutexFlagReadReentrant, +}; + struct SyncVar { SyncVar(); @@ -35,10 +58,7 @@ struct SyncVar { int owner_tid; // Set only by exclusive owners. u64 last_lock; int recursion; - bool is_rw; - bool is_recursive; - bool is_broken; - bool is_linker_init; + atomic_uint32_t flags; u32 next; // in MetaMap DDMutex dd; SyncClock read_clock; // Used for rw mutexes only. @@ -61,6 +81,26 @@ struct SyncVar { *uid = id >> 48; return (uptr)GetLsb(id, 48); } + + bool IsFlagSet(u32 f) const { + return atomic_load_relaxed(&flags); + } + + void SetFlags(u32 f) { + atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f); + } + + void UpdateFlags(u32 flagz) { + // Filter out operation flags. + if (!(flagz & MutexCreationFlagMask)) + return; + u32 current = atomic_load_relaxed(&flags); + if (current & MutexCreationFlagMask) + return; + // Note: this can be called from MutexPostReadLock which holds only read + // lock on the SyncVar. + atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask)); + } }; /* MetaMap allows to map arbitrary user pointers onto various descriptors. diff --git a/test/tsan/custom_mutex.h b/test/tsan/custom_mutex.h new file mode 100644 index 000000000..675ad59b3 --- /dev/null +++ b/test/tsan/custom_mutex.h @@ -0,0 +1,91 @@ +#include "test.h" +#include +#include +#include + +// A very primitive mutex annotated with tsan annotations. +class Mutex { + public: + Mutex(bool prof = true) + : prof_(prof) + , locked_(false) + , seq_(0) { + __tsan_mutex_create(this, 0); + } + + ~Mutex() { + __tsan_mutex_destroy(this, 0); + } + + void Lock() { + __tsan_mutex_pre_lock(this, 0); + LockImpl(); + __tsan_mutex_post_lock(this, 0, 0); + } + + bool TryLock() { + __tsan_mutex_pre_lock(this, __tsan_mutex_try_lock); + bool ok = TryLockImpl(); + __tsan_mutex_post_lock(this, __tsan_mutex_try_lock | + (ok ? 0 : __tsan_mutex_try_lock_failed), 0); + return ok; + } + + void Unlock() { + __tsan_mutex_pre_unlock(this, 0); + UnlockImpl(); + __tsan_mutex_post_unlock(this, 0); + } + + void Wait() { + for (int seq = seq_; seq == seq_;) { + Unlock(); + usleep(100); + Lock(); + } + } + + void Broadcast() { + __tsan_mutex_pre_signal(this, 0); + LockImpl(false); + seq_++; + UnlockImpl(); + __tsan_mutex_post_signal(this, 0); + } + + private: + const bool prof_; + std::atomic locked_; + int seq_; + + // This models mutex profiling subsystem. + static Mutex prof_mu_; + static int prof_data_; + + void LockImpl(bool prof = true) { + while (!TryLockImpl()) + usleep(100); + if (prof && prof_) + Prof(); + } + + bool TryLockImpl() { + return !locked_.exchange(true); + } + + void UnlockImpl() { + locked_.store(false); + } + + void Prof() { + // This happens inside of mutex lock annotations. + __tsan_mutex_pre_divert(this, 0); + prof_mu_.Lock(); + prof_data_++; + prof_mu_.Unlock(); + __tsan_mutex_post_divert(this, 0); + } +}; + +Mutex Mutex::prof_mu_(false); +int Mutex::prof_data_; diff --git a/test/tsan/custom_mutex0.cc b/test/tsan/custom_mutex0.cc new file mode 100644 index 000000000..4079c72a1 --- /dev/null +++ b/test/tsan/custom_mutex0.cc @@ -0,0 +1,31 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +// Test that custom annoations provide normal mutex synchronization +// (no race reports for properly protected critical sections). + +Mutex mu; +long data; + +void *thr(void *arg) { + barrier_wait(&barrier); + mu.Lock(); + data++; + mu.Unlock(); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t th; + pthread_create(&th, 0, thr, 0); + barrier_wait(&barrier); + mu.Lock(); + data++; + mu.Unlock(); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: DONE diff --git a/test/tsan/custom_mutex1.cc b/test/tsan/custom_mutex1.cc new file mode 100644 index 000000000..ec7294ccd --- /dev/null +++ b/test/tsan/custom_mutex1.cc @@ -0,0 +1,39 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +// Test that failed TryLock does not induce parasitic synchronization. + +Mutex mu; +long data; + +void *thr(void *arg) { + mu.Lock(); + data++; + mu.Unlock(); + mu.Lock(); + barrier_wait(&barrier); + barrier_wait(&barrier); + mu.Unlock(); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t th; + pthread_create(&th, 0, thr, 0); + barrier_wait(&barrier); + if (mu.TryLock()) { + fprintf(stderr, "TryLock succeeded, should not\n"); + exit(0); + } + data++; + barrier_wait(&barrier); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: ThreadSanitizer: data race +// CHECK-NEXT: Write of size 8 at {{.*}} by main thread: +// CHECK-NEXT: #0 main {{.*}}custom_mutex1.cc:29 +// CHECK: DONE diff --git a/test/tsan/custom_mutex2.cc b/test/tsan/custom_mutex2.cc new file mode 100644 index 000000000..217b44466 --- /dev/null +++ b/test/tsan/custom_mutex2.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +// Test that Broadcast does not induce parasitic synchronization. + +Mutex mu; +long data; + +void *thr(void *arg) { + barrier_wait(&barrier); + mu.Lock(); + data++; + mu.Unlock(); + data++; + mu.Broadcast(); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t th; + pthread_create(&th, 0, thr, 0); + mu.Lock(); + barrier_wait(&barrier); + while (data == 0) + mu.Wait(); + mu.Unlock(); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: ThreadSanitizer: data race +// CHECK: DONE -- cgit v1.2.1 From ea0ff516f0343d98f338c2403566f68a131b07e3 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 26 Mar 2017 20:59:23 +0000 Subject: [tsan] Only Acquire/Release GCD queues if they're not NULL While it's usually a bug to call GCD APIs, such as dispatch_after, with NULL as a queue, this often "somehow" works and TSan should maintain binary compatibility with existing code. This patch makes sure we don't try to call Acquire and Release on NULL queues, and add one such testcase for dispatch_after. Differential Revision: https://reviews.llvm.org/D31355 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298820 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_libdispatch_mac.cc | 17 +++++++++-------- test/tsan/Darwin/gcd-after-null.mm | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 test/tsan/Darwin/gcd-after-null.mm diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc index 48351e80a..8c759a3be 100644 --- a/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -97,11 +97,11 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc, return new_context; } -#define GET_QUEUE_SYNC_VARS(context, q) \ - bool is_queue_serial = q && IsQueueSerial(q); \ - uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \ - uptr serial_sync = (uptr)sync_ptr; \ - uptr concurrent_sync = ((uptr)sync_ptr) + sizeof(uptr); \ +#define GET_QUEUE_SYNC_VARS(context, q) \ + bool is_queue_serial = q && IsQueueSerial(q); \ + uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \ + uptr serial_sync = (uptr)sync_ptr; \ + uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \ bool serial_task = context->is_barrier_block || is_queue_serial static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc, @@ -112,8 +112,8 @@ static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc, dispatch_queue_t q = context->queue; do { GET_QUEUE_SYNC_VARS(context, q); - Acquire(thr, pc, serial_sync); - if (serial_task) Acquire(thr, pc, concurrent_sync); + if (serial_sync) Acquire(thr, pc, serial_sync); + if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync); if (q) q = GetTargetQueueFromQueue(q); } while (q); @@ -127,7 +127,8 @@ static void dispatch_sync_post_execute(ThreadState *thr, uptr pc, dispatch_queue_t q = context->queue; do { GET_QUEUE_SYNC_VARS(context, q); - Release(thr, pc, serial_task ? serial_sync : concurrent_sync); + if (serial_task && serial_sync) Release(thr, pc, serial_sync); + if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync); if (q) q = GetTargetQueueFromQueue(q); } while (q); diff --git a/test/tsan/Darwin/gcd-after-null.mm b/test/tsan/Darwin/gcd-after-null.mm new file mode 100644 index 000000000..7c9913c0f --- /dev/null +++ b/test/tsan/Darwin/gcd-after-null.mm @@ -0,0 +1,23 @@ +// Regression test to make sure we don't crash when dispatch_after is called with a NULL queue. + +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %run %t 2>&1 | FileCheck %s + +#import + +int main(int argc, const char *argv[]) { + fprintf(stderr, "start\n"); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), NULL, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetMain()); + }); + }); + CFRunLoopRun(); + + fprintf(stderr, "done\n"); + return 0; +} + +// CHECK: start +// CHECK: done -- cgit v1.2.1 From d75e2e9fdddf4fb41973a211fe4c445b07fb7e1f Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 26 Mar 2017 21:20:42 +0000 Subject: [asan] Remove column numbers from test expectations in invalid-pointer-pairs.cc This is failing on some of our internal bots because we're using different symbolizers. It doesn't seem important and we never test for column numbers in any other tests, so let's just remove it. Differential Revision: https://reviews.llvm.org/D30122 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298822 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/invalid-pointer-pairs.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/invalid-pointer-pairs.cc b/test/asan/TestCases/invalid-pointer-pairs.cc index b36e6cd9c..e1df151d1 100644 --- a/test/asan/TestCases/invalid-pointer-pairs.cc +++ b/test/asan/TestCases/invalid-pointer-pairs.cc @@ -13,10 +13,10 @@ int f(char c, char *p, char *q) { // [[PTR1:0x[0-9a-f]+]] [[PTR2:0x[0-9a-f]+]] switch (c) { case 'g': - // CMP: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14 + // CMP: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]] return p > q; case 's': - // SUB: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14 + // SUB: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]] return p - q; case 'k': { // OK-NOT: ERROR @@ -26,7 +26,7 @@ int f(char c, char *p, char *q) { case 'f': { char *p3 = p + 20; free(p); - // FREE: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+2]]:14 + // FREE: #{{[0-9]+ .*}} in f({{char, char\*, char\*|char,char \*,char \*}}) {{.*}}invalid-pointer-pairs.cc:[[@LINE+2]] // FREE: freed by thread return p < p3; } -- cgit v1.2.1 From 8dbff7cb785cc4352d2df5351070ed7fc7dbf3f6 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 27 Mar 2017 07:13:35 +0000 Subject: [XRay][compiler-rt] Use sanitizer_common's atomic ops Instead of std::atomic APIs for atomic operations, we instead use APIs include with sanitizer_common. This allows us to, at runtime, not have to depend on potentially dynamically provided implementations of these atomic operations. Fixes http://llvm.org/PR32274. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298833 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/CMakeLists.txt | 2 +- lib/xray/xray_buffer_queue.cc | 11 +++--- lib/xray/xray_buffer_queue.h | 16 ++++---- lib/xray/xray_fdr_logging.cc | 80 ++++++++++++++++++++++------------------ lib/xray/xray_fdr_logging_impl.h | 26 +++++++------ lib/xray/xray_init.cc | 23 +++++------- lib/xray/xray_interface.cc | 59 ++++++++++++++++------------- lib/xray/xray_log_interface.cc | 15 ++++---- 8 files changed, 127 insertions(+), 105 deletions(-) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index 43878cb15..a1eb4a030 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -49,7 +49,7 @@ macro(add_xray_unittest testname) -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} -lpthread -L${COMPILER_RT_LIBRARY_OUTPUT_DIR} -lclang_rt.xray-${arch} - -latomic -ldl -lrt) + -ldl -lrt) endif() # FIXME: Figure out how to run even just the unit tests on APPLE. endforeach() diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 13d17537e..7ba755ac3 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -23,7 +23,7 @@ using namespace __xray; using namespace __sanitizer; BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) - : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing(false) { + : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing{0} { for (auto &T : Buffers) { void *Tmp = malloc(BufferSize); if (Tmp == nullptr) { @@ -40,9 +40,9 @@ BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) } BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { - if (Finalizing.load(std::memory_order_acquire)) + if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) return ErrorCode::QueueFinalizing; - std::lock_guard Guard(Mutex); + __sanitizer::BlockingMutexLock Guard(&Mutex); if (Buffers.empty()) return ErrorCode::NotEnoughMemory; auto &T = Buffers.front(); @@ -57,7 +57,7 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { if (OwnedBuffers.count(Buf.Buffer) == 0) return ErrorCode::UnrecognizedBuffer; - std::lock_guard Guard(Mutex); + __sanitizer::BlockingMutexLock Guard(&Mutex); // Now that the buffer has been released, we mark it as "used". Buffers.emplace(Buffers.end(), Buf, true /* used */); @@ -67,7 +67,8 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { } BufferQueue::ErrorCode BufferQueue::finalize() { - if (Finalizing.exchange(true, std::memory_order_acq_rel)) + if (__sanitizer::atomic_exchange(&Finalizing, 1, + __sanitizer::memory_order_acq_rel)) return ErrorCode::QueueFinalizing; return ErrorCode::Ok; } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 32f7ae967..28a622069 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -15,10 +15,9 @@ #ifndef XRAY_BUFFER_QUEUE_H #define XRAY_BUFFER_QUEUE_H -#include -#include +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_mutex.h" #include -#include #include #include @@ -42,9 +41,9 @@ private: // We use a bool to indicate whether the Buffer has been used in this // freelist implementation. std::deque> Buffers; - std::mutex Mutex; + __sanitizer::BlockingMutex Mutex; std::unordered_set OwnedBuffers; - std::atomic Finalizing; + __sanitizer::atomic_uint8_t Finalizing; public: enum class ErrorCode : unsigned { @@ -94,7 +93,10 @@ public: /// - ... ErrorCode releaseBuffer(Buffer &Buf); - bool finalizing() const { return Finalizing.load(std::memory_order_acquire); } + bool finalizing() const { + return __sanitizer::atomic_load(&Finalizing, + __sanitizer::memory_order_acquire); + } /// Sets the state of the BufferQueue to finalizing, which ensures that: /// @@ -109,7 +111,7 @@ public: /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a /// releaseBuffer(...) operation. template void apply(F Fn) { - std::lock_guard G(Mutex); + __sanitizer::BlockingMutexLock G(&Mutex); for (const auto &T : Buffers) { if (std::get<1>(T)) Fn(std::get<0>(T)); diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 0a1fb19f0..df95c1d66 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -17,15 +17,14 @@ #include "xray_fdr_logging.h" #include #include -#include #include -#include #include #include #include #include #include +#include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "xray/xray_interface.h" #include "xray/xray_records.h" @@ -41,10 +40,10 @@ namespace __xray { // Global BufferQueue. std::shared_ptr BQ; -std::atomic LoggingStatus{ +__sanitizer::atomic_sint32_t LoggingStatus = { XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; -std::atomic LogFlushStatus{ +__sanitizer::atomic_sint32_t LogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; std::unique_ptr FDROptions; @@ -53,11 +52,12 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, void *Options, size_t OptionsSize) XRAY_NEVER_INSTRUMENT { assert(OptionsSize == sizeof(FDRLoggingOptions)); - XRayLogInitStatus CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; - if (!LoggingStatus.compare_exchange_strong( - CurrentStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZING, - std::memory_order_release, std::memory_order_relaxed)) - return CurrentStatus; + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + if (__sanitizer::atomic_compare_exchange_strong( + &LoggingStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZING, + __sanitizer::memory_order_release)) + return static_cast(CurrentStatus); FDROptions.reset(new FDRLoggingOptions()); *FDROptions = *reinterpret_cast(Options); @@ -74,22 +74,24 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, // Install the actual handleArg0 handler after initialising the buffers. __xray_set_handler(fdrLoggingHandleArg0); - LoggingStatus.store(XRayLogInitStatus::XRAY_LOG_INITIALIZED, - std::memory_order_release); + __sanitizer::atomic_store(&LoggingStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZED, + __sanitizer::memory_order_release); return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } // Must finalize before flushing. XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { - if (LoggingStatus.load(std::memory_order_acquire) != + if (__sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire) != XRayLogInitStatus::XRAY_LOG_FINALIZED) return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; - XRayLogFlushStatus Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; - if (!LogFlushStatus.compare_exchange_strong( - Result, XRayLogFlushStatus::XRAY_LOG_FLUSHING, - std::memory_order_release, std::memory_order_relaxed)) - return Result; + s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + if (__sanitizer::atomic_compare_exchange_strong( + &LogFlushStatus, &Result, XRayLogFlushStatus::XRAY_LOG_FLUSHING, + __sanitizer::memory_order_release)) + return static_cast(Result); // Make a copy of the BufferQueue pointer to prevent other threads that may be // resetting it from blowing away the queue prematurely while we're dealing @@ -110,7 +112,8 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { Fd = getLogFD(); if (Fd == -1) { auto Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; - LogFlushStatus.store(Result, std::memory_order_release); + __sanitizer::atomic_store(&LogFlushStatus, Result, + __sanitizer::memory_order_release); return Result; } @@ -129,43 +132,48 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { retryingWriteAll(Fd, reinterpret_cast(B.Buffer), reinterpret_cast(B.Buffer) + B.Size); }); - LogFlushStatus.store(XRayLogFlushStatus::XRAY_LOG_FLUSHED, - std::memory_order_release); + __sanitizer::atomic_store(&LogFlushStatus, + XRayLogFlushStatus::XRAY_LOG_FLUSHED, + __sanitizer::memory_order_release); return XRayLogFlushStatus::XRAY_LOG_FLUSHED; } XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT { - XRayLogInitStatus CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; - if (!LoggingStatus.compare_exchange_strong( - CurrentStatus, XRayLogInitStatus::XRAY_LOG_FINALIZING, - std::memory_order_release, std::memory_order_relaxed)) - return CurrentStatus; + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; + if (__sanitizer::atomic_compare_exchange_strong( + &LoggingStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_FINALIZING, + __sanitizer::memory_order_release)) + return static_cast(CurrentStatus); // Do special things to make the log finalize itself, and not allow any more // operations to be performed until re-initialized. BQ->finalize(); - LoggingStatus.store(XRayLogInitStatus::XRAY_LOG_FINALIZED, - std::memory_order_release); + __sanitizer::atomic_store(&LoggingStatus, + XRayLogInitStatus::XRAY_LOG_FINALIZED, + __sanitizer::memory_order_release); return XRayLogInitStatus::XRAY_LOG_FINALIZED; } XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { - XRayLogInitStatus CurrentStatus = XRayLogInitStatus::XRAY_LOG_FINALIZED; - if (!LoggingStatus.compare_exchange_strong( - CurrentStatus, XRayLogInitStatus::XRAY_LOG_UNINITIALIZED, - std::memory_order_release, std::memory_order_relaxed)) - return CurrentStatus; + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_FINALIZED; + if (__sanitizer::atomic_compare_exchange_strong( + &LoggingStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZED, + __sanitizer::memory_order_release)) + return static_cast(CurrentStatus); // Release the in-memory buffer queue. BQ.reset(); // Spin until the flushing status is flushed. - XRayLogFlushStatus CurrentFlushingStatus = + s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; - while (!LogFlushStatus.compare_exchange_weak( - CurrentFlushingStatus, XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, - std::memory_order_release, std::memory_order_relaxed)) { + while (__sanitizer::atomic_compare_exchange_weak( + &LogFlushStatus, &CurrentFlushingStatus, + XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, + __sanitizer::memory_order_release)) { if (CurrentFlushingStatus == XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING) break; CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index d65c0f4f4..c232acbb1 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -91,12 +92,12 @@ static void writeTSCWrapMetadata(uint64_t TSC); /// walk backward through its buffer and erase trivial functions to avoid /// polluting the log and may use the buffer queue to obtain or release a /// buffer. -static void -processFunctionHook(int32_t FuncId, XRayEntryType Entry, uint64_t TSC, - unsigned char CPU, - int (*wall_clock_reader)(clockid_t, struct timespec *), - const std::atomic &LoggingStatus, - const std::shared_ptr &BQ); +static void processFunctionHook(int32_t FuncId, XRayEntryType Entry, + uint64_t TSC, unsigned char CPU, + int (*wall_clock_reader)(clockid_t, + struct timespec *), + __sanitizer::atomic_sint32_t &LoggingStatus, + const std::shared_ptr &BQ); //-----------------------------------------------------------------------------| // The rest of the file is implementation. | @@ -166,8 +167,9 @@ public: }; static inline bool loggingInitialized( - const std::atomic &LoggingStatus) XRAY_NEVER_INSTRUMENT { - return LoggingStatus.load(std::memory_order_acquire) == + const __sanitizer::atomic_sint32_t &LoggingStatus) XRAY_NEVER_INSTRUMENT { + return __sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire) == XRayLogInitStatus::XRAY_LOG_INITIALIZED; } @@ -305,10 +307,11 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, static inline void processFunctionHook( int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, int (*wall_clock_reader)(clockid_t, struct timespec *), - const std::atomic &LoggingStatus, + __sanitizer::atomic_sint32_t &LoggingStatus, const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { // Bail out right away if logging is not initialized yet. - if (LoggingStatus.load(std::memory_order_acquire) != + if (__sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire) != XRayLogInitStatus::XRAY_LOG_INITIALIZED) return; @@ -352,7 +355,8 @@ static inline void processFunctionHook( if (Buffer.Buffer == nullptr) { auto EC = LocalBQ->getBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { - auto LS = LoggingStatus.load(std::memory_order_acquire); + auto LS = __sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire); if (LS != XRayLogInitStatus::XRAY_LOG_FINALIZING && LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) Report("Failed to acquire a buffer; error=%s\n", diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index 9d012e9a6..6f558d656 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -12,7 +12,6 @@ // XRay initialisation logic. //===----------------------------------------------------------------------===// -#include #include #include #include @@ -28,7 +27,6 @@ extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak)); extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak)); } -using namespace __sanitizer; using namespace __xray; // When set to 'true' this means the XRay runtime has been initialised. We use @@ -38,10 +36,11 @@ using namespace __xray; // // FIXME: Support DSO instrumentation maps too. The current solution only works // for statically linked executables. -std::atomic XRayInitialized{false}; +__sanitizer::atomic_uint8_t XRayInitialized{0}; // This should always be updated before XRayInitialized is updated. -std::atomic<__xray::XRaySledMap> XRayInstrMap{}; +__sanitizer::SpinMutex XRayInstrMapMutex; +XRaySledMap XRayInstrMap; // __xray_init() will do the actual loading of the current process' memory map // and then proceed to look for the .xray_instr_map section/segment. @@ -52,15 +51,13 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { return; } - // Now initialize the XRayInstrMap global struct with the address of the - // entries, reinterpreted as an array of XRaySledEntry objects. We use the - // virtual pointer we have from the section to provide us the correct - // information. - __xray::XRaySledMap SledMap{}; - SledMap.Sleds = __start_xray_instr_map; - SledMap.Entries = __stop_xray_instr_map - __start_xray_instr_map; - XRayInstrMap.store(SledMap, std::memory_order_release); - XRayInitialized.store(true, std::memory_order_release); + { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + XRayInstrMap.Sleds = __start_xray_instr_map; + XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map; + } + __sanitizer::atomic_store(&XRayInitialized, true, + __sanitizer::memory_order_release); if (flags()->patch_premain) __xray_patch(); diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 39cf8efb3..26ec161fe 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -15,7 +15,6 @@ #include "xray_interface_internal.h" -#include #include #include #include @@ -46,10 +45,10 @@ static const int16_t cSledLength = 8; #endif /* CPU architecture */ // This is the function to call when we encounter the entry or exit sleds. -std::atomic XRayPatchedFunction{nullptr}; +__sanitizer::atomic_uintptr_t XRayPatchedFunction{0}; // This is the function to call from the arg1-enabled sleds/trampolines. -std::atomic XRayArgLogger{nullptr}; +__sanitizer::atomic_uintptr_t XRayArgLogger{0}; // MProtectHelper is an RAII wrapper for calls to mprotect(...) that will undo // any successful mprotect(...) changes. This is used to make a page writeable @@ -88,13 +87,18 @@ public: } // namespace __xray -extern std::atomic XRayInitialized; -extern std::atomic<__xray::XRaySledMap> XRayInstrMap; +extern __sanitizer::SpinMutex XRayInstrMapMutex; +extern __sanitizer::atomic_uint8_t XRayInitialized; +extern __xray::XRaySledMap XRayInstrMap; int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) XRAY_NEVER_INSTRUMENT { - if (XRayInitialized.load(std::memory_order_acquire)) { - __xray::XRayPatchedFunction.store(entry, std::memory_order_release); + if (__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) { + + __sanitizer::atomic_store(&__xray::XRayPatchedFunction, + reinterpret_cast(entry), + __sanitizer::memory_order_release); return 1; } return 0; @@ -104,7 +108,7 @@ int __xray_remove_handler() XRAY_NEVER_INSTRUMENT { return __xray_set_handler(nullptr); } -std::atomic XRayPatching{false}; +__sanitizer::atomic_uint8_t XRayPatching{0}; using namespace __xray; @@ -132,26 +136,29 @@ CleanupInvoker scopeCleanup(Function Fn) XRAY_NEVER_INSTRUMENT { // implementation. |Enable| defines whether we're enabling or disabling the // runtime XRay instrumentation. XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { - if (!XRayInitialized.load(std::memory_order_acquire)) + if (!__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. - static bool NotPatching = false; - if (!XRayPatching.compare_exchange_strong(NotPatching, true, - std::memory_order_acq_rel, - std::memory_order_acquire)) { + uint8_t NotPatching = false; + if (!__sanitizer::atomic_compare_exchange_strong( + &XRayPatching, &NotPatching, true, __sanitizer::memory_order_acq_rel)) return XRayPatchingStatus::ONGOING; // Already patching. - } - bool PatchingSuccess = false; + uint8_t PatchingSuccess = false; auto XRayPatchingStatusResetter = scopeCleanup([&PatchingSuccess] { - if (!PatchingSuccess) { - XRayPatching.store(false, std::memory_order_release); - } + if (!PatchingSuccess) + __sanitizer::atomic_store(&XRayPatching, false, + __sanitizer::memory_order_release); }); // Step 1: Compute the function id, as a unique identifier per function in the // instrumentation map. - XRaySledMap InstrMap = XRayInstrMap.load(std::memory_order_acquire); + XRaySledMap InstrMap; + { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + InstrMap = XRayInstrMap; + } if (InstrMap.Entries == 0) return XRayPatchingStatus::NOT_INITIALIZED; @@ -205,7 +212,8 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { } (void)Success; } - XRayPatching.store(false, std::memory_order_release); + __sanitizer::atomic_store(&XRayPatching, false, + __sanitizer::memory_order_release); PatchingSuccess = true; return XRayPatchingStatus::SUCCESS; } @@ -218,15 +226,16 @@ XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT { return controlPatching(false); } -int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) -{ - if (!XRayInitialized.load(std::memory_order_acquire)) { +int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { + if (!__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) return 0; - } + // A relaxed write might not be visible even if the current thread gets // scheduled on a different CPU/NUMA node. We need to wait for everyone to // have this handler installed for consistency of collected data across CPUs. - XRayArgLogger.store(Handler, std::memory_order_release); + __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast(Handler), + __sanitizer::memory_order_release); return 1; } int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc index c7cfe5080..8fb6e3919 100644 --- a/lib/xray/xray_log_interface.cc +++ b/lib/xray/xray_log_interface.cc @@ -12,45 +12,46 @@ //===----------------------------------------------------------------------===// #include "xray/xray_log_interface.h" +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_mutex.h" #include "xray/xray_interface.h" #include "xray_defs.h" #include -#include -std::mutex XRayImplMutex; +__sanitizer::SpinMutex XRayImplMutex; std::unique_ptr GlobalXRayImpl; void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT { if (Impl.log_init == nullptr || Impl.log_finalize == nullptr || Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) { - std::lock_guard Guard(XRayImplMutex); + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); GlobalXRayImpl.reset(); return; } - std::lock_guard Guard(XRayImplMutex); + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); GlobalXRayImpl.reset(new XRayLogImpl); *GlobalXRayImpl = Impl; } XRayLogInitStatus __xray_init(size_t BufferSize, size_t MaxBuffers, void *Args, size_t ArgsSize) XRAY_NEVER_INSTRUMENT { - std::lock_guard Guard(XRayImplMutex); + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; return GlobalXRayImpl->log_init(BufferSize, MaxBuffers, Args, ArgsSize); } XRayLogInitStatus __xray_log_finalize() XRAY_NEVER_INSTRUMENT { - std::lock_guard Guard(XRayImplMutex); + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; return GlobalXRayImpl->log_finalize(); } XRayLogFlushStatus __xray_log_flushLog() XRAY_NEVER_INSTRUMENT { - std::lock_guard Guard(XRayImplMutex); + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; return GlobalXRayImpl->flush_log(); -- cgit v1.2.1 From bf19b3764d067f2d77d0784a0d24a072ded8bb0a Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Mon, 27 Mar 2017 09:45:38 +0000 Subject: Add --std=c++11 to tests that #include git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298836 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/custom_mutex0.cc | 2 +- test/tsan/custom_mutex1.cc | 2 +- test/tsan/custom_mutex2.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/tsan/custom_mutex0.cc b/test/tsan/custom_mutex0.cc index 4079c72a1..998385ca1 100644 --- a/test/tsan/custom_mutex0.cc +++ b/test/tsan/custom_mutex0.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s #include "custom_mutex.h" // Test that custom annoations provide normal mutex synchronization diff --git a/test/tsan/custom_mutex1.cc b/test/tsan/custom_mutex1.cc index ec7294ccd..06186515f 100644 --- a/test/tsan/custom_mutex1.cc +++ b/test/tsan/custom_mutex1.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s #include "custom_mutex.h" // Test that failed TryLock does not induce parasitic synchronization. diff --git a/test/tsan/custom_mutex2.cc b/test/tsan/custom_mutex2.cc index 217b44466..9329cbc3f 100644 --- a/test/tsan/custom_mutex2.cc +++ b/test/tsan/custom_mutex2.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s #include "custom_mutex.h" // Test that Broadcast does not induce parasitic synchronization. -- cgit v1.2.1 From 97cbaf1d350a8e1d561d09fe5f536bb131713365 Mon Sep 17 00:00:00 2001 From: Ismail Donmez Date: Mon, 27 Mar 2017 10:17:03 +0000 Subject: Fix build error: In file included from /home/abuild/rpmbuild/BUILD/llvm/projects/compiler-rt/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc:15: ../projects/compiler-rt/lib/xray/tests/../xray_fdr_logging_impl.h:221:21: error: use of undeclared identifier 'CLOCK_MONOTONIC' wall_clock_reader(CLOCK_MONOTONIC, &TS); ^ 1 error generated. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298837 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index c232acbb1..caeb27411 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "sanitizer_common/sanitizer_common.h" -- cgit v1.2.1 From 82b27a27ce1839468c43b5e41e380a6a88df7dd7 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 27 Mar 2017 14:06:49 +0000 Subject: Disable use_tls_dynamic on 32-bit linux Summary: This test fails with a false negative due to an unrelated change. Since we expect a number of false negatives on 32-bit lsan, disable this test on linux-i386 and linux-i686. Reviewers: kubamracek, m.ostapenko, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31300 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298847 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/use_tls_dynamic.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc index 770ffafe2..c20232dc3 100644 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -5,6 +5,7 @@ // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: LSAN_OPTIONS="" %run %t 2>&1 +// UNSUPPORTED: i386-linux,i686-linux #ifndef BUILD_DSO #include -- cgit v1.2.1 From 3fbf3a4149ca94d84b77797f9e7b3a60b785cddc Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 27 Mar 2017 14:07:50 +0000 Subject: Use pthreads for thread-local lsan allocator cache on darwin Summary: This patch allows us to move away from using __thread on darwin, which is requiring for building lsan for darwin on ios version 7 and on iossim i386. Reviewers: kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31291 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298848 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 38 +------------------------------------- lib/lsan/lsan_allocator.h | 37 +++++++++++++++++++++++++++++++++++++ lib/lsan/lsan_common_linux.cc | 4 ++++ lib/lsan/lsan_common_mac.cc | 8 +++++++- 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index a08dcf286..640497d40 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,54 +24,18 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { - -struct ChunkMetadata { - u8 allocated : 8; // Must be first. - ChunkTag tag : 2; -#if SANITIZER_WORDSIZE == 64 - uptr requested_size : 54; -#else - uptr requested_size : 32; - uptr padding : 22; -#endif - u32 stack_trace_id; -}; - -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) #if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; -#else +#elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; -#endif -static const uptr kRegionSizeLog = 20; -static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; -typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; #else static const uptr kMaxAllowedMallocSize = 8UL << 30; - -struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. - static const uptr kMetadataSize = sizeof(ChunkMetadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; -}; - -typedef SizeClassAllocator64 PrimaryAllocator; #endif -typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; -static THREADLOCAL AllocatorCache allocator_cache; -AllocatorCache *GetAllocatorCache() { return &allocator_cache; } void InitializeAllocator() { allocator.InitLinkerInitialized( diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index f56460119..9c3dce97a 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -15,8 +15,10 @@ #ifndef LSAN_ALLOCATOR_H #define LSAN_ALLOCATOR_H +#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" +#include "lsan_common.h" namespace __lsan { @@ -34,6 +36,41 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); +struct ChunkMetadata { + u8 allocated : 8; // Must be first. + ChunkTag tag : 2; +#if SANITIZER_WORDSIZE == 64 + uptr requested_size : 54; +#else + uptr requested_size : 32; + uptr padding : 22; +#endif + u32 stack_trace_id; +}; + +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; +#elif defined(__x86_64__) +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; + +AllocatorCache *GetAllocatorCache(); } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 0e10d4191..e73768e58 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,6 +22,7 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "lsan_allocator.h" namespace __lsan { @@ -38,6 +39,9 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } + __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 7f5e0550d..f70ebdd0e 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -12,12 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" #if CAN_SANITIZE_LEAKS && SANITIZER_MAC +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "lsan_allocator.h" + #include namespace __lsan { @@ -25,6 +27,7 @@ namespace __lsan { typedef struct { int disable_counter; u32 current_thread_id; + AllocatorCache cache; } thread_local_data_t; static pthread_key_t key; @@ -40,6 +43,7 @@ static thread_local_data_t *get_tls_val() { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; + ptr->cache = AllocatorCache(); pthread_setspecific(key, ptr); } @@ -62,6 +66,8 @@ u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } +AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } + void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); } -- cgit v1.2.1 From e7eb94b993f82d3a33f5426b1340ca0c027f4e2b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 27 Mar 2017 17:14:48 +0000 Subject: [sanitizers] Avoid using -fomit-frame-pointer on Darwin On Darwin, we're having multiple issues with using -fomit-frame-pointer in the AddressSanitizer and ThreadSanitizer runtimes, so we're actually not using -fomit-frame-pointer in the our builds of the sanitizer dylibs. This patch just pushes our internal change upstream. The issues are usually with debuggers, profilers and other tools that unwind the stack (crash reporter), which are often simply not able to get a stack trace. And crashlogs that don't contain a stack trace are a huge problem. Differential Revision: https://reviews.llvm.org/D31376 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298859 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db083491f..32358a126 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ if(NOT WIN32) endif() append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS) -if(NOT COMPILER_RT_DEBUG) +if(NOT COMPILER_RT_DEBUG AND NOT APPLE) append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS) endif() append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS) -- cgit v1.2.1 From 83871acc2e6e61912f723645d52df54b590f419c Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 27 Mar 2017 17:16:47 +0000 Subject: [sanitizers] Upgrade ios min version to 8 Differential Revision: https://reviews.llvm.org/D29787 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298860 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 26eb53255..027b22646 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -208,7 +208,7 @@ if(APPLE) list(APPEND DARWIN_EMBEDDED_PLATFORMS ios) set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min) set(DARWIN_ios_SANITIZER_MIN_VER_FLAG - ${DARWIN_ios_MIN_VER_FLAG}=7.0) + ${DARWIN_ios_MIN_VER_FLAG}=8.0) endif() if(COMPILER_RT_ENABLE_WATCHOS) list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos) -- cgit v1.2.1 From 724beb7097dd6c42e5e6e6db872db95f3e6d76e3 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Mon, 27 Mar 2017 18:08:37 +0000 Subject: Revert "[Compiler-rt][Builtins] Implement lit-test support (part 2 of 2)" This broke GreenDragon: http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/29505/consoleFull git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298868 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/CMakeLists.txt | 17 -------- test/builtins/Unit/lit.cfg | 80 -------------------------------------- test/builtins/Unit/lit.site.cfg.in | 12 ------ 3 files changed, 109 deletions(-) delete mode 100644 test/builtins/Unit/lit.cfg delete mode 100644 test/builtins/Unit/lit.site.cfg.in diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index 8b5479d83..443e552f8 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -9,23 +9,6 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg ) -#Unit tests. - -include(builtin-config-ix) - -foreach(arch ${BUILTIN_SUPPORTED_ARCH}) - set(BUILTINS_TEST_TARGET_ARCH ${arch}) - string(TOLOWER "-${arch}-${OS_NAME}" BUILTINS_TEST_CONFIG_SUFFIX) - get_test_cc_for_arch(${arch} BUILTINS_TEST_TARGET_CC BUILTINS_TEST_TARGET_CFLAGS) - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg - ) - list(APPEND BUILTINS_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) -endforeach() - add_lit_testsuite(check-builtins "Running the Builtins tests" ${BUILTINS_TESTSUITES} DEPENDS ${BUILTINS_TEST_DEPS}) diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg deleted file mode 100644 index f29f7e00d..000000000 --- a/test/builtins/Unit/lit.cfg +++ /dev/null @@ -1,80 +0,0 @@ -# -*- Python -*- - -import os -import platform - -import lit.formats - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if attr_value == None: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -# Setup config name. -config.name = 'Builtins' + config.name_suffix - -# Platform-specific default Builtins_OPTIONS for lit tests. -default_builtins_opts = '' - -# Setup source root. -config.test_source_root = os.path.dirname(__file__) - -# Path to the static library -base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a " - % config.target_arch) - -builtins_source_dir = os.path.join( - get_required_attr(config, "compiler_rt_src_root"), "lib", "builtins") -builtins_lit_source_dir = get_required_attr(config, "builtins_lit_source_dir") - -extra_link_flags = ["-nodefaultlibs"] -config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') ) - -target_cflags = [get_required_attr(config, "target_cflags")] -target_cflags += ['-fno-builtin', '-I', builtins_source_dir] -target_cflags += extra_link_flags -target_cxxflags = config.cxx_mode_flags + target_cflags -clang_builtins_static_cflags = ([""] + - config.debug_info_flags + target_cflags) -clang_builtins_static_cxxflags = config.cxx_mode_flags + \ - clang_builtins_static_cflags - -clang_builtins_cflags = clang_builtins_static_cflags -clang_builtins_cxxflags = clang_builtins_static_cxxflags - - -config.available_features.add('not-android') -clang_wrapper = "" - -def build_invocation(compile_flags): - return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " " - - -target_arch = config.target_arch -if (target_arch == "arm"): - target_arch = "armv7" - -config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) -config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) -config.substitutions.append( ("%clang_builtins ", \ - build_invocation(clang_builtins_cflags))) -config.substitutions.append( ("%clangxx_builtins ", \ - build_invocation(clang_builtins_cxxflags))) - -# FIXME: move the call_apsr.s into call_apsr.h as inline-asm. -# some ARM tests needs call_apsr.s -call_apsr_source = os.path.join(builtins_lit_source_dir, 'arm', 'call_apsr.S') -march_flag = '-march=' + target_arch -call_apsr_flags = ['-c', march_flag, call_apsr_source] -config.substitutions.append( ("%arm_call_apsr ", \ - build_invocation(call_apsr_flags)) ) - -# Default test suffixes. -config.suffixes = ['.c', '.cc', '.cpp'] - -if not config.emulator: - config.available_features.add('native-run') diff --git a/test/builtins/Unit/lit.site.cfg.in b/test/builtins/Unit/lit.site.cfg.in deleted file mode 100644 index 4b4009d1e..000000000 --- a/test/builtins/Unit/lit.site.cfg.in +++ /dev/null @@ -1,12 +0,0 @@ -@LIT_SITE_CFG_IN_HEADER@ - -config.name_suffix = "@BUILTINS_TEST_CONFIG_SUFFIX@" -config.builtins_lit_source_dir = "@BUILTINS_LIT_SOURCE_DIR@/Unit" -config.target_cflags = "@BUILTINS_TEST_TARGET_CFLAGS@" -config.target_arch = "@BUILTINS_TEST_TARGET_ARCH@" - -# Load common config for all compiler-rt lit tests. -lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") - -# Load tool-specific config that would do the real work. -lit_config.load_config(config, "@BUILTINS_LIT_SOURCE_DIR@/Unit/lit.cfg") -- cgit v1.2.1 From fa1f07dfb28c517c19e30a48422b431aa1b84065 Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Mon, 27 Mar 2017 18:36:06 +0000 Subject: [powerpc] deactivate ManyThreadsTest asan test on powerpc64 This test case occassionally hangs when run on powerpc. This is also a problem on AArch64 (see https://bugs.llvm.org/show_bug.cgi?id=24389). Reactivate this when the problem is fixed. This could also be related to the same problem as with the tests ThreadedOneSizeMallocStressTest, ThreadedMallocStressTest, and several others that do not run reliably on powerpc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298873 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 425e7fc9c..31215cf56 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -337,8 +337,9 @@ void *ManyThreadsWorker(void *a) { return 0; } -#if !defined(__aarch64__) +#if !defined(__aarch64__) && !defined(__powerpc64__) // FIXME: Infinite loop in AArch64 (PR24389). +// FIXME: Also occasional hang on powerpc. Maybe same problem as on AArch64? TEST(AddressSanitizer, ManyThreadsTest) { const size_t kNumThreads = (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000; -- cgit v1.2.1 From 7b6358233355baa5620614d245f7be117919d758 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 27 Mar 2017 19:42:37 +0000 Subject: Move lsan allocator cache from lsan_common_linux to lsan_linux Having this function in common seems to trigger a lot of unrelated test failures. Given that this isn't really common code anyway, move this to a new linux-specific lsan file. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298878 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/CMakeLists.txt | 1 + lib/lsan/lsan_common_linux.cc | 4 ---- lib/lsan/lsan_linux.cc | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 lib/lsan/lsan_linux.cc diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index a48b85fa6..4e66100c3 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -11,6 +11,7 @@ set(LSAN_COMMON_SOURCES set(LSAN_SOURCES lsan.cc lsan_allocator.cc + lsan_linux.cc lsan_interceptors.cc lsan_preinit.cc lsan_thread.cc) diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index e73768e58..0e10d4191 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -22,7 +22,6 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#include "lsan_allocator.h" namespace __lsan { @@ -39,9 +38,6 @@ static THREADLOCAL u32 current_thread_tid = kInvalidTid; u32 GetCurrentThread() { return current_thread_tid; } void SetCurrentThread(u32 tid) { current_thread_tid = tid; } -static THREADLOCAL AllocatorCache allocator_cache; -AllocatorCache *GetAllocatorCache() { return &allocator_cache; } - __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_linux.cc b/lib/lsan/lsan_linux.cc new file mode 100644 index 000000000..616c06c75 --- /dev/null +++ b/lib/lsan/lsan_linux.cc @@ -0,0 +1,26 @@ +//=-- lsan_linux.cc -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. Linux-specific code. +// +//===----------------------------------------------------------------------===// + +#if SANITIZER_LINUX + +#include "lsan_allocator.h" + +namespace __lsan { + +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } + +} // namespace __lsan + +#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX + -- cgit v1.2.1 From 049542483398c47d0bb142d16ba6487f2a6c4e34 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 27 Mar 2017 19:44:11 +0000 Subject: Fix comment in lsan_linux.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298879 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsan/lsan_linux.cc b/lib/lsan/lsan_linux.cc index 616c06c75..944551c77 100644 --- a/lib/lsan/lsan_linux.cc +++ b/lib/lsan/lsan_linux.cc @@ -22,5 +22,5 @@ AllocatorCache *GetAllocatorCache() { return &allocator_cache; } } // namespace __lsan -#endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX +#endif // SANITIZER_LINUX -- cgit v1.2.1 From 7af31ae824382d704e68daf4ef7478fe11433d00 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 27 Mar 2017 20:22:02 +0000 Subject: Fix missing sanitizer platform include git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298884 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_linux.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/lsan/lsan_linux.cc b/lib/lsan/lsan_linux.cc index 944551c77..c0b6f4b65 100644 --- a/lib/lsan/lsan_linux.cc +++ b/lib/lsan/lsan_linux.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_platform.h" + #if SANITIZER_LINUX #include "lsan_allocator.h" @@ -23,4 +25,3 @@ AllocatorCache *GetAllocatorCache() { return &allocator_cache; } } // namespace __lsan #endif // SANITIZER_LINUX - -- cgit v1.2.1 From e6100317e73d09436ac5a2ff8b31cc847f8007b1 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Mon, 27 Mar 2017 23:57:44 +0000 Subject: Reland "[Compiler-rt][Builtins] Implement lit-test support (part 2 of 2)" Re-land of r298714 which got reverted in r298868. It looks like the current lit tests won't run for Apple. Possible reason is the libname is different. (need to update the base_lib variable of lit.cfg) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298892 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/CMakeLists.txt | 20 ++++++++++ test/builtins/Unit/lit.cfg | 80 ++++++++++++++++++++++++++++++++++++++ test/builtins/Unit/lit.site.cfg.in | 12 ++++++ 3 files changed, 112 insertions(+) create mode 100644 test/builtins/Unit/lit.cfg create mode 100644 test/builtins/Unit/lit.site.cfg.in diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index 443e552f8..fa7a0f4ad 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -9,6 +9,26 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg ) +#Unit tests. + +include(builtin-config-ix) + +#TODO: Add support for Apple. +if (NOT APPLE) +foreach(arch ${BUILTIN_SUPPORTED_ARCH}) + set(BUILTINS_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}-${OS_NAME}" BUILTINS_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} BUILTINS_TEST_TARGET_CC BUILTINS_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}/lit.site.cfg + ) + list(APPEND BUILTINS_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${CONFIG_NAME}) +endforeach() +endif() + add_lit_testsuite(check-builtins "Running the Builtins tests" ${BUILTINS_TESTSUITES} DEPENDS ${BUILTINS_TEST_DEPS}) diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg new file mode 100644 index 000000000..f29f7e00d --- /dev/null +++ b/test/builtins/Unit/lit.cfg @@ -0,0 +1,80 @@ +# -*- Python -*- + +import os +import platform + +import lit.formats + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +# Setup config name. +config.name = 'Builtins' + config.name_suffix + +# Platform-specific default Builtins_OPTIONS for lit tests. +default_builtins_opts = '' + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Path to the static library +base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a " + % config.target_arch) + +builtins_source_dir = os.path.join( + get_required_attr(config, "compiler_rt_src_root"), "lib", "builtins") +builtins_lit_source_dir = get_required_attr(config, "builtins_lit_source_dir") + +extra_link_flags = ["-nodefaultlibs"] +config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') ) + +target_cflags = [get_required_attr(config, "target_cflags")] +target_cflags += ['-fno-builtin', '-I', builtins_source_dir] +target_cflags += extra_link_flags +target_cxxflags = config.cxx_mode_flags + target_cflags +clang_builtins_static_cflags = ([""] + + config.debug_info_flags + target_cflags) +clang_builtins_static_cxxflags = config.cxx_mode_flags + \ + clang_builtins_static_cflags + +clang_builtins_cflags = clang_builtins_static_cflags +clang_builtins_cxxflags = clang_builtins_static_cxxflags + + +config.available_features.add('not-android') +clang_wrapper = "" + +def build_invocation(compile_flags): + return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " " + + +target_arch = config.target_arch +if (target_arch == "arm"): + target_arch = "armv7" + +config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) +config.substitutions.append( ("%clang_builtins ", \ + build_invocation(clang_builtins_cflags))) +config.substitutions.append( ("%clangxx_builtins ", \ + build_invocation(clang_builtins_cxxflags))) + +# FIXME: move the call_apsr.s into call_apsr.h as inline-asm. +# some ARM tests needs call_apsr.s +call_apsr_source = os.path.join(builtins_lit_source_dir, 'arm', 'call_apsr.S') +march_flag = '-march=' + target_arch +call_apsr_flags = ['-c', march_flag, call_apsr_source] +config.substitutions.append( ("%arm_call_apsr ", \ + build_invocation(call_apsr_flags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +if not config.emulator: + config.available_features.add('native-run') diff --git a/test/builtins/Unit/lit.site.cfg.in b/test/builtins/Unit/lit.site.cfg.in new file mode 100644 index 000000000..4b4009d1e --- /dev/null +++ b/test/builtins/Unit/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +config.name_suffix = "@BUILTINS_TEST_CONFIG_SUFFIX@" +config.builtins_lit_source_dir = "@BUILTINS_LIT_SOURCE_DIR@/Unit" +config.target_cflags = "@BUILTINS_TEST_TARGET_CFLAGS@" +config.target_arch = "@BUILTINS_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@BUILTINS_LIT_SOURCE_DIR@/Unit/lit.cfg") -- cgit v1.2.1 From 1e39eaad45fc92b49e189badf0a5a675fbfb4ad0 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 28 Mar 2017 21:56:44 +0000 Subject: Enable i386 builds for darwin lsan Summary: Now that __thread is no longer used for lsan on darwin, i386 builds can be enabled. Reviewers: kcc, kubamracek Subscribers: danalbert, srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D29995 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298946 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 10 +--------- lib/lsan/lsan_common.h | 8 +++++--- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 6 ++++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 027b22646..e61a4f146 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -164,15 +164,7 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) - -# Darwin does not support 32-bit thread-local storage on ios versions -# below 9.0. Until the min ios version is bumped to 9.0, lsan will -# not build for 32-bit darwin targets. -if(APPLE) - set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${ARM64}) -else() - set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) -endif() +set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64} ${MIPS32} ${MIPS64} ${S390X}) diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index c457d1b84..cb8126aa5 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -30,12 +30,14 @@ // To enable LeakSanitizer on new architecture, one need to implement // internal_clone function as well as (probably) adjust TLS machinery for // new architecture inside sanitizer library. -#if (SANITIZER_LINUX && !SANITIZER_ANDROID || CAN_SANITIZE_LEAKS_MAC) \ - && (SANITIZER_WORDSIZE == 64) && (defined(__x86_64__) \ - || defined(__mips64) || defined(__aarch64__)) +#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) && \ + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) #define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_LINUX && !SANITIZER_ANDROID && defined(__i386__) #define CAN_SANITIZE_LEAKS 1 +#elif CAN_SANITIZE_LEAKS_MAC && (defined(__x86_64__) || defined(__mips64) || \ + defined(__aarch64__) || defined(__i386__)) +#define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 #endif diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 4cccc295e..a7aa2f06c 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -13,7 +13,8 @@ #include "sanitizer_platform.h" -#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) +#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ + defined(__mips64) || defined(__i386)) #include "sanitizer_stoptheworld.h" @@ -35,4 +36,5 @@ uptr SuspendedThreadsList::RegisterCount() { } } // namespace __sanitizer -#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) +#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || + // defined(__mips64) || defined(__i386)) -- cgit v1.2.1 From 4d2e2402a0106a7f45fd00c5a7708d786ee19217 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 28 Mar 2017 21:56:45 +0000 Subject: Postpone lsan tls allocation until required Summary: This prevents InternalAlloc from being called before the sanitizers are fully initialized. Reviewers: kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31306 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298947 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index f70ebdd0e..32d0c97a4 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -35,11 +35,11 @@ static pthread_once_t key_once = PTHREAD_ONCE_INIT; static void make_tls_key() { CHECK_EQ(pthread_key_create(&key, NULL), 0); } -static thread_local_data_t *get_tls_val() { +static thread_local_data_t *get_tls_val(bool alloc) { pthread_once(&key_once, make_tls_key); thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key); - if (ptr == NULL) { + if (ptr == NULL && alloc) { ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr)); ptr->disable_counter = 0; ptr->current_thread_id = kInvalidTid; @@ -50,23 +50,26 @@ static thread_local_data_t *get_tls_val() { return ptr; } -bool DisabledInThisThread() { return get_tls_val()->disable_counter > 0; } +bool DisabledInThisThread() { + thread_local_data_t *data = get_tls_val(false); + return data ? data->disable_counter > 0 : false; +} -void DisableInThisThread() { ++get_tls_val()->disable_counter; } +void DisableInThisThread() { ++get_tls_val(true)->disable_counter; } void EnableInThisThread() { - int *disable_counter = &get_tls_val()->disable_counter; + int *disable_counter = &get_tls_val(true)->disable_counter; if (*disable_counter == 0) { DisableCounterUnderflow(); } --*disable_counter; } -u32 GetCurrentThread() { return get_tls_val()->current_thread_id; } +u32 GetCurrentThread() { return get_tls_val(true)->current_thread_id; } -void SetCurrentThread(u32 tid) { get_tls_val()->current_thread_id = tid; } +void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } -AllocatorCache *GetAllocatorCache() { return &get_tls_val()->cache; } +AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; } void InitializePlatformSpecificModules() { CHECK(0 && "unimplemented"); -- cgit v1.2.1 From 260f2c513bdffce646c53abc285fb1343afc9719 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Wed, 29 Mar 2017 03:36:46 +0000 Subject: [Builtin] Unxfail tests for armhf Summary: Originally, a few tests fail for armhf target due to: 1) COMPILER_RT_ARMHF_TARGET was not set when building the lib 2) COMPILER_RT_ABI should not be defined as `__attribute__((pcs("aapcs")))` for armhf when building for both lib and tests This address https://bugs.llvm.org//show_bug.cgi?id=32261 mulsc3_test.c is a newly exposed issue, which will be addressed separately. Reviewers: rengolin, compnerd Reviewed By: compnerd Subscribers: aemerson, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D31448 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298974 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 2 +- lib/builtins/int_lib.h | 6 +++++- test/builtins/CMakeLists.txt | 5 +++++ test/builtins/Unit/comparedf2_test.c | 2 -- test/builtins/Unit/comparesf2_test.c | 2 -- test/builtins/Unit/eqdf2vfp_test.c | 2 -- test/builtins/Unit/eqsf2vfp_test.c | 2 -- test/builtins/Unit/fixdfsivfp_test.c | 2 -- test/builtins/Unit/fixsfsivfp_test.c | 2 -- test/builtins/Unit/fixunssfsivfp_test.c | 2 -- test/builtins/Unit/gedf2vfp_test.c | 2 -- test/builtins/Unit/gesf2vfp_test.c | 2 -- test/builtins/Unit/gtdf2vfp_test.c | 2 -- test/builtins/Unit/gtsf2vfp_test.c | 2 -- test/builtins/Unit/ledf2vfp_test.c | 2 -- test/builtins/Unit/lesf2vfp_test.c | 2 -- test/builtins/Unit/ltdf2vfp_test.c | 2 -- test/builtins/Unit/ltsf2vfp_test.c | 2 -- test/builtins/Unit/mulsc3_test.c | 2 ++ test/builtins/Unit/nedf2vfp_test.c | 2 -- test/builtins/Unit/nesf2vfp_test.c | 2 -- test/builtins/Unit/truncdfhf2_test.c | 2 -- test/builtins/Unit/truncdfsf2_test.c | 2 -- test/builtins/Unit/truncsfhf2_test.c | 2 -- test/builtins/Unit/unorddf2vfp_test.c | 2 -- test/builtins/Unit/unordsf2vfp_test.c | 2 -- 26 files changed, 13 insertions(+), 46 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index ad9059c33..3f648dcb3 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -499,7 +499,7 @@ else () # Needed for clear_cache on debug mode, due to r7's usage in inline asm. # Release mode already sets it via -O2/3, Debug mode doesn't. if (${arch} STREQUAL "armhf") - list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer) + list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET) endif() add_compiler_rt_runtime(clang_rt.builtins diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h index 39eee18d9..8a202dde7 100644 --- a/lib/builtins/int_lib.h +++ b/lib/builtins/int_lib.h @@ -32,7 +32,11 @@ #if __ARM_EABI__ # define ARM_EABI_FNALIAS(aeabi_name, name) \ void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); -# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +# ifdef COMPILER_RT_ARMHF_TARGET +# define COMPILER_RT_ABI +# else +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +# endif #else # define ARM_EABI_FNALIAS(aeabi_name, name) # define COMPILER_RT_ABI diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index fa7a0f4ad..f37e46d3a 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -19,6 +19,11 @@ foreach(arch ${BUILTIN_SUPPORTED_ARCH}) set(BUILTINS_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}-${OS_NAME}" BUILTINS_TEST_CONFIG_SUFFIX) get_test_cc_for_arch(${arch} BUILTINS_TEST_TARGET_CC BUILTINS_TEST_TARGET_CFLAGS) + if (${arch} STREQUAL "armhf") + list(APPEND BUILTINS_TEST_TARGET_CFLAGS -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET) + string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}") + endif() + string(TOUPPER ${arch} ARCH_UPPER_CASE) set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) configure_lit_site_cfg( diff --git a/test/builtins/Unit/comparedf2_test.c b/test/builtins/Unit/comparedf2_test.c index a7db7a433..844690197 100644 --- a/test/builtins/Unit/comparedf2_test.c +++ b/test/builtins/Unit/comparedf2_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- cmpdf2_test.c - Test __cmpdf2 -------------------------------------===// // diff --git a/test/builtins/Unit/comparesf2_test.c b/test/builtins/Unit/comparesf2_test.c index 9f42d9784..1b5902f37 100644 --- a/test/builtins/Unit/comparesf2_test.c +++ b/test/builtins/Unit/comparesf2_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- cmpsf2_test.c - Test __cmpsf2 -------------------------------------===// // diff --git a/test/builtins/Unit/eqdf2vfp_test.c b/test/builtins/Unit/eqdf2vfp_test.c index 549c37e1a..69dd37b8f 100644 --- a/test/builtins/Unit/eqdf2vfp_test.c +++ b/test/builtins/Unit/eqdf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- eqdf2vfp_test.c - Test __eqdf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/eqsf2vfp_test.c b/test/builtins/Unit/eqsf2vfp_test.c index 628b0fd75..9c8dc1659 100644 --- a/test/builtins/Unit/eqsf2vfp_test.c +++ b/test/builtins/Unit/eqsf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- eqsf2vfp_test.c - Test __eqsf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/fixdfsivfp_test.c b/test/builtins/Unit/fixdfsivfp_test.c index 3cd420aa6..33b4d2408 100644 --- a/test/builtins/Unit/fixdfsivfp_test.c +++ b/test/builtins/Unit/fixdfsivfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- fixdfsivfp_test.c - Test __fixdfsivfp -----------------------------===// // diff --git a/test/builtins/Unit/fixsfsivfp_test.c b/test/builtins/Unit/fixsfsivfp_test.c index 0e233a5f8..ee33a1dc9 100644 --- a/test/builtins/Unit/fixsfsivfp_test.c +++ b/test/builtins/Unit/fixsfsivfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- fixsfsivfp_test.c - Test __fixsfsivfp -----------------------------===// // diff --git a/test/builtins/Unit/fixunssfsivfp_test.c b/test/builtins/Unit/fixunssfsivfp_test.c index f745d6f55..c1d8ed77f 100644 --- a/test/builtins/Unit/fixunssfsivfp_test.c +++ b/test/builtins/Unit/fixunssfsivfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- fixunssfsivfp_test.c - Test __fixunssfsivfp -----------------------===// // diff --git a/test/builtins/Unit/gedf2vfp_test.c b/test/builtins/Unit/gedf2vfp_test.c index 17cca9f22..ad72083b4 100644 --- a/test/builtins/Unit/gedf2vfp_test.c +++ b/test/builtins/Unit/gedf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- gedf2vfp_test.c - Test __gedf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/gesf2vfp_test.c b/test/builtins/Unit/gesf2vfp_test.c index 240880acb..8a855e12f 100644 --- a/test/builtins/Unit/gesf2vfp_test.c +++ b/test/builtins/Unit/gesf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- gesf2vfp_test.c - Test __gesf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/gtdf2vfp_test.c b/test/builtins/Unit/gtdf2vfp_test.c index 9180ec248..e6eb545db 100644 --- a/test/builtins/Unit/gtdf2vfp_test.c +++ b/test/builtins/Unit/gtdf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- gtdf2vfp_test.c - Test __gtdf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/gtsf2vfp_test.c b/test/builtins/Unit/gtsf2vfp_test.c index 52e77fee2..e0442c6cd 100644 --- a/test/builtins/Unit/gtsf2vfp_test.c +++ b/test/builtins/Unit/gtsf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- gtsf2vfp_test.c - Test __gtsf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/ledf2vfp_test.c b/test/builtins/Unit/ledf2vfp_test.c index b24832377..f0cd56eab 100644 --- a/test/builtins/Unit/ledf2vfp_test.c +++ b/test/builtins/Unit/ledf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- ledf2vfp_test.c - Test __ledf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/lesf2vfp_test.c b/test/builtins/Unit/lesf2vfp_test.c index c8ca59045..02ae182e6 100644 --- a/test/builtins/Unit/lesf2vfp_test.c +++ b/test/builtins/Unit/lesf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- lesf2vfp_test.c - Test __lesf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/ltdf2vfp_test.c b/test/builtins/Unit/ltdf2vfp_test.c index 238a6f07c..1edb319d4 100644 --- a/test/builtins/Unit/ltdf2vfp_test.c +++ b/test/builtins/Unit/ltdf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- ltdf2vfp_test.c - Test __ltdf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/ltsf2vfp_test.c b/test/builtins/Unit/ltsf2vfp_test.c index 837e0a800..2fc0c1127 100644 --- a/test/builtins/Unit/ltsf2vfp_test.c +++ b/test/builtins/Unit/ltsf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- ltsf2vfp_test.c - Test __ltsf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c index 4eac07e8d..6b38908fc 100644 --- a/test/builtins/Unit/mulsc3_test.c +++ b/test/builtins/Unit/mulsc3_test.c @@ -1,4 +1,6 @@ // RUN: %clang_builtins %s %librt -lm -o %t && %run %t +// XFAIL: armhf-target-arch +// See pr32261 //===-- mulsc3_test.c - Test __mulsc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/nedf2vfp_test.c b/test/builtins/Unit/nedf2vfp_test.c index 46bca5ae9..536917af3 100644 --- a/test/builtins/Unit/nedf2vfp_test.c +++ b/test/builtins/Unit/nedf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- nedf2vfp_test.c - Test __nedf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/nesf2vfp_test.c b/test/builtins/Unit/nesf2vfp_test.c index b6491700a..bb0149087 100644 --- a/test/builtins/Unit/nesf2vfp_test.c +++ b/test/builtins/Unit/nesf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- nesf2vfp_test.c - Test __nesf2vfp ---------------------------------===// // diff --git a/test/builtins/Unit/truncdfhf2_test.c b/test/builtins/Unit/truncdfhf2_test.c index 94595fc97..b172811a1 100644 --- a/test/builtins/Unit/truncdfhf2_test.c +++ b/test/builtins/Unit/truncdfhf2_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===--------------- truncdfhf2_test.c - Test __truncdfhf2 ----------------===// // diff --git a/test/builtins/Unit/truncdfsf2_test.c b/test/builtins/Unit/truncdfsf2_test.c index a692edee8..04bebf4c6 100644 --- a/test/builtins/Unit/truncdfsf2_test.c +++ b/test/builtins/Unit/truncdfsf2_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===--------------- truncdfsf2_test.c - Test __truncdfsf2 ----------------===// // diff --git a/test/builtins/Unit/truncsfhf2_test.c b/test/builtins/Unit/truncsfhf2_test.c index b83d8fd8a..2240c14a5 100644 --- a/test/builtins/Unit/truncsfhf2_test.c +++ b/test/builtins/Unit/truncsfhf2_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===--------------- truncsfhf2_test.c - Test __truncsfhf2 ----------------===// // diff --git a/test/builtins/Unit/unorddf2vfp_test.c b/test/builtins/Unit/unorddf2vfp_test.c index 7fe3894bc..21938d044 100644 --- a/test/builtins/Unit/unorddf2vfp_test.c +++ b/test/builtins/Unit/unorddf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- unorddf2vfp_test.c - Test __unorddf2vfp ---------------------------===// // diff --git a/test/builtins/Unit/unordsf2vfp_test.c b/test/builtins/Unit/unordsf2vfp_test.c index 670d3351b..712665294 100644 --- a/test/builtins/Unit/unordsf2vfp_test.c +++ b/test/builtins/Unit/unordsf2vfp_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: armhf-target-arch -// This test fails for armhf (see pr32261) //===-- unordsf2vfp_test.c - Test __unordsf2vfp ---------------------------===// // -- cgit v1.2.1 From 8b987788165d15b1c5980751392c179defa86ab7 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 29 Mar 2017 05:19:24 +0000 Subject: [XRay][compiler-rt] Add an end-to-end test for FDR Logging Summary: This change exercises the end-to-end functionality defined in the FDR logging implementation. We also prepare for being able to run traces generated by the FDR logging implementation from being analysed with the llvm-xray command that comes with the LLVM distribution. This also unblocks D31385, D31384, and D31345. Reviewers: kpw, pelikan Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D31452 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298977 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/CMakeLists.txt | 3 +- include/xray/xray_log_interface.h | 9 +++++ lib/xray/xray_fdr_logging.cc | 19 +++++------ lib/xray/xray_fdr_logging.h | 8 ----- lib/xray/xray_log_interface.cc | 5 +-- lib/xray/xray_utils.cc | 5 +-- test/xray/TestCases/Linux/fdr-mode.cc | 62 +++++++++++++++++++++++++++++++++++ test/xray/lit.cfg | 5 +++ 8 files changed, 91 insertions(+), 25 deletions(-) create mode 100644 test/xray/TestCases/Linux/fdr-mode.cc diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 6104aded2..3d6c96be9 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -12,7 +12,8 @@ set(SANITIZER_HEADERS sanitizer/tsan_interface_atomic.h) set(XRAY_HEADERS - xray/xray_interface.h) + xray/xray_interface.h + xray/xray_log_interface.h) set(COMPILER_RT_HEADERS ${SANITIZER_HEADERS} diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h index f98b33110..a8709c3a7 100644 --- a/include/xray/xray_log_interface.h +++ b/include/xray/xray_log_interface.h @@ -48,4 +48,13 @@ XRayLogFlushStatus __xray_log_flushLog(); } // extern "C" +namespace __xray { +// Options used by the LLVM XRay FDR implementation. +struct FDRLoggingOptions { + bool ReportErrors = false; + int Fd = -1; +}; + +} // namespace __xray + #endif // XRAY_XRAY_LOG_INTERFACE_H diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index df95c1d66..a86cf0b14 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -51,19 +51,18 @@ std::unique_ptr FDROptions; XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, void *Options, size_t OptionsSize) XRAY_NEVER_INSTRUMENT { - assert(OptionsSize == sizeof(FDRLoggingOptions)); + if (OptionsSize != sizeof(FDRLoggingOptions)) + return static_cast(__sanitizer::atomic_load( + &LoggingStatus, __sanitizer::memory_order_acquire)); s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LoggingStatus, &CurrentStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZING, __sanitizer::memory_order_release)) return static_cast(CurrentStatus); FDROptions.reset(new FDRLoggingOptions()); - *FDROptions = *reinterpret_cast(Options); - if (FDROptions->ReportErrors) - SetPrintfAndReportCallback(printToStdErr); - + memcpy(FDROptions.get(), Options, OptionsSize); bool Success = false; BQ = std::make_shared(BufferSize, BufferMax, Success); if (!Success) { @@ -77,6 +76,7 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, __sanitizer::atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZED, __sanitizer::memory_order_release); + Report("XRay FDR init successful.\n"); return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } @@ -88,7 +88,7 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LogFlushStatus, &Result, XRayLogFlushStatus::XRAY_LOG_FLUSHING, __sanitizer::memory_order_release)) return static_cast(Result); @@ -140,7 +140,7 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT { s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LoggingStatus, &CurrentStatus, XRayLogInitStatus::XRAY_LOG_FINALIZING, __sanitizer::memory_order_release)) @@ -168,8 +168,7 @@ XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { BQ.reset(); // Spin until the flushing status is flushed. - s32 CurrentFlushingStatus = - XRayLogFlushStatus::XRAY_LOG_FLUSHED; + s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; while (__sanitizer::atomic_compare_exchange_weak( &LogFlushStatus, &CurrentFlushingStatus, XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, diff --git a/lib/xray/xray_fdr_logging.h b/lib/xray/xray_fdr_logging.h index 93c33b417..426b54dc7 100644 --- a/lib/xray/xray_fdr_logging.h +++ b/lib/xray/xray_fdr_logging.h @@ -26,14 +26,6 @@ // default mode of always writing fixed-size records. namespace __xray { - -// Options used by the FDR implementation. -struct FDRLoggingOptions { - bool ReportErrors = false; - int Fd = -1; -}; - -// Flight Data Recorder mode implementation interfaces. XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, size_t OptionsSize); XRayLogInitStatus fdrLoggingFinalize(); diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc index 8fb6e3919..ffed601c0 100644 --- a/lib/xray/xray_log_interface.cc +++ b/lib/xray/xray_log_interface.cc @@ -35,8 +35,9 @@ void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT { *GlobalXRayImpl = Impl; } -XRayLogInitStatus __xray_init(size_t BufferSize, size_t MaxBuffers, void *Args, - size_t ArgsSize) XRAY_NEVER_INSTRUMENT { +XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, + void *Args, + size_t ArgsSize) XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; diff --git a/lib/xray/xray_utils.cc b/lib/xray/xray_utils.cc index 5d6390c80..b9a38d1b9 100644 --- a/lib/xray/xray_utils.cc +++ b/lib/xray/xray_utils.cc @@ -93,8 +93,6 @@ bool readValueFromFile(const char *Filename, } int getLogFD() XRAY_NEVER_INSTRUMENT { - // FIXME: Figure out how to make this less stderr-dependent. - SetPrintfAndReportCallback(printToStdErr); // Open a temporary file once for the log. static char TmpFilename[256] = {}; static char TmpWildcardPattern[] = "XXXXXX"; @@ -119,8 +117,7 @@ int getLogFD() XRAY_NEVER_INSTRUMENT { TmpFilename); return -1; } - if (Verbosity()) - fprintf(stderr, "XRay: Log file in '%s'\n", TmpFilename); + Report("XRay: Log file in '%s'\n", TmpFilename); return Fd; } diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc new file mode 100644 index 000000000..88660802e --- /dev/null +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -0,0 +1,62 @@ +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s +// FIXME: %llvm_xray convert -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: rm fdr-logging-test-* + +#include "xray/xray_log_interface.h" +#include +#include +#include +#include +#include +#include +#include + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +thread_local uint64_t var = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) fC() { ++var; } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fB() { fC(); } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fA() { fB(); } + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Options; + std::cout << "Logging before init." << std::endl; + // CHECK: Logging before init. + auto status = __xray_log_init(kBufferSize, kBufferMax, &Options, + sizeof(FDRLoggingOptions)); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + std::cout << "Init status " << status << std::endl; + // CHECK: Init status {{.*}} + std::cout << "Patching..." << std::endl; + // CHECK: Patching... + __xray_patch(); + fA(); + fC(); + fB(); + fA(); + fC(); + std::thread other_thread([]() { + fC(); + fB(); + fA(); + }); + other_thread.join(); + std::cout << "Joined" << std::endl; + // CHECK: Joined + std::cout << "Finalize status " << __xray_log_finalize() << std::endl; + // CHECK: Finalize status {{.*}} + fC(); + std::cout << "Main execution var = " << var << std::endl; + // CHECK: Main execution var = 6 + std::cout << "Flush status " << __xray_log_flushLog() << std::endl; + // CHECK: Flush status {{.*}} + __xray_unpatch(); + return 0; +} + +// TRACE: { function } diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg index 9142ad136..b07dcbd79 100644 --- a/test/xray/lit.cfg +++ b/test/xray/lit.cfg @@ -16,6 +16,9 @@ clang_xray_cxxflags = config.cxx_mode_flags + clang_xray_cflags def build_invocation(compile_flags): return ' ' + ' '.join([config.clang] + compile_flags) + ' ' +# Assume that llvm-xray is in the config.llvm_tools_dir. +llvm_xray = os.path.join(config.llvm_tools_dir, 'llvm-xray') + # Setup substitutions. config.substitutions.append( ('%clang ', build_invocation([config.target_cflags]))) @@ -26,6 +29,8 @@ config.substitutions.append( ('%clang_xray ', build_invocation(clang_xray_cflags))) config.substitutions.append( ('%clangxx_xray', build_invocation(clang_xray_cxxflags))) +config.substitutions.append( + ('%llvm_xray', llvm_xray)) # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -- cgit v1.2.1 From eacaa8fb837ccbfb65e100a6c12259c78428f3b1 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 29 Mar 2017 05:56:37 +0000 Subject: [XRay] [compiler-rt] Write buffer length to FDR log before writing buffer. Summary: Currently the FDR log writer, upon flushing, dumps a sequence of buffers from its freelist to disk. A reader can read the first buffer up to an EOB record, but then it is unclear how far ahead to scan to find the next threads traces. There are a few ways to handle this problem. 1. The reader has externalized knowledge of the buffer size. 2. The size of buffers is in the file header or otherwise encoded in the log. 3. Only write out the portion of the buffer with records. When released, the buffers are marked with a size. 4. The reader looks for memory that matches a pattern and synchronizes on it. 2 and 3 seem the most flexible and 2 does not rule 3 out. This is an implementation of 2. In addition, the function handler for fdr more aggressively checks for finalization and makes an attempt to release its buffer. Reviewers: pelikan, dberris Reviewed By: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31384 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298982 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_records.h | 21 +++++++++++++++++---- lib/xray/xray_buffer_queue.h | 3 +++ lib/xray/xray_fdr_logging.cc | 10 +++++++--- lib/xray/xray_fdr_logging_impl.h | 20 +++++++++++++++++--- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/include/xray/xray_records.h b/include/xray/xray_records.h index 71637d1fe..feb8d228b 100644 --- a/include/xray/xray_records.h +++ b/include/xray/xray_records.h @@ -24,6 +24,14 @@ enum FileTypes { FDR_LOG = 1, }; +// FDR mode use of the union field in the XRayFileHeader. +struct alignas(16) FdrAdditionalHeaderData { + uint64_t ThreadBufferSize; +}; + +static_assert(sizeof(FdrAdditionalHeaderData) == 16, + "FdrAdditionalHeaderData != 16 bytes"); + // This data structure is used to describe the contents of the file. We use this // for versioning the supported XRay file formats. struct alignas(32) XRayFileHeader { @@ -42,10 +50,15 @@ struct alignas(32) XRayFileHeader { // The frequency by which TSC increases per-second. alignas(8) uint64_t CycleFrequency = 0; - // The current civiltime timestamp, as retrived from 'clock_gettime'. This - // allows readers of the file to determine when the file was created or - // written down. - struct timespec TS; + union { + char FreeForm[16]; + // The current civiltime timestamp, as retrived from 'clock_gettime'. This + // allows readers of the file to determine when the file was created or + // written down. + struct timespec TS; + + struct FdrAdditionalHeaderData FdrData; + }; } __attribute__((packed)); static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes"); diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 28a622069..e051695a2 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -98,6 +98,9 @@ public: __sanitizer::memory_order_acquire); } + /// Returns the configured size of the buffers in the buffer queue. + size_t ConfiguredBufferSize() const { return BufferSize; } + /// Sets the state of the BufferQueue to finalizing, which ensures that: /// /// - All subsequent attempts to retrieve a Buffer will fail. diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index a86cf0b14..ba1a6ab2c 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -125,12 +125,16 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { // before setting the values in the header. Header.ConstantTSC = 1; Header.NonstopTSC = 1; - clock_gettime(CLOCK_REALTIME, &Header.TS); + Header.FdrData = FdrAdditionalHeaderData{LocalBQ->ConfiguredBufferSize()}; retryingWriteAll(Fd, reinterpret_cast(&Header), reinterpret_cast(&Header) + sizeof(Header)); + LocalBQ->apply([&](const BufferQueue::Buffer &B) { - retryingWriteAll(Fd, reinterpret_cast(B.Buffer), - reinterpret_cast(B.Buffer) + B.Size); + uint64_t BufferSize = B.Size; + if (BufferSize > 0) { + retryingWriteAll(Fd, reinterpret_cast(B.Buffer), + reinterpret_cast(B.Buffer) + B.Size); + } }); __sanitizer::atomic_store(&LogFlushStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index caeb27411..b0b2a7340 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -311,10 +311,24 @@ static inline void processFunctionHook( __sanitizer::atomic_sint32_t &LoggingStatus, const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { // Bail out right away if logging is not initialized yet. - if (__sanitizer::atomic_load(&LoggingStatus, - __sanitizer::memory_order_acquire) != - XRayLogInitStatus::XRAY_LOG_INITIALIZED) + // We should take the opportunity to release the buffer though. + auto Status = __sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire); + if (Status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { + if (RecordPtr != nullptr && + (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || + Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { + writeEOBMetadata(); + auto EC = BQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + BufferQueue::getErrorString(EC)); + return; + } + RecordPtr = nullptr; + } return; + } // We use a thread_local variable to keep track of which CPUs we've already // run, and the TSC times for these CPUs. This allows us to stop repeating the -- cgit v1.2.1 From 897c2d32c22efc3ce5e9b3753166c51d3ad415cc Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Wed, 29 Mar 2017 14:55:51 +0000 Subject: [Compiler-RT][Builtins] Remove XFAIL for mulsc3; NFC It was XFAILed in r298974. However, the problem was not exposed on the buildbot because hardfp flag was not passed during the test. We can fix the CMAKE to pass the same flag as building the lib to the RUN line to see if the problem is still there. For now, we remove the XFAIL. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@298997 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/mulsc3_test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/builtins/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c index 6b38908fc..4eac07e8d 100644 --- a/test/builtins/Unit/mulsc3_test.c +++ b/test/builtins/Unit/mulsc3_test.c @@ -1,6 +1,4 @@ // RUN: %clang_builtins %s %librt -lm -o %t && %run %t -// XFAIL: armhf-target-arch -// See pr32261 //===-- mulsc3_test.c - Test __mulsc3 -------------------------------------===// // // The LLVM Compiler Infrastructure -- cgit v1.2.1 From b78c5b858d7bf07dfa2eceb9bcdc917f06bb45cc Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Wed, 29 Mar 2017 16:59:09 +0000 Subject: [Builtins] Mark mulsc3_test as UNSUPPORTED for armhf; NFC The same test fails on clang-cmake-armv7-a15-full biuld bot but passes the clang-cmake-thumbv7-a15-full. For now, we mark it as UNSUPPORTED for armhf target. Bug 32457 tracks it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299005 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/mulsc3_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/builtins/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c index 4eac07e8d..b14e237d3 100644 --- a/test/builtins/Unit/mulsc3_test.c +++ b/test/builtins/Unit/mulsc3_test.c @@ -1,4 +1,6 @@ // RUN: %clang_builtins %s %librt -lm -o %t && %run %t +// UNSUPPORTED: armhf-target-arch +// see pr 32475. //===-- mulsc3_test.c - Test __mulsc3 -------------------------------------===// // // The LLVM Compiler Infrastructure -- cgit v1.2.1 From 195832b0e60dd84e5ca89840a1a324506e46d07f Mon Sep 17 00:00:00 2001 From: Filipe Cabecinhas Date: Wed, 29 Mar 2017 18:17:22 +0000 Subject: Add allocator_frees_and_returns_null_on_realloc_zero=false flag for compatibility with allocators which allow a realloc(p, 0) and don't free the pointer. Summary: I know of two implementations that do this (ASan is not protecting against accessing the returned memory for now, just like malloc(0)): SIE libc on the PS4 dlmalloc has a flag for this This allows us to properly support this behaviour. Reviewers: vsk, kcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31295 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299016 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 8 ++++++-- lib/asan/asan_flags.inc | 4 ++++ test/asan/TestCases/realloc.cc | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 test/asan/TestCases/realloc.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 4be1f1ce2..6db2b4db5 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -800,8 +800,12 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { if (!p) return instance.Allocate(size, 8, stack, FROM_MALLOC, true); if (size == 0) { - instance.Deallocate(p, 0, stack, FROM_MALLOC); - return nullptr; + if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { + instance.Deallocate(p, 0, stack, FROM_MALLOC); + return nullptr; + } + // Allocate a size of 1 if we shouldn't free() on Realloc to 0 + size = 1; } return instance.Reallocate(p, size, stack); } diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 4712efb86..f316afdb3 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -148,3 +148,7 @@ ASAN_FLAG(bool, halt_on_error, true, "(WARNING: USE AT YOUR OWN RISK!)") ASAN_FLAG(bool, use_odr_indicator, false, "Use special ODR indicator symbol for ODR violation detection") +ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, + "realloc(p, 0) is equivalent to free(p) by default (Same as the " + "POSIX standard). If set to false, realloc(p, 0) will return a " + "pointer to an allocated space which can not be used.") diff --git a/test/asan/TestCases/realloc.cc b/test/asan/TestCases/realloc.cc new file mode 100644 index 000000000..fcf383b1a --- /dev/null +++ b/test/asan/TestCases/realloc.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// Default is true (free on realloc to 0 size) +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=allocator_frees_and_returns_null_on_realloc_zero=true %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=allocator_frees_and_returns_null_on_realloc_zero=false %run %t 2>&1 | FileCheck %s --check-prefix=NO-FREE + +#include +#include + +int main() { + void *p = malloc(42); + p = realloc(p, 0); + if (p) { + // NO-FREE: Allocated something on realloc(p, 0) + fprintf(stderr, "Allocated something on realloc(p, 0)\n"); + } else { + // CHECK: realloc(p, 0) returned nullptr + fprintf(stderr, "realloc(p, 0) returned nullptr\n"); + } + free(p); +} -- cgit v1.2.1 From 6e194c2470701a559e8955334e927720bf379799 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 29 Mar 2017 21:49:13 +0000 Subject: Remove failing check from platform specific darwin lsan initializer Summary: We currently don't have any platform specific darwin lsan modules, don't force failure if they don't exist. Reviewers: kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31473 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299031 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 32d0c97a4..5fd2b89af 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -71,9 +71,9 @@ void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; } -void InitializePlatformSpecificModules() { - CHECK(0 && "unimplemented"); -} +// Required on Linux for initialization of TLS behavior, but should not be +// required on Darwin. +void InitializePlatformSpecificModules() {} // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { -- cgit v1.2.1 From 386f8e576672858f5d4f4675675192371db2bae9 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 29 Mar 2017 21:49:47 +0000 Subject: Move current thread data out of lsan_common on linux Summary: Now that we have a platform-specific non-common lsan file, use it to store non-common lsan data. Reviewers: kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31472 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299032 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_linux.cc | 4 ---- lib/lsan/lsan_linux.cc | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 0e10d4191..931b5112a 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -34,10 +34,6 @@ static bool IsLinker(const char* full_name) { return LibraryNameIs(full_name, kLinkerName); } -static THREADLOCAL u32 current_thread_tid = kInvalidTid; -u32 GetCurrentThread() { return current_thread_tid; } -void SetCurrentThread(u32 tid) { current_thread_tid = tid; } - __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } diff --git a/lib/lsan/lsan_linux.cc b/lib/lsan/lsan_linux.cc index c0b6f4b65..a60f7413a 100644 --- a/lib/lsan/lsan_linux.cc +++ b/lib/lsan/lsan_linux.cc @@ -19,6 +19,10 @@ namespace __lsan { +static THREADLOCAL u32 current_thread_tid = kInvalidTid; +u32 GetCurrentThread() { return current_thread_tid; } +void SetCurrentThread(u32 tid) { current_thread_tid = tid; } + static THREADLOCAL AllocatorCache allocator_cache; AllocatorCache *GetAllocatorCache() { return &allocator_cache; } -- cgit v1.2.1 From 4eeb34e26794b216fc5461c72e0d934c6c2ab90b Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 29 Mar 2017 22:59:28 +0000 Subject: =?UTF-8?q?[sanitizers]=20Fix=20get=5Fgroups=20interceptor=20in=20?= =?UTF-8?q?sanitizer=20(https://reviews.llvm.org/D31332,=20patch=20by=20Ma?= =?UTF-8?q?rtin=20Li=C5=A1ka)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299036 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 15 +++++++++++++++ lib/sanitizer_common/sanitizer_common_interceptors.inc | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 6f4dd99b3..59c40d384 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3502,6 +3502,21 @@ TEST(MemorySanitizer, getgroups) { EXPECT_NOT_POISONED(gids[i]); } +TEST(MemorySanitizer, getgroups_zero) { + gid_t group; + int n = getgroups(0, &group); + ASSERT_GE(n, 0); +} + +TEST(MemorySanitizer, getgroups_negative) { + gid_t group; + int n = getgroups(-1, 0); + ASSERT_EQ(-1, n); + + n = getgroups(-1, 0); + ASSERT_EQ(-1, n); +} + TEST(MemorySanitizer, wordexp) { wordexp_t w; int res = wordexp("a b c", &w, 0); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 4f4cd43ab..b4148621d 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3471,7 +3471,8 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) { // its metadata. See // https://github.com/google/sanitizers/issues/321. int res = REAL(getgroups)(size, lst); - if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); + if (res >= 0 && lst && size > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); return res; } #define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups); -- cgit v1.2.1 From a4ebae933f45ec8434bd934a3f7c060d82977745 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 30 Mar 2017 00:35:58 +0000 Subject: [XRay][compiler-rt] Use llvm-xray in FDR mode tests Summary: This change allows us to do an end-to-end test of the FDR mode implementation that uses the llvm-xray tooling to verify that what we are both writing and reading the data in a consistent manner. Reviewers: kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31454 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299042 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 24 +++++++++++++++--- test/xray/TestCases/Linux/fdr-thread-order.cc | 36 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 test/xray/TestCases/Linux/fdr-thread-order.cc diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index 88660802e..0acf04b27 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: %clangxx_xray -g -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s -// FIXME: %llvm_xray convert -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-logging-test-* #include "xray/xray_log_interface.h" @@ -59,4 +59,22 @@ int main(int argc, char *argv[]) { return 0; } -// TRACE: { function } + + +// Check that we're able to see two threads, each entering and exiting fA(). +// TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// +// Do the same as above for fC() +// TRACE-DAG: - { type: 0, func-id: [[FIDC:[0-9]+]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } + +// Do the same as above for fB() +// TRACE-DAG: - { type: 0, func-id: [[FIDB:[0-9]+]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc new file mode 100644 index 000000000..8977dabab --- /dev/null +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -0,0 +1,36 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: rm fdr-thread-order.* +#include "xray/xray_log_interface.h" +#include +#include + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +thread_local uint64_t var = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { ++var; } +[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { ++var; } + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Options; + assert(__xray_log_init(kBufferSize, kBufferMax, &Options, + sizeof(FDRLoggingOptions)) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + __xray_patch(); + std::thread t1([] { f1(); }); + std::thread t2([] { f2(); }); + t1.join(); + t2.join(); + __xray_log_finalize(); + __xray_log_flushLog(); + // CHECK: =={{[0-9]+}}==XRay: Log file in '{{.*}}' +} + +// We want to make sure that the order of the function log doesn't matter. +// TRACE-DAG: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2:[0-9]+]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } -- cgit v1.2.1 From 3f1112dbf71588d2d2f7945f1e219ea4e3b23800 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 00:41:09 +0000 Subject: [asan] Support line numbers in StackVarDescr When -fsanitize-address-use-after-scope is used, the instrumentation produces line numbers in stack frame descriptions. This patch make sure the ASan runtime supports this format (ParseFrameDescription needs to be able to parse "varname:line") and prepares lit tests to allow line numbers in ASan report output. Differential Revision: https://reviews.llvm.org/D31484 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299043 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_descriptions.cc | 3 +++ lib/asan/asan_report.cc | 12 +++++++++-- lib/asan/asan_report.h | 1 + test/asan/TestCases/Linux/memmem_test.cc | 4 ++-- .../asan/TestCases/Posix/stack-use-after-return.cc | 4 ++-- .../asan/TestCases/Windows/dll_intercept_memchr.cc | 2 +- .../asan/TestCases/Windows/dll_intercept_memcpy.cc | 2 +- .../Windows/dll_intercept_memcpy_indirect.cc | 2 +- .../asan/TestCases/Windows/dll_intercept_memset.cc | 2 +- test/asan/TestCases/Windows/dll_noreturn.cc | 2 +- test/asan/TestCases/Windows/dll_poison_unpoison.cc | 2 +- .../Windows/dll_stack_use_after_return.cc | 2 +- .../Windows/dll_thread_stack_array_left_oob.cc | 2 +- test/asan/TestCases/Windows/intercept_memcpy.cc | 2 +- test/asan/TestCases/Windows/intercept_strlen.cc | 2 +- .../asan/TestCases/Windows/stack_array_left_oob.cc | 2 +- .../TestCases/Windows/stack_array_right_oob.cc | 2 +- .../TestCases/Windows/stack_use_after_return.cc | 2 +- .../TestCases/Windows/wrong_downcast_on_stack.cc | 2 +- .../stack-buffer-overflow-with-position.cc | 24 +++++++++++----------- test/asan/TestCases/strcasestr-1.c | 2 +- test/asan/TestCases/strcasestr-2.c | 2 +- test/asan/TestCases/strcspn-1.c | 2 +- test/asan/TestCases/strcspn-2.c | 2 +- test/asan/TestCases/strpbrk-1.c | 2 +- test/asan/TestCases/strpbrk-2.c | 2 +- test/asan/TestCases/strspn-1.c | 2 +- test/asan/TestCases/strspn-2.c | 2 +- test/asan/TestCases/strstr-1.c | 2 +- test/asan/TestCases/strstr-2.c | 2 +- test/asan/TestCases/strtok.c | 10 ++++----- test/asan/TestCases/use-after-scope-inlined.cc | 8 ++++---- 32 files changed, 63 insertions(+), 51 deletions(-) diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc index 0ecbe091c..822a6a62d 100644 --- a/lib/asan/asan_descriptions.cc +++ b/lib/asan/asan_descriptions.cc @@ -252,6 +252,9 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, str.append("%c", var.name_pos[i]); } str.append("'"); + if (var.line > 0) { + str.append(" (line %d)", var.line); + } if (pos_descr) { Decorator d; // FIXME: we may want to also print the size of the access here, diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index cd44ba873..f751b6184 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -88,7 +88,8 @@ bool ParseFrameDescription(const char *frame_descr, char *p; // This string is created by the compiler and has the following form: // "n alloc_1 alloc_2 ... alloc_n" - // where alloc_i looks like "offset size len ObjectName". + // where alloc_i looks like "offset size len ObjectName" + // or "offset size len ObjectName:line". uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); if (n_objects == 0) return false; @@ -101,7 +102,14 @@ bool ParseFrameDescription(const char *frame_descr, return false; } p++; - StackVarDescr var = {beg, size, p, len}; + char *colon_pos = internal_strchr(p, ':'); + uptr line = 0; + uptr name_len = len; + if (colon_pos != nullptr && colon_pos < p + len) { + name_len = colon_pos - p; + line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10); + } + StackVarDescr var = {beg, size, p, name_len, line}; vars->push_back(var); p += len; } diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index 5ebfda693..5a3533a31 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -23,6 +23,7 @@ struct StackVarDescr { uptr size; const char *name_pos; uptr name_len; + uptr line; }; // Returns the number of globals close to the provided address and copies diff --git a/test/asan/TestCases/Linux/memmem_test.cc b/test/asan/TestCases/Linux/memmem_test.cc index 661381cdd..a838cb56a 100644 --- a/test/asan/TestCases/Linux/memmem_test.cc +++ b/test/asan/TestCases/Linux/memmem_test.cc @@ -15,10 +15,10 @@ int main(int argc, char **argv) { // A1: AddressSanitizer: stack-buffer-overflow // A1: {{#0.*memmem}} // A1-NEXT: {{#1.*main}} - // A1: 'a1' <== Memory access at offset + // A1: 'a1'{{.*}} <== Memory access at offset // // A2: AddressSanitizer: stack-buffer-overflow // A2: {{#0.*memmem}} - // A2: 'a2' <== Memory access at offset + // A2: 'a2'{{.*}} <== Memory access at offset return res == NULL; } diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index 232f93f89..822d5be94 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -53,11 +53,11 @@ void Func2(char *x) { // CHECK: WRITE of size 1 {{.*}} thread T0 // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]] // CHECK: is located in stack of thread T0 at offset - // CHECK: 'local' <== Memory access at offset {{16|32}} is inside this variable + // CHECK: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}} // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]] // THREAD: is located in stack of thread T{{[1-9]}} at offset - // THREAD: 'local' <== Memory access at offset {{16|32}} is inside this variable + // THREAD: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20 // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24 } diff --git a/test/asan/TestCases/Windows/dll_intercept_memchr.cc b/test/asan/TestCases/Windows/dll_intercept_memchr.cc index 4f794a212..6360cec87 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memchr.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memchr.cc @@ -22,6 +22,6 @@ int test_function() { // CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc -// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc index 736e6969d..a5981fa5b 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc @@ -27,6 +27,6 @@ int test_function() { // CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc:[[@LINE-4]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc -// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc index 4e2890592..f05ee2121 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc @@ -29,6 +29,6 @@ int test_function() { // CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc -// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_intercept_memset.cc b/test/asan/TestCases/Windows/dll_intercept_memset.cc index d4be376f2..4baa0a161 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memset.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memset.cc @@ -27,6 +27,6 @@ int test_function() { // CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc:[[@LINE-4]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc -// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_noreturn.cc b/test/asan/TestCases/Windows/dll_noreturn.cc index 8b5e3d005..2f6f0c755 100644 --- a/test/asan/TestCases/Windows/dll_noreturn.cc +++ b/test/asan/TestCases/Windows/dll_noreturn.cc @@ -17,7 +17,7 @@ void noreturn_f() { // // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: noreturn_f{{.*}}dll_noreturn.cc -// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable +// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable // CHECK-LABEL: SUMMARY } diff --git a/test/asan/TestCases/Windows/dll_poison_unpoison.cc b/test/asan/TestCases/Windows/dll_poison_unpoison.cc index 9b25a126e..6bd58eca2 100644 --- a/test/asan/TestCases/Windows/dll_poison_unpoison.cc +++ b/test/asan/TestCases/Windows/dll_poison_unpoison.cc @@ -30,6 +30,6 @@ int test_function() { // // CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: test_function{{.*}}\dll_poison_unpoison.cc -// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable +// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc index 642871846..b6166d681 100644 --- a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc +++ b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc @@ -22,7 +22,7 @@ int test_function() { // // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: #0 {{.*}} foo{{.*}}dll_stack_use_after_return.cc -// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable +// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable return 0; } diff --git a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc index dc7c7c6ad..75a094e54 100644 --- a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc +++ b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc @@ -16,7 +16,7 @@ DWORD WINAPI thread_proc(void *context) { // CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: thread_proc{{.*}}dll_thread_stack_array_left_oob.cc // -// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable +// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable return 0; } diff --git a/test/asan/TestCases/Windows/intercept_memcpy.cc b/test/asan/TestCases/Windows/intercept_memcpy.cc index 6e45e7fc6..d71333d0b 100644 --- a/test/asan/TestCases/Windows/intercept_memcpy.cc +++ b/test/asan/TestCases/Windows/intercept_memcpy.cc @@ -27,5 +27,5 @@ int main() { // CHECK-NEXT: main {{.*}}intercept_memcpy.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: #0 {{.*}} main -// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable } diff --git a/test/asan/TestCases/Windows/intercept_strlen.cc b/test/asan/TestCases/Windows/intercept_strlen.cc index 928a286be..938e6c9b5 100644 --- a/test/asan/TestCases/Windows/intercept_strlen.cc +++ b/test/asan/TestCases/Windows/intercept_strlen.cc @@ -22,6 +22,6 @@ int main() { // CHECK-NEXT: main {{.*}}intercept_strlen.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: main {{.*}}intercept_strlen.cc -// CHECK: 'str' <== Memory access at offset {{.*}} overflows this variable +// CHECK: 'str'{{.*}} <== Memory access at offset {{.*}} overflows this variable return len < 6; } diff --git a/test/asan/TestCases/Windows/stack_array_left_oob.cc b/test/asan/TestCases/Windows/stack_array_left_oob.cc index 845a1f332..8d601fc8d 100644 --- a/test/asan/TestCases/Windows/stack_array_left_oob.cc +++ b/test/asan/TestCases/Windows/stack_array_left_oob.cc @@ -12,5 +12,5 @@ int main() { // CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}:[[@LINE-3]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}} -// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable +// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable } diff --git a/test/asan/TestCases/Windows/stack_array_right_oob.cc b/test/asan/TestCases/Windows/stack_array_right_oob.cc index a370246aa..721834d1a 100644 --- a/test/asan/TestCases/Windows/stack_array_right_oob.cc +++ b/test/asan/TestCases/Windows/stack_array_right_oob.cc @@ -12,5 +12,5 @@ int main() { // CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}:[[@LINE-3]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}} -// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] overflows this variable +// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] overflows this variable } diff --git a/test/asan/TestCases/Windows/stack_use_after_return.cc b/test/asan/TestCases/Windows/stack_use_after_return.cc index 9c31922af..ca1c142af 100644 --- a/test/asan/TestCases/Windows/stack_use_after_return.cc +++ b/test/asan/TestCases/Windows/stack_use_after_return.cc @@ -18,5 +18,5 @@ int main() { // CHECK: is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: {{#0 0x.* in foo.*stack_use_after_return.cc}} // -// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable +// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable } diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc index 2859ecc52..7848cf3be 100644 --- a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc +++ b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc @@ -20,7 +20,7 @@ int main(void) { // CHECK-NEXT: {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_stack.cc}}:[[@LINE-3]] // CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:[0-9]+]] in frame // CHECK-NEXT: {{#0 0x[0-9a-f]* in main }} -// CHECK: 'p' <== Memory access at offset [[OFFSET]] overflows this variable +// CHECK: 'p'{{.*}} <== Memory access at offset [[OFFSET]] overflows this variable return 0; } diff --git a/test/asan/TestCases/stack-buffer-overflow-with-position.cc b/test/asan/TestCases/stack-buffer-overflow-with-position.cc index 88f5825ba..2a575f775 100644 --- a/test/asan/TestCases/stack-buffer-overflow-with-position.cc +++ b/test/asan/TestCases/stack-buffer-overflow-with-position.cc @@ -30,15 +30,15 @@ int main(int argc, char **argv) { // make sure BBB and CCC are not removed; return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2]; } -// CHECK-m2: 'AAA' <== {{.*}}underflows this variable -// CHECK-m1: 'AAA' <== {{.*}}partially underflows this variable -// CHECK-9: 'AAA' <== {{.*}}partially overflows this variable -// CHECK-10: 'AAA' <== {{.*}}overflows this variable -// CHECK-30: 'BBB' <== {{.*}}underflows this variable -// CHECK-31: 'BBB' <== {{.*}}partially underflows this variable -// CHECK-41: 'BBB' <== {{.*}}partially overflows this variable -// CHECK-42: 'BBB' <== {{.*}}overflows this variable -// CHECK-62: 'CCC' <== {{.*}}underflows this variable -// CHECK-63: 'CCC' <== {{.*}}partially underflows this variable -// CHECK-73: 'CCC' <== {{.*}}partially overflows this variable -// CHECK-74: 'CCC' <== {{.*}}overflows this variable +// CHECK-m2: 'AAA'{{.*}} <== {{.*}}underflows this variable +// CHECK-m1: 'AAA'{{.*}} <== {{.*}}partially underflows this variable +// CHECK-9: 'AAA'{{.*}} <== {{.*}}partially overflows this variable +// CHECK-10: 'AAA'{{.*}} <== {{.*}}overflows this variable +// CHECK-30: 'BBB'{{.*}} <== {{.*}}underflows this variable +// CHECK-31: 'BBB'{{.*}} <== {{.*}}partially underflows this variable +// CHECK-41: 'BBB'{{.*}} <== {{.*}}partially overflows this variable +// CHECK-42: 'BBB'{{.*}} <== {{.*}}overflows this variable +// CHECK-62: 'CCC'{{.*}} <== {{.*}}underflows this variable +// CHECK-63: 'CCC'{{.*}} <== {{.*}}partially underflows this variable +// CHECK-73: 'CCC'{{.*}} <== {{.*}}partially overflows this variable +// CHECK-74: 'CCC'{{.*}} <== {{.*}}overflows this variable diff --git a/test/asan/TestCases/strcasestr-1.c b/test/asan/TestCases/strcasestr-1.c index c38871ea5..dccfbcde7 100644 --- a/test/asan/TestCases/strcasestr-1.c +++ b/test/asan/TestCases/strcasestr-1.c @@ -19,7 +19,7 @@ int main(int argc, char **argv) { char s1[4] = "abC"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strcasestr(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == s1 + 2); return 0; } diff --git a/test/asan/TestCases/strcasestr-2.c b/test/asan/TestCases/strcasestr-2.c index 47fd69225..70de2dda4 100644 --- a/test/asan/TestCases/strcasestr-2.c +++ b/test/asan/TestCases/strcasestr-2.c @@ -20,6 +20,6 @@ int main(int argc, char **argv) { __asan_poison_memory_region ((char *)&s2[2], 2); r = strcasestr(s1, s2); assert(r == 0); - // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable return 0; } diff --git a/test/asan/TestCases/strcspn-1.c b/test/asan/TestCases/strcspn-1.c index 6cda2e210..2a9f7d7fb 100644 --- a/test/asan/TestCases/strcspn-1.c +++ b/test/asan/TestCases/strcspn-1.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s1[4] = "caB"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strcspn(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == 1); return 0; } diff --git a/test/asan/TestCases/strcspn-2.c b/test/asan/TestCases/strcspn-2.c index 8bb4b8a57..a51fb911e 100644 --- a/test/asan/TestCases/strcspn-2.c +++ b/test/asan/TestCases/strcspn-2.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s2[4] = "abc"; __asan_poison_memory_region ((char *)&s2[2], 2); r = strcspn(s1, s2); - // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == 0); return 0; } diff --git a/test/asan/TestCases/strpbrk-1.c b/test/asan/TestCases/strpbrk-1.c index 626e8777e..eb3232678 100644 --- a/test/asan/TestCases/strpbrk-1.c +++ b/test/asan/TestCases/strpbrk-1.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s1[4] = "cab"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strpbrk(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == s1 + 1); return 0; } diff --git a/test/asan/TestCases/strpbrk-2.c b/test/asan/TestCases/strpbrk-2.c index 29f3150e6..1f24656dc 100644 --- a/test/asan/TestCases/strpbrk-2.c +++ b/test/asan/TestCases/strpbrk-2.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s2[4] = "bca"; __asan_poison_memory_region ((char *)&s2[2], 2); r = strpbrk(s1, s2); - // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == s1); return 0; } diff --git a/test/asan/TestCases/strspn-1.c b/test/asan/TestCases/strspn-1.c index b0c40ea4d..5ddb14f50 100644 --- a/test/asan/TestCases/strspn-1.c +++ b/test/asan/TestCases/strspn-1.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s1[4] = "acb"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strspn(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == 1); return 0; } diff --git a/test/asan/TestCases/strspn-2.c b/test/asan/TestCases/strspn-2.c index 4c899108d..d564ef8ae 100644 --- a/test/asan/TestCases/strspn-2.c +++ b/test/asan/TestCases/strspn-2.c @@ -14,7 +14,7 @@ int main(int argc, char **argv) { char s2[5] = "abcd"; __asan_poison_memory_region ((char *)&s2[3], 2); r = strspn(s1, s2); - // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r >= 2); return 0; } diff --git a/test/asan/TestCases/strstr-1.c b/test/asan/TestCases/strstr-1.c index 06a8a8a55..319cff546 100644 --- a/test/asan/TestCases/strstr-1.c +++ b/test/asan/TestCases/strstr-1.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) { char s1[4] = "acb"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strstr(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} {{partially overflows this variable|is inside this variable}} + // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} {{partially overflows this variable|is inside this variable}} assert(r == s1 + 1); return 0; } diff --git a/test/asan/TestCases/strstr-2.c b/test/asan/TestCases/strstr-2.c index 8bc6e9902..4d00c6e63 100644 --- a/test/asan/TestCases/strstr-2.c +++ b/test/asan/TestCases/strstr-2.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) { char s2[4] = "cab"; __asan_poison_memory_region ((char *)&s2[2], 2); r = strstr(s1, s2); - // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable assert(r == 0); return 0; } diff --git a/test/asan/TestCases/strtok.c b/test/asan/TestCases/strtok.c index 37c23ea2d..e1eee89ee 100644 --- a/test/asan/TestCases/strtok.c +++ b/test/asan/TestCases/strtok.c @@ -35,7 +35,7 @@ void test1() { char token_delimiter[2] = "b"; __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, token_delimiter); - // CHECK1:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK1: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable } // Check that we find overflows in the delimiters on the second call (str == NULL) @@ -48,7 +48,7 @@ void test2() { assert(strcmp(token, "a") == 0); __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(NULL, token_delimiter); - // CHECK2:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK2: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable } // Check that we find overflows in the string (only on the first call) with strict_string_checks. @@ -58,7 +58,7 @@ void test3() { char token_delimiter[2] = "b"; __asan_poison_memory_region ((char *)&s[3], 2); token = strtok(s, token_delimiter); - // CHECK3:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK3: 's'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable } // Check that we do not crash when strtok returns NULL with strict_string_checks. @@ -78,7 +78,7 @@ void test5() { __asan_poison_memory_region ((char *)&s[2], 2); __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, token_delimiter); - // CHECK5:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK5: 's'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable } // Check that we find overflows in the delimiters (only on the first call) with !strict_string_checks. @@ -88,7 +88,7 @@ void test6() { char token_delimiter[1] = {'d'}; __asan_poison_memory_region ((char *)&token_delimiter[1], 2); token = strtok(s, &token_delimiter[1]); - // CHECK6:'token_delimiter' <== Memory access at offset {{[0-9]+}} overflows this variable + // CHECK6: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} overflows this variable } int main(int argc, char **argv) { diff --git a/test/asan/TestCases/use-after-scope-inlined.cc b/test/asan/TestCases/use-after-scope-inlined.cc index 98a455cbc..bed9814c8 100644 --- a/test/asan/TestCases/use-after-scope-inlined.cc +++ b/test/asan/TestCases/use-after-scope-inlined.cc @@ -21,8 +21,8 @@ int main(int argc, char *argv[]) { // CHECK: READ of size 4 at 0x{{.*}} thread T0 // CHECK: #0 0x{{.*}} in main // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]] - // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset - // CHECK: [[OFFSET:[^ ]*]] in frame - // CHECK: main - // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i:[[@LINE-15]]' + // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset [[OFFSET:[^ ]*]] in frame + // CHECK: {{.*}} in main + // CHECK: This frame has + // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' (line [[@LINE-15]]) } -- cgit v1.2.1 From e014e3455f0f8ac9fed619c3e4acdcc2008e28af Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 30 Mar 2017 02:48:50 +0000 Subject: [XRay][compiler-rt] XFAIL the FDR mode tests on aarch64-42vma Followup on D31454. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299048 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 2 ++ test/xray/TestCases/Linux/fdr-thread-order.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index 0acf04b27..7f19ec59c 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -2,6 +2,8 @@ // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-logging-test-* +// FIXME: Figure out how to make llvm-xray work for aarch64-42vma +// XFAIL: aarch64-42vma #include "xray/xray_log_interface.h" #include diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 8977dabab..52cbcfddc 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -2,6 +2,7 @@ // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* +// XFAIL: aarch64-42vma #include "xray/xray_log_interface.h" #include #include -- cgit v1.2.1 From 8e08f7371083c0d536b57edd95c4f712759f3dce Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 30 Mar 2017 03:18:48 +0000 Subject: [XRay][compiler-rt] Only run tests using llvm-xray in x86_64 for now Followup on D31454. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299049 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 4 ++-- test/xray/TestCases/Linux/fdr-thread-order.cc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index 7f19ec59c..cdb024995 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -2,8 +2,8 @@ // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-logging-test-* -// FIXME: Figure out how to make llvm-xray work for aarch64-42vma -// XFAIL: aarch64-42vma +// FIXME: Make llvm-xray work on non-x86_64 as well. +// REQUIRES: x86_64 #include "xray/xray_log_interface.h" #include diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 52cbcfddc..a52428f2b 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -2,7 +2,8 @@ // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* -// XFAIL: aarch64-42vma +// FIXME: Make llvm-xray work on non-x86_64 as well. +// REQUIRES: x86_64 #include "xray/xray_log_interface.h" #include #include -- cgit v1.2.1 From b1170d7727ba630d3a0acc5588e773b030864c5c Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 30 Mar 2017 03:50:56 +0000 Subject: [XRay][compiler-rt] Spell REQUIRES properly for x86_64-linux Until llvm-xray starts running/supporting binaries that are not ELF64 we only run the FDR tests on x86_64-linux. Previous changes caused the tests to not actually run on x86_64. Follow-up on D31454. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299050 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 2 +- test/xray/TestCases/Linux/fdr-thread-order.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index cdb024995..4aa3964c9 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -3,7 +3,7 @@ // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-logging-test-* // FIXME: Make llvm-xray work on non-x86_64 as well. -// REQUIRES: x86_64 +// REQUIRES: x86_64-linux #include "xray/xray_log_interface.h" #include diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index a52428f2b..5edef2be2 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -3,7 +3,7 @@ // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. -// REQUIRES: x86_64 +// REQUIRES: x86_64-linux #include "xray/xray_log_interface.h" #include #include -- cgit v1.2.1 From 8b391d0ed5fc8278094b25299c01a953e932e942 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 30 Mar 2017 07:25:33 +0000 Subject: [sanitizer] Move fread and fwrite interceptors to sanitizer_common {M, T, E}San have fread and fwrite interceptors, let's move them to sanitizer_common to enable ASan checks as well. Differential Revision: https://reviews.llvm.org/D31456 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299061 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/esan/esan_interceptors.cpp | 14 --------- lib/msan/msan_interceptors.cc | 8 ----- .../sanitizer_common_interceptors.inc | 33 +++++++++++++++++++++ .../sanitizer_platform_interceptors.h | 3 ++ lib/tsan/rtl/tsan_interceptors.cc | 18 ------------ test/asan/TestCases/Posix/fread_fwrite.cc | 34 ++++++++++++++++++++++ test/msan/fread_fwrite.cc | 34 ++++++++++++++++++++++ 7 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 test/asan/TestCases/Posix/fread_fwrite.cc create mode 100644 test/msan/fread_fwrite.cc diff --git a/lib/esan/esan_interceptors.cpp b/lib/esan/esan_interceptors.cpp index 9ae5482a3..9740f4dae 100644 --- a/lib/esan/esan_interceptors.cpp +++ b/lib/esan/esan_interceptors.cpp @@ -304,20 +304,6 @@ INTERCEPTOR(int, unlink, char *path) { return REAL(unlink)(path); } -INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, f); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size * nmemb); - return REAL(fread)(ptr, size, nmemb, f); -} - -INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, f); - COMMON_INTERCEPTOR_READ_RANGE(ctx, p, size * nmemb); - return REAL(fwrite)(p, size, nmemb, f); -} - INTERCEPTOR(int, puts, const char *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, puts, s); diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index f3d5f4a09..15543bd91 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -123,14 +123,6 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { #define CHECK_UNPOISONED_STRING(x, n) \ CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n)) -INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { - ENSURE_MSAN_INITED(); - SIZE_T res = REAL(fread)(ptr, size, nmemb, file); - if (res > 0) - __msan_unpoison(ptr, res *size); - return res; -} - #if !SANITIZER_FREEBSD INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index b4148621d..7ecde2294 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -888,6 +888,23 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { #define INIT_READ #endif +#if SANITIZER_INTERCEPT_FREAD +INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, file); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(fread)(ptr, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res * size); + return res; +} +#define INIT_FREAD COMMON_INTERCEPT_FUNCTION(fread) +#else +#define INIT_FREAD +#endif + #if SANITIZER_INTERCEPT_PREAD INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; @@ -988,6 +1005,20 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { #define INIT_WRITE #endif +#if SANITIZER_INTERCEPT_FWRITE +INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file); + SIZE_T res = REAL(fwrite)(p, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, p, res * size); + return res; +} +#define INIT_FWRITE COMMON_INTERCEPT_FUNCTION(fwrite) +#else +#define INIT_FWRITE +#endif + #if SANITIZER_INTERCEPT_PWRITE INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; @@ -6142,12 +6173,14 @@ static void InitializeCommonInterceptors() { INIT_MEMRCHR; INIT_MEMMEM; INIT_READ; + INIT_FREAD; INIT_PREAD; INIT_PREAD64; INIT_READV; INIT_PREADV; INIT_PREADV64; INIT_WRITE; + INIT_FWRITE; INIT_PWRITE; INIT_PWRITE64; INIT_WRITEV; diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index e56557530..a583e989c 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -104,6 +104,9 @@ #define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FREAD SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FWRITE SI_NOT_WINDOWS + #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 17a914371..bb2badbff 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -1648,24 +1648,6 @@ TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { #define TSAN_MAYBE_INTERCEPT_TMPFILE64 #endif -TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f); - MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true); - } - return REAL(fread)(ptr, size, nmemb, f); -} - -TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f); - MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false); - } - return REAL(fwrite)(p, size, nmemb, f); -} - static void FlushStreams() { // Flushing all the streams here may freeze the process if a child thread is // performing file stream operations at the same time. diff --git a/test/asan/TestCases/Posix/fread_fwrite.cc b/test/asan/TestCases/Posix/fread_fwrite.cc new file mode 100644 index 000000000..97d44b752 --- /dev/null +++ b/test/asan/TestCases/Posix/fread_fwrite.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_asan -g %s -o %t +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE +// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD + +#include +#include + +int test_fread() { + FILE *f = fopen("/dev/zero", "r"); + char buf[2]; + fread(buf, sizeof(buf), 2, f); // BOOM + fclose(f); + return 0; +} + +int test_fwrite() { + FILE *f = fopen("/dev/null", "w"); + char buf[2]; + fwrite(buf, sizeof(buf), 2, f); // BOOM + return fclose(f); +} + +int main(int argc, char *argv[]) { + if (argc > 1) + test_fread(); + else + test_fwrite(); + return 0; +} + +// CHECK-FREAD: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FREAD: #{{.*}} in {{(wrap_|__interceptor_)?}}fread +// CHECK-FWRITE: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FWRITE: #{{.*}} in {{(wrap_|__interceptor_)?}}fwrite diff --git a/test/msan/fread_fwrite.cc b/test/msan/fread_fwrite.cc new file mode 100644 index 000000000..3d500342a --- /dev/null +++ b/test/msan/fread_fwrite.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_msan -g %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %t 1 + +#include +#include + +int test_fread() { + FILE *f = fopen("/dev/zero", "r"); + char c; + unsigned read = fread(&c, sizeof(c), 1, f); + fclose(f); + if (c == '1') // No error + return 1; + return 0; +} + +int test_fwrite() { + FILE *f = fopen("/dev/null", "w"); + char c; + if (fwrite(&c, sizeof(c), 1, f) != sizeof(c)) // BOOM + return 1; + return fclose(f); +} + +int main(int argc, char *argv[]) { + if (argc > 1) + test_fread(); + else + test_fwrite(); + return 0; +} + +// CHECK: Uninitialized bytes in __interceptor_fwrite at offset 0 inside -- cgit v1.2.1 From 7b09945185c7f9173ac183715e6fa6b74ff2e79a Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 30 Mar 2017 13:22:30 +0000 Subject: Use count instead of grep -c. Using count is more common in llvm and avoids a subshell. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299076 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 2 +- test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 5d7eff06e..1b26173d7 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -5,7 +5,7 @@ // RUN: rm -f 1.txt // RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >>1.txt 2>&1 // RUN: FileCheck %s < 1.txt -// RUN: [ $(grep -c 'ERROR: AddressSanitizer: use-after-poison' 1.txt) -eq 10 ] +// RUN: grep 'ERROR: AddressSanitizer: use-after-poison' 1.txt | count 10 // RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt // // Collisions are unlikely but still possible so we need the ||. diff --git a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc index 98ef85165..b9d85ef94 100644 --- a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc +++ b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc @@ -8,7 +8,7 @@ // Check that we die after reaching different reports number threshold. // RUN: rm -f %t1.log // RUN: %env_asan_opts=halt_on_error=false not %run %t 1 >> %t1.log 2>&1 -// RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t1.log) -eq 25 ] +// RUN: grep 'ERROR: AddressSanitizer: stack-buffer-overflow' %t1.log | count 25 // // Check suppress_equal_pcs=true behavior is equal to default one. // RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=true %run %t 2>&1 | FileCheck %s @@ -16,7 +16,7 @@ // Check suppress_equal_pcs=false behavior isn't equal to default one. // RUN: rm -f %t2.log // RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t >> %t2.log 2>&1 -// RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t2.log) -eq 30 ] +// RUN: grep 'ERROR: AddressSanitizer: stack-buffer-overflow' %t2.log | count 30 #define ACCESS_ARRAY_FIVE_ELEMENTS(array, i) \ array[i] = i; \ -- cgit v1.2.1 From 4aad00e01cdb286aab2c326c6c03c4674ce7e402 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 30 Mar 2017 13:33:22 +0000 Subject: Add LIT_USE_INTERNAL_SHELL to compiler-rt tests. I am working on improving our internal bot infrastructure. One thing that is unique to the ps4 is that we want to run the posix tests, but have to execute them on windows. We currently have a local hack to use a shell on windows, but it is pretty much impossible to get all all the tools to play nice with all the heuristics for what is a path and what is a command line option. This adds support LIT_USE_INTERNAL_SHELL and I will then try to fix the tests that fail with it but adding the missing features. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299077 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 648c7fa3c..d59d7d668 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -11,8 +11,19 @@ import subprocess import lit.formats import lit.util -# Setup test format. Use bash on Unix and the lit shell on Windows. -execute_external = (not sys.platform in ['win32']) + +# Choose between lit's internal shell pipeline runner and a real shell. If +# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. +use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") +if use_lit_shell: + # 0 is external, "" is default, and everything else is internal. + execute_external = (use_lit_shell == "0") +else: + # Otherwise we default to internal on Windows and external elsewhere, as + # bash on Windows is usually very slow. + execute_external = (not sys.platform in ['win32']) + +# Setup test format. config.test_format = lit.formats.ShTest(execute_external) if execute_external: config.available_features.add('shell') -- cgit v1.2.1 From 9fa19db0eb2fffd24a1ed62e2cce546250555f97 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 30 Mar 2017 14:02:08 +0000 Subject: Use FileCheck instead of [. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299081 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-maybe-open-file.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc index cab3d5770..95f2b5449 100644 --- a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc +++ b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc @@ -6,7 +6,7 @@ // RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file // RUN: %env_asan_opts=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success // RUN: %env_asan_opts=coverage=0 %run %t | FileCheck %s --check-prefix=CHECK-fail -// RUN: [ "$(cat test.sancov.packed)" == "test" ] +// RUN: FileCheck %s < test.sancov.packed -implicit-check-not={{.}} --check-prefix=CHECK-test // RUN: cd .. && rm -rf %T/coverage-maybe-open-file #include @@ -30,3 +30,4 @@ int main(int argc, char **argv) { // CHECK-success: SUCCESS // CHECK-fail: FAIL +// CHECK-test: {{^}}test{{$}} -- cgit v1.2.1 From 323e69dcc28f0c7b846dafbe8026d0d7a6e633ca Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 30 Mar 2017 14:05:46 +0000 Subject: Enable leak detection on linux-i686 by default Summary: This is already assumed by the test suite, and by asan_flags.cc. Reviewers: m.ostapenko, vitalybuka, kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31462 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299082 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flags.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index f1113698d..e61d1c3b4 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -62,8 +62,7 @@ COMMON_FLAG( COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") -COMMON_FLAG(bool, detect_leaks, SANITIZER_WORDSIZE == 64, - "Enable memory leak detection.") +COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.") COMMON_FLAG( bool, leak_check_at_exit, true, "Invoke leak checking in an atexit handler. Has no effect if " -- cgit v1.2.1 From fa43e8248dacd7956934c66ab803d00f713b96cd Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 30 Mar 2017 15:02:24 +0000 Subject: avoid a subshell. Instead of using grep -v we can just expand the globs a bit. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299084 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/asan/TestCases/Posix/coverage.cc b/test/asan/TestCases/Posix/coverage.cc index 7c1c4949f..3d1dccfbd 100644 --- a/test/asan/TestCases/Posix/coverage.cc +++ b/test/asan/TestCases/Posix/coverage.cc @@ -2,15 +2,15 @@ // RUN: %clangxx_asan -fsanitize-coverage=func %s %ld_flags_rpath_exe -o %t // RUN: rm -rf %T/coverage && mkdir -p %T/coverage && cd %T/coverage // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main -// RUN: %sancov print `ls coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo -// RUN: %sancov print `ls coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar -// RUN: %sancov print `ls *coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar -// RUN: %sancov print `ls *coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 -// RUN: %sancov print `ls *coverage.*sancov | grep '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 -// RUN: %sancov merge `ls *coverage.*sancov | grep -v '.so'` > merged-cov +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 +// RUN: %sancov print libcoverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 +// RUN: %sancov merge coverage.*sancov > merged-cov // RUN: %sancov print merged-cov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: %env_asan_opts=coverage=1:verbosity=1 not %run %t foo bar 4 2>&1 | FileCheck %s --check-prefix=CHECK-report // RUN: %env_asan_opts=coverage=1:verbosity=1 not %run %t foo bar 4 5 2>&1 | FileCheck %s --check-prefix=CHECK-segv -- cgit v1.2.1 From e17862e22900583883fc7f1b97b561aa4e18593e Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 15:44:57 +0000 Subject: [asan] Implement "scribble" flags, which overwrite free'd memory with 0x55 This patch implements "Malloc Scribble" in ASan via "max_free_fill_size" and "free_fill_byte" flags, which can be used to overwrite free()'d memory. We also match the behavior of MallocScribble and MallocPreScribble env vars on macOS (see https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html), which is a helpful tool to detect use-after-free bugs that happen in non-instrumented code. Differential Revision: https://reviews.llvm.org/D30101 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299085 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 12 ++++++++ lib/asan/asan_flags.cc | 12 ++++++++ lib/asan/asan_flags.inc | 6 ++++ test/asan/TestCases/Darwin/scribble.cc | 56 ++++++++++++++++++++++++++++++++++ test/asan/TestCases/scribble.cc | 55 +++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+) create mode 100644 test/asan/TestCases/Darwin/scribble.cc create mode 100644 test/asan/TestCases/scribble.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 6db2b4db5..7010b6023 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -523,6 +523,18 @@ struct Allocator { AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; m->free_context_id = StackDepotPut(*stack); + + Flags &fl = *flags(); + if (fl.max_free_fill_size > 0) { + // We have to skip the chunk header, it contains free_context_id. + uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size; + if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area. + uptr size_to_fill = m->UsedSize() - kChunkHeader2Size; + size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size); + REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill); + } + } + // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 74c441a04..555cc04db 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -95,6 +95,18 @@ void InitializeFlags() { RegisterCommonFlags(&ubsan_parser); #endif + if (SANITIZER_MAC) { + // Support macOS MallocScribble and MallocPreScribble: + // + if (GetEnv("MallocScribble")) { + f->max_free_fill_size = 0x1000; + } + if (GetEnv("MallocPreScribble")) { + f->malloc_fill_byte = 0xaa; + } + } + // Override from ASan compile definition. const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); asan_parser.ParseString(asan_compile_def); diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index f316afdb3..65a1d173f 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -63,8 +63,14 @@ ASAN_FLAG( int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K. "ASan allocator flag. max_malloc_fill_size is the maximal amount of " "bytes that will be filled with malloc_fill_byte on malloc.") +ASAN_FLAG( + int, max_free_fill_size, 0, + "ASan allocator flag. max_free_fill_size is the maximal amount of " + "bytes that will be filled with free_fill_byte during free.") ASAN_FLAG(int, malloc_fill_byte, 0xbe, "Value used to fill the newly allocated memory.") +ASAN_FLAG(int, free_fill_byte, 0x55, + "Value used to fill deallocated memory.") ASAN_FLAG(bool, allow_user_poisoning, true, "If set, user may manually mark memory regions as poisoned or " "unpoisoned.") diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc new file mode 100644 index 000000000..180f3994b --- /dev/null +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -0,0 +1,56 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s +// RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s +// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s + +#include +#include +#include + +struct Isa { + const char *class_name; +}; + +struct MyClass { + long padding; + Isa *isa; + long data; + + void print_my_class_name(); +}; + +__attribute__((no_sanitize("address"))) +void MyClass::print_my_class_name() { + fprintf(stderr, "this = %p\n", this); + fprintf(stderr, "padding = 0x%lx\n", this->padding); + fprintf(stderr, "isa = %p\n", this->isa); + + if ((uint32_t)(uintptr_t)this->isa != 0x55555555) { + fprintf(stderr, "class name: %s\n", this->isa->class_name); + } +} + +int main() { + Isa *my_class_isa = (Isa *)malloc(sizeof(Isa)); + memset(my_class_isa, 0x77, sizeof(Isa)); + my_class_isa->class_name = "MyClass"; + + MyClass *my_object = (MyClass *)malloc(sizeof(MyClass)); + memset(my_object, 0x88, sizeof(MyClass)); + my_object->isa = my_class_isa; + my_object->data = 42; + + my_object->print_my_class_name(); + // CHECK-SCRIBBLE: class name: MyClass + // CHECK-NOSCRIBBLE: class name: MyClass + + free(my_object); + + my_object->print_my_class_name(); + // CHECK-NOSCRIBBLE: class name: MyClass + // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} + + printf("okthxbai!\n"); + // CHECK-SCRIBBLE: okthxbai! + // CHECK-NOSCRIBBLE: okthxbai! +} diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc new file mode 100644 index 000000000..d1e433c45 --- /dev/null +++ b/test/asan/TestCases/scribble.cc @@ -0,0 +1,55 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s +// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s + +#include +#include +#include + +struct Isa { + const char *class_name; +}; + +struct MyClass { + long padding; + Isa *isa; + long data; + + void print_my_class_name(); +}; + +__attribute__((no_sanitize("address"))) +void MyClass::print_my_class_name() { + fprintf(stderr, "this = %p\n", this); + fprintf(stderr, "padding = 0x%lx\n", this->padding); + fprintf(stderr, "isa = %p\n", this->isa); + + if ((uint32_t)(uintptr_t)this->isa != 0x55555555) { + fprintf(stderr, "class name: %s\n", this->isa->class_name); + } +} + +int main() { + Isa *my_class_isa = (Isa *)malloc(sizeof(Isa)); + memset(my_class_isa, 0x77, sizeof(Isa)); + my_class_isa->class_name = "MyClass"; + + MyClass *my_object = (MyClass *)malloc(sizeof(MyClass)); + memset(my_object, 0x88, sizeof(MyClass)); + my_object->isa = my_class_isa; + my_object->data = 42; + + my_object->print_my_class_name(); + // CHECK-SCRIBBLE: class name: MyClass + // CHECK-NOSCRIBBLE: class name: MyClass + + free(my_object); + + my_object->print_my_class_name(); + // CHECK-NOSCRIBBLE: class name: MyClass + // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} + + printf("okthxbai!\n"); + // CHECK-SCRIBBLE: okthxbai! + // CHECK-NOSCRIBBLE: okthxbai! +} -- cgit v1.2.1 From ee2f75fcfd47f41d2113e831cb10fa5828b1f84b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 15:48:25 +0000 Subject: [tsan] Add interceptor for xpc_connection_cancel to avoid false positives TSan reports a false positive when using xpc_connection_cancel. We're missing a happens-before edge from xpc_connection_cancel to the event handler on the same connection. Differential Revision: https://reviews.llvm.org/D31475 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299086 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors_mac.cc | 6 ++++++ test/tsan/Darwin/xpc-cancel.mm | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/tsan/Darwin/xpc-cancel.mm diff --git a/lib/tsan/rtl/tsan_interceptors_mac.cc b/lib/tsan/rtl/tsan_interceptors_mac.cc index fc5eb0499..f6bf8a0e5 100644 --- a/lib/tsan/rtl/tsan_interceptors_mac.cc +++ b/lib/tsan/rtl/tsan_interceptors_mac.cc @@ -281,6 +281,12 @@ TSAN_INTERCEPTOR(void, xpc_connection_send_message_with_reply, (connection, message, replyq, new_handler); } +TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) { + SCOPED_TSAN_INTERCEPTOR(xpc_connection_cancel, connection); + Release(thr, pc, (uptr)connection); + REAL(xpc_connection_cancel)(connection); +} + // On macOS, libc++ is always linked dynamically, so intercepting works the // usual way. #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR diff --git a/test/tsan/Darwin/xpc-cancel.mm b/test/tsan/Darwin/xpc-cancel.mm new file mode 100644 index 000000000..5e326b7e4 --- /dev/null +++ b/test/tsan/Darwin/xpc-cancel.mm @@ -0,0 +1,37 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %run %t 2>&1 | FileCheck %s + +#import +#import + +long global; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT); + xpc_connection_t server_conn = xpc_connection_create(NULL, server_q); + + xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) { + if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) { + global = 43; + + dispatch_async(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + } + }); + xpc_connection_resume(server_conn); + + global = 42; + + xpc_connection_cancel(server_conn); + + CFRunLoopRun(); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. -- cgit v1.2.1 From 1732335497690781a7749354e9d387c9f9f733e4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 17:01:35 +0000 Subject: Fixup for r299085: Include stdint.h in scribble.cc to make uintptr_t available. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299089 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/scribble.cc | 1 + test/asan/TestCases/scribble.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc index 180f3994b..a69d28471 100644 --- a/test/asan/TestCases/Darwin/scribble.cc +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -3,6 +3,7 @@ // RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s // RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s +#include #include #include #include diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc index d1e433c45..8d824697b 100644 --- a/test/asan/TestCases/scribble.cc +++ b/test/asan/TestCases/scribble.cc @@ -2,6 +2,7 @@ // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s // RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s +#include #include #include #include -- cgit v1.2.1 From cef58227a66f0a9fbb8d48ff9652013292e6942d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 17:21:51 +0000 Subject: Fixup for r299085: Print all output to stderr. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299090 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/scribble.cc | 2 +- test/asan/TestCases/scribble.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc index a69d28471..ae4b5e65d 100644 --- a/test/asan/TestCases/Darwin/scribble.cc +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -51,7 +51,7 @@ int main() { // CHECK-NOSCRIBBLE: class name: MyClass // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} - printf("okthxbai!\n"); + fprintf(stderr, "okthxbai!\n"); // CHECK-SCRIBBLE: okthxbai! // CHECK-NOSCRIBBLE: okthxbai! } diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc index 8d824697b..90f999e78 100644 --- a/test/asan/TestCases/scribble.cc +++ b/test/asan/TestCases/scribble.cc @@ -50,7 +50,7 @@ int main() { // CHECK-NOSCRIBBLE: class name: MyClass // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} - printf("okthxbai!\n"); + fprintf(stderr, "okthxbai!\n"); // CHECK-SCRIBBLE: okthxbai! // CHECK-NOSCRIBBLE: okthxbai! } -- cgit v1.2.1 From cad6e941281dbb3bc148b52f01256a96dfca66d7 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 17:48:41 +0000 Subject: Fixup for r299085: On Windows %p doesn't print 0x prefix. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299092 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/scribble.cc | 2 +- test/asan/TestCases/scribble.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc index ae4b5e65d..33f64e19c 100644 --- a/test/asan/TestCases/Darwin/scribble.cc +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -49,7 +49,7 @@ int main() { my_object->print_my_class_name(); // CHECK-NOSCRIBBLE: class name: MyClass - // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} + // CHECK-SCRIBBLE: isa = {{(0x)?}}{{5555555555555555|55555555}} fprintf(stderr, "okthxbai!\n"); // CHECK-SCRIBBLE: okthxbai! diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc index 90f999e78..9da46edda 100644 --- a/test/asan/TestCases/scribble.cc +++ b/test/asan/TestCases/scribble.cc @@ -48,7 +48,7 @@ int main() { my_object->print_my_class_name(); // CHECK-NOSCRIBBLE: class name: MyClass - // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} + // CHECK-SCRIBBLE: isa = {{(0x)?}}{{5555555555555555|55555555}} fprintf(stderr, "okthxbai!\n"); // CHECK-SCRIBBLE: okthxbai! -- cgit v1.2.1 From a7455404b763e2605a1f6867c44eb48efefeadbe Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 19:36:49 +0000 Subject: Fixup for r299085: Disable the scribble.cc test on AArch64. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299099 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/scribble.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc index 9da46edda..d5e43d888 100644 --- a/test/asan/TestCases/scribble.cc +++ b/test/asan/TestCases/scribble.cc @@ -2,6 +2,8 @@ // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s // RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s +// REQUIRES: stable-runtime + #include #include #include -- cgit v1.2.1 From ca8992d680b0220ff52b041489e8fb7c6426e88d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 30 Mar 2017 23:34:44 +0000 Subject: Fixup for r299085: Keep the scribble.cc test on Darwin only, while I investigate why this test sometimes fails on Linux. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299130 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/scribble.cc | 58 ----------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 test/asan/TestCases/scribble.cc diff --git a/test/asan/TestCases/scribble.cc b/test/asan/TestCases/scribble.cc deleted file mode 100644 index d5e43d888..000000000 --- a/test/asan/TestCases/scribble.cc +++ /dev/null @@ -1,58 +0,0 @@ -// RUN: %clang_asan -O2 %s -o %t -// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s -// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s - -// REQUIRES: stable-runtime - -#include -#include -#include -#include - -struct Isa { - const char *class_name; -}; - -struct MyClass { - long padding; - Isa *isa; - long data; - - void print_my_class_name(); -}; - -__attribute__((no_sanitize("address"))) -void MyClass::print_my_class_name() { - fprintf(stderr, "this = %p\n", this); - fprintf(stderr, "padding = 0x%lx\n", this->padding); - fprintf(stderr, "isa = %p\n", this->isa); - - if ((uint32_t)(uintptr_t)this->isa != 0x55555555) { - fprintf(stderr, "class name: %s\n", this->isa->class_name); - } -} - -int main() { - Isa *my_class_isa = (Isa *)malloc(sizeof(Isa)); - memset(my_class_isa, 0x77, sizeof(Isa)); - my_class_isa->class_name = "MyClass"; - - MyClass *my_object = (MyClass *)malloc(sizeof(MyClass)); - memset(my_object, 0x88, sizeof(MyClass)); - my_object->isa = my_class_isa; - my_object->data = 42; - - my_object->print_my_class_name(); - // CHECK-SCRIBBLE: class name: MyClass - // CHECK-NOSCRIBBLE: class name: MyClass - - free(my_object); - - my_object->print_my_class_name(); - // CHECK-NOSCRIBBLE: class name: MyClass - // CHECK-SCRIBBLE: isa = {{(0x)?}}{{5555555555555555|55555555}} - - fprintf(stderr, "okthxbai!\n"); - // CHECK-SCRIBBLE: okthxbai! - // CHECK-NOSCRIBBLE: okthxbai! -} -- cgit v1.2.1 From be5ba6663d03af0a4b8207c212edc44148fd1ef4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 31 Mar 2017 03:00:29 +0000 Subject: [asan] Turn -fsanitize-address-use-after-scope on by default [compiler-rt part] AddressSanitizer has an optional compile-time flag, -fsanitize-address-use-after-scope, which enables detection of use-after-scope bugs. We'd like to have this feature on by default, because it is already very well tested, it's used in several projects already (LLVM automatically enables it when using -DLLVM_USE_SANITIZER=Address), it's low overhead and there are no known issues or incompatibilities. This patch enables use-after-scope by default via the Clang driver, where we set true as the default value for AsanUseAfterScope. This also causes the lifetime markers to be generated whenever fsanitize=address is used. This has some nice consequences, e.g. we now have line numbers for all local variables. Differential Revision: https://reviews.llvm.org/D31479 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299175 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/use-after-scope.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/asan/TestCases/use-after-scope.cc b/test/asan/TestCases/use-after-scope.cc index d92dae657..4c5998abe 100644 --- a/test/asan/TestCases/use-after-scope.cc +++ b/test/asan/TestCases/use-after-scope.cc @@ -1,6 +1,10 @@ // RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s +// -fsanitize-address-use-after-scope is now on by default: +// RUN: %clangxx_asan -O1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s + volatile int *p = 0; int main() { -- cgit v1.2.1 From 00f49884313e8e13ee62216b011cab5ecd5bbd7c Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 31 Mar 2017 06:36:37 +0000 Subject: [asan] Move AsanCheckDynamicRTPrereqs check under flag The patch addresses https://github.com/google/sanitizers/issues/786. Currently AsanCheckDynamicRTPrereqs prevents dynamic ASan runtime from running in some important environments e.g. cowbuilder and fakeroot that may also work with interposition. Let's allow users to switch off the check given that they know what they do. Differential Revision: https://reviews.llvm.org/D31420 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299188 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.inc | 3 +++ lib/asan/asan_linux.cc | 2 +- test/asan/TestCases/Linux/asan_dlopen_test.cc | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 65a1d173f..f2216c2e9 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -158,3 +158,6 @@ ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, "realloc(p, 0) is equivalent to free(p) by default (Same as the " "POSIX standard). If set to false, realloc(p, 0) will return a " "pointer to an allocated space which can not be used.") +ASAN_FLAG(bool, verify_asan_link_order, true, + "Check position of ASan runtime in library list (needs to be disabled" + " when other library has to be preloaded system-wide)") diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 6d150de79..50ef84c39 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -111,7 +111,7 @@ static void ReportIncompatibleRT() { } void AsanCheckDynamicRTPrereqs() { - if (!ASAN_DYNAMIC) + if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) return; // Ensure that dynamic RT is the first DSO in the list diff --git a/test/asan/TestCases/Linux/asan_dlopen_test.cc b/test/asan/TestCases/Linux/asan_dlopen_test.cc index f1e31b0a0..5081b7753 100644 --- a/test/asan/TestCases/Linux/asan_dlopen_test.cc +++ b/test/asan/TestCases/Linux/asan_dlopen_test.cc @@ -2,6 +2,8 @@ // // RUN: %clangxx %s -DRT=\"%shared_libasan\" -o %t -ldl // RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=verify_asan_link_order=true not %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=verify_asan_link_order=false %run %t 2>&1 // REQUIRES: asan-dynamic-runtime // XFAIL: android -- cgit v1.2.1 From 7596a2af0eaf685e074dde3e1294ac706913da1b Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Fri, 31 Mar 2017 12:07:58 +0000 Subject: Remove unused variable. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299206 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/esan/TestCases/workingset-samples.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/esan/TestCases/workingset-samples.cpp b/test/esan/TestCases/workingset-samples.cpp index cf198d2f3..7db2110b9 100644 --- a/test/esan/TestCases/workingset-samples.cpp +++ b/test/esan/TestCases/workingset-samples.cpp @@ -8,7 +8,6 @@ #include const int size = 0x1 << 25; // 523288 cache lines -const int iters = 6; int main(int argc, char **argv) { char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE, -- cgit v1.2.1 From fc209f28f84498f36526713eb29f87410a3ffa2f Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 31 Mar 2017 13:35:37 +0000 Subject: Simplify test. We don't need && since that is how various run lines are combined. The redirects were not being used. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299215 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/closed-fds.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/closed-fds.cc b/test/asan/TestCases/Posix/closed-fds.cc index b7bca26c3..75e3216aa 100644 --- a/test/asan/TestCases/Posix/closed-fds.cc +++ b/test/asan/TestCases/Posix/closed-fds.cc @@ -2,7 +2,8 @@ // symbolizer still works. // RUN: rm -f %t.log.* -// RUN: %clangxx_asan -O0 %s -o %t 2>&1 && %env_asan_opts=log_path='"%t.log"':verbosity=2 not %run %t 2>&1 +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=log_path='"%t.log"':verbosity=2 not %run %t // RUN: FileCheck %s --check-prefix=CHECK-FILE < %t.log.* // FIXME: copy %t.log back from the device and re-enable on Android. -- cgit v1.2.1 From 172de69304b20ab06cdba8f91ec62587533f0d51 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 31 Mar 2017 16:49:37 +0000 Subject: Replace wc -l with count. This is a far more common way in llvm of counting lines in tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299231 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/coverage-missing.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index 49487d39a..cb5d71a27 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -8,15 +8,15 @@ // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t // RUN: %sancov print *.sancov > main.txt // RUN: rm *.sancov -// RUN: [ $(cat main.txt | wc -l) == 1 ] +// RUN: count 1 < main.txt // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x // RUN: %sancov print *.sancov > foo.txt // RUN: rm *.sancov -// RUN: [ $(cat foo.txt | wc -l) == 3 ] +// RUN: count 3 < foo.txt // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x x // RUN: %sancov print *.sancov > bar.txt // RUN: rm *.sancov -// RUN: [ $(cat bar.txt | wc -l) == 4 ] +// RUN: count 4 < bar.txt // RUN: %sancov missing %t < foo.txt > foo-missing.txt // RUN: sort main.txt foo-missing.txt -o foo-missing-with-main.txt // The "missing from foo" set may contain a few bogus PCs from the sanitizer @@ -35,11 +35,11 @@ // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x // RUN: %sancov print $LIBNAME.*.sancov > foo.txt // RUN: rm *.sancov -// RUN: [ $(cat foo.txt | wc -l) == 2 ] +// RUN: count 2 < foo.txt // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x x // RUN: %sancov print $LIBNAME.*.sancov > bar.txt // RUN: rm *.sancov -// RUN: [ $(cat bar.txt | wc -l) == 3 ] +// RUN: count 3 < bar.txt // RUN: %sancov missing %dynamiclib < foo.txt > foo-missing.txt // RUN: ( diff bar.txt foo-missing.txt || true ) | not grep "^<" -- cgit v1.2.1 From ef626e4f64cf58956952dc3428fdc4cba8f09ae4 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 4 Apr 2017 17:49:45 +0000 Subject: Avoid sub shell. Another step in getting these tests to run with the integrated one. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299452 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/coverage-missing.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index cb5d71a27..2bb103d82 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -22,7 +22,8 @@ // The "missing from foo" set may contain a few bogus PCs from the sanitizer // runtime, but it must include the entire "bar" code path as a subset. Sorted // lists can be tested for set inclusion with diff + grep. -// RUN: ( diff bar.txt foo-missing-with-main.txt || true ) | not grep "^<" +// RUN: diff bar.txt foo-missing-with-main.txt > %t.log || true +// RUN: not grep "^<" %t.log // Second case: coverage from DSO. // cd %T @@ -41,7 +42,8 @@ // RUN: rm *.sancov // RUN: count 3 < bar.txt // RUN: %sancov missing %dynamiclib < foo.txt > foo-missing.txt -// RUN: ( diff bar.txt foo-missing.txt || true ) | not grep "^<" +// RUN: diff bar.txt foo-missing.txt > %t.log || true +// RUN: not grep "^<" %t.log // REQUIRES: x86-target-arch // XFAIL: android -- cgit v1.2.1 From 3608344405021595b4cf343be74770dabfad4d98 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 4 Apr 2017 21:42:59 +0000 Subject: Don't remove the cwd. This works with a regular shell since the kernel can keep track of a deleted cwd. Since we just keep a path string, the following subprocess invocations fail. I think this would also fail on windows. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299471 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/coverage-missing.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index 2bb103d82..16c05b256 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -30,6 +30,7 @@ // RUN: %clangxx_asan -fsanitize-coverage=func %s -o %dynamiclib -DFOOBAR -shared -fPIC // RUN: %clangxx_asan -fsanitize-coverage=func %s %dynamiclib -o %t -DMAIN // RUN: export LIBNAME=`basename %dynamiclib` +// RUN: cd .. // RUN: rm -rf %T/coverage-missing // RUN: mkdir -p %T/coverage-missing // RUN: cd %T/coverage-missing -- cgit v1.2.1 From 9093a35c599fe41278606a20b51095ea8bd5a081 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 4 Apr 2017 22:33:02 +0000 Subject: Avoid calling basename to compute xdynamiclib_namespec. This also exposes a xdynamiclib_filename that can be used to simplify a few tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299478 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 7765a248d..37ba10df6 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -202,8 +202,9 @@ elif config.host_os == 'Linux': config.substitutions.append( ("%ld_flags_rpath_so", '') ) # Must be defined after the substitutions that use %dynamiclib. -config.substitutions.append( ("%dynamiclib", '%T/lib%xdynamiclib_namespec.so') ) -config.substitutions.append( ("%xdynamiclib_namespec", '$(basename %t).dynamic') ) +config.substitutions.append( ("%dynamiclib", '%T/%xdynamiclib_filename') ) +config.substitutions.append( ("%xdynamiclib_filename", 'lib%xdynamiclib_namespec.so') ) +config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL # because the test hangs. Adding armhf as we now have two modes. -- cgit v1.2.1 From bd4e3b4a89e06dc8cd1258db401455b2764d750e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 5 Apr 2017 20:26:33 +0000 Subject: Simplify test a bit. There are two cases to consider: We are using the internal shell. This will still fail because of ulimit. We are using an external shell. In this case the difference is that we now also constrain FileCheck to use less than 4 MB of of stack, which it should :-) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299586 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/deep_call_stack.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/deep_call_stack.cc b/test/asan/TestCases/Posix/deep_call_stack.cc index 18ba563db..2d2b056d6 100644 --- a/test/asan/TestCases/Posix/deep_call_stack.cc +++ b/test/asan/TestCases/Posix/deep_call_stack.cc @@ -1,6 +1,7 @@ // Check that UAR mode can handle very deep recusrion. -// RUN: %clangxx_asan -O2 %s -o %t && \ -// RUN: (ulimit -s 4096; %env_asan_opts=detect_stack_use_after_return=1 %run %t) 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: ulimit -s 4096 +// RUN: %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | FileCheck %s // Also check that use_sigaltstack+verbosity doesn't crash. // RUN: %env_asan_opts=verbosity=1:use_sigaltstack=1:detect_stack_use_after_return=1 %run %t | FileCheck %s -- cgit v1.2.1 From 9f4261ccd66971648245a09ffbe1d0da20410261 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 6 Apr 2017 00:34:45 +0000 Subject: [cfi] Fix symbol lookup hack in cross-dso cfi to handle LLD binaries. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299604 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc index d463ca8da..e41ab3371 100644 --- a/lib/cfi/cfi.cc +++ b/lib/cfi/cfi.cc @@ -188,12 +188,14 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) { } } if (!dynamic) return 0; - uptr strtab = 0, symtab = 0; + uptr strtab = 0, symtab = 0, strsz = 0; for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) { if (p->d_tag == DT_SYMTAB) symtab = p->d_un.d_ptr; else if (p->d_tag == DT_STRTAB) strtab = p->d_un.d_ptr; + else if (p->d_tag == DT_STRSZ) + strsz = p->d_un.d_ptr; } if (symtab > strtab) { @@ -209,7 +211,8 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) { if (phdr->p_type == PT_LOAD) { uptr beg = info->dlpi_addr + phdr->p_vaddr; uptr end = beg + phdr->p_memsz; - if (strtab >= beg && strtab < end && symtab >= beg && symtab < end) + if (strtab >= beg && strtab + strsz < end && symtab >= beg && + symtab < end) break; } } @@ -222,6 +225,10 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) { for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab; ++p) { + // There is no reliable way to find the end of the symbol table. In + // lld-produces files, there are other sections between symtab and strtab. + // Stop looking when the symbol name is not inside strtab. + if (p->st_name >= strsz) break; char *name = (char*)(strtab + p->st_name); if (strcmp(name, "__cfi_check") == 0) { assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)); -- cgit v1.2.1 From 6b3405390034772c3e52d36f033a363d3f108a8c Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Thu, 6 Apr 2017 06:13:39 +0000 Subject: [Builtins] Fix div0 error in udivsi3 Summary: Need to save `lr` before bl to aeabi_div0 Reviewers: rengolin, compnerd Reviewed By: compnerd Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31716 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299628 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/udivsi3.S | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S index fcc472b4f..b97b3080b 100644 --- a/lib/builtins/arm/udivsi3.S +++ b/lib/builtins/arm/udivsi3.S @@ -37,7 +37,16 @@ DEFINE_COMPILERRT_FUNCTION(__udivsi3) beq LOCAL_LABEL(divby0) udiv r0, r0, r1 bx lr -#else + +LOCAL_LABEL(divby0): + mov r0, #0 +# ifdef __ARM_EABI__ + b __aeabi_idiv0 +# else + JMP(lr) +# endif + +#else /* ! __ARM_ARCH_EXT_IDIV__ */ cmp r1, #1 bcc LOCAL_LABEL(divby0) #if __ARM_ARCH_ISA_THUMB == 1 @@ -186,9 +195,12 @@ LOCAL_LABEL(skip_1): LOCAL_LABEL(divby0): movs r0, #0 # if defined(__ARM_EABI__) + push {r7, lr} bl __aeabi_idiv0 // due to relocation limit, can't use b. -# endif + pop {r7, pc} +# else JMP(lr) +# endif #if __ARM_ARCH_ISA_THUMB == 1 @@ -252,16 +264,6 @@ LOCAL_LABEL(div0block): JMP(lr) #endif /* __ARM_ARCH_EXT_IDIV__ */ -#if __ARM_ARCH_EXT_IDIV__ -LOCAL_LABEL(divby0): - mov r0, #0 -# ifdef __ARM_EABI__ - b __aeabi_idiv0 -# else - JMP(lr) -# endif -#endif - END_COMPILERRT_FUNCTION(__udivsi3) NO_EXEC_STACK_DIRECTIVE -- cgit v1.2.1 From 7b9666449c81e5522fd8d32a0e4db368a12e0b41 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 6 Apr 2017 07:14:43 +0000 Subject: [XRay] [compiler-rt] Unwriting FDR mode buffers when functions are short. Summary: "short" is defined as an xray flag, and buffer rewinding happens for both exits and tail exits. I've made the choice to seek backwards finding pairs of FunctionEntry, TailExit record pairs and erasing them if the FunctionEntry occurred before exit from the currently exiting function. This is a compromise so that we don't skip logging tail calls if the function that they call into takes longer our duration. This works by counting the consecutive function and function entry, tail exit pairs that proceed the current point in the buffer. The buffer is rewound to check whether these entry points happened recently enough to be erased. It is still possible we will omit them if they call into a child function that is not instrumented which calls a fast grandchild that is instrumented before doing other processing. Reviewers: pelikan, dberris Reviewed By: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31345 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299629 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 139 +++++++++++++++++++++++++++++++++- lib/xray/xray_flags.inc | 3 + test/xray/TestCases/Linux/fdr-mode.cc | 15 +++- 3 files changed, 150 insertions(+), 7 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index b0b2a7340..0867227f1 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -32,6 +32,8 @@ #include "xray_buffer_queue.h" #include "xray_defs.h" #include "xray_fdr_log_records.h" +#include "xray_flags.h" +#include "xray_tsc.h" namespace __xray { @@ -108,9 +110,17 @@ static void processFunctionHook(int32_t FuncId, XRayEntryType Entry, //-----------------------------------------------------------------------------| namespace { + thread_local BufferQueue::Buffer Buffer; thread_local char *RecordPtr = nullptr; +// The number of FunctionEntry records immediately preceding RecordPtr. +thread_local uint8_t NumConsecutiveFnEnters = 0; + +// The number of adjacent, consecutive pairs of FunctionEntry, Tail Exit +// records preceding RecordPtr. +thread_local uint8_t NumTailCalls = 0; + constexpr auto MetadataRecSize = sizeof(MetadataRecord); constexpr auto FunctionRecSize = sizeof(FunctionRecord); @@ -209,6 +219,8 @@ static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, } std::memcpy(MemPtr, Records, sizeof(MetadataRecord) * InitRecordsCount); MemPtr += sizeof(MetadataRecord) * InitRecordsCount; + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; } static inline void setupNewBuffer(const BufferQueue::Buffer &Buffer, @@ -221,6 +233,8 @@ static inline void setupNewBuffer(const BufferQueue::Buffer &Buffer, // This is typically clock_gettime, but callers have injection ability. wall_clock_reader(CLOCK_MONOTONIC, &TS); writeNewBufferPreamble(Tid, TS, RecordPtr); + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; } static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, @@ -237,6 +251,8 @@ static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); std::memcpy(MemPtr, &NewCPUId, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; } static inline void writeNewCPUIdMetadata(uint16_t CPU, @@ -251,6 +267,8 @@ static inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { // For now we don't write any bytes into the Data field. std::memcpy(MemPtr, &EOBMeta, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; } static inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { @@ -269,6 +287,8 @@ static inline void writeTSCWrapMetadata(uint64_t TSC, std::memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); std::memcpy(MemPtr, &TSCWrap, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; } static inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { @@ -289,13 +309,35 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, switch (EntryType) { case XRayEntryType::ENTRY: + ++NumConsecutiveFnEnters; + FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); + break; case XRayEntryType::LOG_ARGS_ENTRY: + // We should not rewind functions with logged args. + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); break; case XRayEntryType::EXIT: + // If we've decided to log the function exit, we will never erase the log + // before it. + NumConsecutiveFnEnters = 0; + NumTailCalls = 0; FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); break; case XRayEntryType::TAIL: + // If we just entered the function we're tail exiting from or erased every + // invocation since then, this function entry tail pair is a candidate to + // be erased when the child function exits. + if (NumConsecutiveFnEnters > 0) { + ++NumTailCalls; + NumConsecutiveFnEnters = 0; + } else { + // We will never be able to erase this tail call since we have logged + // something in between the function entry and tail exit. + NumTailCalls = 0; + NumConsecutiveFnEnters = 0; + } FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); break; @@ -337,6 +379,8 @@ static inline void processFunctionHook( // We assume that we'll support only 65536 CPUs for x86_64. thread_local uint16_t CurrentCPU = std::numeric_limits::max(); thread_local uint64_t LastTSC = 0; + thread_local uint64_t LastFunctionEntryTSC = 0; + thread_local uint64_t NumberOfTicksThreshold = 0; // Make sure a thread that's ever called handleArg0 has a thread-local // live reference to the buffer queue for this particular instance of @@ -379,6 +423,10 @@ static inline void processFunctionHook( return; } + uint64_t CycleFrequency = getTSCFrequency(); + NumberOfTicksThreshold = CycleFrequency * + flags()->xray_fdr_log_func_duration_threshold_us / + 1000000; setupNewBuffer(Buffer, wall_clock_reader); } @@ -441,6 +489,10 @@ static inline void processFunctionHook( BufferQueue::getErrorString(EC)); return; } + uint64_t CycleFrequency = getTSCFrequency(); + NumberOfTicksThreshold = CycleFrequency * + flags()->xray_fdr_log_func_duration_threshold_us / + 1000000; setupNewBuffer(Buffer, wall_clock_reader); } @@ -486,10 +538,92 @@ static inline void processFunctionHook( RecordTSCDelta = Delta; } - // We then update our "LastTSC" and "CurrentCPU" thread-local variables to aid - // us in future computations of this TSC delta value. LastTSC = TSC; CurrentCPU = CPU; + using AlignedFuncStorage = + std::aligned_storage::type; + switch (Entry) { + case XRayEntryType::ENTRY: + case XRayEntryType::LOG_ARGS_ENTRY: + // Update the thread local state for the next invocation. + LastFunctionEntryTSC = TSC; + break; + case XRayEntryType::TAIL: + break; + case XRayEntryType::EXIT: + // Break out and write the exit record if we can't erase any functions. + if (NumConsecutiveFnEnters == 0 || + (TSC - LastFunctionEntryTSC) >= NumberOfTicksThreshold) + break; + // Otherwise we unwind functions that are too short to log by decrementing + // our view ptr into the buffer. We can erase a Function Entry record and + // neglect to log our EXIT. We have to make sure to update some state like + // the LastTSC and count of consecutive FunctionEntry records. + RecordPtr -= FunctionRecSize; + AlignedFuncStorage AlignedFuncRecordBuffer; + const auto &FuncRecord = *reinterpret_cast( + std::memcpy(&AlignedFuncRecordBuffer, RecordPtr, FunctionRecSize)); + assert(FuncRecord.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && + "Expected to find function entry recording when rewinding."); + assert(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && + "Expected matching function id when rewinding Exit"); + --NumConsecutiveFnEnters; + LastTSC -= FuncRecord.TSCDelta; + + // We unwound one call. Update the state and return without writing a log. + if (NumConsecutiveFnEnters != 0) { + LastFunctionEntryTSC = LastFunctionEntryTSC - FuncRecord.TSCDelta; + return; + } + + // Otherwise we've rewound the stack of all function entries, we might be + // able to rewind further by erasing tail call functions that are being + // exited from via this exit. + LastFunctionEntryTSC = 0; + auto RewindingTSC = LastTSC; + auto RewindingRecordPtr = RecordPtr - FunctionRecSize; + while (NumTailCalls > 0) { + AlignedFuncStorage TailExitRecordBuffer; + // Rewind the TSC back over the TAIL EXIT record. + const auto &ExpectedTailExit = + *reinterpret_cast(std::memcpy( + &TailExitRecordBuffer, RewindingRecordPtr, FunctionRecSize)); + + assert(ExpectedTailExit.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && + "Expected to find tail exit when rewinding."); + auto TailExitFuncId = ExpectedTailExit.FuncId; + RewindingRecordPtr -= FunctionRecSize; + RewindingTSC -= ExpectedTailExit.TSCDelta; + AlignedFuncStorage FunctionEntryBuffer; + const auto &ExpectedFunctionEntry = + *reinterpret_cast(std::memcpy( + &FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); + assert(ExpectedFunctionEntry.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && + "Expected to find function entry when rewinding tail call."); + assert(ExpectedFunctionEntry.FuncId == TailExitFuncId && + "Expected funcids to match when rewinding tail call."); + + if ((TSC - RewindingTSC) < NumberOfTicksThreshold) { + // We can erase a tail exit pair that we're exiting through since + // its duration is under threshold. + --NumTailCalls; + RewindingRecordPtr -= FunctionRecSize; + RewindingTSC -= ExpectedFunctionEntry.TSCDelta; + RecordPtr -= 2 * FunctionRecSize; + LastTSC = RewindingTSC; + } else { + // This tail call exceeded the threshold duration. It will not + // be erased. + NumTailCalls = 0; + return; + } + } + return; // without writing log. + } writeFunctionRecord(FuncId, RecordTSCDelta, Entry, RecordPtr); @@ -510,5 +644,4 @@ static inline void processFunctionHook( } // namespace __xray_fdr_internal } // namespace __xray - #endif // XRAY_XRAY_FDR_LOGGING_IMPL_H diff --git a/lib/xray/xray_flags.inc b/lib/xray/xray_flags.inc index 7a16c4147..7ddce78eb 100644 --- a/lib/xray/xray_flags.inc +++ b/lib/xray/xray_flags.inc @@ -22,3 +22,6 @@ XRAY_FLAG(const char *, xray_logfile_base, "xray-log.", "Filename base for the xray logfile.") XRAY_FLAG(bool, xray_fdr_log, false, "Whether to install the flight data recorder logging implementation.") +XRAY_FLAG(int, xray_fdr_log_func_duration_threshold_us, 5, + "FDR logging will try to skip functions that execute for fewer " + "microseconds than this threshold.") diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index 4aa3964c9..9fb54ce7b 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -1,7 +1,10 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-unwrite-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=5000" %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix=TRACE +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-unwrite-test-* | head -1`" | FileCheck %s --check-prefix=UNWRITE // RUN: rm fdr-logging-test-* +// RUN: rm fdr-unwrite-test-* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux @@ -61,8 +64,6 @@ int main(int argc, char *argv[]) { return 0; } - - // Check that we're able to see two threads, each entering and exiting fA(). // TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } // TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } @@ -80,3 +81,9 @@ int main(int argc, char *argv[]) { // TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } // TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } // TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } + +// Assert that when unwriting is enabled with a high threshold time, all the function records are erased. A CPU switch could erroneously fail this test, but +// is unlikely given the test program. +// UNWRITE: header +// UNWRITE-NOT: function-enter +// UNWRITE-NOT: function-exit -- cgit v1.2.1 From 500b2fd06f162094319a95424bcbebf25cd35fd2 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 6 Apr 2017 07:42:27 +0000 Subject: [lsan] Avoid segfaults during threads destruction under high load This patch addresses two issues: * It turned out that suspended thread may have dtls->dtv_size == kDestroyedThread (-1) and LSan wrongly assumes that DTV is available. This leads to SEGV when LSan tries to iterate through DTV that is invalid. * In some rare cases GetRegistersAndSP can fail with errno 3 (ESRCH). In this case LSan assumes that the whole stack of a given thread is available. This is wrong because ESRCH can indicate that suspended thread was destroyed and its stack was unmapped. This patch properly handles ESRCH from GetRegistersAndSP in order to avoid invalid accesses to already unpapped threads stack. Differential Revision: https://reviews.llvm.org/D30818 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299630 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 18 ++++++++++++------ lib/sanitizer_common/sanitizer_stoptheworld.h | 9 ++++++++- .../sanitizer_stoptheworld_linux_libcdep.cc | 14 +++++++++----- lib/sanitizer_common/sanitizer_tls_get_addr.cc | 6 ++++++ lib/sanitizer_common/sanitizer_tls_get_addr.h | 2 ++ 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 5ae3ad27e..ade8b0a02 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -201,11 +201,13 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, continue; } uptr sp; - bool have_registers = - (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); - if (!have_registers) { - Report("Unable to get registers from thread %d.\n"); - // If unable to get SP, consider the entire stack to be reachable. + PtraceRegistersStatus have_registers = + suspended_threads.GetRegistersAndSP(i, registers.data(), &sp); + if (have_registers != REGISTERS_AVAILABLE) { + Report("Unable to get registers from thread %d.\n", os_id); + // If unable to get SP, consider the entire stack to be reachable unless + // GetRegistersAndSP failed with ESRCH. + if (have_registers == REGISTERS_UNAVAILABLE_FATAL) continue; sp = stack_begin; } @@ -253,7 +255,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, if (tls_end > cache_end) ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); } - if (dtls) { + if (dtls && !DTLSInDestruction(dtls)) { for (uptr j = 0; j < dtls->dtv_size; ++j) { uptr dtls_beg = dtls->dtv[j].beg; uptr dtls_end = dtls_beg + dtls->dtv[j].size; @@ -263,6 +265,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, kReachable); } } + } else { + // We are handling a thread with DTLS under destruction. Log about + // this and continue. + LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id); } } } diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h index aa6f5d833..41752d8f6 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -20,6 +20,12 @@ namespace __sanitizer { typedef int SuspendedThreadID; +enum PtraceRegistersStatus { + REGISTERS_UNAVAILABLE_FATAL = -1, + REGISTERS_UNAVAILABLE = 0, + REGISTERS_AVAILABLE = 1 +}; + // Holds the list of suspended threads and provides an interface to dump their // register contexts. class SuspendedThreadsList { @@ -30,7 +36,8 @@ class SuspendedThreadsList { CHECK_LT(index, thread_ids_.size()); return thread_ids_[index]; } - int GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; // The buffer in GetRegistersAndSP should be at least this big. static uptr RegisterCount(); uptr thread_count() const { return thread_ids_.size(); } diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index ce8873b9e..3c0fd7b13 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -493,9 +493,9 @@ typedef _user_regs_struct regs_struct; #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) -int SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, + uptr *buffer, + uptr *sp) const { pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; @@ -513,12 +513,16 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index, if (isErr) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); - return -1; + // ESRCH means that the given thread is not suspended or already dead. + // Therefore it's unsafe to inspect its data (e.g. walk through stack) and + // we should notify caller about this. + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; } *sp = regs.REG_SP; internal_memcpy(buffer, ®s, sizeof(regs)); - return 0; + return REGISTERS_AVAILABLE; } uptr SuspendedThreadsList::RegisterCount() { diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 77c1947d5..aa146d01f 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -136,11 +136,17 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) { DTLS *DTLS_Get() { return &dtls; } +bool DTLSInDestruction(DTLS *dtls) { + return dtls->dtv_size == kDestroyedThread; +} + #else void DTLS_on_libc_memalign(void *ptr, uptr size) {} DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } DTLS *DTLS_Get() { return 0; } void DTLS_Destroy() {} +bool DTLSInDestruction(DTLS *dtls) { UNREACHABLE(); } + #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.h b/lib/sanitizer_common/sanitizer_tls_get_addr.h index 58d47634d..199a3b2e9 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.h +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -55,6 +55,8 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin, void DTLS_on_libc_memalign(void *ptr, uptr size); DTLS *DTLS_Get(); void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. +// Returns true if DTLS of suspended thread is in destruction process. +bool DTLSInDestruction(DTLS *dtls); } // namespace __sanitizer -- cgit v1.2.1 From e3ebbf0ee725d0e0799476b345c2d2b31a2e7819 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 6 Apr 2017 07:53:26 +0000 Subject: Try to fix windows buildbot after r299630 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299631 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_tls_get_addr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index aa146d01f..a45b085c2 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -145,7 +145,7 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {} DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } DTLS *DTLS_Get() { return 0; } void DTLS_Destroy() {} -bool DTLSInDestruction(DTLS *dtls) { UNREACHABLE(); } +bool DTLSInDestruction(DTLS *dtls) { return true; } #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR -- cgit v1.2.1 From 5829a6235d14f6cbf0c07d67d453a306d6ba655a Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 6 Apr 2017 08:17:09 +0000 Subject: Try to fix MAC buildbot after r299630 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299632 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 8 ++++---- lib/sanitizer_common/sanitizer_tls_get_addr.cc | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index a7aa2f06c..047472a65 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -23,11 +23,11 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { CHECK(0 && "unimplemented"); } -int SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, + uptr *buffer, + uptr *sp) const { CHECK(0 && "unimplemented"); - return 0; + return REGISTERS_UNAVAILABLE_FATAL; } uptr SuspendedThreadsList::RegisterCount() { diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index a45b085c2..29db37b8a 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -145,7 +145,9 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {} DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } DTLS *DTLS_Get() { return 0; } void DTLS_Destroy() {} -bool DTLSInDestruction(DTLS *dtls) { return true; } +bool DTLSInDestruction(DTLS *dtls) { + UNREACHABLE("dtls is unsupported on this platform!"); +} #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR -- cgit v1.2.1 From c4b0a1a3e563b3369e43710f67e34948f11be416 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 6 Apr 2017 11:27:53 +0000 Subject: [XRay][compiler-rt] Remove unused local variable The local was only referenced in assertions. Follow-up to D31345. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299644 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 0867227f1..20e89d6c1 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -594,7 +594,6 @@ static inline void processFunctionHook( assert(ExpectedTailExit.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && "Expected to find tail exit when rewinding."); - auto TailExitFuncId = ExpectedTailExit.FuncId; RewindingRecordPtr -= FunctionRecSize; RewindingTSC -= ExpectedTailExit.TSCDelta; AlignedFuncStorage FunctionEntryBuffer; @@ -604,7 +603,7 @@ static inline void processFunctionHook( assert(ExpectedFunctionEntry.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && "Expected to find function entry when rewinding tail call."); - assert(ExpectedFunctionEntry.FuncId == TailExitFuncId && + assert(ExpectedFunctionEntry.FuncId == ExpectedTailExit.FuncId && "Expected funcids to match when rewinding tail call."); if ((TSC - RewindingTSC) < NumberOfTicksThreshold) { -- cgit v1.2.1 From af3a7b5594e854f434e4b5f990e0f758aa81832a Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 6 Apr 2017 17:09:08 +0000 Subject: [TSan] Adjust expectation for check_analyze.sh r299658 fixed a case where InstCombine was replicating instructions instead of combining. Fixing this reduced the number of pushes and pops in the __tsan_read and __tsan_write functions. Adjust the expectations to account for this after talking to Dmitry Vyukov. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299661 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/check_analyze.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh index a5d3632df..d454ec2dd 100755 --- a/lib/tsan/check_analyze.sh +++ b/lib/tsan/check_analyze.sh @@ -26,22 +26,16 @@ check() { fi } -for f in write1; do +for f in write1 write2 write4 write8; do check $f rsp 1 check $f push 2 check $f pop 2 done -for f in write2 write4 write8; do - check $f rsp 1 - check $f push 3 - check $f pop 3 -done - for f in read1 read2 read4 read8; do check $f rsp 1 - check $f push 5 - check $f pop 5 + check $f push 4 + check $f pop 4 done for f in func_entry func_exit; do -- cgit v1.2.1 From 9ba14dedfd9580d20d665a9bd02851ae30c0272f Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 6 Apr 2017 17:41:26 +0000 Subject: Enable builds of darwin lsan by default Summary: Testing and asan leak detection are disabled by default. Reviewers: kubamracek, kcc Subscribers: srhines, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D31307 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299669 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 7 ------- lib/asan/CMakeLists.txt | 4 ---- lib/asan/asan_flags.cc | 2 +- lib/lsan/CMakeLists.txt | 4 ---- lib/lsan/lsan_common.h | 9 ++++----- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 6 files changed, 6 insertions(+), 22 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index e61a4f146..e336541b5 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -477,13 +477,6 @@ else() set(COMPILER_RT_HAS_LSAN FALSE) endif() -if(APPLE) - option(COMPILER_RT_ENABLE_LSAN_OSX "Enable building LSan for OS X - Experimental" Off) - if(COMPILER_RT_ENABLE_LSAN_OSX) - set(COMPILER_RT_HAS_LSAN TRUE) - endif() -endif() - if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux") set(COMPILER_RT_HAS_MSAN TRUE) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index e940cc756..a2d4630df 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -37,10 +37,6 @@ include_directories(..) set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) -# FIXME(fjricci) - remove this once lsan for darwin is fully enabled -if(APPLE AND COMPILER_RT_HAS_LSAN) - set(ASAN_CFLAGS ${ASAN_CFLAGS} -DCAN_SANITIZE_LEAKS_MAC=1) -endif() append_rtti_flag(OFF ASAN_CFLAGS) set(ASAN_DYNAMIC_LINK_FLAGS) diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 555cc04db..c8ae3faed 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -61,7 +61,7 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); - cf.detect_leaks = CAN_SANITIZE_LEAKS; + cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index 4e66100c3..e9db8ac62 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -18,10 +18,6 @@ set(LSAN_SOURCES set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -# FIXME(fjricci) - remove this once lsan for darwin is fully enabled -if(APPLE AND COMPILER_RT_HAS_LSAN) - set(LSAN_CFLAGS ${LSAN_CFLAGS} -DCAN_SANITIZE_LEAKS_MAC=1) -endif() add_compiler_rt_object_libraries(RTLSanCommon OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${LSAN_COMMON_SUPPORTED_ARCH} diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index cb8126aa5..082492dec 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -30,13 +30,12 @@ // To enable LeakSanitizer on new architecture, one need to implement // internal_clone function as well as (probably) adjust TLS machinery for // new architecture inside sanitizer library. -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) && \ +#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ + (SANITIZER_WORDSIZE == 64) && \ (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) #define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_LINUX && !SANITIZER_ANDROID && defined(__i386__) -#define CAN_SANITIZE_LEAKS 1 -#elif CAN_SANITIZE_LEAKS_MAC && (defined(__x86_64__) || defined(__mips64) || \ - defined(__aarch64__) || defined(__i386__)) +#elif defined(__i386__) && \ + (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index e61d1c3b4..40f8b6204 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -62,7 +62,7 @@ COMMON_FLAG( COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") -COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.") +COMMON_FLAG(bool, detect_leaks, !SANITIZER_MAC, "Enable memory leak detection.") COMMON_FLAG( bool, leak_check_at_exit, true, "Invoke leak checking in an atexit handler. Has no effect if " -- cgit v1.2.1 From 0536342a37dcd79009a74983d0d265bc2585d686 Mon Sep 17 00:00:00 2001 From: Ivan Krasin Date: Thu, 6 Apr 2017 17:58:45 +0000 Subject: Add a virtual destructor to a class with virtual methods. Summary: Recently, Clang enabled the check for virtual destructors in the presence of virtual methods. That broke the bootstrap build. Fixing it. Reviewers: pcc Reviewed By: pcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31776 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299672 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flag_parser.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 2477aeddb..18f1adc12 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -22,6 +22,7 @@ namespace __sanitizer { class FlagHandlerBase { public: + virtual ~FlagHandlerBase() {} virtual bool Parse(const char *value) { return false; } }; -- cgit v1.2.1 From 35c61d8119e5a2ecce5c93dc15e143d3f1910033 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 6 Apr 2017 18:12:02 +0000 Subject: Add __ffssi2 implementation to compiler-rt builtins Summary: During MIPS implementation work for FreeBSD, John Baldwin (jhb@FreeBSD.org) found that gcc 6.x emits calls to __ffssi2() when compiling libc and some userland programs in the base system. Add it to compiler-rt's builtins, based off of the existing __ffsdi2() implementation. Also update the CMake files and add a test case. Reviewers: howard.hinnant, weimingz, rengolin, compnerd Reviewed By: weimingz Subscribers: dberris, mgorny, llvm-commits, emaste Differential Revision: https://reviews.llvm.org/D31721 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299675 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 1 + lib/builtins/README.txt | 1 + lib/builtins/ffssi2.c | 29 ++++++++++++++++++++ test/builtins/Unit/ffssi2_test.c | 57 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 lib/builtins/ffssi2.c create mode 100644 test/builtins/Unit/ffssi2_test.c diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 3f648dcb3..28901034e 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -71,6 +71,7 @@ set(GENERIC_SOURCES extendsfdf2.c extendhfsf2.c ffsdi2.c + ffssi2.c ffsti2.c fixdfdi.c fixdfsi.c diff --git a/lib/builtins/README.txt b/lib/builtins/README.txt index ad36e4e52..b3d083614 100644 --- a/lib/builtins/README.txt +++ b/lib/builtins/README.txt @@ -45,6 +45,7 @@ si_int __ctzsi2(si_int a); // count trailing zeros si_int __ctzdi2(di_int a); // count trailing zeros si_int __ctzti2(ti_int a); // count trailing zeros +si_int __ffssi2(si_int a); // find least significant 1 bit si_int __ffsdi2(di_int a); // find least significant 1 bit si_int __ffsti2(ti_int a); // find least significant 1 bit diff --git a/lib/builtins/ffssi2.c b/lib/builtins/ffssi2.c new file mode 100644 index 000000000..e5180eff5 --- /dev/null +++ b/lib/builtins/ffssi2.c @@ -0,0 +1,29 @@ +/* ===-- ffssi2.c - Implement __ffssi2 -------------------------------------=== + * + * 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 __ffssi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the index of the least significant 1-bit in a, or + * the value zero if a is zero. The least significant bit is index one. + */ + +COMPILER_RT_ABI si_int +__ffssi2(si_int a) +{ + if (a == 0) + { + return 0; + } + return __builtin_ctz(a) + 1; +} diff --git a/test/builtins/Unit/ffssi2_test.c b/test/builtins/Unit/ffssi2_test.c new file mode 100644 index 000000000..5d96b9636 --- /dev/null +++ b/test/builtins/Unit/ffssi2_test.c @@ -0,0 +1,57 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +//===-- ffssi2_test.c - Test __ffssi2 -------------------------------------===// +// +// 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 tests __ffssi2 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" +#include + +// Returns: the index of the least significant 1-bit in a, or +// the value zero if a is zero. The least significant bit is index one. + +COMPILER_RT_ABI si_int __ffssi2(si_int a); + +int test__ffssi2(si_int a, si_int expected) +{ + si_int x = __ffssi2(a); + if (x != expected) + printf("error in __ffssi2(0x%X) = %d, expected %d\n", a, x, expected); + return x != expected; +} + +int main() +{ + if (test__ffssi2(0x00000000, 0)) + return 1; + if (test__ffssi2(0x00000001, 1)) + return 1; + if (test__ffssi2(0x00000002, 2)) + return 1; + if (test__ffssi2(0x00000003, 1)) + return 1; + if (test__ffssi2(0x00000004, 3)) + return 1; + if (test__ffssi2(0x00000005, 1)) + return 1; + if (test__ffssi2(0x0000000A, 2)) + return 1; + if (test__ffssi2(0x10000000, 29)) + return 1; + if (test__ffssi2(0x20000000, 30)) + return 1; + if (test__ffssi2(0x60000000, 30)) + return 1; + if (test__ffssi2(0x80000000u, 32)) + return 1; + + return 0; +} -- cgit v1.2.1 From ee0634886cd058c7d202ee349eb8cde4426936bc Mon Sep 17 00:00:00 2001 From: Ivan Krasin Date: Thu, 6 Apr 2017 18:22:25 +0000 Subject: Revert r299672: Add a virtual destructor to a class with virtual methods. Reason: breaks sanitizers builds. Original Differential Revision: https://reviews.llvm.org/D317 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299679 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flag_parser.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 18f1adc12..2477aeddb 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -22,7 +22,6 @@ namespace __sanitizer { class FlagHandlerBase { public: - virtual ~FlagHandlerBase() {} virtual bool Parse(const char *value) { return false; } }; -- cgit v1.2.1 From 6f78f5c40edb1fa33ca6c830310bfc80470dd096 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 6 Apr 2017 19:38:24 +0000 Subject: Replace a few uses of basename. This replaces a few uses of basename with the recently introduced lit replacements. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299693 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/coverage-missing.cc | 5 ++--- test/asan/TestCases/Posix/coverage-sandboxing.cc | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index 16c05b256..16093498f 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -29,17 +29,16 @@ // cd %T // RUN: %clangxx_asan -fsanitize-coverage=func %s -o %dynamiclib -DFOOBAR -shared -fPIC // RUN: %clangxx_asan -fsanitize-coverage=func %s %dynamiclib -o %t -DMAIN -// RUN: export LIBNAME=`basename %dynamiclib` // RUN: cd .. // RUN: rm -rf %T/coverage-missing // RUN: mkdir -p %T/coverage-missing // RUN: cd %T/coverage-missing // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x -// RUN: %sancov print $LIBNAME.*.sancov > foo.txt +// RUN: %sancov print %xdynamiclib_filename.*.sancov > foo.txt // RUN: rm *.sancov // RUN: count 2 < foo.txt // RUN: %env_asan_opts=coverage=1:coverage_dir=%T/coverage-missing %run %t x x -// RUN: %sancov print $LIBNAME.*.sancov > bar.txt +// RUN: %sancov print %xdynamiclib_filename.*.sancov > bar.txt // RUN: rm *.sancov // RUN: count 3 < bar.txt // RUN: %sancov missing %dynamiclib < foo.txt > foo-missing.txt diff --git a/test/asan/TestCases/Posix/coverage-sandboxing.cc b/test/asan/TestCases/Posix/coverage-sandboxing.cc index c4e6bc7ee..431dce149 100644 --- a/test/asan/TestCases/Posix/coverage-sandboxing.cc +++ b/test/asan/TestCases/Posix/coverage-sandboxing.cc @@ -12,9 +12,9 @@ // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t a b 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox // RUN: %sancov unpack coverage_sandboxing_test.sancov.packed // RUN: cd .. -// RUN: %sancov print vanilla/`basename %dynamiclib`*.sancov > vanilla.txt -// RUN: %sancov print sandbox1/`basename %dynamiclib`*.sancov > sandbox1.txt -// RUN: %sancov print sandbox2/`basename %dynamiclib`*.sancov > sandbox2.txt +// RUN: %sancov print vanilla/%xdynamiclib_filename*.sancov > vanilla.txt +// RUN: %sancov print sandbox1/%xdynamiclib_filename*.sancov > sandbox1.txt +// RUN: %sancov print sandbox2/%xdynamiclib_filename*.sancov > sandbox2.txt // RUN: diff vanilla.txt sandbox1.txt // RUN: diff vanilla.txt sandbox2.txt // RUN: rm -r %T/coverage_sandboxing_test -- cgit v1.2.1 From 58cce4a232c4be366fc49418a89c7da8902f6a86 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 6 Apr 2017 19:55:52 +0000 Subject: [asan] Fix dead stripping of globals on Linux (compiler-rt). This is a re-land of r298173, r298169, r298159. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299698 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 20 ++++++++++++++++++++ lib/asan/asan_interface.inc | 2 ++ lib/asan/asan_interface_internal.h | 5 +++++ test/asan/CMakeLists.txt | 2 +- test/asan/TestCases/Linux/global-overflow-bfd.cc | 18 ++++++++++++++++++ test/asan/TestCases/Linux/global-overflow-lld.cc | 19 +++++++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections-lld.cc | 15 +++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections.cc | 13 ------------- 8 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 test/asan/TestCases/Linux/global-overflow-bfd.cc create mode 100644 test/asan/TestCases/Linux/global-overflow-lld.cc create mode 100644 test/asan/TestCases/Linux/globals-gc-sections-lld.cc delete mode 100644 test/asan/TestCases/Linux/globals-gc-sections.cc diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index b72330673..eebada804 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -332,6 +332,26 @@ void __asan_unregister_image_globals(uptr *flag) { *flag = 0; } +void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { + if (*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_register_globals(globals_start, globals_stop - globals_start); + *flag = 1; +} + +void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { + if (!*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_unregister_globals(globals_start, globals_stop - globals_start); + *flag = 0; +} + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc index 351be4da5..e65f61722 100644 --- a/lib/asan/asan_interface.inc +++ b/lib/asan/asan_interface.inc @@ -64,6 +64,7 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_print_accumulated_stats) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_register_globals) +INTERFACE_FUNCTION(__asan_register_elf_globals) INTERFACE_FUNCTION(__asan_register_image_globals) INTERFACE_FUNCTION(__asan_report_error) INTERFACE_FUNCTION(__asan_report_exp_load1) @@ -149,6 +150,7 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) +INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index b18c31548..b974c0cc4 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -67,6 +67,11 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_elf_globals(uptr *flag, void *start, void *stop); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop); + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 4b4fdf19d..597a3e10d 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -22,7 +22,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(WIN32 AND COMPILER_RT_HAS_LLD) + if(NOT APPLE AND COMPILER_RT_HAS_LLD) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc new file mode 100644 index 000000000..117a761af --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-bfd.cc @@ -0,0 +1,18 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the BFD linker. +// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc new file mode 100644 index 000000000..f4d0bc977 --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-lld.cc @@ -0,0 +1,19 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the LLD linker. +// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: lld + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc new file mode 100644 index 000000000..0d8bcdd1c --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// REQUIRES: lld + +int undefined(); + +// On i386 clang adds --export-dynamic when linking with ASan, which adds all +// non-hidden globals to GC roots. +__attribute__((visibility("hidden"))) int (*unused)() = undefined; + +int main() { + return 0; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc deleted file mode 100644 index 72a9e9498..000000000 --- a/test/asan/TestCases/Linux/globals-gc-sections.cc +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 - -// https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// XFAIL: * - -int undefined(); - -int (*unused)() = undefined; - -int main() { - return 0; -} -- cgit v1.2.1 From 5a5d83e7f9aa2b358697712f94bcc4495242b0e4 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 01:23:15 +0000 Subject: [lit] Fix Darwin pickling errors with process pools For a function to be pickle-able, it has to be in the top-level of a real Python module. So, I made one for this code snippet. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299738 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/lit.common.unit.cfg | 11 ++++++++--- unittests/lit_unittest_cfg_utils.py | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 unittests/lit_unittest_cfg_utils.py diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg index 475b22d41..42df60433 100644 --- a/unittests/lit.common.unit.cfg +++ b/unittests/lit.common.unit.cfg @@ -35,6 +35,11 @@ if config.host_os == 'Darwin': # of large mmap'd regions (terabytes) by the kernel. lit_config.parallelism_groups["darwin-64bit-sanitizer"] = 3 - def darwin_sanitizer_parallelism_group_func(test): - return "darwin-64bit-sanitizer" if "x86_64" in test.file_path else "" - config.darwin_sanitizer_parallelism_group_func = darwin_sanitizer_parallelism_group_func + # The test config gets pickled and sent to multiprocessing workers, and that + # only works for code if it is stored at the top level of some module. + # Therefore, we have to put the code in a .py file, add it to path, and import + # it to store it in the config. + site.addsitedir(os.path.dirname(__file__)) + import lit_unittest_cfg_utils + config.darwin_sanitizer_parallelism_group_func = \ + lit_unittest_cfg_utils.darwin_sanitizer_parallelism_group_func diff --git a/unittests/lit_unittest_cfg_utils.py b/unittests/lit_unittest_cfg_utils.py new file mode 100644 index 000000000..ff7b1ee01 --- /dev/null +++ b/unittests/lit_unittest_cfg_utils.py @@ -0,0 +1,4 @@ +# Put all 64-bit sanitizer tests in the darwin-64bit-sanitizer parallelism +# group. This will only run three of them concurrently. +def darwin_sanitizer_parallelism_group_func(test): + return "darwin-64bit-sanitizer" if "x86_64" in test.file_path else "" -- cgit v1.2.1 From 7f45a60017e3b7401486ef3aeadac8d88b43f072 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 01:24:48 +0000 Subject: Add missing import git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299739 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/lit.common.unit.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg index 42df60433..b08c1fe12 100644 --- a/unittests/lit.common.unit.cfg +++ b/unittests/lit.common.unit.cfg @@ -39,6 +39,7 @@ if config.host_os == 'Darwin': # only works for code if it is stored at the top level of some module. # Therefore, we have to put the code in a .py file, add it to path, and import # it to store it in the config. + import site site.addsitedir(os.path.dirname(__file__)) import lit_unittest_cfg_utils config.darwin_sanitizer_parallelism_group_func = \ -- cgit v1.2.1 From 5584d09fda7674ea184463ffc4a47e53307534f1 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 16:35:09 +0000 Subject: [builtins] Get the builtins tests passing on Windows Many things were broken: - We stopped building most builtins on Windows in r261432 for reasons that are not at all clear to me. This essentially reverts that patch. - Fix %librt to expand to clang_rt.builtins-$arch.lib on Windows instead of libclang_rt.builtins-$arch.a. - Fix memory protection tests (trampoline, enable executable, clear cache) on Windows. One issue was that the MSVC incremental linker generates ILT thunks for functions with external linkage, so memcpying the functions into the executable stack buffer wasn't working. You can't memcpy an RIP-relative jump without fixing up the offset. - Disable tests that rely on C99 complex library functions when using the MSVC CRT, which isn't compatible with clang's C99 _Complex. In theory, these could all be separate patches, but it would not green the tests, so let's try for it all at once. Hopefully this fixes the clang-x64-ninja-win7 bot. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299780 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 13 ++--------- test/builtins/CMakeLists.txt | 2 ++ test/builtins/Unit/clear_cache_test.c | 21 ++++------------- test/builtins/Unit/divdc3_test.c | 2 ++ test/builtins/Unit/divsc3_test.c | 2 ++ test/builtins/Unit/divtc3_test.c | 2 ++ test/builtins/Unit/divxc3_test.c | 2 ++ test/builtins/Unit/enable_execute_stack_test.c | 32 ++++---------------------- test/builtins/Unit/lit.cfg | 14 ++++++++--- test/builtins/Unit/lit.site.cfg.in | 2 +- test/builtins/Unit/muldc3_test.c | 2 ++ test/builtins/Unit/mulsc3_test.c | 2 ++ test/builtins/Unit/mulxc3_test.c | 2 ++ test/builtins/Unit/trampoline_setup_test.c | 1 - 14 files changed, 38 insertions(+), 61 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 28901034e..161487e70 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -176,15 +176,6 @@ if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN) atomic.c) endif() -set(MSVC_SOURCES - divsc3.c - divdc3.c - divxc3.c - mulsc3.c - muldc3.c - mulxc3.c) - - if(APPLE) set(GENERIC_SOURCES ${GENERIC_SOURCES} @@ -264,9 +255,9 @@ else () # MSVC x86_64/floatdidf.c x86_64/floatdisf.c x86_64/floatdixf.c - ${MSVC_SOURCES}) + ${GENERIC_SOURCES}) set(x86_64h_SOURCES ${x86_64_SOURCES}) - set(i386_SOURCES ${MSVC_SOURCES}) + set(i386_SOURCES ${GENERIC_SOURCES}) set(i686_SOURCES ${i386_SOURCES}) endif () # if (NOT MSVC) diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt index f37e46d3a..cabf76722 100644 --- a/test/builtins/CMakeLists.txt +++ b/test/builtins/CMakeLists.txt @@ -13,6 +13,8 @@ configure_lit_site_cfg( include(builtin-config-ix) +pythonize_bool(MSVC) + #TODO: Add support for Apple. if (NOT APPLE) foreach(arch ${BUILTIN_SUPPORTED_ARCH}) diff --git a/test/builtins/Unit/clear_cache_test.c b/test/builtins/Unit/clear_cache_test.c index 590be7eb2..58960ce3c 100644 --- a/test/builtins/Unit/clear_cache_test.c +++ b/test/builtins/Unit/clear_cache_test.c @@ -16,12 +16,6 @@ #include #if defined(_WIN32) #include -void __clear_cache(void* start, void* end) -{ - if (!FlushInstructionCache(GetCurrentProcess(), start, end-start)) - exit(1); -} - static uintptr_t get_page_size() { SYSTEM_INFO si; GetSystemInfo(&si); @@ -30,27 +24,20 @@ static uintptr_t get_page_size() { #else #include #include -extern void __clear_cache(void* start, void* end); static uintptr_t get_page_size() { return sysconf(_SC_PAGE_SIZE); } #endif - +extern void __clear_cache(void* start, void* end); typedef int (*pfunc)(void); -int func1() -{ - return 1; -} - -int func2() -{ - return 2; -} +// Make these static to avoid ILT jumps for incremental linking on Windows. +static int func1() { return 1; } +static int func2() { return 2; } void *__attribute__((noinline)) memcpy_f(void *dst, const void *src, size_t n) { diff --git a/test/builtins/Unit/divdc3_test.c b/test/builtins/Unit/divdc3_test.c index 3c69cf3d0..042fd23f0 100644 --- a/test/builtins/Unit/divdc3_test.c +++ b/test/builtins/Unit/divdc3_test.c @@ -17,6 +17,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the quotient of (a + ib) / (c + id) COMPILER_RT_ABI double _Complex diff --git a/test/builtins/Unit/divsc3_test.c b/test/builtins/Unit/divsc3_test.c index 42430151f..daa221825 100644 --- a/test/builtins/Unit/divsc3_test.c +++ b/test/builtins/Unit/divsc3_test.c @@ -17,6 +17,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the quotient of (a + ib) / (c + id) COMPILER_RT_ABI float _Complex diff --git a/test/builtins/Unit/divtc3_test.c b/test/builtins/Unit/divtc3_test.c index f561a9644..7474330f6 100644 --- a/test/builtins/Unit/divtc3_test.c +++ b/test/builtins/Unit/divtc3_test.c @@ -18,6 +18,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the quotient of (a + ib) / (c + id) COMPILER_RT_ABI long double _Complex diff --git a/test/builtins/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c index d71660bfe..d0cdb0169 100644 --- a/test/builtins/Unit/divxc3_test.c +++ b/test/builtins/Unit/divxc3_test.c @@ -19,6 +19,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the quotient of (a + ib) / (c + id) COMPILER_RT_ABI long double _Complex diff --git a/test/builtins/Unit/enable_execute_stack_test.c b/test/builtins/Unit/enable_execute_stack_test.c index 24165ed9f..72fc042e6 100644 --- a/test/builtins/Unit/enable_execute_stack_test.c +++ b/test/builtins/Unit/enable_execute_stack_test.c @@ -13,39 +13,14 @@ #include #include #include -#if defined(_WIN32) -#include -void __clear_cache(void* start, void* end) -{ - if (!FlushInstructionCache(GetCurrentProcess(), start, end-start)) - exit(1); -} -void __enable_execute_stack(void *addr) -{ - MEMORY_BASIC_INFORMATION b; - - if (!VirtualQuery(addr, &b, sizeof(b))) - exit(1); - if (!VirtualProtect(b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, &b.Protect)) - exit(1); -} -#else -#include extern void __clear_cache(void* start, void* end); extern void __enable_execute_stack(void* addr); -#endif typedef int (*pfunc)(void); -int func1() -{ - return 1; -} - -int func2() -{ - return 2; -} +// Make these static to avoid ILT jumps for incremental linking on Windows. +static int func1() { return 1; } +static int func2() { return 2; } void *__attribute__((noinline)) memcpy_f(void *dst, const void *src, size_t n) { @@ -69,6 +44,7 @@ int main() // verify you can copy and execute a function pfunc f1 = (pfunc)memcpy_f(execution_buffer, func1, 128); __clear_cache(execution_buffer, &execution_buffer[128]); + printf("f1: %p\n", f1); if ((*f1)() != 1) return 1; diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg index f29f7e00d..9e3a0d6f7 100644 --- a/test/builtins/Unit/lit.cfg +++ b/test/builtins/Unit/lit.cfg @@ -24,15 +24,21 @@ default_builtins_opts = '' config.test_source_root = os.path.dirname(__file__) # Path to the static library -base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a " - % config.target_arch) +is_msvc = get_required_attr(config, "builtins_is_msvc") +if is_msvc: + base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.builtins-%s.lib " + % config.target_arch) + config.substitutions.append( ("%librt ", base_lib) ) +else: + base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.builtins-%s.a" + % config.target_arch) + config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') ) builtins_source_dir = os.path.join( get_required_attr(config, "compiler_rt_src_root"), "lib", "builtins") builtins_lit_source_dir = get_required_attr(config, "builtins_lit_source_dir") extra_link_flags = ["-nodefaultlibs"] -config.substitutions.append( ("%librt ", base_lib + ' -lc -lm ') ) target_cflags = [get_required_attr(config, "target_cflags")] target_cflags += ['-fno-builtin', '-I', builtins_source_dir] @@ -46,6 +52,8 @@ clang_builtins_static_cxxflags = config.cxx_mode_flags + \ clang_builtins_cflags = clang_builtins_static_cflags clang_builtins_cxxflags = clang_builtins_static_cxxflags +if not is_msvc: + config.available_features.add('c99-complex') config.available_features.add('not-android') clang_wrapper = "" diff --git a/test/builtins/Unit/lit.site.cfg.in b/test/builtins/Unit/lit.site.cfg.in index 4b4009d1e..16dc5ab68 100644 --- a/test/builtins/Unit/lit.site.cfg.in +++ b/test/builtins/Unit/lit.site.cfg.in @@ -4,7 +4,7 @@ config.name_suffix = "@BUILTINS_TEST_CONFIG_SUFFIX@" config.builtins_lit_source_dir = "@BUILTINS_LIT_SOURCE_DIR@/Unit" config.target_cflags = "@BUILTINS_TEST_TARGET_CFLAGS@" config.target_arch = "@BUILTINS_TEST_TARGET_ARCH@" - +config.builtins_is_msvc = "@MSVC_PYBOOL@" # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/test/builtins/Unit/muldc3_test.c b/test/builtins/Unit/muldc3_test.c index add09f4e8..5a856bc2c 100644 --- a/test/builtins/Unit/muldc3_test.c +++ b/test/builtins/Unit/muldc3_test.c @@ -17,6 +17,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the product of a + ib and c + id COMPILER_RT_ABI double _Complex diff --git a/test/builtins/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c index b14e237d3..46309c3e4 100644 --- a/test/builtins/Unit/mulsc3_test.c +++ b/test/builtins/Unit/mulsc3_test.c @@ -19,6 +19,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the product of a + ib and c + id COMPILER_RT_ABI float _Complex diff --git a/test/builtins/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c index 384c6ee11..3260b7521 100644 --- a/test/builtins/Unit/mulxc3_test.c +++ b/test/builtins/Unit/mulxc3_test.c @@ -19,6 +19,8 @@ #include #include +// REQUIRES: c99-complex + // Returns: the product of a + ib and c + id COMPILER_RT_ABI long double _Complex diff --git a/test/builtins/Unit/trampoline_setup_test.c b/test/builtins/Unit/trampoline_setup_test.c index 5a75724f4..b8c3eae2d 100644 --- a/test/builtins/Unit/trampoline_setup_test.c +++ b/test/builtins/Unit/trampoline_setup_test.c @@ -13,7 +13,6 @@ #include #include #include -#include /* * Tests nested functions -- cgit v1.2.1 From 27ebbdc985fb55567329aa2b510229cc19bd62c5 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 16:54:32 +0000 Subject: [builtins] Fix MSVC build Avoid __attribute__((constructor)) in cpu_model.c. Use more C99 _Complex emulation in divtc3.c. Joerg Sonnenberger added this builtin just after the last round of C99 _Complex emulation landed in r249514 (Oct 2015). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299784 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 19 +++++++++++++------ lib/builtins/divtc3.c | 22 +++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 9a3737020..5ff6baf43 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -27,6 +27,10 @@ #include #endif +#ifndef __has_attribute +#define __has_attribute(attr) 0 +#endif + enum VendorSignatures { SIG_INTEL = 0x756e6547 /* Genu */, SIG_AMD = 0x68747541 /* Auth */ @@ -720,14 +724,17 @@ static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, return Features; } -#ifdef HAVE_INIT_PRIORITY -#define CONSTRUCTOR_PRIORITY (101) +#if defined(HAVE_INIT_PRIORITY) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) +#elif __has_attribute(__constructor__) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) #else -#define CONSTRUCTOR_PRIORITY +// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that +// this runs during initialization. +#define CONSTRUCTOR_ATTRIBUTE #endif -int __cpu_indicator_init(void) - __attribute__((constructor CONSTRUCTOR_PRIORITY)); +int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; struct __processor_model { unsigned int __cpu_vendor; @@ -742,7 +749,7 @@ struct __processor_model { the priority set. However, it still runs after ifunc initializers and needs to be called explicitly there. */ -int __attribute__((constructor CONSTRUCTOR_PRIORITY)) +int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { unsigned int EAX, EBX, ECX, EDX; unsigned int MaxLeaf = 5; diff --git a/lib/builtins/divtc3.c b/lib/builtins/divtc3.c index 04693df47..16e538ba4 100644 --- a/lib/builtins/divtc3.c +++ b/lib/builtins/divtc3.c @@ -17,7 +17,7 @@ /* Returns: the quotient of (a + ib) / (c + id) */ -COMPILER_RT_ABI long double _Complex +COMPILER_RT_ABI Lcomplex __divtc3(long double __a, long double __b, long double __c, long double __d) { int __ilogbw = 0; @@ -29,31 +29,31 @@ __divtc3(long double __a, long double __b, long double __c, long double __d) __d = crt_scalbnl(__d, -__ilogbw); } long double __denom = __c * __c + __d * __d; - long double _Complex z; - __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); - __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); - if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + Lcomplex z; + COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); + COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) { if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) { - __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a; - __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b; + COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a; + COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b; } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) && crt_isfinite(__d)) { __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a); __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b); - __real__ z = CRT_INFINITY * (__a * __c + __b * __d); - __imag__ z = CRT_INFINITY * (__b * __c - __a * __d); + COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d); + COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d); } else if (crt_isinf(__logbw) && __logbw > 0.0 && crt_isfinite(__a) && crt_isfinite(__b)) { __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c); __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d); - __real__ z = 0.0 * (__a * __c + __b * __d); - __imag__ z = 0.0 * (__b * __c - __a * __d); + COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d); + COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d); } } return z; -- cgit v1.2.1 From 3cefeceb93691feccb4208de1004d4a887c2d63e Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 17:18:43 +0000 Subject: [builtins] Make some ISA macro checks work with MSVC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299786 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 2 +- lib/builtins/x86_64/floatdidf.c | 2 +- lib/builtins/x86_64/floatdisf.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index a68f9fcfb..25570fc21 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -90,7 +90,7 @@ uintptr_t GetCurrentProcess(void); */ void __clear_cache(void *start, void *end) { -#if __i386__ || __x86_64__ +#if __i386__ || __x86_64__ || defined(_M_IX86) || defined(_M_X64) /* * Intel processors have a unified instruction and data cache * so there is nothing to do diff --git a/lib/builtins/x86_64/floatdidf.c b/lib/builtins/x86_64/floatdidf.c index 388404e5e..dead0ed42 100644 --- a/lib/builtins/x86_64/floatdidf.c +++ b/lib/builtins/x86_64/floatdidf.c @@ -4,7 +4,7 @@ /* double __floatdidf(di_int a); */ -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) #include "../int_lib.h" diff --git a/lib/builtins/x86_64/floatdisf.c b/lib/builtins/x86_64/floatdisf.c index 96c3728e9..99d5621c6 100644 --- a/lib/builtins/x86_64/floatdisf.c +++ b/lib/builtins/x86_64/floatdisf.c @@ -2,7 +2,7 @@ * License. See LICENSE.TXT for details. */ -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) #include "../int_lib.h" -- cgit v1.2.1 From 47c2a986a937ff2d5b34f56936fe6ed13eeb1301 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 7 Apr 2017 17:40:25 +0000 Subject: [builtins] Remove stray quotes to fix check-builtins on non-Windows :( git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299790 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/lit.site.cfg.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builtins/Unit/lit.site.cfg.in b/test/builtins/Unit/lit.site.cfg.in index 16dc5ab68..4241bdc9c 100644 --- a/test/builtins/Unit/lit.site.cfg.in +++ b/test/builtins/Unit/lit.site.cfg.in @@ -4,7 +4,7 @@ config.name_suffix = "@BUILTINS_TEST_CONFIG_SUFFIX@" config.builtins_lit_source_dir = "@BUILTINS_LIT_SOURCE_DIR@/Unit" config.target_cflags = "@BUILTINS_TEST_TARGET_CFLAGS@" config.target_arch = "@BUILTINS_TEST_TARGET_ARCH@" -config.builtins_is_msvc = "@MSVC_PYBOOL@" +config.builtins_is_msvc = @MSVC_PYBOOL@ # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") -- cgit v1.2.1 From 0e4db8459796c37e6d4c1dbbf453a97a2c28fb0b Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 7 Apr 2017 18:55:03 +0000 Subject: Use a temp file to avoid Process Substitution. Thanks to Reid Kleckner for the suggestion. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299794 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/swapcontext_annotation.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/asan/TestCases/Linux/swapcontext_annotation.cc b/test/asan/TestCases/Linux/swapcontext_annotation.cc index 56e811942..44189c060 100644 --- a/test/asan/TestCases/Linux/swapcontext_annotation.cc +++ b/test/asan/TestCases/Linux/swapcontext_annotation.cc @@ -4,10 +4,11 @@ // RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK -// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK -// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK -// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: seq 60 | xargs -i -- grep LOOPCHECK %s > %t.checks +// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK // // This test is too subtle to try on non-x86 arch for now. -- cgit v1.2.1 From 85fba5b8386cf1450c4ffbbbeb2e3be548a8fbcd Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 7 Apr 2017 22:52:08 +0000 Subject: [cfi] Accept weak definition of __cfi_check. https://reviews.llvm.org/D31796 results in LLD emitting __cfi_check as a weak symbol, while Gold keeps it strong. Accept both. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299804 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc index e41ab3371..f720230a7 100644 --- a/lib/cfi/cfi.cc +++ b/lib/cfi/cfi.cc @@ -231,7 +231,8 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) { if (p->st_name >= strsz) break; char *name = (char*)(strtab + p->st_name); if (strcmp(name, "__cfi_check") == 0) { - assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)); + assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || + p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)); uptr addr = info->dlpi_addr + p->st_value; return addr; } -- cgit v1.2.1 From f14d140b756af46674e4f2914f99ea7f2575ced4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 17:22:06 +0000 Subject: [msan] Reorder unittests for future parametrization. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31892 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299858 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 136 ++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 59c40d384..f5c7c0ea1 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -927,74 +927,6 @@ TEST(MemorySanitizer, accept) { close(listen_socket); } -TEST(MemorySanitizer, getaddrinfo) { - struct addrinfo *ai; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - int res = getaddrinfo("localhost", NULL, &hints, &ai); - ASSERT_EQ(0, res); - EXPECT_NOT_POISONED(*ai); - ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); - EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); -} - -TEST(MemorySanitizer, getnameinfo) { - struct sockaddr_in sai; - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = 80; - sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - char host[500]; - char serv[500]; - int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host, - sizeof(host), serv, sizeof(serv), 0); - ASSERT_EQ(0, res); - EXPECT_NOT_POISONED(host[0]); - EXPECT_POISONED(host[sizeof(host) - 1]); - - ASSERT_NE(0U, strlen(host)); - EXPECT_NOT_POISONED(serv[0]); - EXPECT_POISONED(serv[sizeof(serv) - 1]); - ASSERT_NE(0U, strlen(serv)); -} - -#define EXPECT_HOSTENT_NOT_POISONED(he) \ - do { \ - EXPECT_NOT_POISONED(*(he)); \ - ASSERT_NE((void *) 0, (he)->h_name); \ - ASSERT_NE((void *) 0, (he)->h_aliases); \ - ASSERT_NE((void *) 0, (he)->h_addr_list); \ - EXPECT_NOT_POISONED(strlen((he)->h_name)); \ - char **p = (he)->h_aliases; \ - while (*p) { \ - EXPECT_NOT_POISONED(strlen(*p)); \ - ++p; \ - } \ - char **q = (he)->h_addr_list; \ - while (*q) { \ - EXPECT_NOT_POISONED(*q[0]); \ - ++q; \ - } \ - EXPECT_NOT_POISONED(*q); \ - } while (0) - -TEST(MemorySanitizer, gethostent) { - struct hostent *he = gethostent(); - ASSERT_NE((void *)NULL, he); - EXPECT_HOSTENT_NOT_POISONED(he); -} - -#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME - -TEST(MemorySanitizer, gethostbyname) { - struct hostent *he = gethostbyname("localhost"); - ASSERT_NE((void *)NULL, he); - EXPECT_HOSTENT_NOT_POISONED(he); -} - -#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME - TEST(MemorySanitizer, recvmsg) { int server_socket = socket(AF_INET, SOCK_DGRAM, 0); ASSERT_LT(0, server_socket); @@ -1065,6 +997,74 @@ TEST(MemorySanitizer, recvmsg) { close(client_socket); } +#define EXPECT_HOSTENT_NOT_POISONED(he) \ + do { \ + EXPECT_NOT_POISONED(*(he)); \ + ASSERT_NE((void *)0, (he)->h_name); \ + ASSERT_NE((void *)0, (he)->h_aliases); \ + ASSERT_NE((void *)0, (he)->h_addr_list); \ + EXPECT_NOT_POISONED(strlen((he)->h_name)); \ + char **p = (he)->h_aliases; \ + while (*p) { \ + EXPECT_NOT_POISONED(strlen(*p)); \ + ++p; \ + } \ + char **q = (he)->h_addr_list; \ + while (*q) { \ + EXPECT_NOT_POISONED(*q[0]); \ + ++q; \ + } \ + EXPECT_NOT_POISONED(*q); \ + } while (0) + +TEST(MemorySanitizer, gethostent) { + struct hostent *he = gethostent(); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME + +TEST(MemorySanitizer, gethostbyname) { + struct hostent *he = gethostbyname("localhost"); + ASSERT_NE((void *)NULL, he); + EXPECT_HOSTENT_NOT_POISONED(he); +} + +#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME + +TEST(MemorySanitizer, getaddrinfo) { + struct addrinfo *ai; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + int res = getaddrinfo("localhost", NULL, &hints, &ai); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(*ai); + ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); + EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); +} + +TEST(MemorySanitizer, getnameinfo) { + struct sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; + sai.sin_port = 80; + sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + char host[500]; + char serv[500]; + int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host, + sizeof(host), serv, sizeof(serv), 0); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(host[0]); + EXPECT_POISONED(host[sizeof(host) - 1]); + + ASSERT_NE(0U, strlen(host)); + EXPECT_NOT_POISONED(serv[0]); + EXPECT_POISONED(serv[sizeof(serv) - 1]); + ASSERT_NE(0U, strlen(serv)); +} + TEST(MemorySanitizer, gethostbyname2) { struct hostent *he = gethostbyname2("localhost", AF_INET); ASSERT_NE((void *)NULL, he); -- cgit v1.2.1 From 633658ab098aa98697bc2747a37ed553d5488a0e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 17:56:37 +0000 Subject: [msan] Wrap sockaddr_in and socket for future IPv6 support. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31893 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299859 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 128 ++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 51 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index f5c7c0ea1..e85db097d 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -175,10 +175,16 @@ void ExpectPoisonedWithOrigin(const T& t, unsigned origin) { } #define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x))) +#define EXPECT_NOT_POISONED2(data, size) \ + EXPECT_EQ(true, TestForNotPoisoned((data), (size))) + +bool TestForNotPoisoned(const void *data, size_t size) { + return __msan_test_shadow(data, size) == -1; +} template bool TestForNotPoisoned(const T& t) { - return __msan_test_shadow((void*)&t, sizeof(t)) == -1; + return TestForNotPoisoned((void *)&t, sizeof(t)); } static U8 poisoned_array[100]; @@ -879,48 +885,78 @@ TEST(MemorySanitizer, bind_getsockname) { close(sock); } +class SocketAddr { + public: + virtual ~SocketAddr() = default; + virtual struct sockaddr *ptr() = 0; + virtual size_t size() const = 0; +}; + +class SocketAddr4 : public SocketAddr { + public: + SocketAddr4() { EXPECT_POISONED(sai_); } + explicit SocketAddr4(uint16_t port) { + memset(&sai_, 0, sizeof(sai_)); + sai_.sin_family = AF_INET; + sai_.sin_port = port; + sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + sockaddr *ptr() override { + return reinterpret_cast(&sai_); + } + + size_t size() const override { return sizeof(sai_); } + + private: + sockaddr_in sai_; +}; + +template +std::unique_ptr CreateSockAddr(Args... args) { + return std::unique_ptr(new SocketAddr4(args...)); +} + +int CreateSocket(int socket_type) { return socket(AF_INET, socket_type, 0); } + TEST(MemorySanitizer, accept) { - int listen_socket = socket(AF_INET, SOCK_STREAM, 0); + int listen_socket = CreateSocket(SOCK_STREAM); ASSERT_LT(0, listen_socket); - struct sockaddr_in sai; - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = 0; - sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai)); + auto sai = CreateSockAddr(0); + int res = bind(listen_socket, sai->ptr(), sai->size()); ASSERT_EQ(0, res); res = listen(listen_socket, 1); ASSERT_EQ(0, res); - socklen_t sz = sizeof(sai); - res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz); + socklen_t sz = sai->size(); + res = getsockname(listen_socket, sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); + ASSERT_EQ(sai->size(), sz); - int connect_socket = socket(AF_INET, SOCK_STREAM, 0); + int connect_socket = CreateSocket(SOCK_STREAM); ASSERT_LT(0, connect_socket); res = fcntl(connect_socket, F_SETFL, O_NONBLOCK); ASSERT_EQ(0, res); - res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai)); + res = connect(connect_socket, sai->ptr(), sai->size()); // On FreeBSD this connection completes immediately. if (res != 0) { ASSERT_EQ(-1, res); ASSERT_EQ(EINPROGRESS, errno); } - __msan_poison(&sai, sizeof(sai)); - int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz); + __msan_poison(sai->ptr(), sai->size()); + int new_sock = accept(listen_socket, sai->ptr(), &sz); ASSERT_LT(0, new_sock); - ASSERT_EQ(sizeof(sai), sz); - EXPECT_NOT_POISONED(sai); + ASSERT_EQ(sai->size(), sz); + EXPECT_NOT_POISONED2(sai->ptr(), sai->size()); - __msan_poison(&sai, sizeof(sai)); - res = getpeername(new_sock, (struct sockaddr *)&sai, &sz); + __msan_poison(sai->ptr(), sai->size()); + res = getpeername(new_sock, sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); - EXPECT_NOT_POISONED(sai); + ASSERT_EQ(sai->size(), sz); + EXPECT_NOT_POISONED2(sai->ptr(), sai->size()); close(new_sock); close(connect_socket); @@ -928,38 +964,29 @@ TEST(MemorySanitizer, accept) { } TEST(MemorySanitizer, recvmsg) { - int server_socket = socket(AF_INET, SOCK_DGRAM, 0); + int server_socket = CreateSocket(SOCK_DGRAM); ASSERT_LT(0, server_socket); - struct sockaddr_in sai; - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = 0; - sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai)); + auto sai = CreateSockAddr(0); + int res = bind(server_socket, sai->ptr(), sai->size()); ASSERT_EQ(0, res); - socklen_t sz = sizeof(sai); - res = getsockname(server_socket, (struct sockaddr *)&sai, &sz); + socklen_t sz = sai->size(); + res = getsockname(server_socket, sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); - + ASSERT_EQ(sai->size(), sz); - int client_socket = socket(AF_INET, SOCK_DGRAM, 0); + int client_socket = CreateSocket(SOCK_DGRAM); ASSERT_LT(0, client_socket); - struct sockaddr_in client_sai; - memset(&client_sai, 0, sizeof(client_sai)); - client_sai.sin_family = AF_INET; - client_sai.sin_port = 0; - client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai)); + auto client_sai = CreateSockAddr(0); + res = bind(client_socket, client_sai->ptr(), client_sai->size()); ASSERT_EQ(0, res); - sz = sizeof(client_sai); - res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz); + sz = client_sai->size(); + res = getsockname(client_socket, client_sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(client_sai), sz); + ASSERT_EQ(client_sai->size(), sz); const char *s = "message text"; struct iovec iov; @@ -967,30 +994,29 @@ TEST(MemorySanitizer, recvmsg) { iov.iov_len = strlen(s) + 1; struct msghdr msg; memset(&msg, 0, sizeof(msg)); - msg.msg_name = &sai; - msg.msg_namelen = sizeof(sai); + msg.msg_name = sai->ptr(); + msg.msg_namelen = sai->size(); msg.msg_iov = &iov; msg.msg_iovlen = 1; res = sendmsg(client_socket, &msg, 0); ASSERT_LT(0, res); - char buf[1000]; struct iovec recv_iov; recv_iov.iov_base = (void *)&buf; recv_iov.iov_len = sizeof(buf); - struct sockaddr_in recv_sai; + auto recv_sai = CreateSockAddr(); struct msghdr recv_msg; memset(&recv_msg, 0, sizeof(recv_msg)); - recv_msg.msg_name = &recv_sai; - recv_msg.msg_namelen = sizeof(recv_sai); + recv_msg.msg_name = recv_sai->ptr(); + recv_msg.msg_namelen = recv_sai->size(); recv_msg.msg_iov = &recv_iov; recv_msg.msg_iovlen = 1; res = recvmsg(server_socket, &recv_msg, 0); ASSERT_LT(0, res); - ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen); - EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name); + ASSERT_EQ(recv_sai->size(), recv_msg.msg_namelen); + EXPECT_NOT_POISONED2(recv_sai->ptr(), recv_sai->size()); EXPECT_STREQ(s, buf); close(server_socket); @@ -1042,7 +1068,7 @@ TEST(MemorySanitizer, getaddrinfo) { ASSERT_EQ(0, res); EXPECT_NOT_POISONED(*ai); ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); - EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); + EXPECT_NOT_POISONED(*(sockaddr_in *)ai->ai_addr); } TEST(MemorySanitizer, getnameinfo) { -- cgit v1.2.1 From fed59961d750ac9b50b2ff772f6498836e8a02cb Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 17:58:03 +0000 Subject: [msan] Replace AF_INET with AF_UNIX to avoid IPv4 vs IPv6 issues. Summary: This reverts commit 79cf16bf224d6ac9fb9e0356c5947ebc4fd6ff92. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31895 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299860 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/ioctl.cc | 2 +- test/msan/ioctl_custom.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/msan/ioctl.cc b/test/msan/ioctl.cc index e21ef636c..66ac6e95b 100644 --- a/test/msan/ioctl.cc +++ b/test/msan/ioctl.cc @@ -8,7 +8,7 @@ #include int main(int argc, char **argv) { - int fd = socket(AF_INET, SOCK_DGRAM, 0); + int fd = socket(AF_UNIX, SOCK_DGRAM, 0); unsigned int z; int res = ioctl(fd, FIOGETOWN, &z); diff --git a/test/msan/ioctl_custom.cc b/test/msan/ioctl_custom.cc index 6df22d75e..eaab63384 100644 --- a/test/msan/ioctl_custom.cc +++ b/test/msan/ioctl_custom.cc @@ -14,7 +14,7 @@ #include int main(int argc, char **argv) { - int fd = socket(AF_INET, SOCK_STREAM, 0); + int fd = socket(AF_UNIX, SOCK_STREAM, 0); struct ifreq ifreqs[20]; struct ifconf ifc; -- cgit v1.2.1 From 3b81e31e9e0e47ea424cce966f86e56023c76474 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 17:59:07 +0000 Subject: [msan] Make test to fall-back to IPv6 if IPv4 is not available. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31896 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299862 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/Linux/sendmsg.cc | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/test/msan/Linux/sendmsg.cc b/test/msan/Linux/sendmsg.cc index 6a8ef83c1..4fc6c88cc 100644 --- a/test/msan/Linux/sendmsg.cc +++ b/test/msan/Linux/sendmsg.cc @@ -33,17 +33,31 @@ int main() { char buf[kBufSize] = {0}; pthread_t client_thread; struct sockaddr_in serveraddr; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in6 serveraddr6; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = 0; - - bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); + struct sockaddr *addr = (struct sockaddr *)&serveraddr; socklen_t addrlen = sizeof(serveraddr); - getsockname(sockfd, (struct sockaddr *)&serveraddr, &addrlen); + + sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); + if (sockfd <= 0) { + // Try to fall-back to IPv6 + memset(&serveraddr6, 0, sizeof(serveraddr6)); + serveraddr6.sin6_family = AF_INET6; + serveraddr6.sin6_addr = in6addr_any; + serveraddr6.sin6_port = 0; + addr = (struct sockaddr *)&serveraddr6; + addrlen = sizeof(serveraddr6); + + sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); + } + assert(sockfd > 0); + + bind(sockfd, addr, addrlen); + getsockname(sockfd, addr, &addrlen); #if defined(POISON) __msan_poison(buf + 7, 1); @@ -52,7 +66,7 @@ int main() { #if defined(SENDMSG) struct iovec iov[2] = {{buf, 5}, {buf + 5, 5}}; struct msghdr msg; - msg.msg_name = &serveraddr; + msg.msg_name = addr; msg.msg_namelen = addrlen; msg.msg_iov = iov; msg.msg_iovlen = 2; @@ -62,14 +76,13 @@ int main() { #endif #if defined(SEND) - ret = connect(sockfd, (struct sockaddr *)&serveraddr, addrlen); + ret = connect(sockfd, addr, addrlen); assert(ret == 0); ret = send(sockfd, buf, kBufSize, 0); // SEND: Uninitialized bytes in __interceptor_send at offset 7 inside [{{.*}}, 10) assert(ret > 0); #elif defined(SENDTO) - ret = - sendto(sockfd, buf, kBufSize, 0, (struct sockaddr *)&serveraddr, addrlen); + ret = sendto(sockfd, buf, kBufSize, 0, addr, addrlen); // SENDTO: Uninitialized bytes in __interceptor_sendto at offset 7 inside [{{.*}}, 10) assert(ret > 0); #elif defined(SENDMSG) -- cgit v1.2.1 From e2a1b2466a031742b659881d02a4677c59b5f057 Mon Sep 17 00:00:00 2001 From: "Ivan A. Kosarev" Date: Mon, 10 Apr 2017 19:13:47 +0000 Subject: [Asan] Eliminate SHADOW_TO_MEM() macro Differential Revision: https://reviews.llvm.org/D31592 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299867 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_mapping.h | 1 - lib/asan/asan_thread.cc | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index d8e60a4b3..695740cd9 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -191,7 +191,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) -#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE) #define kLowMemBeg 0 #define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0) diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index 2f9fa81e1..aaa32d6ea 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -300,24 +300,27 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr, return true; } uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. + uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY); u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); u8 *shadow_bottom = (u8*)MemToShadow(bottom); while (shadow_ptr >= shadow_bottom && *shadow_ptr != kAsanStackLeftRedzoneMagic) { shadow_ptr--; + mem_ptr -= SHADOW_GRANULARITY; } while (shadow_ptr >= shadow_bottom && *shadow_ptr == kAsanStackLeftRedzoneMagic) { shadow_ptr--; + mem_ptr -= SHADOW_GRANULARITY; } if (shadow_ptr < shadow_bottom) { return false; } - uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); + uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY); CHECK(ptr[0] == kCurrentStackFrameMagic); access->offset = addr - (uptr)ptr; access->frame_pc = ptr[2]; -- cgit v1.2.1 From 39c38f1fd54cfc3e34d444a6d5a59693540b1d4d Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 10 Apr 2017 20:36:43 +0000 Subject: Revert "[asan] Fix dead stripping of globals on Linux (compiler-rt)." This reverts r299698, which caused a big increase in object file size. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299881 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 20 -------------------- lib/asan/asan_interface.inc | 2 -- lib/asan/asan_interface_internal.h | 5 ----- test/asan/CMakeLists.txt | 2 +- test/asan/TestCases/Linux/global-overflow-bfd.cc | 18 ------------------ test/asan/TestCases/Linux/global-overflow-lld.cc | 19 ------------------- test/asan/TestCases/Linux/globals-gc-sections-lld.cc | 15 --------------- test/asan/TestCases/Linux/globals-gc-sections.cc | 13 +++++++++++++ 8 files changed, 14 insertions(+), 80 deletions(-) delete mode 100644 test/asan/TestCases/Linux/global-overflow-bfd.cc delete mode 100644 test/asan/TestCases/Linux/global-overflow-lld.cc delete mode 100644 test/asan/TestCases/Linux/globals-gc-sections-lld.cc create mode 100644 test/asan/TestCases/Linux/globals-gc-sections.cc diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index eebada804..b72330673 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -332,26 +332,6 @@ void __asan_unregister_image_globals(uptr *flag) { *flag = 0; } -void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { - if (*flag) return; - if (!start) return; - CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); - __asan_global *globals_start = (__asan_global*)start; - __asan_global *globals_stop = (__asan_global*)stop; - __asan_register_globals(globals_start, globals_stop - globals_start); - *flag = 1; -} - -void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { - if (!*flag) return; - if (!start) return; - CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); - __asan_global *globals_start = (__asan_global*)start; - __asan_global *globals_stop = (__asan_global*)stop; - __asan_unregister_globals(globals_start, globals_stop - globals_start); - *flag = 0; -} - // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc index e65f61722..351be4da5 100644 --- a/lib/asan/asan_interface.inc +++ b/lib/asan/asan_interface.inc @@ -64,7 +64,6 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_print_accumulated_stats) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_register_globals) -INTERFACE_FUNCTION(__asan_register_elf_globals) INTERFACE_FUNCTION(__asan_register_image_globals) INTERFACE_FUNCTION(__asan_report_error) INTERFACE_FUNCTION(__asan_report_exp_load1) @@ -150,7 +149,6 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) -INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index b974c0cc4..b18c31548 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -67,11 +67,6 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); - SANITIZER_INTERFACE_ATTRIBUTE - void __asan_register_elf_globals(uptr *flag, void *start, void *stop); - SANITIZER_INTERFACE_ATTRIBUTE - void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop); - // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 597a3e10d..4b4fdf19d 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -22,7 +22,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(NOT APPLE AND COMPILER_RT_HAS_LLD) + if(WIN32 AND COMPILER_RT_HAS_LLD) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc deleted file mode 100644 index 117a761af..000000000 --- a/test/asan/TestCases/Linux/global-overflow-bfd.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Test that gc-sections-friendly instrumentation of globals does not introduce -// false negatives with the BFD linker. -// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s - -#include -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at}} - // CHECK: {{located 0 bytes to the right of global variable}} - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc deleted file mode 100644 index f4d0bc977..000000000 --- a/test/asan/TestCases/Linux/global-overflow-lld.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Test that gc-sections-friendly instrumentation of globals does not introduce -// false negatives with the LLD linker. -// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: lld - -#include -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at}} - // CHECK: {{located 0 bytes to the right of global variable}} - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc deleted file mode 100644 index 0d8bcdd1c..000000000 --- a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1 - -// https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// REQUIRES: lld - -int undefined(); - -// On i386 clang adds --export-dynamic when linking with ASan, which adds all -// non-hidden globals to GC roots. -__attribute__((visibility("hidden"))) int (*unused)() = undefined; - -int main() { - return 0; -} diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc new file mode 100644 index 000000000..72a9e9498 --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// XFAIL: * + +int undefined(); + +int (*unused)() = undefined; + +int main() { + return 0; +} -- cgit v1.2.1 From f6ffcbb423e8ec9ee9238800d51b47f03336dcf9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 21:03:18 +0000 Subject: [msan] Choose in runtime if IPv4 or IPv6 are supported. Summary: This reverts commit cab5051c691ce27a7ffac41e8e76ceb222ad9549. Reviewers: eugenis Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D31894 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299884 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/CMakeLists.txt | 1 + lib/msan/tests/msan_test.cc | 62 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index 8e911dc10..65fbc732d 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -35,6 +35,7 @@ set(MSAN_UNITTEST_COMMON_CFLAGS -Wno-zero-length-array -Wno-uninitialized -Werror=sign-compare + -Wno-gnu-zero-variadic-macro-arguments ) set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS ${MSAN_UNITTEST_COMMON_CFLAGS} diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index e85db097d..12d6092ef 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -902,9 +902,7 @@ class SocketAddr4 : public SocketAddr { sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } - sockaddr *ptr() override { - return reinterpret_cast(&sai_); - } + sockaddr *ptr() override { return reinterpret_cast(&sai_); } size_t size() const override { return sizeof(sai_); } @@ -912,14 +910,60 @@ class SocketAddr4 : public SocketAddr { sockaddr_in sai_; }; -template -std::unique_ptr CreateSockAddr(Args... args) { - return std::unique_ptr(new SocketAddr4(args...)); +class SocketAddr6 : public SocketAddr { + public: + SocketAddr6() { EXPECT_POISONED(sai_); } + explicit SocketAddr6(uint16_t port) { + memset(&sai_, 0, sizeof(sai_)); + sai_.sin6_family = AF_INET6; + sai_.sin6_port = port; + sai_.sin6_addr = in6addr_loopback; + } + + sockaddr *ptr() override { return reinterpret_cast(&sai_); } + + size_t size() const override { return sizeof(sai_); } + + private: + sockaddr_in6 sai_; +}; + +class MemorySanitizerIpTest : public ::testing::TestWithParam { + public: + void SetUp() override { + ASSERT_TRUE(GetParam() == AF_INET || GetParam() == AF_INET6); + } + + template + std::unique_ptr CreateSockAddr(Args... args) const { + if (GetParam() == AF_INET) + return std::unique_ptr(new SocketAddr4(args...)); + return std::unique_ptr(new SocketAddr6(args...)); + } + + int CreateSocket(int socket_type) const { + return socket(GetParam(), socket_type, 0); + } +}; + +std::vector GetAvailableIpSocketFamilies() { + std::vector result; + + for (int i : std::vector(AF_INET, AF_INET6)) { + int s = socket(i, SOCK_STREAM, 0); + if (s > 0) { + result.push_back(i); + close(s); + } + } + + return result; } -int CreateSocket(int socket_type) { return socket(AF_INET, socket_type, 0); } +INSTANTIATE_TEST_CASE_P(IpTests, MemorySanitizerIpTest, + ::testing::ValuesIn(GetAvailableIpSocketFamilies())); -TEST(MemorySanitizer, accept) { +TEST_P(MemorySanitizerIpTest, accept) { int listen_socket = CreateSocket(SOCK_STREAM); ASSERT_LT(0, listen_socket); @@ -963,7 +1007,7 @@ TEST(MemorySanitizer, accept) { close(listen_socket); } -TEST(MemorySanitizer, recvmsg) { +TEST_P(MemorySanitizerIpTest, recvmsg) { int server_socket = CreateSocket(SOCK_DGRAM); ASSERT_LT(0, server_socket); -- cgit v1.2.1 From 3fa7e26dd981a5420aea038d14f5ba2b03060233 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 10 Apr 2017 21:03:21 +0000 Subject: [tsan] Fall-back to IPv6 if IPv4 is not available. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D31897 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299885 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/fd_socket_connect_norace.cc | 45 ++++++++++++++++++++++++----------- test/tsan/fd_socket_norace.cc | 45 ++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/test/tsan/fd_socket_connect_norace.cc b/test/tsan/fd_socket_connect_norace.cc index b9fb4340a..12375189a 100644 --- a/test/tsan/fd_socket_connect_norace.cc +++ b/test/tsan/fd_socket_connect_norace.cc @@ -1,20 +1,24 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include +#include -struct sockaddr_in addr; +struct sockaddr_in addr4; +struct sockaddr_in6 addr6; +struct sockaddr *addr; +socklen_t addrlen; int X; void *ClientThread(void *x) { - int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + int c = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); X = 42; - if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) { + if (connect(c, addr, addrlen)) { perror("connect"); exit(1); } @@ -23,13 +27,26 @@ void *ClientThread(void *x) { } int main() { - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - addr.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); - addr.sin_port = INADDR_ANY; - socklen_t len = sizeof(addr); - bind(s, (sockaddr*)&addr, len); - getsockname(s, (sockaddr*)&addr, &len); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr4.sin_port = INADDR_ANY; + addr = (struct sockaddr *)&addr4; + addrlen = sizeof(addr4); + + int s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (s <= 0) { + // Try to fall-back to IPv6 + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = in6addr_loopback; + addr6.sin6_port = INADDR_ANY; + addr = (struct sockaddr *)&addr6; + addrlen = sizeof(addr6); + s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + } + assert(s > 0); + + bind(s, addr, addrlen); + getsockname(s, addr, &addrlen); listen(s, 10); pthread_t t; pthread_create(&t, 0, ClientThread, 0); diff --git a/test/tsan/fd_socket_norace.cc b/test/tsan/fd_socket_norace.cc index 07b0cb356..a1761cb27 100644 --- a/test/tsan/fd_socket_norace.cc +++ b/test/tsan/fd_socket_norace.cc @@ -1,20 +1,24 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include +#include -struct sockaddr_in addr; +struct sockaddr_in addr4; +struct sockaddr_in6 addr6; +struct sockaddr *addr; +socklen_t addrlen; int X; void *ClientThread(void *x) { X = 42; - int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) { + int c = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (connect(c, addr, addrlen)) { perror("connect"); exit(1); } @@ -27,13 +31,26 @@ void *ClientThread(void *x) { } int main() { - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - addr.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); - addr.sin_port = INADDR_ANY; - socklen_t len = sizeof(addr); - bind(s, (sockaddr*)&addr, len); - getsockname(s, (sockaddr*)&addr, &len); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr4.sin_port = INADDR_ANY; + addr = (struct sockaddr *)&addr4; + addrlen = sizeof(addr4); + + int s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (s <= 0) { + // Try to fall-back to IPv6 + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = in6addr_loopback; + addr6.sin6_port = INADDR_ANY; + addr = (struct sockaddr *)&addr6; + addrlen = sizeof(addr6); + s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + } + assert(s > 0); + + bind(s, addr, addrlen); + getsockname(s, addr, &addrlen); listen(s, 10); pthread_t t; pthread_create(&t, 0, ClientThread, 0); -- cgit v1.2.1 From 227b4236671846ac63e018656df3377d33921baf Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 10 Apr 2017 23:24:50 +0000 Subject: [PPC64, Sanitizers] Proper stack frame for the thread spawned in internal_clone Summary: Set up the proper stack frame for the thread spawned in internal_clone, the current code does not follow ABI (and causes SEGV trying to use this malformed frame). Reviewers: wschmidt Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D31555 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299896 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 75 ++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index ab65e2db5..e166d1dcd 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1113,36 +1113,50 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long long res; -/* Stack frame offsets. */ -#if _CALL_ELF != 2 -#define FRAME_MIN_SIZE 112 -#define FRAME_TOC_SAVE 40 +// Stack frame structure. +#if SANITIZER_PPC64V1 +// Back chain == 0 (SP + 112) +// Frame (112 bytes): +// Parameter save area (SP + 48), 8 doublewords +// TOC save area (SP + 40) +// Link editor doubleword (SP + 32) +// Compiler doubleword (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 112 +# define FRAME_TOC_SAVE_OFFSET 40 +#elif SANITIZER_PPC64V2 +// Back chain == 0 (SP + 32) +// Frame (32 bytes): +// TOC save area (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 32 +# define FRAME_TOC_SAVE_OFFSET 24 #else -#define FRAME_MIN_SIZE 32 -#define FRAME_TOC_SAVE 24 +# error "Unsupported PPC64 ABI" #endif if (!fn || !child_stack) return -EINVAL; CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); - ((unsigned long long *)child_stack)[0] = (uptr)fn; - ((unsigned long long *)child_stack)[1] = (uptr)arg; register int (*__fn)(void *) __asm__("r3") = fn; register void *__cstack __asm__("r4") = child_stack; register int __flags __asm__("r5") = flags; - register void * __arg __asm__("r6") = arg; - register int * __ptidptr __asm__("r7") = parent_tidptr; - register void * __newtls __asm__("r8") = newtls; - register int * __ctidptr __asm__("r9") = child_tidptr; + register void *__arg __asm__("r6") = arg; + register int *__ptidptr __asm__("r7") = parent_tidptr; + register void *__newtls __asm__("r8") = newtls; + register int *__ctidptr __asm__("r9") = child_tidptr; __asm__ __volatile__( - /* fn, arg, child_stack are saved acrVoss the syscall */ + /* fn and arg are saved across the syscall */ "mr 28, %5\n\t" - "mr 29, %6\n\t" "mr 27, %8\n\t" /* syscall + r0 == __NR_clone r3 == flags r4 == child_stack r5 == parent_tidptr @@ -1160,15 +1174,21 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" "bne- cr1, 1f\n\t" + /* Set up stack frame */ + "li 29, 0\n\t" + "stdu 29, -8(1)\n\t" + "stdu 1, -%12(1)\n\t" /* Do the function call */ "std 2, %13(1)\n\t" -#if _CALL_ELF != 2 +#if SANITIZER_PPC64V1 "ld 0, 0(28)\n\t" "ld 2, 8(28)\n\t" "mtctr 0\n\t" -#else +#elif SANITIZER_PPC64V2 "mr 12, 28\n\t" "mtctr 12\n\t" +#else +# error "Unsupported PPC64 ABI" #endif "mr 3, 27\n\t" "bctrl\n\t" @@ -1182,13 +1202,20 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, "1:\n\t" "mr %0, 3\n\t" : "=r" (res) - : "0" (-1), "i" (EINVAL), - "i" (__NR_clone), "i" (__NR_exit), - "r" (__fn), "r" (__cstack), "r" (__flags), - "r" (__arg), "r" (__ptidptr), "r" (__newtls), - "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE) - : "cr0", "cr1", "memory", "ctr", - "r0", "r29", "r27", "r28"); + : "0" (-1), + "i" (EINVAL), + "i" (__NR_clone), + "i" (__NR_exit), + "r" (__fn), + "r" (__cstack), + "r" (__flags), + "r" (__arg), + "r" (__ptidptr), + "r" (__newtls), + "r" (__ctidptr), + "i" (FRAME_SIZE), + "i" (FRAME_TOC_SAVE_OFFSET) + : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); return res; } #elif defined(__i386__) && SANITIZER_LINUX -- cgit v1.2.1 From 2150691eef203a062918b563cd5131e4ee32b907 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 11 Apr 2017 06:04:08 +0000 Subject: [XRay][compiler-rt] Remove the xray_fdr_log_printer_tool Summary: We can move this functionality into LLVM's tools instead, as it no longer is strictly required for the compiler-rt testing infrastructure. It also is blocking the successful bootstrapping of the clang compiler due to a missing virtual destructor in one of the flag parsing library. Since this binary isn't critical for the XRay runtime testing effort anymore (yet), we remove it in the meantime with the hope of moving the functionality in LLVM proper instead. Reviewers: kpw, pelikan, rnk, seurer, eugenis Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D31926 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299916 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/unit/CMakeLists.txt | 2 - lib/xray/tests/unit/xray_fdr_log_printer_tool.cc | 330 ----------------------- 2 files changed, 332 deletions(-) delete mode 100644 lib/xray/tests/unit/xray_fdr_log_printer_tool.cc diff --git a/lib/xray/tests/unit/CMakeLists.txt b/lib/xray/tests/unit/CMakeLists.txt index 4ed919518..62d01f239 100644 --- a/lib/xray/tests/unit/CMakeLists.txt +++ b/lib/xray/tests/unit/CMakeLists.txt @@ -2,5 +2,3 @@ add_xray_unittest(XRayBufferQueueTest SOURCES buffer_queue_test.cc xray_unit_test_main.cc) add_xray_unittest(XRayFDRLoggingTest SOURCES fdr_logging_test.cc xray_unit_test_main.cc) - -add_executable(xray_fdr_log_printer xray_fdr_log_printer_tool.cc) diff --git a/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc b/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc deleted file mode 100644 index 6e209809e..000000000 --- a/lib/xray/tests/unit/xray_fdr_log_printer_tool.cc +++ /dev/null @@ -1,330 +0,0 @@ -//===-- xray_fdr_log_printer_tool.cc --------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of XRay, a function call tracing system. -// -//===----------------------------------------------------------------------===// - -#include "xray_fdr_logging.h" -#include "xray_fdr_logging_impl.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xray/xray_records.h" - -// Writes out xray fdr mode log records to stdout based on a sequence of -// formatted data read from stdin. -// -// Interprets an adhoc format of Top Level Types and parameter maps of the form: -// -// RecordType : { Parameter1 = Value, Parameter2 = value , Parameter3 = value} -// OtherRecordType : { ParameterOne = Value } -// -// Each line corresponds to a type of record written by the Xray Flight Data -// Recorder mode to a buffer. This program synthesizes records in the FDR binary -// format and writes them to std::cout. - -namespace { - -/// A crude lexer to read tokens and skip over whitespace. -class TokenReader { -public: - TokenReader() : LastDelimPresent(false), FoundEof(false), LastDelim(0) {} - std::string readToken(std::istream &Stream); - bool hasLastDelim() const { return LastDelimPresent; } - char getLastDelim() const { return LastDelim; } - void setLastDelim(char Delim) { - LastDelimPresent = true; - LastDelim = Delim; - } - void clearLastDelim() { - LastDelimPresent = false; - LastDelim = 0; - } - bool isEof() { return FoundEof; } - void setFoundEof(bool eof) { FoundEof = eof; } - -private: - bool LastDelimPresent; - bool FoundEof; - char LastDelim; -}; - -// Globally tracks whether we reached EOF and caches delimiters that qualify as -// tokens. -static TokenReader TokenReader{}; - -bool isWhitespace(char c) { - // Hardcode the whitespace characters we will not return as tokens even though - // they are token delimiters. - static const std::vector Whitespace{' ', '\n', '\t'}; - return std::find(Whitespace.begin(), Whitespace.end(), c) != Whitespace.end(); -} - -bool isDelimiter(char c) { - // Hardcode a set of token delimiters. - static const std::vector Delimiters{' ', ':', ',', '\n', - '\t', '{', '}', '='}; - return std::find(Delimiters.begin(), Delimiters.end(), c) != Delimiters.end(); -} - -std::string TokenReader::readToken(std::istream &Stream) { - // If on the last call we read a trailing delimiter that also qualifies as a - // token, return it now. - if (hasLastDelim()) { - char Token = getLastDelim(); - clearLastDelim(); - return std::string{Token}; - } - - std::stringstream Builder{}; - char c; - c = Stream.get(); - while (!isDelimiter(c) && !Stream.eof()) { - Builder << c; - c = Stream.get(); - } - - setFoundEof(Stream.eof()); - - std::string Token = Builder.str(); - - if (Token.empty()) { - // We read a whitespace delimiter only. Skip over it. - if (!isEof() && isWhitespace(c)) { - return readToken(Stream); - } else if (isWhitespace(c)) { - // We only read a whitespace delimiter. - return ""; - } else { - // We read a delimiter that matters as a token. - return std::string{c}; - } - } - - // If we found a delimiter that's a valid token. Store it to return as the - // next token. - if (!isWhitespace(c)) - setLastDelim(c); - - return Token; -} - -// Reads an expected token or dies a gruesome death. -void eatExpectedToken(std::istream &Stream, const std::string &Expected) { - std::string Token = TokenReader.readToken(Stream); - if (Token.compare(Expected) != 0) { - std::cerr << "Expecting token '" << Expected << "'. Found '" << Token - << "'.\n"; - std::exit(1); - } -} - -// Constructs a map of key value pairs from a token stream. -// Expects to read an expression of the form: -// -// { a = b, c = d, e = f} -// -// If not, the driver will crash. -std::map readMap(std::istream &Stream) { - using StrMap = std::map; - using StrVector = std::vector; - - eatExpectedToken(Stream, "{"); - StrVector TokenList{}; - - while (!TokenReader.isEof()) { - std::string CurrentToken = TokenReader.readToken(Stream); - if (CurrentToken.compare("}") == 0) { - break; - } - TokenList.push_back(CurrentToken); - if (TokenReader.isEof()) { - std::cerr << "Got EOF while building a param map.\n"; - std::exit(1); - } - } - - if (TokenList.size() == 0) { - StrMap EmptyMap{}; - return EmptyMap; - } - if (TokenList.size() % 4 != 3) { - std::cerr << "Error while building token map. Expected triples of tokens " - "in the form 'a = b' separated by commas.\n"; - std::exit(1); - } - - StrMap TokenMap{}; - std::size_t ElementIndex = 0; - for (; ElementIndex < TokenList.size(); ElementIndex += 4) { - if (TokenList[ElementIndex + 1].compare("=") != 0) { - std::cerr << "Expected an assignment when building a param map.\n"; - std::exit(1); - } - TokenMap[TokenList[ElementIndex]] = TokenList[ElementIndex + 2]; - if (ElementIndex + 3 < TokenList.size()) { - if (TokenList[ElementIndex + 3].compare(",") != 0) { - std::cerr << "Expected assignment statements to be separated by commas." - << "\n"; - std::exit(1); - } - } - } - return TokenMap; -} - -std::string getOrDie(const std::map &Lookup, - const std::string &Key) { - auto MapIter = Lookup.find(Key); - if (MapIter == Lookup.end()) { - std::cerr << "Expected key '" << Key << "'. Was not found.\n"; - std::exit(1); - } - return MapIter->second; -} - -// Reads a numeric type from a string token through the magic of -// std::stringstream. -template struct NumberParser { - static NT parse(const std::string &Input) { - NT Number = 0; - std::stringstream Stream(Input); - Stream >> Number; - return Number; - } -}; - -void writeNewBufferOrDie(std::istream &Input) { - auto TokenMap = readMap(Input); - pid_t Tid = NumberParser::parse(getOrDie(TokenMap, "Tid")); - time_t Time = NumberParser::parse(getOrDie(TokenMap, "time")); - timespec TimeSpec = {Time, 0}; - constexpr const size_t OutputSize = 32; - std::array Buffer{}; - char *MemPtr = Buffer.data(); - __xray::__xray_fdr_internal::writeNewBufferPreamble(Tid, TimeSpec, MemPtr); - std::cout.write(Buffer.data(), OutputSize); -} - -void writeNewCPUIdOrDie(std::istream &Input) { - auto TokenMap = readMap(Input); - uint16_t CPU = NumberParser::parse(getOrDie(TokenMap, "CPU")); - uint64_t TSC = NumberParser::parse(getOrDie(TokenMap, "TSC")); - constexpr const size_t OutputSize = 16; - std::array Buffer{}; - char *MemPtr = Buffer.data(); - __xray::__xray_fdr_internal::writeNewCPUIdMetadata(CPU, TSC, MemPtr); - std::cout.write(Buffer.data(), OutputSize); -} - -void writeEOBOrDie(std::istream &Input) { - auto TokenMap = readMap(Input); - constexpr const size_t OutputSize = 16; - std::array Buffer{}; - char *MemPtr = Buffer.data(); - __xray::__xray_fdr_internal::writeEOBMetadata(MemPtr); - std::cout.write(Buffer.data(), OutputSize); -} - -void writeTSCWrapOrDie(std::istream &Input) { - auto TokenMap = readMap(Input); - uint64_t TSC = NumberParser::parse(getOrDie(TokenMap, "TSC")); - constexpr const size_t OutputSize = 16; - std::array Buffer{}; - char *MemPtr = Buffer.data(); - __xray::__xray_fdr_internal::writeTSCWrapMetadata(TSC, MemPtr); - std::cout.write(Buffer.data(), OutputSize); -} - -XRayEntryType decodeEntryType(const std::string &EntryTypeStr) { - if (EntryTypeStr.compare("Entry") == 0) { - return XRayEntryType::ENTRY; - } else if (EntryTypeStr.compare("LogArgsEntry") == 0) { - return XRayEntryType::LOG_ARGS_ENTRY; - } else if (EntryTypeStr.compare("Exit") == 0) { - return XRayEntryType::EXIT; - } else if (EntryTypeStr.compare("Tail") == 0) { - return XRayEntryType::TAIL; - } - std::cerr << "Illegal entry type " << EntryTypeStr << ".\n"; - std::exit(1); -} - -void writeFunctionOrDie(std::istream &Input) { - auto TokenMap = readMap(std::cin); - int FuncId = NumberParser::parse(getOrDie(TokenMap, "FuncId")); - uint32_t TSCDelta = - NumberParser::parse(getOrDie(TokenMap, "TSCDelta")); - std::string EntryType = getOrDie(TokenMap, "EntryType"); - XRayEntryType XrayEntryType = decodeEntryType(EntryType); - constexpr const size_t OutputSize = 8; - std::array Buffer{}; - char *MemPtr = Buffer.data(); - __xray::__xray_fdr_internal::writeFunctionRecord(FuncId, TSCDelta, - XrayEntryType, MemPtr); - std::cout.write(Buffer.data(), OutputSize); -} - -} // namespace - -int main(int argc, char **argv) { - std::map> TopLevelRecordMap; - TopLevelRecordMap["NewBuffer"] = writeNewBufferOrDie; - TopLevelRecordMap["NewCPU"] = writeNewCPUIdOrDie; - TopLevelRecordMap["EOB"] = writeEOBOrDie; - TopLevelRecordMap["TSCWrap"] = writeTSCWrapOrDie; - TopLevelRecordMap["Function"] = writeFunctionOrDie; - - // Write file header - // - // (2) uint16 : version - // (2) uint16 : type - // (4) uint32 : bitfield - // (8) uint64 : cycle frequency - // (16) - : padding - uint16_t HeaderVersion = 1; - uint16_t HeaderType = 1; - uint32_t Bitfield = 3; - uint64_t CycleFreq = 42; - constexpr const size_t HeaderSize = 32; - std::array Header{}; - std::memcpy(Header.data(), &HeaderVersion, sizeof(HeaderVersion)); - std::memcpy(Header.data() + 2, &HeaderType, sizeof(HeaderType)); - std::memcpy(Header.data() + 4, &Bitfield, sizeof(Bitfield)); - std::memcpy(Header.data() + 8, &CycleFreq, sizeof(CycleFreq)); - std::cout.write(Header.data(), HeaderSize); - - std::string CurrentToken; - while (true) { - CurrentToken = TokenReader.readToken(std::cin); - if (TokenReader.isEof()) - break; - auto MapIter = TopLevelRecordMap.find(CurrentToken); - if (MapIter != TopLevelRecordMap.end()) { - eatExpectedToken(std::cin, ":"); - if (TokenReader.isEof()) { - std::cerr << "Got eof when expecting to read a map.\n"; - std::exit(1); - } - MapIter->second(std::cin); - } else { - std::cerr << "Got bad top level instruction '" << CurrentToken << "'.\n"; - std::exit(1); - } - } - return 0; -} -- cgit v1.2.1 From 769089a0ba7eaefe9d6670fa2c49850e50151364 Mon Sep 17 00:00:00 2001 From: Douglas Yung Date: Tue, 11 Apr 2017 07:45:16 +0000 Subject: [XRay][compiler-rt] Add support for TSC emulation for x86_64 to xray_fdr_logging.cc Previously in r297800, a work-around was created to use TSC emulation on x86_64 when RDTSCP was not available on the host. A similar change was needed in the file xray_fdr_logging.cc which this patch ports over to that file. Eventually the code should be refactored as there will be 3 locations with the same code, but that can be done as a separate step. This patch is just to keep the test from failing on my machine due to an illegal instruction since RDTSCP is not available on my x86_64 linux VM. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31909 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index ba1a6ab2c..f2ff4076e 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -192,7 +192,21 @@ void fdrLoggingHandleArg0(int32_t FuncId, // we've seen this CPU before. We also do it before we load anything else, to // allow for forward progress with the scheduling. unsigned char CPU; - uint64_t TSC = __xray::readTSC(CPU); + uint64_t TSC; + + if(probeRequiredCPUFeatures()) { + TSC = __xray::readTSC(CPU); + } else { + // FIXME: This code needs refactoring as it appears in multiple locations + timespec TS; + int result = clock_gettime(CLOCK_REALTIME, &TS); + if (result != 0) { + Report("clock_gettime(2) return %d, errno=%d", result, int(errno)); + TS = {0, 0}; + } + CPU = 0; + TSC = TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; + } __xray_fdr_internal::processFunctionHook(FuncId, Entry, TSC, CPU, clock_gettime, LoggingStatus, BQ); -- cgit v1.2.1 From 77094f117908a9b2f3b2cb4ebe5dbf6c744a851d Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Tue, 11 Apr 2017 08:13:38 +0000 Subject: [lsan] Enable LSan for arm Linux This patch enables LSan for arm Linux. Differential Revision: https://reviews.llvm.org/D29586 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299923 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 7 ++- lib/asan/tests/asan_test.cc | 8 +++ lib/lsan/lsan_allocator.cc | 2 +- lib/lsan/lsan_allocator.h | 3 +- lib/lsan/lsan_common.h | 34 +++++++++-- lib/sanitizer_common/sanitizer_linux.cc | 66 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_linux.h | 3 +- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 16 ++++-- lib/sanitizer_common/sanitizer_platform.h | 6 ++ .../sanitizer_stoptheworld_linux_libcdep.cc | 5 +- test/asan/TestCases/Linux/clang_gcc_abi.cc | 2 +- test/asan/lit.cfg | 5 ++ test/lsan/TestCases/large_allocation_leak.cc | 2 +- test/lsan/TestCases/swapcontext.cc | 8 ++- test/lsan/TestCases/use_registers.cc | 5 ++ test/lsan/TestCases/use_tls_dynamic.cc | 2 +- test/lsan/lit.common.cfg | 7 ++- test/sanitizer_common/print_address.h | 2 +- 18 files changed, 159 insertions(+), 24 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index e336541b5..60cb39a93 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -164,7 +164,12 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) -set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) + +if(APPLE) + set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) +else() + set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32}) +endif() set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64} ${MIPS32} ${MIPS64} ${S390X}) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 31215cf56..7ac72955f 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -685,6 +685,7 @@ void *ThreadStackReuseFunc2(void *unused) { return 0; } +#if !defined(__thumb__) TEST(AddressSanitizer, ThreadStackReuseTest) { pthread_t t; PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0); @@ -692,6 +693,7 @@ TEST(AddressSanitizer, ThreadStackReuseTest) { PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0); PTHREAD_JOIN(t, 0); } +#endif #if defined(__SSE2__) #include @@ -1091,6 +1093,11 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) { } } +// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing +// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string +// that confuses LSan on Thumb because it fails to understand that this +// allocation happens in dynamic linker and should be ignored. +#if !defined(__thumb__) static void *PthreadExit(void *a) { pthread_exit(0); return 0; @@ -1103,6 +1110,7 @@ TEST(AddressSanitizer, PthreadExitTest) { PTHREAD_JOIN(t, 0); } } +#endif // FIXME: Why does clang-cl define __EXCEPTIONS? #if defined(__EXCEPTIONS) && !defined(_WIN32) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 640497d40..9c8acc186 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,7 +24,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -#if defined(__i386__) +#if defined(__i386__) || defined(__arm__) static const uptr kMaxAllowedMallocSize = 1UL << 30; #elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 9c3dce97a..bd19211c4 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -48,7 +48,8 @@ struct ChunkMetadata { u32 stack_trace_id; }; -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ + defined(__arm__) static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 082492dec..2851a6672 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -37,6 +37,9 @@ #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 +#elif defined(__arm__) && \ + SANITIZER_LINUX && !SANITIZER_ANDROID +#define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 #endif @@ -144,13 +147,36 @@ struct ScopedInterceptorDisabler { ~ScopedInterceptorDisabler() { EnableInThisThread(); } }; +// According to Itanium C++ ABI array cookie is a one word containing +// size of allocated array. +static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, + uptr addr) { + return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && + *reinterpret_cast(chunk_beg) == 0; +} + +// According to ARM C++ ABI array cookie consists of two words: +// struct array_cookie { +// std::size_t element_size; // element_size != 0 +// std::size_t element_count; +// }; +static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, + uptr addr) { + return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && + *reinterpret_cast(chunk_beg + sizeof(uptr)) == 0; +} + // Special case for "new T[0]" where T is a type with DTOR. -// new T[0] will allocate one word for the array size (0) and store a pointer -// to the end of allocated chunk. +// new T[0] will allocate a cookie (one or two words) for the array size (0) +// and store a pointer to the end of allocated chunk. The actual cookie layout +// varies between platforms according to their C++ ABI implementation. inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, uptr addr) { - return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && - *reinterpret_cast(chunk_beg) == 0; +#if defined(__arm__) + return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); +#else + return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); +#endif } // The following must be implemented in the parent tool. diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index e166d1dcd..fef5b3179 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1283,6 +1283,72 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory"); return res; } +#elif defined(__arm__) && SANITIZER_LINUX +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + unsigned int res; + if (!fn || !child_stack) + return -EINVAL; + child_stack = (char *)child_stack - 2 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)fn; + ((unsigned int *)child_stack)[1] = (uptr)arg; + register int r0 __asm__("r0") = flags; + register void *r1 __asm__("r1") = child_stack; + register int *r2 __asm__("r2") = parent_tidptr; + register void *r3 __asm__("r3") = newtls; + register int *r4 __asm__("r4") = child_tidptr; + register int r7 __asm__("r7") = __NR_clone; + +#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) +# define ARCH_HAS_BX +#endif +#if __ARM_ARCH > 4 +# define ARCH_HAS_BLX +#endif + +#ifdef ARCH_HAS_BX +# ifdef ARCH_HAS_BLX +# define BLX(R) "blx " #R "\n" +# else +# define BLX(R) "mov lr, pc; bx" #R "\n" +# endif +#else +# define BLX(R) "mov lr, pc; mov pc," #R "\n" +#endif + + __asm__ __volatile__( + /* %r0 = syscall(%r7 = SYSCALL(clone), + * %r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = new_tls, + * %r4 = child_tidptr) + */ + + /* Do the system call */ + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldr r0, [sp, #4]\n" + "ldr ip, [sp], #8\n" + BLX(ip) + /* Call _exit(%r0). */ + "mov r7, %7\n" + "swi 0x0\n" + "1:\n" + "mov %0, r0\n" + : "=r"(res) + : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), + "i"(__NR_exit) + : "memory"); + return res; +} #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index bba8624a9..14047b480 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -48,7 +48,8 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact); #endif void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ - || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) + || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ + || defined(__arm__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index a5e284025..6fde671f8 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -183,8 +183,8 @@ void InitTlsSize() { } #endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO #if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ - || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \ - && SANITIZER_LINUX && !SANITIZER_ANDROID + || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \ + || defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID // sizeof(struct pthread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; @@ -192,14 +192,14 @@ uptr ThreadDescriptorSize() { uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; -#if defined(__x86_64__) || defined(__i386__) +#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) #ifdef _CS_GNU_LIBC_VERSION char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); - if (end != buf + 8 && (*end == '\0' || *end == '.')) { + if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) { int patch = 0; if (*end == '.') // strtoll will return 0 if no valid conversion could be performed @@ -208,6 +208,9 @@ uptr ThreadDescriptorSize() { /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. + // For ARM sizeof(struct pthread) changed in Glibc 2.23. + else if (SANITIZER_ARM) + val = minor <= 22 ? 1120 : 1216; else if (minor <= 3) val = FIRST_32_SECOND_64(1104, 1696); else if (minor == 4) @@ -293,7 +296,7 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) +# elif defined(__aarch64__) || defined(__arm__) descr_addr = reinterpret_cast(__builtin_thread_pointer()) - ThreadDescriptorSize(); # elif defined(__s390__) @@ -342,7 +345,8 @@ static void GetTls(uptr *addr, uptr *size) { *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ + || defined(__arm__) *addr = ThreadSelf(); *size = GetTlsSize(); # else diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index d9a8e8df1..1a6410878 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -162,6 +162,12 @@ # define SANITIZER_PPC64V2 0 #endif +#if defined(__arm__) +# define SANITIZER_ARM 1 +#else +# define SANITIZER_ARM 0 +#endif + // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 // does not work well and we need to fallback to SizeClassAllocator32. diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 3c0fd7b13..6e4baeeca 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -16,7 +16,8 @@ #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__)) + defined(__s390__) || defined(__i386__) || \ + defined(__arm__)) #include "sanitizer_stoptheworld.h" @@ -532,4 +533,4 @@ uptr SuspendedThreadsList::RegisterCount() { #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) // || defined(__aarch64__) || defined(__powerpc64__) - // || defined(__s390__) || defined(__i386__) + // || defined(__s390__) || defined(__i386__) || defined(__arm__) diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc index 845f4121a..79710dc83 100644 --- a/test/asan/TestCases/Linux/clang_gcc_abi.cc +++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -3,7 +3,7 @@ // RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: arm-target-arch +// REQUIRES: arm-target-arch, fast-unwinder-works // XFAIL: armv7l-unknown-linux-gnueabihf #include diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 37ba10df6..9093b44c1 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -2,6 +2,7 @@ import os import platform +import re import lit.formats @@ -211,6 +212,10 @@ config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64': config.available_features.add('stable-runtime') +# Fast unwinder doesn't work with Thumb +if not re.match('-mthumb', config.target_cflags): + config.available_features.add('fast-unwinder-works') + # Turn on leak detection on 64-bit Linux. if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): config.available_features.add('leak-detection') diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index 7254f9cbe..c3da932a4 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -5,7 +5,7 @@ // For 32 bit LSan it's pretty likely that large chunks are "reachable" from some // internal data structures (e.g. Glibc global data). -// UNSUPPORTED: x86 +// UNSUPPORTED: x86, arm #include #include diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index f7e95ed2c..f990526cf 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -2,8 +2,10 @@ // memory. Make sure we don't report these leaks. // RUN: %clangxx_lsan %s -o %t -// RUN: %run %t 2>&1 -// RUN: not %run %t foo 2>&1 | FileCheck %s +// RUN: LSAN_BASE="detect_leaks=1" +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// UNSUPPORTED: arm #include #if defined(__APPLE__) @@ -23,7 +25,7 @@ void Child() { } int main(int argc, char *argv[]) { - char stack_memory[kStackSize + 1]; + char stack_memory[kStackSize + 1] __attribute__((aligned(16))); char *heap_memory = new char[kStackSize + 1]; char *child_stack = (argc > 1) ? stack_memory : heap_memory; diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 789687401..2fe13318e 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -33,6 +33,11 @@ void *registers_thread_func(void *arg) { : : "r" (p) ); +#elif defined(__arm__) + asm ( "mov r5, %0" + : + : "r" (p) + ); #else #error "Test is not supported on this architecture." #endif diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc index c20232dc3..6af82d59e 100644 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: LSAN_OPTIONS="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux +// UNSUPPORTED: i386-linux,i686-linux,arm #ifndef BUILD_DSO #include diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 8580eec33..f47d76e6d 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -3,6 +3,7 @@ # Common configuration for running leak detection tests under LSan/ASan. import os +import re import lit.util @@ -52,7 +53,11 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']: +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf']: + config.unsupported = True + +# Don't support Thumb due to broken fast unwinder +if re.match('-mthumb', config.target_cflags): config.unsupported = True config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/test/sanitizer_common/print_address.h b/test/sanitizer_common/print_address.h index 99261b331..63d9a93f1 100644 --- a/test/sanitizer_common/print_address.h +++ b/test/sanitizer_common/print_address.h @@ -11,7 +11,7 @@ void print_address(const char *str, int n, ...) { // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not // match to the format used in the diagnotic message. fprintf(stderr, "0x%012lx ", (unsigned long) p); -#elif defined(__i386__) +#elif defined(__i386__) || defined(__arm__) fprintf(stderr, "0x%8lx ", (unsigned long) p); #elif defined(__mips64) fprintf(stderr, "0x%010lx ", (unsigned long) p); -- cgit v1.2.1 From da0f8e2b7891543e9e98e2afadbbabb5e3eea16b Mon Sep 17 00:00:00 2001 From: Catherine Moore Date: Tue, 11 Apr 2017 13:45:05 +0000 Subject: This patch causes the installation of headers for the sanitizer and/or xray to be disabled when COMPILER_RT_BUILD_SANITIZERS=OFF and/or COMPILER_RT_BUILD_XRAY=OFF. Reviewer: dberris Subscribers: dberris, mgorny, llvm-commits, clm Differential Revision: https://reviews.llvm.org/D31864 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299940 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/CMakeLists.txt | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 3d6c96be9..ec3bf40b9 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,19 +1,23 @@ -set(SANITIZER_HEADERS - sanitizer/allocator_interface.h - sanitizer/asan_interface.h - sanitizer/common_interface_defs.h - sanitizer/coverage_interface.h - sanitizer/dfsan_interface.h - sanitizer/esan_interface.h - sanitizer/linux_syscall_hooks.h - sanitizer/lsan_interface.h - sanitizer/msan_interface.h - sanitizer/tsan_interface.h - sanitizer/tsan_interface_atomic.h) +if (COMPILER_RT_BUILD_SANITIZERS) + set(SANITIZER_HEADERS + sanitizer/allocator_interface.h + sanitizer/asan_interface.h + sanitizer/common_interface_defs.h + sanitizer/coverage_interface.h + sanitizer/dfsan_interface.h + sanitizer/esan_interface.h + sanitizer/linux_syscall_hooks.h + sanitizer/lsan_interface.h + sanitizer/msan_interface.h + sanitizer/tsan_interface.h + sanitizer/tsan_interface_atomic.h) +endif(COMPILER_RT_BUILD_SANITIZERS) -set(XRAY_HEADERS - xray/xray_interface.h - xray/xray_log_interface.h) +if (COMPILER_RT_BUILD_XRAY) + set(XRAY_HEADERS + xray/xray_interface.h + xray/xray_log_interface.h) +endif(COMPILER_RT_BUILD_XRAY) set(COMPILER_RT_HEADERS ${SANITIZER_HEADERS} -- cgit v1.2.1 From 056881d0b45d6148ab00fa12cb58cd75e4f64e48 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 11 Apr 2017 14:28:49 +0000 Subject: Revert r299923, it doesn't build in bootstrap builds. FAILED: lib/sanitizer_common/CMakeFiles/RTSanitizerCommon.arm.dir/sanitizer_linux.cc.o lib/sanitizer_common/sanitizer_linux.cc:1340:24: error: invalid instruction BLX(ip) ^ lib/sanitizer_common/sanitizer_linux.cc:1313:19: note: expanded from macro 'BLX' # define BLX(R) "mov lr, pc; bx" #R "\n" ^ :6:13: note: instantiated into assembly here mov lr, pc; bxip ^~~~ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299943 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 7 +-- lib/asan/tests/asan_test.cc | 8 --- lib/lsan/lsan_allocator.cc | 2 +- lib/lsan/lsan_allocator.h | 3 +- lib/lsan/lsan_common.h | 34 ++--------- lib/sanitizer_common/sanitizer_linux.cc | 66 ---------------------- lib/sanitizer_common/sanitizer_linux.h | 3 +- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 16 ++---- lib/sanitizer_common/sanitizer_platform.h | 6 -- .../sanitizer_stoptheworld_linux_libcdep.cc | 5 +- test/asan/TestCases/Linux/clang_gcc_abi.cc | 2 +- test/asan/lit.cfg | 5 -- test/lsan/TestCases/large_allocation_leak.cc | 2 +- test/lsan/TestCases/swapcontext.cc | 8 +-- test/lsan/TestCases/use_registers.cc | 5 -- test/lsan/TestCases/use_tls_dynamic.cc | 2 +- test/lsan/lit.common.cfg | 7 +-- test/sanitizer_common/print_address.h | 2 +- 18 files changed, 24 insertions(+), 159 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 60cb39a93..e336541b5 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -164,12 +164,7 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) - -if(APPLE) - set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) -else() - set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32}) -endif() +set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64} ${MIPS32} ${MIPS64} ${S390X}) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7ac72955f..31215cf56 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -685,7 +685,6 @@ void *ThreadStackReuseFunc2(void *unused) { return 0; } -#if !defined(__thumb__) TEST(AddressSanitizer, ThreadStackReuseTest) { pthread_t t; PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0); @@ -693,7 +692,6 @@ TEST(AddressSanitizer, ThreadStackReuseTest) { PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0); PTHREAD_JOIN(t, 0); } -#endif #if defined(__SSE2__) #include @@ -1093,11 +1091,6 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) { } } -// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing -// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string -// that confuses LSan on Thumb because it fails to understand that this -// allocation happens in dynamic linker and should be ignored. -#if !defined(__thumb__) static void *PthreadExit(void *a) { pthread_exit(0); return 0; @@ -1110,7 +1103,6 @@ TEST(AddressSanitizer, PthreadExitTest) { PTHREAD_JOIN(t, 0); } } -#endif // FIXME: Why does clang-cl define __EXCEPTIONS? #if defined(__EXCEPTIONS) && !defined(_WIN32) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 9c8acc186..640497d40 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,7 +24,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -#if defined(__i386__) || defined(__arm__) +#if defined(__i386__) static const uptr kMaxAllowedMallocSize = 1UL << 30; #elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index bd19211c4..9c3dce97a 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -48,8 +48,7 @@ struct ChunkMetadata { u32 stack_trace_id; }; -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ - defined(__arm__) +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 2851a6672..082492dec 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -37,9 +37,6 @@ #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__arm__) && \ - SANITIZER_LINUX && !SANITIZER_ANDROID -#define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 #endif @@ -147,36 +144,13 @@ struct ScopedInterceptorDisabler { ~ScopedInterceptorDisabler() { EnableInThisThread(); } }; -// According to Itanium C++ ABI array cookie is a one word containing -// size of allocated array. -static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, - uptr addr) { - return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && - *reinterpret_cast(chunk_beg) == 0; -} - -// According to ARM C++ ABI array cookie consists of two words: -// struct array_cookie { -// std::size_t element_size; // element_size != 0 -// std::size_t element_count; -// }; -static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, - uptr addr) { - return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && - *reinterpret_cast(chunk_beg + sizeof(uptr)) == 0; -} - // Special case for "new T[0]" where T is a type with DTOR. -// new T[0] will allocate a cookie (one or two words) for the array size (0) -// and store a pointer to the end of allocated chunk. The actual cookie layout -// varies between platforms according to their C++ ABI implementation. +// new T[0] will allocate one word for the array size (0) and store a pointer +// to the end of allocated chunk. inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, uptr addr) { -#if defined(__arm__) - return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); -#else - return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); -#endif + return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && + *reinterpret_cast(chunk_beg) == 0; } // The following must be implemented in the parent tool. diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index fef5b3179..e166d1dcd 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1283,72 +1283,6 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory"); return res; } -#elif defined(__arm__) && SANITIZER_LINUX -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - unsigned int res; - if (!fn || !child_stack) - return -EINVAL; - child_stack = (char *)child_stack - 2 * sizeof(unsigned int); - ((unsigned int *)child_stack)[0] = (uptr)fn; - ((unsigned int *)child_stack)[1] = (uptr)arg; - register int r0 __asm__("r0") = flags; - register void *r1 __asm__("r1") = child_stack; - register int *r2 __asm__("r2") = parent_tidptr; - register void *r3 __asm__("r3") = newtls; - register int *r4 __asm__("r4") = child_tidptr; - register int r7 __asm__("r7") = __NR_clone; - -#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) -# define ARCH_HAS_BX -#endif -#if __ARM_ARCH > 4 -# define ARCH_HAS_BLX -#endif - -#ifdef ARCH_HAS_BX -# ifdef ARCH_HAS_BLX -# define BLX(R) "blx " #R "\n" -# else -# define BLX(R) "mov lr, pc; bx" #R "\n" -# endif -#else -# define BLX(R) "mov lr, pc; mov pc," #R "\n" -#endif - - __asm__ __volatile__( - /* %r0 = syscall(%r7 = SYSCALL(clone), - * %r0 = flags, - * %r1 = child_stack, - * %r2 = parent_tidptr, - * %r3 = new_tls, - * %r4 = child_tidptr) - */ - - /* Do the system call */ - "swi 0x0\n" - - /* if (%r0 != 0) - * return %r0; - */ - "cmp r0, #0\n" - "bne 1f\n" - - /* In the child, now. Call "fn(arg)". */ - "ldr r0, [sp, #4]\n" - "ldr ip, [sp], #8\n" - BLX(ip) - /* Call _exit(%r0). */ - "mov r7, %7\n" - "swi 0x0\n" - "1:\n" - "mov %0, r0\n" - : "=r"(res) - : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), - "i"(__NR_exit) - : "memory"); - return res; -} #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 14047b480..bba8624a9 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -48,8 +48,7 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact); #endif void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ - || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ - || defined(__arm__) + || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 6fde671f8..a5e284025 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -183,8 +183,8 @@ void InitTlsSize() { } #endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO #if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ - || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \ - || defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID + || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \ + && SANITIZER_LINUX && !SANITIZER_ANDROID // sizeof(struct pthread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; @@ -192,14 +192,14 @@ uptr ThreadDescriptorSize() { uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; -#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) +#if defined(__x86_64__) || defined(__i386__) #ifdef _CS_GNU_LIBC_VERSION char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); - if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) { + if (end != buf + 8 && (*end == '\0' || *end == '.')) { int patch = 0; if (*end == '.') // strtoll will return 0 if no valid conversion could be performed @@ -208,9 +208,6 @@ uptr ThreadDescriptorSize() { /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. - // For ARM sizeof(struct pthread) changed in Glibc 2.23. - else if (SANITIZER_ARM) - val = minor <= 22 ? 1120 : 1216; else if (minor <= 3) val = FIRST_32_SECOND_64(1104, 1696); else if (minor == 4) @@ -296,7 +293,7 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) || defined(__arm__) +# elif defined(__aarch64__) descr_addr = reinterpret_cast(__builtin_thread_pointer()) - ThreadDescriptorSize(); # elif defined(__s390__) @@ -345,8 +342,7 @@ static void GetTls(uptr *addr, uptr *size) { *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ - || defined(__arm__) +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) *addr = ThreadSelf(); *size = GetTlsSize(); # else diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 1a6410878..d9a8e8df1 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -162,12 +162,6 @@ # define SANITIZER_PPC64V2 0 #endif -#if defined(__arm__) -# define SANITIZER_ARM 1 -#else -# define SANITIZER_ARM 0 -#endif - // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 // does not work well and we need to fallback to SizeClassAllocator32. diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 6e4baeeca..3c0fd7b13 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -16,8 +16,7 @@ #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__) || \ - defined(__arm__)) + defined(__s390__) || defined(__i386__)) #include "sanitizer_stoptheworld.h" @@ -533,4 +532,4 @@ uptr SuspendedThreadsList::RegisterCount() { #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) // || defined(__aarch64__) || defined(__powerpc64__) - // || defined(__s390__) || defined(__i386__) || defined(__arm__) + // || defined(__s390__) || defined(__i386__) diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc index 79710dc83..845f4121a 100644 --- a/test/asan/TestCases/Linux/clang_gcc_abi.cc +++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -3,7 +3,7 @@ // RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: arm-target-arch, fast-unwinder-works +// REQUIRES: arm-target-arch // XFAIL: armv7l-unknown-linux-gnueabihf #include diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 9093b44c1..37ba10df6 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -2,7 +2,6 @@ import os import platform -import re import lit.formats @@ -212,10 +211,6 @@ config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64': config.available_features.add('stable-runtime') -# Fast unwinder doesn't work with Thumb -if not re.match('-mthumb', config.target_cflags): - config.available_features.add('fast-unwinder-works') - # Turn on leak detection on 64-bit Linux. if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): config.available_features.add('leak-detection') diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index c3da932a4..7254f9cbe 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -5,7 +5,7 @@ // For 32 bit LSan it's pretty likely that large chunks are "reachable" from some // internal data structures (e.g. Glibc global data). -// UNSUPPORTED: x86, arm +// UNSUPPORTED: x86 #include #include diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index f990526cf..f7e95ed2c 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -2,10 +2,8 @@ // memory. Make sure we don't report these leaks. // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_BASE="detect_leaks=1" -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s -// UNSUPPORTED: arm +// RUN: %run %t 2>&1 +// RUN: not %run %t foo 2>&1 | FileCheck %s #include #if defined(__APPLE__) @@ -25,7 +23,7 @@ void Child() { } int main(int argc, char *argv[]) { - char stack_memory[kStackSize + 1] __attribute__((aligned(16))); + char stack_memory[kStackSize + 1]; char *heap_memory = new char[kStackSize + 1]; char *child_stack = (argc > 1) ? stack_memory : heap_memory; diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 2fe13318e..789687401 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -33,11 +33,6 @@ void *registers_thread_func(void *arg) { : : "r" (p) ); -#elif defined(__arm__) - asm ( "mov r5, %0" - : - : "r" (p) - ); #else #error "Test is not supported on this architecture." #endif diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc index 6af82d59e..c20232dc3 100644 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: LSAN_OPTIONS="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux,arm +// UNSUPPORTED: i386-linux,i686-linux #ifndef BUILD_DSO #include diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index f47d76e6d..8580eec33 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -3,7 +3,6 @@ # Common configuration for running leak detection tests under LSan/ASan. import os -import re import lit.util @@ -53,11 +52,7 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf']: - config.unsupported = True - -# Don't support Thumb due to broken fast unwinder -if re.match('-mthumb', config.target_cflags): +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']: config.unsupported = True config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/test/sanitizer_common/print_address.h b/test/sanitizer_common/print_address.h index 63d9a93f1..99261b331 100644 --- a/test/sanitizer_common/print_address.h +++ b/test/sanitizer_common/print_address.h @@ -11,7 +11,7 @@ void print_address(const char *str, int n, ...) { // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not // match to the format used in the diagnotic message. fprintf(stderr, "0x%012lx ", (unsigned long) p); -#elif defined(__i386__) || defined(__arm__) +#elif defined(__i386__) fprintf(stderr, "0x%8lx ", (unsigned long) p); #elif defined(__mips64) fprintf(stderr, "0x%010lx ", (unsigned long) p); -- cgit v1.2.1 From 8d8e5f3b6c3f6c74c0ddcdbdd169ffe3fefadfe3 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Tue, 11 Apr 2017 14:58:26 +0000 Subject: Reapply "Enable LSan for arm Linux" This patch reapplies r299923 with typo fixed in BLX macros. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299948 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 7 ++- lib/asan/tests/asan_test.cc | 8 +++ lib/lsan/lsan_allocator.cc | 2 +- lib/lsan/lsan_allocator.h | 3 +- lib/lsan/lsan_common.h | 34 +++++++++-- lib/sanitizer_common/sanitizer_linux.cc | 66 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_linux.h | 3 +- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 16 ++++-- lib/sanitizer_common/sanitizer_platform.h | 6 ++ .../sanitizer_stoptheworld_linux_libcdep.cc | 5 +- test/asan/TestCases/Linux/clang_gcc_abi.cc | 2 +- test/asan/lit.cfg | 5 ++ test/lsan/TestCases/large_allocation_leak.cc | 2 +- test/lsan/TestCases/swapcontext.cc | 8 ++- test/lsan/TestCases/use_registers.cc | 5 ++ test/lsan/TestCases/use_tls_dynamic.cc | 2 +- test/lsan/lit.common.cfg | 9 ++- test/sanitizer_common/print_address.h | 2 +- 18 files changed, 160 insertions(+), 25 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index e336541b5..60cb39a93 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -164,7 +164,12 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) -set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) + +if(APPLE) + set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) +else() + set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32}) +endif() set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64} ${MIPS32} ${MIPS64} ${S390X}) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 31215cf56..7ac72955f 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -685,6 +685,7 @@ void *ThreadStackReuseFunc2(void *unused) { return 0; } +#if !defined(__thumb__) TEST(AddressSanitizer, ThreadStackReuseTest) { pthread_t t; PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0); @@ -692,6 +693,7 @@ TEST(AddressSanitizer, ThreadStackReuseTest) { PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0); PTHREAD_JOIN(t, 0); } +#endif #if defined(__SSE2__) #include @@ -1091,6 +1093,11 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) { } } +// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing +// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string +// that confuses LSan on Thumb because it fails to understand that this +// allocation happens in dynamic linker and should be ignored. +#if !defined(__thumb__) static void *PthreadExit(void *a) { pthread_exit(0); return 0; @@ -1103,6 +1110,7 @@ TEST(AddressSanitizer, PthreadExitTest) { PTHREAD_JOIN(t, 0); } } +#endif // FIXME: Why does clang-cl define __EXCEPTIONS? #if defined(__EXCEPTIONS) && !defined(_WIN32) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 640497d40..9c8acc186 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -24,7 +24,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -#if defined(__i386__) +#if defined(__i386__) || defined(__arm__) static const uptr kMaxAllowedMallocSize = 1UL << 30; #elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 9c3dce97a..bd19211c4 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -48,7 +48,8 @@ struct ChunkMetadata { u32 stack_trace_id; }; -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) +#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ + defined(__arm__) static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 082492dec..2851a6672 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -37,6 +37,9 @@ #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 +#elif defined(__arm__) && \ + SANITIZER_LINUX && !SANITIZER_ANDROID +#define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 #endif @@ -144,13 +147,36 @@ struct ScopedInterceptorDisabler { ~ScopedInterceptorDisabler() { EnableInThisThread(); } }; +// According to Itanium C++ ABI array cookie is a one word containing +// size of allocated array. +static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, + uptr addr) { + return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && + *reinterpret_cast(chunk_beg) == 0; +} + +// According to ARM C++ ABI array cookie consists of two words: +// struct array_cookie { +// std::size_t element_size; // element_size != 0 +// std::size_t element_count; +// }; +static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, + uptr addr) { + return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && + *reinterpret_cast(chunk_beg + sizeof(uptr)) == 0; +} + // Special case for "new T[0]" where T is a type with DTOR. -// new T[0] will allocate one word for the array size (0) and store a pointer -// to the end of allocated chunk. +// new T[0] will allocate a cookie (one or two words) for the array size (0) +// and store a pointer to the end of allocated chunk. The actual cookie layout +// varies between platforms according to their C++ ABI implementation. inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, uptr addr) { - return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && - *reinterpret_cast(chunk_beg) == 0; +#if defined(__arm__) + return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); +#else + return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); +#endif } // The following must be implemented in the parent tool. diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index e166d1dcd..0b5473d95 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1283,6 +1283,72 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory"); return res; } +#elif defined(__arm__) && SANITIZER_LINUX +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + unsigned int res; + if (!fn || !child_stack) + return -EINVAL; + child_stack = (char *)child_stack - 2 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)fn; + ((unsigned int *)child_stack)[1] = (uptr)arg; + register int r0 __asm__("r0") = flags; + register void *r1 __asm__("r1") = child_stack; + register int *r2 __asm__("r2") = parent_tidptr; + register void *r3 __asm__("r3") = newtls; + register int *r4 __asm__("r4") = child_tidptr; + register int r7 __asm__("r7") = __NR_clone; + +#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) +# define ARCH_HAS_BX +#endif +#if __ARM_ARCH > 4 +# define ARCH_HAS_BLX +#endif + +#ifdef ARCH_HAS_BX +# ifdef ARCH_HAS_BLX +# define BLX(R) "blx " #R "\n" +# else +# define BLX(R) "mov lr, pc; bx " #R "\n" +# endif +#else +# define BLX(R) "mov lr, pc; mov pc," #R "\n" +#endif + + __asm__ __volatile__( + /* %r0 = syscall(%r7 = SYSCALL(clone), + * %r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = new_tls, + * %r4 = child_tidptr) + */ + + /* Do the system call */ + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldr r0, [sp, #4]\n" + "ldr ip, [sp], #8\n" + BLX(ip) + /* Call _exit(%r0). */ + "mov r7, %7\n" + "swi 0x0\n" + "1:\n" + "mov %0, r0\n" + : "=r"(res) + : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), + "i"(__NR_exit) + : "memory"); + return res; +} #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index bba8624a9..14047b480 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -48,7 +48,8 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact); #endif void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ - || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) + || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ + || defined(__arm__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index a5e284025..6fde671f8 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -183,8 +183,8 @@ void InitTlsSize() { } #endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO #if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ - || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \ - && SANITIZER_LINUX && !SANITIZER_ANDROID + || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \ + || defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID // sizeof(struct pthread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; @@ -192,14 +192,14 @@ uptr ThreadDescriptorSize() { uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; -#if defined(__x86_64__) || defined(__i386__) +#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) #ifdef _CS_GNU_LIBC_VERSION char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); - if (end != buf + 8 && (*end == '\0' || *end == '.')) { + if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) { int patch = 0; if (*end == '.') // strtoll will return 0 if no valid conversion could be performed @@ -208,6 +208,9 @@ uptr ThreadDescriptorSize() { /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. + // For ARM sizeof(struct pthread) changed in Glibc 2.23. + else if (SANITIZER_ARM) + val = minor <= 22 ? 1120 : 1216; else if (minor <= 3) val = FIRST_32_SECOND_64(1104, 1696); else if (minor == 4) @@ -293,7 +296,7 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) +# elif defined(__aarch64__) || defined(__arm__) descr_addr = reinterpret_cast(__builtin_thread_pointer()) - ThreadDescriptorSize(); # elif defined(__s390__) @@ -342,7 +345,8 @@ static void GetTls(uptr *addr, uptr *size) { *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ + || defined(__arm__) *addr = ThreadSelf(); *size = GetTlsSize(); # else diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index d9a8e8df1..1a6410878 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -162,6 +162,12 @@ # define SANITIZER_PPC64V2 0 #endif +#if defined(__arm__) +# define SANITIZER_ARM 1 +#else +# define SANITIZER_ARM 0 +#endif + // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 // does not work well and we need to fallback to SizeClassAllocator32. diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 3c0fd7b13..6e4baeeca 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -16,7 +16,8 @@ #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__)) + defined(__s390__) || defined(__i386__) || \ + defined(__arm__)) #include "sanitizer_stoptheworld.h" @@ -532,4 +533,4 @@ uptr SuspendedThreadsList::RegisterCount() { #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) // || defined(__aarch64__) || defined(__powerpc64__) - // || defined(__s390__) || defined(__i386__) + // || defined(__s390__) || defined(__i386__) || defined(__arm__) diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc index 845f4121a..79710dc83 100644 --- a/test/asan/TestCases/Linux/clang_gcc_abi.cc +++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -3,7 +3,7 @@ // RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: arm-target-arch +// REQUIRES: arm-target-arch, fast-unwinder-works // XFAIL: armv7l-unknown-linux-gnueabihf #include diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 37ba10df6..9093b44c1 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -2,6 +2,7 @@ import os import platform +import re import lit.formats @@ -211,6 +212,10 @@ config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64': config.available_features.add('stable-runtime') +# Fast unwinder doesn't work with Thumb +if not re.match('-mthumb', config.target_cflags): + config.available_features.add('fast-unwinder-works') + # Turn on leak detection on 64-bit Linux. if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): config.available_features.add('leak-detection') diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index 7254f9cbe..c3da932a4 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -5,7 +5,7 @@ // For 32 bit LSan it's pretty likely that large chunks are "reachable" from some // internal data structures (e.g. Glibc global data). -// UNSUPPORTED: x86 +// UNSUPPORTED: x86, arm #include #include diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index f7e95ed2c..f990526cf 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -2,8 +2,10 @@ // memory. Make sure we don't report these leaks. // RUN: %clangxx_lsan %s -o %t -// RUN: %run %t 2>&1 -// RUN: not %run %t foo 2>&1 | FileCheck %s +// RUN: LSAN_BASE="detect_leaks=1" +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// UNSUPPORTED: arm #include #if defined(__APPLE__) @@ -23,7 +25,7 @@ void Child() { } int main(int argc, char *argv[]) { - char stack_memory[kStackSize + 1]; + char stack_memory[kStackSize + 1] __attribute__((aligned(16))); char *heap_memory = new char[kStackSize + 1]; char *child_stack = (argc > 1) ? stack_memory : heap_memory; diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 789687401..2fe13318e 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -33,6 +33,11 @@ void *registers_thread_func(void *arg) { : : "r" (p) ); +#elif defined(__arm__) + asm ( "mov r5, %0" + : + : "r" (p) + ); #else #error "Test is not supported on this architecture." #endif diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc index c20232dc3..6af82d59e 100644 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: LSAN_OPTIONS="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux +// UNSUPPORTED: i386-linux,i686-linux,arm #ifndef BUILD_DSO #include diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 8580eec33..b0e5e7e0e 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -3,6 +3,7 @@ # Common configuration for running leak detection tests under LSan/ASan. import os +import re import lit.util @@ -51,8 +52,12 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']: +# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', armv7l]: + config.unsupported = True + +# Don't support Thumb due to broken fast unwinder +if re.match('-mthumb', config.target_cflags): config.unsupported = True config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/test/sanitizer_common/print_address.h b/test/sanitizer_common/print_address.h index 99261b331..63d9a93f1 100644 --- a/test/sanitizer_common/print_address.h +++ b/test/sanitizer_common/print_address.h @@ -11,7 +11,7 @@ void print_address(const char *str, int n, ...) { // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not // match to the format used in the diagnotic message. fprintf(stderr, "0x%012lx ", (unsigned long) p); -#elif defined(__i386__) +#elif defined(__i386__) || defined(__arm__) fprintf(stderr, "0x%8lx ", (unsigned long) p); #elif defined(__mips64) fprintf(stderr, "0x%010lx ", (unsigned long) p); -- cgit v1.2.1 From 2c3562da9bf5c5fa316ec2fa27b87bb2149962bf Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 11 Apr 2017 15:51:39 +0000 Subject: [Profile] PE binary coverage bug fix PR/32584 Differential Revision: https://reviews.llvm.org/D31939 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299954 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index 6ef1625d8..5f3540a2c 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -622,6 +622,19 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * specified via command line. */ #define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename +#ifdef _WIN32 +/* Runtime section names and name strings. */ +#define INSTR_PROF_DATA_SECT_NAME .lprfd +#define INSTR_PROF_NAME_SECT_NAME .lprfn +#define INSTR_PROF_CNTS_SECT_NAME .lprfc +/* Array of pointers. Each pointer points to a list + * of value nodes associated with one value site. + */ +#define INSTR_PROF_VALS_SECT_NAME .lprfv +/* Value profile nodes section. */ +#define INSTR_PROF_VNODES_SECT_NAME .lprfnd +#define INSTR_PROF_COVMAP_SECT_NAME .lcovmap +#else /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names @@ -633,6 +646,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, /* Value profile nodes section. */ #define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap +#endif #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) -- cgit v1.2.1 From 8df0cf03780e9c77d175d2984423c17a5fc9db2f Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Tue, 11 Apr 2017 16:22:19 +0000 Subject: [lsan] Fix typo in test/lsan/lit.common.cfg git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299957 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index b0e5e7e0e..0b9e5a4a7 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -53,7 +53,7 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', armv7l]: +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 4f28340f8ea4c3944375966cc9bd2c5579628b97 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 11 Apr 2017 16:27:26 +0000 Subject: Revert 299954 : test failure needs to be fixed git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299960 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index 5f3540a2c..6ef1625d8 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -622,19 +622,6 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * specified via command line. */ #define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename -#ifdef _WIN32 -/* Runtime section names and name strings. */ -#define INSTR_PROF_DATA_SECT_NAME .lprfd -#define INSTR_PROF_NAME_SECT_NAME .lprfn -#define INSTR_PROF_CNTS_SECT_NAME .lprfc -/* Array of pointers. Each pointer points to a list - * of value nodes associated with one value site. - */ -#define INSTR_PROF_VALS_SECT_NAME .lprfv -/* Value profile nodes section. */ -#define INSTR_PROF_VNODES_SECT_NAME .lprfnd -#define INSTR_PROF_COVMAP_SECT_NAME .lcovmap -#else /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names @@ -646,7 +633,6 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, /* Value profile nodes section. */ #define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap -#endif #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) -- cgit v1.2.1 From 73b0c20fc41d4ef48b9b2e3edecb705c2f6aaf77 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 11 Apr 2017 19:57:12 +0000 Subject: Don't delete lsan thread-local data until it's no longer required Summary: The routines for thread destruction in the thread registry require the lsan thread index, which is stored in pthread tls on OS X. This means that we need to make sure that the lsan tls isn't destroyed until after the thread registry tls. This change ensures that we don't delete the lsan tls until we've finished destroying the thread in the registry, ensuring that the destructor for the lsan tls runs after the destructor for the thread registry tls. This patch also adds a check to ensure that the thread ID is valid before returning it in GetThreadID(), to ensure that the above behavior is working correctly. Reviewers: dvyukov, kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31884 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299978 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 18 ++++++++++++++++-- lib/lsan/lsan_thread.cc | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 5fd2b89af..549595da5 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -33,7 +33,17 @@ typedef struct { static pthread_key_t key; static pthread_once_t key_once = PTHREAD_ONCE_INIT; -static void make_tls_key() { CHECK_EQ(pthread_key_create(&key, NULL), 0); } +// The main thread destructor requires the current thread id, +// so we can't destroy it until it's been used and reset to invalid tid +void restore_tid_data(void *ptr) { + thread_local_data_t *data = (thread_local_data_t *)ptr; + if (data->current_thread_id != kInvalidTid) + pthread_setspecific(key, data); +} + +static void make_tls_key() { + CHECK_EQ(pthread_key_create(&key, restore_tid_data), 0); +} static thread_local_data_t *get_tls_val(bool alloc) { pthread_once(&key_once, make_tls_key); @@ -65,7 +75,11 @@ void EnableInThisThread() { --*disable_counter; } -u32 GetCurrentThread() { return get_tls_val(true)->current_thread_id; } +u32 GetCurrentThread() { + thread_local_data_t *data = get_tls_val(false); + CHECK(data); + return data->current_thread_id; +} void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index ebec6cdbf..09eeb9c24 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -92,6 +92,7 @@ void ThreadStart(u32 tid, uptr os_id) { void ThreadFinish() { thread_registry->FinishThread(GetCurrentThread()); + SetCurrentThread(kInvalidTid); } ThreadContext *CurrentThreadContext() { -- cgit v1.2.1 From ef3c0d303156bf2dbc222a292e9785cb66535a33 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 11 Apr 2017 20:05:02 +0000 Subject: Implement standalone lsan interceptors for OS X Summary: Mimicks the existing tsan and asan implementations of Darwin interception. Reviewers: kubamracek, kcc, glider Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D31889 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299979 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/CMakeLists.txt | 1 + lib/lsan/lsan.cc | 1 + lib/lsan/lsan.h | 7 ++++++ lib/lsan/lsan_allocator.cc | 31 ++++++++++++++++++++++++ lib/lsan/lsan_allocator.h | 11 +++++++++ lib/lsan/lsan_interceptors.cc | 55 ++++++++++++++++++------------------------- lib/lsan/lsan_linux.cc | 2 ++ lib/lsan/lsan_malloc_mac.cc | 55 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 131 insertions(+), 32 deletions(-) create mode 100644 lib/lsan/lsan_malloc_mac.cc diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index e9db8ac62..55c825f5c 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -13,6 +13,7 @@ set(LSAN_SOURCES lsan_allocator.cc lsan_linux.cc lsan_interceptors.cc + lsan_malloc_mac.cc lsan_preinit.cc lsan_thread.cc) diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc index c7c342991..6c4767d61 100644 --- a/lib/lsan/lsan.cc +++ b/lib/lsan/lsan.cc @@ -76,6 +76,7 @@ extern "C" void __lsan_init() { InitializeFlags(); InitCommonLsan(); InitializeAllocator(); + ReplaceSystemMalloc(); InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h index ec5eb93dc..1061d2fcf 100644 --- a/lib/lsan/lsan.h +++ b/lib/lsan/lsan.h @@ -41,6 +41,13 @@ namespace __lsan { void InitializeInterceptors(); +void ReplaceSystemMalloc(); + +#define ENSURE_LSAN_INITED do { \ + CHECK(!lsan_init_is_running); \ + if (!lsan_inited) \ + __lsan_init(); \ +} while (0) } // namespace __lsan diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 9c8acc186..011979eee 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -117,6 +117,37 @@ uptr GetMallocUsableSize(const void *p) { return m->requested_size; } +void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) { + return Allocate(stack, size, alignment, kAlwaysClearMemory); +} + +void *lsan_malloc(uptr size, const StackTrace &stack) { + return Allocate(stack, size, 1, kAlwaysClearMemory); +} + +void lsan_free(void *p) { + Deallocate(p); +} + +void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { + return Reallocate(stack, p, size, 1); +} + +void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { + size *= nmemb; + return Allocate(stack, size, 1, true); +} + +void *lsan_valloc(uptr size, const StackTrace &stack) { + if (size == 0) + size = GetPageSizeCached(); + return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); +} + +uptr lsan_mz_size(const void *p) { + return GetMallocUsableSize(p); +} + ///// Interface to the common LSan module. ///// void LockAllocator() { diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index bd19211c4..e5def17d4 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -36,6 +36,8 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end); void AllocatorThreadFinish(); void InitializeAllocator(); +const bool kAlwaysClearMemory = true; + struct ChunkMetadata { u8 allocated : 8; // Must be first. ChunkTag tag : 2; @@ -72,6 +74,15 @@ typedef SizeClassAllocator64 PrimaryAllocator; typedef SizeClassAllocatorLocalCache AllocatorCache; AllocatorCache *GetAllocatorCache(); + +void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack); +void *lsan_malloc(uptr size, const StackTrace &stack); +void lsan_free(void *p); +void *lsan_realloc(void *p, uptr size, const StackTrace &stack); +void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack); +void *lsan_valloc(uptr size, const StackTrace &stack); +uptr lsan_mz_size(const void *p); + } // namespace __lsan #endif // LSAN_ALLOCATOR_H diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 876b39df3..2cc6fad36 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -39,29 +39,22 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v)); int pthread_setspecific(unsigned key, const void *v); } -#define ENSURE_LSAN_INITED do { \ - CHECK(!lsan_init_is_running); \ - if (!lsan_inited) \ - __lsan_init(); \ -} while (0) - ///// Malloc/free interceptors. ///// -const bool kAlwaysClearMemory = true; - namespace std { struct nothrow_t; } +#if !SANITIZER_MAC INTERCEPTOR(void*, malloc, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - return Allocate(stack, size, 1, kAlwaysClearMemory); + return lsan_malloc(size, stack); } INTERCEPTOR(void, free, void *p) { ENSURE_LSAN_INITED; - Deallocate(p); + lsan_free(p); } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { @@ -79,28 +72,42 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr; ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - size *= nmemb; - return Allocate(stack, size, 1, true); + return lsan_calloc(nmemb, size, stack); } INTERCEPTOR(void*, realloc, void *q, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - return Reallocate(stack, q, size, 1); + return lsan_realloc(q, size, stack); } +INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { + ENSURE_LSAN_INITED; + GET_STACK_TRACE_MALLOC; + *memptr = lsan_memalign(alignment, size, stack); + // FIXME: Return ENOMEM if user requested more than max alloc size. + return 0; +} + +INTERCEPTOR(void*, valloc, uptr size) { + ENSURE_LSAN_INITED; + GET_STACK_TRACE_MALLOC; + return lsan_valloc(size, stack); +} +#endif + #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - return Allocate(stack, size, alignment, kAlwaysClearMemory); + return lsan_memalign(alignment, size, stack); } #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - void *res = Allocate(stack, size, alignment, kAlwaysClearMemory); + void *res = lsan_memalign(alignment, size, stack); DTLS_on_libc_memalign(res, size); return res; } @@ -114,29 +121,13 @@ INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - return Allocate(stack, size, alignment, kAlwaysClearMemory); + return lsan_memalign(alignment, size, stack); } #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) #else #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC #endif -INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { - ENSURE_LSAN_INITED; - GET_STACK_TRACE_MALLOC; - *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory); - // FIXME: Return ENOMEM if user requested more than max alloc size. - return 0; -} - -INTERCEPTOR(void*, valloc, uptr size) { - ENSURE_LSAN_INITED; - GET_STACK_TRACE_MALLOC; - if (size == 0) - size = GetPageSizeCached(); - return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); -} - #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { ENSURE_LSAN_INITED; diff --git a/lib/lsan/lsan_linux.cc b/lib/lsan/lsan_linux.cc index a60f7413a..c9749c745 100644 --- a/lib/lsan/lsan_linux.cc +++ b/lib/lsan/lsan_linux.cc @@ -26,6 +26,8 @@ void SetCurrentThread(u32 tid) { current_thread_tid = tid; } static THREADLOCAL AllocatorCache allocator_cache; AllocatorCache *GetAllocatorCache() { return &allocator_cache; } +void ReplaceSystemMalloc() {} + } // namespace __lsan #endif // SANITIZER_LINUX diff --git a/lib/lsan/lsan_malloc_mac.cc b/lib/lsan/lsan_malloc_mac.cc new file mode 100644 index 000000000..9c1dacc05 --- /dev/null +++ b/lib/lsan/lsan_malloc_mac.cc @@ -0,0 +1,55 @@ +//===-- lsan_malloc_mac.cc ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer (LSan), a memory leak detector. +// +// Mac-specific malloc interception. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_MAC + +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_thread.h" + +using namespace __lsan; +#define COMMON_MALLOC_ZONE_NAME "lsan" +#define COMMON_MALLOC_ENTER() ENSURE_LSAN_INITED +#define COMMON_MALLOC_SANITIZER_INITIALIZED lsan_inited +#define COMMON_MALLOC_FORCE_LOCK() +#define COMMON_MALLOC_FORCE_UNLOCK() +#define COMMON_MALLOC_MEMALIGN(alignment, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = lsan_memalign(alignment, size, stack) +#define COMMON_MALLOC_MALLOC(size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = lsan_malloc(size, stack) +#define COMMON_MALLOC_REALLOC(ptr, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = lsan_realloc(ptr, size, stack) +#define COMMON_MALLOC_CALLOC(count, size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = lsan_calloc(count, size, stack) +#define COMMON_MALLOC_VALLOC(size) \ + GET_STACK_TRACE_MALLOC; \ + void *p = lsan_valloc(size, stack) +#define COMMON_MALLOC_FREE(ptr) \ + lsan_free(ptr) +#define COMMON_MALLOC_SIZE(ptr) \ + uptr size = lsan_mz_size(ptr) +#define COMMON_MALLOC_FILL_STATS(zone, stats) +#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \ + (void)zone_name; \ + Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr); +#define COMMON_MALLOC_NAMESPACE __lsan + +#include "sanitizer_common/sanitizer_malloc_mac.inc" + +#endif // SANITIZER_MAC -- cgit v1.2.1 From b6240efd1f34bf5e72bd5350166957d829a10d7d Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 12 Apr 2017 00:12:34 +0000 Subject: [msan] fix iconv interceptor. before the fix the interceptor failed to mark memory as initialized if iconv returned -1. Found in a hard way while fuzzing libxml2 :( git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300010 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 2 +- test/sanitizer_common/TestCases/Linux/iconv_test.c | 28 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/sanitizer_common/TestCases/Linux/iconv_test.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7ecde2294..7b4e6d27d 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4637,7 +4637,7 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, // its metadata. See // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft); - if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) { + if (outbuf && *outbuf > outbuf_orig) { SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz); } diff --git a/test/sanitizer_common/TestCases/Linux/iconv_test.c b/test/sanitizer_common/TestCases/Linux/iconv_test.c new file mode 100644 index 000000000..08da34d89 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/iconv_test.c @@ -0,0 +1,28 @@ +// RUN: %clang %s -o %t && %run %t +// Verify that even if iconv returned -1 +// we still treat the initialized part of outbuf as properly initialized. +#include +#include +#include + +int main() { + iconv_t cd = iconv_open("UTF-8", "no"); + assert(cd != (iconv_t)-1); + char in[11] = {0x7e, 0x7e, 0x5f, 0x53, 0x55, 0x3e, + 0x99, 0x3c, 0x7e, 0x7e, 0x7e}; + fprintf(stderr, "cd: %p\n", (void*)cd); + char out[100]; + char *inbuf = &in[0]; + size_t inbytesleft = 11; + char *outbuf = &out[0]; + size_t outbytesleft = 100; + int ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + assert(ret == -1); + assert(outbuf - &out[0] == 10); + for (int i = 0; i < 10; i++) { + if (out[i] == 0x77) return 1; + fprintf(stderr, "OUT%d 0x%x -- OK\n", i, (unsigned char)out[i]); + } + iconv_close(cd); +} + -- cgit v1.2.1 From 379a34bac1483eb835f96072829253390ef42df9 Mon Sep 17 00:00:00 2001 From: Douglas Yung Date: Wed, 12 Apr 2017 01:24:48 +0000 Subject: [XRay][compiler-rt] Add another work-around to XRay FDR tests when TSC emulation is needed This patch applies a work-around to the XRay FDR tests when TSC emulation is needed because the processor frequency cannot be determined. This fixes PR32620 using the suggestion given by Dean in comment 1. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31967 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300017 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 3 ++- lib/xray/xray_fdr_logging_impl.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index f2ff4076e..5c6bbd41c 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -120,7 +120,8 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { XRayFileHeader Header; Header.Version = 1; Header.Type = FileTypes::FDR_LOG; - Header.CycleFrequency = getTSCFrequency(); + Header.CycleFrequency = probeRequiredCPUFeatures() + ? getTSCFrequency() : __xray::NanosecondsPerSecond; // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc' // before setting the values in the header. Header.ConstantTSC = 1; diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 20e89d6c1..bc795b3b6 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -423,7 +423,9 @@ static inline void processFunctionHook( return; } - uint64_t CycleFrequency = getTSCFrequency(); + uint64_t CycleFrequency = probeRequiredCPUFeatures() + ? getTSCFrequency() + : __xray::NanosecondsPerSecond; NumberOfTicksThreshold = CycleFrequency * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; -- cgit v1.2.1 From 4f0068953dc26c44908dbe9cc1d5b650fbe5831a Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Wed, 12 Apr 2017 01:31:17 +0000 Subject: [XRay] [compiler-rt] Simplify FDR logging handler. [NFC] Summary: Not repeating screamy failure paths makes the 300+ line function a bit shorter. There's no need to overload the variable name "Buffer" if it only works on the thread local buffer. Fix some comments while there. I plan to move the rewinding logic into a separate function too, but in this diff it would be too much of a mess to comprehend. This is trivially NFC. Reviewers: kpw, dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31930 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300018 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index bc795b3b6..756bbe347 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -51,7 +51,7 @@ namespace __xray_fdr_internal { /// Writes the new buffer record and wallclock time that begin a buffer for a /// thread to MemPtr and increments MemPtr. Bypasses the thread local state -// machine and writes directly to memory without checks. +/// machine and writes directly to memory without checks. static void writeNewBufferPreamble(pid_t Tid, timespec TS, char *&MemPtr); /// Write a metadata record to switch to a new CPU to MemPtr and increments @@ -75,8 +75,7 @@ static void writeFunctionRecord(int FuncId, uint32_t TSCDelta, /// Sets up a new buffer in thread_local storage and writes a preamble. The /// wall_clock_reader function is used to populate the WallTimeRecord entry. -static void setupNewBuffer(const BufferQueue::Buffer &Buffer, - int (*wall_clock_reader)(clockid_t, +static void setupNewBuffer(int (*wall_clock_reader)(clockid_t, struct timespec *)); /// Called to record CPU time for a new CPU within the current thread. @@ -223,8 +222,7 @@ static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, NumTailCalls = 0; } -static inline void setupNewBuffer(const BufferQueue::Buffer &Buffer, - int (*wall_clock_reader)(clockid_t, +static inline void setupNewBuffer(int (*wall_clock_reader)(clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { RecordPtr = static_cast(Buffer.Buffer); @@ -246,7 +244,7 @@ static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, // The data for the New CPU will contain the following bytes: // - CPU ID (uint16_t, 2 bytes) // - Full TSC (uint64_t, 8 bytes) - // Total = 12 bytes. + // Total = 10 bytes. std::memcpy(&NewCPUId.Data, &CPU, sizeof(CPU)); std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); std::memcpy(MemPtr, &NewCPUId, sizeof(MetadataRecord)); @@ -347,6 +345,16 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, MemPtr += sizeof(FunctionRecord); } +static inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { + auto EC = BQ->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + BufferQueue::getErrorString(EC)); + return false; + } + return true; +} + static inline void processFunctionHook( int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, int (*wall_clock_reader)(clockid_t, struct timespec *), @@ -361,12 +369,8 @@ static inline void processFunctionHook( (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { writeEOBMetadata(); - auto EC = BQ->releaseBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - BufferQueue::getErrorString(EC)); + if (!releaseThreadLocalBuffer(BQ.get())) return; - } RecordPtr = nullptr; } return; @@ -402,12 +406,8 @@ static inline void processFunctionHook( if (!loggingInitialized(LoggingStatus) || LocalBQ->finalizing()) { writeEOBMetadata(); - auto EC = BQ->releaseBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - BufferQueue::getErrorString(EC)); + if (!releaseThreadLocalBuffer(BQ.get())) return; - } RecordPtr = nullptr; } @@ -429,7 +429,7 @@ static inline void processFunctionHook( NumberOfTicksThreshold = CycleFrequency * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; - setupNewBuffer(Buffer, wall_clock_reader); + setupNewBuffer(wall_clock_reader); } if (CurrentCPU == std::numeric_limits::max()) { @@ -479,13 +479,9 @@ static inline void processFunctionHook( if ((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart < static_cast(MetadataRecSize)) { writeEOBMetadata(); - auto EC = LocalBQ->releaseBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - BufferQueue::getErrorString(EC)); + if (!releaseThreadLocalBuffer(LocalBQ.get())) return; - } - EC = LocalBQ->getBuffer(Buffer); + auto EC = LocalBQ->getBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to acquire a buffer; error=%s\n", BufferQueue::getErrorString(EC)); @@ -495,7 +491,7 @@ static inline void processFunctionHook( NumberOfTicksThreshold = CycleFrequency * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; - setupNewBuffer(Buffer, wall_clock_reader); + setupNewBuffer(wall_clock_reader); } // By this point, we are now ready to write at most 24 bytes (one metadata @@ -632,12 +628,8 @@ static inline void processFunctionHook( // make sure that other threads may start using this buffer. if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { writeEOBMetadata(); - auto EC = LocalBQ->releaseBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed releasing buffer at %p; error=%s\n", Buffer.Buffer, - BufferQueue::getErrorString(EC)); + if (!releaseThreadLocalBuffer(LocalBQ.get())) return; - } RecordPtr = nullptr; } } -- cgit v1.2.1 From 4153a1785daf49cfb9d2ee91aada9db1bd05519c Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Wed, 12 Apr 2017 05:30:35 +0000 Subject: [XRay] [compiler-rt] Refactor rewinding FDR logging. Summary: While there, make the threshold in ticks for the rewind computed only once and not per function, unify the two versions we had and slightly reformat bits according to coding standards. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31971 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300028 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 159 +++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 756bbe347..ce360cb03 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -345,6 +345,83 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, MemPtr += sizeof(FunctionRecord); } +static uint64_t thresholdTicks() { + static uint64_t TicksPerSec = probeRequiredCPUFeatures() ? getTSCFrequency() : + __xray::NanosecondsPerSecond; + static const uint64_t ThresholdTicks = + TicksPerSec * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; + return ThresholdTicks; +} + +// Re-point the thread local pointer into this thread's Buffer before the recent +// "Function Entry" record and any "Tail Call Exit" records after that. +static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, + uint64_t &LastFunctionEntryTSC, int32_t FuncId) { + using AlignedFuncStorage = + std::aligned_storage::type; + RecordPtr -= FunctionRecSize; + AlignedFuncStorage AlignedFuncRecordBuffer; + const auto &FuncRecord = *reinterpret_cast( + std::memcpy(&AlignedFuncRecordBuffer, RecordPtr, FunctionRecSize)); + assert(FuncRecord.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && + "Expected to find function entry recording when rewinding."); + assert(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && + "Expected matching function id when rewinding Exit"); + --NumConsecutiveFnEnters; + LastTSC -= FuncRecord.TSCDelta; + + // We unwound one call. Update the state and return without writing a log. + if (NumConsecutiveFnEnters != 0) { + LastFunctionEntryTSC -= FuncRecord.TSCDelta; + return; + } + + // Otherwise we've rewound the stack of all function entries, we might be + // able to rewind further by erasing tail call functions that are being + // exited from via this exit. + LastFunctionEntryTSC = 0; + auto RewindingTSC = LastTSC; + auto RewindingRecordPtr = RecordPtr - FunctionRecSize; + while (NumTailCalls > 0) { + AlignedFuncStorage TailExitRecordBuffer; + // Rewind the TSC back over the TAIL EXIT record. + const auto &ExpectedTailExit = + *reinterpret_cast(std::memcpy( + &TailExitRecordBuffer, RewindingRecordPtr, FunctionRecSize)); + + assert(ExpectedTailExit.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && + "Expected to find tail exit when rewinding."); + RewindingRecordPtr -= FunctionRecSize; + RewindingTSC -= ExpectedTailExit.TSCDelta; + AlignedFuncStorage FunctionEntryBuffer; + const auto &ExpectedFunctionEntry = + *reinterpret_cast(std::memcpy( + &FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); + assert(ExpectedFunctionEntry.RecordKind == + uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && + "Expected to find function entry when rewinding tail call."); + assert(ExpectedFunctionEntry.FuncId == ExpectedTailExit.FuncId && + "Expected funcids to match when rewinding tail call."); + + // This tail call exceeded the threshold duration. It will not be erased. + if ((TSC - RewindingTSC) >= thresholdTicks()) { + NumTailCalls = 0; + return; + } + + // We can erase a tail exit pair that we're exiting through since + // its duration is under threshold. + --NumTailCalls; + RewindingRecordPtr -= FunctionRecSize; + RewindingTSC -= ExpectedFunctionEntry.TSCDelta; + RecordPtr -= 2 * FunctionRecSize; + LastTSC = RewindingTSC; + } +} + static inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { auto EC = BQ->releaseBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { @@ -384,7 +461,6 @@ static inline void processFunctionHook( thread_local uint16_t CurrentCPU = std::numeric_limits::max(); thread_local uint64_t LastTSC = 0; thread_local uint64_t LastFunctionEntryTSC = 0; - thread_local uint64_t NumberOfTicksThreshold = 0; // Make sure a thread that's ever called handleArg0 has a thread-local // live reference to the buffer queue for this particular instance of @@ -423,12 +499,6 @@ static inline void processFunctionHook( return; } - uint64_t CycleFrequency = probeRequiredCPUFeatures() - ? getTSCFrequency() - : __xray::NanosecondsPerSecond; - NumberOfTicksThreshold = CycleFrequency * - flags()->xray_fdr_log_func_duration_threshold_us / - 1000000; setupNewBuffer(wall_clock_reader); } @@ -487,10 +557,6 @@ static inline void processFunctionHook( BufferQueue::getErrorString(EC)); return; } - uint64_t CycleFrequency = getTSCFrequency(); - NumberOfTicksThreshold = CycleFrequency * - flags()->xray_fdr_log_func_duration_threshold_us / - 1000000; setupNewBuffer(wall_clock_reader); } @@ -538,9 +604,6 @@ static inline void processFunctionHook( LastTSC = TSC; CurrentCPU = CPU; - using AlignedFuncStorage = - std::aligned_storage::type; switch (Entry) { case XRayEntryType::ENTRY: case XRayEntryType::LOG_ARGS_ENTRY: @@ -552,73 +615,9 @@ static inline void processFunctionHook( case XRayEntryType::EXIT: // Break out and write the exit record if we can't erase any functions. if (NumConsecutiveFnEnters == 0 || - (TSC - LastFunctionEntryTSC) >= NumberOfTicksThreshold) + (TSC - LastFunctionEntryTSC) >= thresholdTicks()) break; - // Otherwise we unwind functions that are too short to log by decrementing - // our view ptr into the buffer. We can erase a Function Entry record and - // neglect to log our EXIT. We have to make sure to update some state like - // the LastTSC and count of consecutive FunctionEntry records. - RecordPtr -= FunctionRecSize; - AlignedFuncStorage AlignedFuncRecordBuffer; - const auto &FuncRecord = *reinterpret_cast( - std::memcpy(&AlignedFuncRecordBuffer, RecordPtr, FunctionRecSize)); - assert(FuncRecord.RecordKind == - uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && - "Expected to find function entry recording when rewinding."); - assert(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && - "Expected matching function id when rewinding Exit"); - --NumConsecutiveFnEnters; - LastTSC -= FuncRecord.TSCDelta; - - // We unwound one call. Update the state and return without writing a log. - if (NumConsecutiveFnEnters != 0) { - LastFunctionEntryTSC = LastFunctionEntryTSC - FuncRecord.TSCDelta; - return; - } - - // Otherwise we've rewound the stack of all function entries, we might be - // able to rewind further by erasing tail call functions that are being - // exited from via this exit. - LastFunctionEntryTSC = 0; - auto RewindingTSC = LastTSC; - auto RewindingRecordPtr = RecordPtr - FunctionRecSize; - while (NumTailCalls > 0) { - AlignedFuncStorage TailExitRecordBuffer; - // Rewind the TSC back over the TAIL EXIT record. - const auto &ExpectedTailExit = - *reinterpret_cast(std::memcpy( - &TailExitRecordBuffer, RewindingRecordPtr, FunctionRecSize)); - - assert(ExpectedTailExit.RecordKind == - uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && - "Expected to find tail exit when rewinding."); - RewindingRecordPtr -= FunctionRecSize; - RewindingTSC -= ExpectedTailExit.TSCDelta; - AlignedFuncStorage FunctionEntryBuffer; - const auto &ExpectedFunctionEntry = - *reinterpret_cast(std::memcpy( - &FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); - assert(ExpectedFunctionEntry.RecordKind == - uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && - "Expected to find function entry when rewinding tail call."); - assert(ExpectedFunctionEntry.FuncId == ExpectedTailExit.FuncId && - "Expected funcids to match when rewinding tail call."); - - if ((TSC - RewindingTSC) < NumberOfTicksThreshold) { - // We can erase a tail exit pair that we're exiting through since - // its duration is under threshold. - --NumTailCalls; - RewindingRecordPtr -= FunctionRecSize; - RewindingTSC -= ExpectedFunctionEntry.TSCDelta; - RecordPtr -= 2 * FunctionRecSize; - LastTSC = RewindingTSC; - } else { - // This tail call exceeded the threshold duration. It will not - // be erased. - NumTailCalls = 0; - return; - } - } + rewindRecentCall(TSC, LastTSC, LastFunctionEntryTSC, FuncId); return; // without writing log. } -- cgit v1.2.1 From e68ed060201e0d633ae664dd174606a5afc79eb0 Mon Sep 17 00:00:00 2001 From: Ismail Donmez Date: Wed, 12 Apr 2017 09:42:46 +0000 Subject: Fix compile error git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300041 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 5c6bbd41c..c5b63b0a5 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -17,6 +17,7 @@ #include "xray_fdr_logging.h" #include #include +#include #include #include #include -- cgit v1.2.1 From 8037ab9c5d4900cc73cd19eabac8ba2abf1c7247 Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Wed, 12 Apr 2017 09:45:08 +0000 Subject: Revert "[lsan] Fix typo in test/lsan/lit.common.cfg" This reverts commit r299957. It broke the Thumb bots. We need to make sure why and maybe stop it from being tested on Thumb environments. But for now, let's get the bots green. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300042 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 0b9e5a4a7..b0e5e7e0e 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -53,7 +53,7 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', armv7l]: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 4d122dd84d259567e6fe8e4e57291ccfc043bb7a Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Wed, 12 Apr 2017 10:12:49 +0000 Subject: [LSAN] Disable on ARM/Thumb for good I didn't pay enough attention to the patch I reverted, now I'm going to hit it with a bigger hammer until we can understand what the problems are. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300044 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/lit.common.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index b0e5e7e0e..202620cdd 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -53,7 +53,8 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', armv7l]: +# LSAN breaks on Thumb, so disabling from all ARM targets until we sort this out. PR32636. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 3cd04e32a8cd9497bd2882d7767e40ae9a936e24 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 12 Apr 2017 14:25:28 +0000 Subject: Use 0-padding for i386 and arm print format specifiers Summary: This is used for the other architectures in print_address, but is missing from i386 and arm. Reviewers: m.ostapenko, spetrovic Subscribers: aemerson, rengolin, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31977 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300065 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/print_address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/print_address.h b/test/sanitizer_common/print_address.h index 63d9a93f1..db2e8341a 100644 --- a/test/sanitizer_common/print_address.h +++ b/test/sanitizer_common/print_address.h @@ -12,7 +12,7 @@ void print_address(const char *str, int n, ...) { // match to the format used in the diagnotic message. fprintf(stderr, "0x%012lx ", (unsigned long) p); #elif defined(__i386__) || defined(__arm__) - fprintf(stderr, "0x%8lx ", (unsigned long) p); + fprintf(stderr, "0x%08lx ", (unsigned long) p); #elif defined(__mips64) fprintf(stderr, "0x%010lx ", (unsigned long) p); #endif -- cgit v1.2.1 From 059c103b581e37d2be47cb403769bff20808bca2 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 12 Apr 2017 17:31:41 +0000 Subject: Fix memory leaks in address sanitizer darwin tests Summary: These leaks are detected by leak sanitizer for darwin. Reviewers: glider, kubamracek, kcc, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31978 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300080 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_mac_test_helpers.mm | 1 + test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc | 1 + test/asan/TestCases/Darwin/scribble.cc | 1 + test/asan/TestCases/Darwin/suppressions-darwin.cc | 1 + test/asan/TestCases/Darwin/suppressions-sandbox.cc | 1 + 5 files changed, 5 insertions(+) diff --git a/lib/asan/tests/asan_mac_test_helpers.mm b/lib/asan/tests/asan_mac_test_helpers.mm index a7e4b9d19..3f8fa26d9 100644 --- a/lib/asan/tests/asan_mac_test_helpers.mm +++ b/lib/asan/tests/asan_mac_test_helpers.mm @@ -237,4 +237,5 @@ void TestNSURLDeallocation() { [[NSURL alloc] initWithString:@"Saved Application State" relativeToURL:base]; [u release]; + [base release]; } diff --git a/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc index 2c643bc03..b9b96ef05 100644 --- a/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc +++ b/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc @@ -47,5 +47,6 @@ int main() { memset(mem[i], 'a', 8 * (i % kNumIter)); free(mem[i]); } + malloc_destroy_zone(zone); return 0; } diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc index 33f64e19c..0ddee6b5e 100644 --- a/test/asan/TestCases/Darwin/scribble.cc +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -54,4 +54,5 @@ int main() { fprintf(stderr, "okthxbai!\n"); // CHECK-SCRIBBLE: okthxbai! // CHECK-NOSCRIBBLE: okthxbai! + free(my_class_isa); } diff --git a/test/asan/TestCases/Darwin/suppressions-darwin.cc b/test/asan/TestCases/Darwin/suppressions-darwin.cc index a177c4e17..8c207b102 100644 --- a/test/asan/TestCases/Darwin/suppressions-darwin.cc +++ b/test/asan/TestCases/Darwin/suppressions-darwin.cc @@ -27,6 +27,7 @@ int main() { kCFStringEncodingUTF8, FALSE); // BOOM fprintf(stderr, "Ignored.\n"); free(a); + CFRelease(str); } // CHECK-CRASH: AddressSanitizer: heap-buffer-overflow diff --git a/test/asan/TestCases/Darwin/suppressions-sandbox.cc b/test/asan/TestCases/Darwin/suppressions-sandbox.cc index ddbad466f..c0b84adda 100644 --- a/test/asan/TestCases/Darwin/suppressions-sandbox.cc +++ b/test/asan/TestCases/Darwin/suppressions-sandbox.cc @@ -18,6 +18,7 @@ int main() { kCFStringEncodingUTF8, FALSE); // BOOM fprintf(stderr, "Ignored.\n"); free(a); + CFRelease(str); } // CHECK-CRASH: AddressSanitizer: heap-buffer-overflow -- cgit v1.2.1 From d1ca180de86b6d4f0b1bd3e19c320193c2352b3e Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 12 Apr 2017 20:51:42 +0000 Subject: Avoid calling SizeClassMap::MaxCachedHint on hot path, it's not free. Summary: Remove unecessary SizeClassMap::MaxCachedHint call. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31989 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300103 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_local_cache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index e1172e0c2..a36619446 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -102,7 +102,7 @@ struct SizeClassAllocator64LocalCache { NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator, uptr class_id) { InitCache(); - uptr num_requested_chunks = SizeClassMap::MaxCachedHint(class_id); + uptr num_requested_chunks = c->max_count / 2; allocator->GetFromAllocator(&stats_, class_id, c->chunks, num_requested_chunks); c->count = num_requested_chunks; -- cgit v1.2.1 From 28db59a5ee579a34296f69fc79670ce051567b78 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 12 Apr 2017 21:44:56 +0000 Subject: Cache size per class size in SizeClassAllocatorXLocalCache. Summary: Allocator::ClassIdToSize() is not free and calling it in every Allocate/Deallocate has noticeable impact on perf. Reviewers: eugenis, kcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D31991 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300107 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_local_cache.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index a36619446..1b72b17fa 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -45,8 +45,8 @@ struct SizeClassAllocator64LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); - stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Add(AllocatorStatAllocated, c->class_size); if (UNLIKELY(c->count == 0)) Refill(c, allocator, class_id); CHECK_GT(c->count, 0); @@ -62,8 +62,8 @@ struct SizeClassAllocator64LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); - stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(c, allocator, class_id, c->max_count / 2); @@ -85,6 +85,7 @@ struct SizeClassAllocator64LocalCache { struct PerClass { u32 count; u32 max_count; + uptr class_size; CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint]; }; PerClass per_class_[kNumClasses]; @@ -96,6 +97,7 @@ struct SizeClassAllocator64LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * SizeClassMap::MaxCachedHint(i); + c->class_size = Allocator::ClassIdToSize(i); } } @@ -141,8 +143,8 @@ struct SizeClassAllocator32LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); - stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Add(AllocatorStatAllocated, c->class_size); if (UNLIKELY(c->count == 0)) Refill(allocator, class_id); void *res = c->batch[--c->count]; @@ -156,8 +158,8 @@ struct SizeClassAllocator32LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); - stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(allocator, class_id); @@ -177,6 +179,7 @@ struct SizeClassAllocator32LocalCache { struct PerClass { uptr count; uptr max_count; + uptr class_size; void *batch[2 * TransferBatch::kMaxNumCached]; }; PerClass per_class_[kNumClasses]; @@ -188,6 +191,7 @@ struct SizeClassAllocator32LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * TransferBatch::MaxCached(i); + c->class_size = Allocator::ClassIdToSize(i); } } -- cgit v1.2.1 From c2cc1e207470cc5baf5af6473c2bde825f6f6934 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 13 Apr 2017 00:36:02 +0000 Subject: [msan] Fix invalid use of vector constructor introduced by r299884. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300149 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 12d6092ef..eebce5ee2 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -949,7 +949,7 @@ class MemorySanitizerIpTest : public ::testing::TestWithParam { std::vector GetAvailableIpSocketFamilies() { std::vector result; - for (int i : std::vector(AF_INET, AF_INET6)) { + for (int i : {AF_INET, AF_INET6}) { int s = socket(i, SOCK_STREAM, 0); if (s > 0) { result.push_back(i); -- cgit v1.2.1 From 4a814b2e509432c806ba7b0523bbed84923cab21 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 13 Apr 2017 00:36:03 +0000 Subject: [msan] Fix msan_test broken after r299884. Bind to ANY as some machines may have IPv6 support but without IPv6 on loopback interface. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31998 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300150 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index eebce5ee2..4e962e108 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -899,7 +899,7 @@ class SocketAddr4 : public SocketAddr { memset(&sai_, 0, sizeof(sai_)); sai_.sin_family = AF_INET; sai_.sin_port = port; - sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sai_.sin_addr.s_addr = htonl(INADDR_ANY); } sockaddr *ptr() override { return reinterpret_cast(&sai_); } @@ -917,7 +917,7 @@ class SocketAddr6 : public SocketAddr { memset(&sai_, 0, sizeof(sai_)); sai_.sin6_family = AF_INET6; sai_.sin6_port = port; - sai_.sin6_addr = in6addr_loopback; + sai_.sin6_addr = in6addr_any; } sockaddr *ptr() override { return reinterpret_cast(&sai_); } -- cgit v1.2.1 From a1687c29181cb02ce005689e09613af28de45de0 Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Thu, 13 Apr 2017 07:39:04 +0000 Subject: Revert "Cache size per class size in SizeClassAllocatorXLocalCache." This reverts commit r300107 because it broke the ARM and AArch64 buildbots. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300180 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_local_cache.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index 1b72b17fa..a36619446 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -45,8 +45,8 @@ struct SizeClassAllocator64LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); + stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - stats_.Add(AllocatorStatAllocated, c->class_size); if (UNLIKELY(c->count == 0)) Refill(c, allocator, class_id); CHECK_GT(c->count, 0); @@ -62,8 +62,8 @@ struct SizeClassAllocator64LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); + stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(c, allocator, class_id, c->max_count / 2); @@ -85,7 +85,6 @@ struct SizeClassAllocator64LocalCache { struct PerClass { u32 count; u32 max_count; - uptr class_size; CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint]; }; PerClass per_class_[kNumClasses]; @@ -97,7 +96,6 @@ struct SizeClassAllocator64LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * SizeClassMap::MaxCachedHint(i); - c->class_size = Allocator::ClassIdToSize(i); } } @@ -143,8 +141,8 @@ struct SizeClassAllocator32LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); + stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - stats_.Add(AllocatorStatAllocated, c->class_size); if (UNLIKELY(c->count == 0)) Refill(allocator, class_id); void *res = c->batch[--c->count]; @@ -158,8 +156,8 @@ struct SizeClassAllocator32LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); + stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(allocator, class_id); @@ -179,7 +177,6 @@ struct SizeClassAllocator32LocalCache { struct PerClass { uptr count; uptr max_count; - uptr class_size; void *batch[2 * TransferBatch::kMaxNumCached]; }; PerClass per_class_[kNumClasses]; @@ -191,7 +188,6 @@ struct SizeClassAllocator32LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * TransferBatch::MaxCached(i); - c->class_size = Allocator::ClassIdToSize(i); } } -- cgit v1.2.1 From b84477f989c2bc595ba252f22bc346bdc8de597c Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 13 Apr 2017 12:00:56 +0000 Subject: [lsan] Reenable lsan tests on ARM bots This patch addresses pr32636. Enable lsan tests on ARM bots filtering out Thumb targets. Tested locally on ARM Arndale board in two configurations: 1) CFLAGS="-march=armv7-a" Testing Time: 37.57s Expected Passes : 69 Unsupported Tests : 7 2) CFLAGS="-march=armv7-a -mthumb" Testing Time: 0.16s Unsupported Tests : 76 Differential Revision: https://reviews.llvm.org/D32007 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300194 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 2 +- test/lsan/lit.common.cfg | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 9093b44c1..7d684a1ae 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -213,7 +213,7 @@ if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.targ config.available_features.add('stable-runtime') # Fast unwinder doesn't work with Thumb -if not re.match('-mthumb', config.target_cflags): +if re.search('mthumb', config.target_cflags) is not None: config.available_features.add('fast-unwinder-works') # Turn on leak detection on 64-bit Linux. diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 202620cdd..b90c7ef48 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -53,12 +53,11 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -# LSAN breaks on Thumb, so disabling from all ARM targets until we sort this out. PR32636. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']: +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -if re.match('-mthumb', config.target_cflags): +if re.search('mthumb', config.target_cflags) is not None: config.unsupported = True config.suffixes = ['.c', '.cc', '.cpp'] -- cgit v1.2.1 From f91aadbae931996cb078643c4e16e25b7dbd57fd Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 13 Apr 2017 14:00:24 +0000 Subject: Free zone name when destroying malloc zone Summary: The darwin interceptor for malloc_destroy_zone manually frees the zone struct, but does not free the name component. Make sure to free the name if it has been set. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31983 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300195 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_malloc_mac.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_malloc_mac.inc b/lib/sanitizer_common/sanitizer_malloc_mac.inc index 6fbee07c1..5699c5904 100644 --- a/lib/sanitizer_common/sanitizer_malloc_mac.inc +++ b/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -59,6 +59,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) { uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); } + if (zone->zone_name) { + COMMON_MALLOC_FREE((void *)zone->zone_name); + } COMMON_MALLOC_FREE(zone); } -- cgit v1.2.1 From 546e70f188dbda325cea1af5675042981d0ba38a Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 13 Apr 2017 16:17:32 +0000 Subject: Enable LSan on PowerPC64. Summary: With D31555 commited, looks like basic LSan functionality works on PPC64. Time to enable LSan there. Reviewers: eugenis Subscribers: nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D31995 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300204 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 2 +- lib/lsan/lsan_common.h | 3 ++- test/lsan/lit.common.cfg | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index e5def17d4..fad5adb01 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> PrimaryAllocator; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__powerpc64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; static const uptr kSpaceSize = 0x40000000000ULL; // 4T. diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 2851a6672..fb962701d 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -32,7 +32,8 @@ // new architecture inside sanitizer library. #if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ + defined(__powerpc64__)) #define CAN_SANITIZE_LEAKS 1 #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index b90c7ef48..c0107e777 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -52,8 +52,9 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: +# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux and mips64 Linux only. +# LSAN breaks on Thumb, so disabling from all ARM targets until we sort this out. PR32636. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l', 'ppc64']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 365d041bb0cb543aa639c385eeaf31c33d802730 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 13 Apr 2017 16:49:16 +0000 Subject: Cache size per class size in SizeClassAllocatorXLocalCache. Summary: Allocator::ClassIdToSize() is not free and calling it in every Allocate/Deallocate has noticeable impact on perf. Reapplying D31991 with the appropriate fixes. Reviewers: cryptoad Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32024 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300216 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_local_cache.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index a36619446..d6c66604e 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -45,10 +45,10 @@ struct SizeClassAllocator64LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); - stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; if (UNLIKELY(c->count == 0)) Refill(c, allocator, class_id); + stats_.Add(AllocatorStatAllocated, c->class_size); CHECK_GT(c->count, 0); CompactPtrT chunk = c->chunks[--c->count]; void *res = reinterpret_cast(allocator->CompactPtrToPointer( @@ -62,8 +62,8 @@ struct SizeClassAllocator64LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); - stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(c, allocator, class_id, c->max_count / 2); @@ -85,6 +85,7 @@ struct SizeClassAllocator64LocalCache { struct PerClass { u32 count; u32 max_count; + uptr class_size; CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint]; }; PerClass per_class_[kNumClasses]; @@ -96,6 +97,7 @@ struct SizeClassAllocator64LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * SizeClassMap::MaxCachedHint(i); + c->class_size = Allocator::ClassIdToSize(i); } } @@ -141,10 +143,10 @@ struct SizeClassAllocator32LocalCache { void *Allocate(SizeClassAllocator *allocator, uptr class_id) { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); - stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; if (UNLIKELY(c->count == 0)) Refill(allocator, class_id); + stats_.Add(AllocatorStatAllocated, c->class_size); void *res = c->batch[--c->count]; PREFETCH(c->batch[c->count - 1]); return res; @@ -156,8 +158,8 @@ struct SizeClassAllocator32LocalCache { // If the first allocator call on a new thread is a deallocation, then // max_count will be zero, leading to check failure. InitCache(); - stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; + stats_.Sub(AllocatorStatAllocated, c->class_size); CHECK_NE(c->max_count, 0UL); if (UNLIKELY(c->count == c->max_count)) Drain(allocator, class_id); @@ -177,6 +179,7 @@ struct SizeClassAllocator32LocalCache { struct PerClass { uptr count; uptr max_count; + uptr class_size; void *batch[2 * TransferBatch::kMaxNumCached]; }; PerClass per_class_[kNumClasses]; @@ -188,6 +191,7 @@ struct SizeClassAllocator32LocalCache { for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; c->max_count = 2 * TransferBatch::MaxCached(i); + c->class_size = Allocator::ClassIdToSize(i); } } -- cgit v1.2.1 From 6357c2dc3041c3d05cba75440a28be62f29c92a9 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 13 Apr 2017 17:28:52 +0000 Subject: Don't assume PTHREAD_CREATE_JOINABLE is 0 on all systems Summary: Lsan was using PTHREAD_CREATE_JOINABLE/PTHREAD_CREATE_DETACHED as truthy values, which works on Linux, where the values are 0 and 1, but this fails on OS X, where the values are 1 and 2. Set PTHREAD_CREATE_DETACHED to the correct value for a given system. Reviewers: kcc, glider, kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31883 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300221 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_interceptors.cc | 4 +++- lib/sanitizer_common/sanitizer_posix.h | 3 +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc | 4 ++++ lib/tsan/rtl/tsan_interceptors.cc | 14 ++------------ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 2cc6fad36..fe1f49bcd 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -21,6 +21,7 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" @@ -281,7 +282,8 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); } if (res == 0) { - int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached); + int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, + IsStateDetached(detached)); CHECK_NE(tid, 0); atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index 7f862cd9e..e7d37cbf0 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -87,6 +87,9 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum); uptr internal_execve(const char *filename, char *const argv[], char *const envp[]); + +bool IsStateDetached(int state); + } // namespace __sanitizer #endif // SANITIZER_POSIX_H diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index dd62140b5..8d688f377 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -418,6 +418,10 @@ int WaitForProcess(pid_t pid) { return process_status; } +bool IsStateDetached(int state) { + return state == PTHREAD_CREATE_DETACHED; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index bb2badbff..d0fd91aec 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -18,6 +18,7 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "interception/interception.h" @@ -29,9 +30,6 @@ #include "tsan_mman.h" #include "tsan_fd.h" -#if SANITIZER_POSIX -#include "sanitizer_common/sanitizer_posix.h" -#endif using namespace __tsan; // NOLINT @@ -46,13 +44,6 @@ using namespace __tsan; // NOLINT #define mallopt(a, b) #endif -#if SANITIZER_LINUX || SANITIZER_FREEBSD -#define PTHREAD_CREATE_DETACHED 1 -#elif SANITIZER_MAC -#define PTHREAD_CREATE_DETACHED 2 -#endif - - #ifdef __mips__ const int kSigCount = 129; #else @@ -928,8 +919,7 @@ TSAN_INTERCEPTOR(int, pthread_create, ThreadIgnoreEnd(thr, pc); } if (res == 0) { - int tid = ThreadCreate(thr, pc, *(uptr*)th, - detached == PTHREAD_CREATE_DETACHED); + int tid = ThreadCreate(thr, pc, *(uptr*)th, IsStateDetached(detached)); CHECK_NE(tid, 0); // Synchronization on p.tid serves two purposes: // 1. ThreadCreate must finish before the new thread starts. -- cgit v1.2.1 From 55b1f4fcdf5fdf4a0dd761285a9f713ec19cd8f2 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 13 Apr 2017 18:40:19 +0000 Subject: Implement global pointer scanning for darwin leak sanitizer Reviewers: kubamracek, kcc, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32012 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300234 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 17 +++++++++++++++++ lib/lsan/lsan_common.h | 1 + lib/lsan/lsan_common_linux.cc | 15 +-------------- lib/lsan/lsan_common_mac.cc | 16 +++++++++++++++- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index ade8b0a02..6cc737498 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -175,6 +175,23 @@ void ScanRangeForPointers(uptr begin, uptr end, } } +// Scans a global range for pointers +void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) { + uptr allocator_begin = 0, allocator_end = 0; + GetAllocatorGlobalRange(&allocator_begin, &allocator_end); + if (begin <= allocator_begin && allocator_begin < end) { + CHECK_LE(allocator_begin, allocator_end); + CHECK_LE(allocator_end, end); + if (begin < allocator_begin) + ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL", + kReachable); + if (allocator_end < end) + ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", kReachable); + } else { + ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable); + } +} + void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { Frontier *frontier = reinterpret_cast(arg); ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index fb962701d..ad2eb6afa 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -125,6 +125,7 @@ void DoStopTheWorld(StopTheWorldCallback callback, void* argument); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, const char *region_type, ChunkTag tag); +void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier); enum IgnoreObjectResult { kIgnoreObjectSuccess, diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 931b5112a..0d1e998a5 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -78,20 +78,7 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, continue; uptr begin = info->dlpi_addr + phdr->p_vaddr; uptr end = begin + phdr->p_memsz; - uptr allocator_begin = 0, allocator_end = 0; - GetAllocatorGlobalRange(&allocator_begin, &allocator_end); - if (begin <= allocator_begin && allocator_begin < end) { - CHECK_LE(allocator_begin, allocator_end); - CHECK_LE(allocator_end, end); - if (begin < allocator_begin) - ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL", - kReachable); - if (allocator_end < end) - ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", - kReachable); - } else { - ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable); - } + ScanGlobalRange(begin, end, frontier); } return 0; } diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 549595da5..d15551072 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -91,7 +91,21 @@ void InitializePlatformSpecificModules() {} // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { - CHECK(0 && "unimplemented"); + MemoryMappingLayout memory_mapping(false); + InternalMmapVector modules(/*initial_capacity*/ 128); + memory_mapping.DumpListOfModules(&modules); + for (uptr i = 0; i < modules.size(); ++i) { + // Even when global scanning is disabled, we still need to scan + // system libraries for stashed pointers + if (!flags()->use_globals && modules[i].instrumented()) continue; + + for (const __sanitizer::LoadedModule::AddressRange &range : + modules[i].ranges()) { + if (range.executable) continue; + + ScanGlobalRange(range.beg, range.end, frontier); + } + } } void ProcessPlatformSpecificAllocations(Frontier *frontier) { -- cgit v1.2.1 From 89c6616871ef7cb99faa191a5362ee3f7dd43e53 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 13 Apr 2017 18:49:29 +0000 Subject: Revert "Enable LSan on PowerPC64." This reverts commit r300204. Breaks ASAN tests on PPC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300237 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 2 +- lib/lsan/lsan_common.h | 3 +-- test/lsan/lit.common.cfg | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index fad5adb01..e5def17d4 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> PrimaryAllocator; -#elif defined(__x86_64__) || defined(__powerpc64__) +#elif defined(__x86_64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; static const uptr kSpaceSize = 0x40000000000ULL; // 4T. diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index ad2eb6afa..919be0ec2 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -32,8 +32,7 @@ // new architecture inside sanitizer library. #if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ - defined(__powerpc64__)) + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) #define CAN_SANITIZE_LEAKS 1 #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index c0107e777..b90c7ef48 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -52,9 +52,8 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux and mips64 Linux only. -# LSAN breaks on Thumb, so disabling from all ARM targets until we sort this out. PR32636. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l', 'ppc64']: +# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From d4919012c575113890440032263361607debc2ce Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 13 Apr 2017 20:13:53 +0000 Subject: Move Linux-specific lsan tests into a new directory Summary: These tests aren't supported on other platforms, move them to their own directory. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32034 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300247 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/cleanup_in_tsd_destructor.c | 46 ++++++++++++++++ .../TestCases/Linux/disabler_in_tsd_destructor.c | 39 ++++++++++++++ test/lsan/TestCases/Linux/fork.cc | 24 +++++++++ test/lsan/TestCases/Linux/fork_threaded.cc | 43 +++++++++++++++ test/lsan/TestCases/Linux/guard-page.c | 61 ++++++++++++++++++++++ test/lsan/TestCases/Linux/lit.local.cfg | 9 ++++ test/lsan/TestCases/Linux/use_tls_dynamic.cc | 52 ++++++++++++++++++ .../Linux/use_tls_pthread_specific_dynamic.cc | 38 ++++++++++++++ .../Linux/use_tls_pthread_specific_static.cc | 32 ++++++++++++ test/lsan/TestCases/Linux/use_tls_static.cc | 22 ++++++++ test/lsan/TestCases/cleanup_in_tsd_destructor.c | 46 ---------------- test/lsan/TestCases/disabler_in_tsd_destructor.c | 39 -------------- test/lsan/TestCases/fork.cc | 24 --------- test/lsan/TestCases/fork_threaded.cc | 43 --------------- test/lsan/TestCases/guard-page.c | 61 ---------------------- test/lsan/TestCases/use_tls_dynamic.cc | 52 ------------------ .../TestCases/use_tls_pthread_specific_dynamic.cc | 38 -------------- .../TestCases/use_tls_pthread_specific_static.cc | 32 ------------ test/lsan/TestCases/use_tls_static.cc | 22 -------- 19 files changed, 366 insertions(+), 357 deletions(-) create mode 100644 test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c create mode 100644 test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c create mode 100644 test/lsan/TestCases/Linux/fork.cc create mode 100644 test/lsan/TestCases/Linux/fork_threaded.cc create mode 100644 test/lsan/TestCases/Linux/guard-page.c create mode 100644 test/lsan/TestCases/Linux/lit.local.cfg create mode 100644 test/lsan/TestCases/Linux/use_tls_dynamic.cc create mode 100644 test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc create mode 100644 test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc create mode 100644 test/lsan/TestCases/Linux/use_tls_static.cc delete mode 100644 test/lsan/TestCases/cleanup_in_tsd_destructor.c delete mode 100644 test/lsan/TestCases/disabler_in_tsd_destructor.c delete mode 100644 test/lsan/TestCases/fork.cc delete mode 100644 test/lsan/TestCases/fork_threaded.cc delete mode 100644 test/lsan/TestCases/guard-page.c delete mode 100644 test/lsan/TestCases/use_tls_dynamic.cc delete mode 100644 test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc delete mode 100644 test/lsan/TestCases/use_tls_pthread_specific_static.cc delete mode 100644 test/lsan/TestCases/use_tls_static.cc diff --git a/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c b/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c new file mode 100644 index 000000000..6da759563 --- /dev/null +++ b/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c @@ -0,0 +1,46 @@ +// Regression test for thread lifetime tracking. Thread data should be +// considered live during the thread's termination, at least until the +// user-installed TSD destructors have finished running (since they may contain +// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it +// makes its best effort. +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0" +// RUN: %clang_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %run %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include + +#include "sanitizer/lsan_interface.h" +#include "sanitizer_common/print_address.h" + +pthread_key_t key; +__thread void *p; + +void key_destructor(void *arg) { + // Generally this may happen on a different thread. + __lsan_do_leak_check(); +} + +void *thread_func(void *arg) { + p = malloc(1337); + print_address("Test alloc: ", 1, p); + int res = pthread_setspecific(key, (void*)1); + assert(res == 0); + return 0; +} + +int main() { + int res = pthread_key_create(&key, &key_destructor); + assert(res == 0); + pthread_t thread_id; + res = pthread_create(&thread_id, 0, thread_func, 0); + assert(res == 0); + res = pthread_join(thread_id, 0); + assert(res == 0); + return 0; +} +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK: [[ADDR]] (1337 bytes) diff --git a/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c b/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c new file mode 100644 index 000000000..4a3a7ac14 --- /dev/null +++ b/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c @@ -0,0 +1,39 @@ +// Regression test. Disabler should not depend on TSD validity. +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1:use_ld_allocations=0" +// RUN: %clang_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t + +#include +#include +#include +#include + +#include "sanitizer/lsan_interface.h" + +pthread_key_t key; + +void key_destructor(void *arg) { + __lsan_disable(); + void *p = malloc(1337); + // Break optimization. + fprintf(stderr, "Test alloc: %p.\n", p); + pthread_setspecific(key, 0); + __lsan_enable(); +} + +void *thread_func(void *arg) { + int res = pthread_setspecific(key, (void*)1); + assert(res == 0); + return 0; +} + +int main() { + int res = pthread_key_create(&key, &key_destructor); + assert(res == 0); + pthread_t thread_id; + res = pthread_create(&thread_id, 0, thread_func, 0); + assert(res == 0); + res = pthread_join(thread_id, 0); + assert(res == 0); + return 0; +} diff --git a/test/lsan/TestCases/Linux/fork.cc b/test/lsan/TestCases/Linux/fork.cc new file mode 100644 index 000000000..9e72fe871 --- /dev/null +++ b/test/lsan/TestCases/Linux/fork.cc @@ -0,0 +1,24 @@ +// Test that thread local data is handled correctly after forking without exec(). +// RUN: %clangxx_lsan %s -o %t +// RUN: %run %t 2>&1 + +#include +#include +#include +#include +#include + +__thread void *thread_local_var; + +int main() { + int status = 0; + thread_local_var = malloc(1337); + pid_t pid = fork(); + assert(pid >= 0); + if (pid > 0) { + waitpid(pid, &status, 0); + assert(WIFEXITED(status)); + return WEXITSTATUS(status); + } + return 0; +} diff --git a/test/lsan/TestCases/Linux/fork_threaded.cc b/test/lsan/TestCases/Linux/fork_threaded.cc new file mode 100644 index 000000000..62702b4df --- /dev/null +++ b/test/lsan/TestCases/Linux/fork_threaded.cc @@ -0,0 +1,43 @@ +// Test that thread local data is handled correctly after forking without +// exec(). In this test leak checking is initiated from a non-main thread. +// RUN: %clangxx_lsan %s -o %t +// RUN: %run %t 2>&1 + +#include +#include +#include +#include +#include +#include + +__thread void *thread_local_var; + +void *exit_thread_func(void *arg) { + exit(0); +} + +void ExitFromThread() { + pthread_t tid; + int res; + res = pthread_create(&tid, 0, exit_thread_func, 0); + assert(res == 0); + pthread_join(tid, 0); +} + +int main() { + int status = 0; + thread_local_var = malloc(1337); + pid_t pid = fork(); + assert(pid >= 0); + if (pid > 0) { + waitpid(pid, &status, 0); + assert(WIFEXITED(status)); + return WEXITSTATUS(status); + } else { + // Spawn a thread and call exit() from there, to check that we track main + // thread's pid correctly even if leak checking is initiated from another + // thread. + ExitFromThread(); + } + return 0; +} diff --git a/test/lsan/TestCases/Linux/guard-page.c b/test/lsan/TestCases/Linux/guard-page.c new file mode 100644 index 000000000..25d63e272 --- /dev/null +++ b/test/lsan/TestCases/Linux/guard-page.c @@ -0,0 +1,61 @@ +// Check that if LSan finds that SP doesn't point into thread stack (e.g. +// if swapcontext is used), LSan will not hit the guard page. +// RUN: %clang_lsan %s -o %t && %run %t +#include +#include +#include +#include +#include +#include + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +int ctxfunc_started = 0; + +static void die(const char* msg, int err) { + if (err == 0) + err = errno; + fprintf(stderr, "%s: %s\n", msg, strerror(err)); + exit(EXIT_FAILURE); +} + +static void ctxfunc() { + pthread_mutex_lock(&mutex); + ctxfunc_started = 1; + // printf("ctxfunc\n"); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + // Leave this context alive when the program exits. + for (;;); +} + +static void* thread(void* arg) { + (void)arg; + ucontext_t ctx; + void* stack; + + if (getcontext(&ctx) < 0) + die("getcontext", 0); + stack = malloc(1 << 11); + if (stack == NULL) + die("malloc", 0); + ctx.uc_stack.ss_sp = stack; + ctx.uc_stack.ss_size = 1 << 11; + makecontext(&ctx, ctxfunc, 0); + setcontext(&ctx); + die("setcontext", 0); + return NULL; +} + +int main() { + pthread_t tid; + int i; + + pthread_mutex_lock(&mutex); + i = pthread_create(&tid, NULL, thread, NULL); + if (i != 0) + die("pthread_create", i); + while (!ctxfunc_started) pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + return 0; +} diff --git a/test/lsan/TestCases/Linux/lit.local.cfg b/test/lsan/TestCases/Linux/lit.local.cfg new file mode 100644 index 000000000..57271b807 --- /dev/null +++ b/test/lsan/TestCases/Linux/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Linux']: + config.unsupported = True diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc new file mode 100644 index 000000000..6af82d59e --- /dev/null +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -0,0 +1,52 @@ +// Test that dynamically allocated TLS space is included in the root set. +// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0" +// RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// UNSUPPORTED: i386-linux,i686-linux,arm + +#ifndef BUILD_DSO +#include +#include +#include +#include +#include +#include "sanitizer_common/print_address.h" + +int main(int argc, char *argv[]) { + std::string path = std::string(argv[0]) + "-so.so"; + + void *handle = dlopen(path.c_str(), RTLD_LAZY); + assert(handle != 0); + typedef void **(* store_t)(void *p); + store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS"); + assert(dlerror() == 0); + + void *p = malloc(1337); + // If we don't know about dynamic TLS, we will return a false leak above. + void **p_in_tls = StoreToTLS(p); + assert(*p_in_tls == p); + print_address("Test alloc: ", 1, p); + return 0; +} +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: + +#else // BUILD_DSO +// A loadable module with a large thread local section, which would require +// allocation of a new TLS storage chunk when loaded with dlopen(). We use it +// to test the reachability of such chunks in LSan tests. + +// This must be large enough that it doesn't fit into preallocated static TLS +// space (see STATIC_TLS_SURPLUS in glibc). +__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT + +extern "C" void **StoreToTLS(void *p) { + huge_thread_local_array[0] = p; + return &huge_thread_local_array[0]; +} +#endif // BUILD_DSO diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc new file mode 100644 index 000000000..f075d035a --- /dev/null +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc @@ -0,0 +1,38 @@ +// Test that dynamically allocated thread-specific storage is included in the root set. +// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include +#include +#include +#include +#include "sanitizer_common/print_address.h" + +// From glibc: this many keys are stored in the thread descriptor directly. +const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; + +int main() { + static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE; + int res; + pthread_key_t dummy_keys[kDummyKeysCount]; + for (unsigned i = 0; i < kDummyKeysCount; i++) { + res = pthread_key_create(&dummy_keys[i], NULL); + assert(res == 0); + } + pthread_key_t key; + res = pthread_key_create(&key, NULL); + assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE); + assert(res == 0); + void *p = malloc(1337); + res = pthread_setspecific(key, p); + assert(res == 0); + print_address("Test alloc: ", 1, p); + return 0; +} +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc new file mode 100644 index 000000000..d97abab41 --- /dev/null +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc @@ -0,0 +1,32 @@ +// Test that statically allocated thread-specific storage is included in the root set. +// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include +#include +#include +#include +#include "sanitizer_common/print_address.h" + +// From glibc: this many keys are stored in the thread descriptor directly. +const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; + +int main() { + pthread_key_t key; + int res; + res = pthread_key_create(&key, NULL); + assert(res == 0); + assert(key < PTHREAD_KEY_2NDLEVEL_SIZE); + void *p = malloc(1337); + res = pthread_setspecific(key, p); + assert(res == 0); + print_address("Test alloc: ", 1, p); + return 0; +} +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Linux/use_tls_static.cc b/test/lsan/TestCases/Linux/use_tls_static.cc new file mode 100644 index 000000000..be34a3abf --- /dev/null +++ b/test/lsan/TestCases/Linux/use_tls_static.cc @@ -0,0 +1,22 @@ +// Test that statically allocated TLS space is included in the root set. +// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include +#include +#include "sanitizer_common/print_address.h" + +__thread void *tls_var; + +int main() { + tls_var = malloc(1337); + print_address("Test alloc: ", 1, tls_var); + return 0; +} +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/cleanup_in_tsd_destructor.c b/test/lsan/TestCases/cleanup_in_tsd_destructor.c deleted file mode 100644 index 6da759563..000000000 --- a/test/lsan/TestCases/cleanup_in_tsd_destructor.c +++ /dev/null @@ -1,46 +0,0 @@ -// Regression test for thread lifetime tracking. Thread data should be -// considered live during the thread's termination, at least until the -// user-installed TSD destructors have finished running (since they may contain -// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it -// makes its best effort. -// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0" -// RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %run %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s - -#include -#include -#include -#include - -#include "sanitizer/lsan_interface.h" -#include "sanitizer_common/print_address.h" - -pthread_key_t key; -__thread void *p; - -void key_destructor(void *arg) { - // Generally this may happen on a different thread. - __lsan_do_leak_check(); -} - -void *thread_func(void *arg) { - p = malloc(1337); - print_address("Test alloc: ", 1, p); - int res = pthread_setspecific(key, (void*)1); - assert(res == 0); - return 0; -} - -int main() { - int res = pthread_key_create(&key, &key_destructor); - assert(res == 0); - pthread_t thread_id; - res = pthread_create(&thread_id, 0, thread_func, 0); - assert(res == 0); - res = pthread_join(thread_id, 0); - assert(res == 0); - return 0; -} -// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] -// CHECK: [[ADDR]] (1337 bytes) diff --git a/test/lsan/TestCases/disabler_in_tsd_destructor.c b/test/lsan/TestCases/disabler_in_tsd_destructor.c deleted file mode 100644 index 4a3a7ac14..000000000 --- a/test/lsan/TestCases/disabler_in_tsd_destructor.c +++ /dev/null @@ -1,39 +0,0 @@ -// Regression test. Disabler should not depend on TSD validity. -// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1:use_ld_allocations=0" -// RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t - -#include -#include -#include -#include - -#include "sanitizer/lsan_interface.h" - -pthread_key_t key; - -void key_destructor(void *arg) { - __lsan_disable(); - void *p = malloc(1337); - // Break optimization. - fprintf(stderr, "Test alloc: %p.\n", p); - pthread_setspecific(key, 0); - __lsan_enable(); -} - -void *thread_func(void *arg) { - int res = pthread_setspecific(key, (void*)1); - assert(res == 0); - return 0; -} - -int main() { - int res = pthread_key_create(&key, &key_destructor); - assert(res == 0); - pthread_t thread_id; - res = pthread_create(&thread_id, 0, thread_func, 0); - assert(res == 0); - res = pthread_join(thread_id, 0); - assert(res == 0); - return 0; -} diff --git a/test/lsan/TestCases/fork.cc b/test/lsan/TestCases/fork.cc deleted file mode 100644 index 9e72fe871..000000000 --- a/test/lsan/TestCases/fork.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Test that thread local data is handled correctly after forking without exec(). -// RUN: %clangxx_lsan %s -o %t -// RUN: %run %t 2>&1 - -#include -#include -#include -#include -#include - -__thread void *thread_local_var; - -int main() { - int status = 0; - thread_local_var = malloc(1337); - pid_t pid = fork(); - assert(pid >= 0); - if (pid > 0) { - waitpid(pid, &status, 0); - assert(WIFEXITED(status)); - return WEXITSTATUS(status); - } - return 0; -} diff --git a/test/lsan/TestCases/fork_threaded.cc b/test/lsan/TestCases/fork_threaded.cc deleted file mode 100644 index 62702b4df..000000000 --- a/test/lsan/TestCases/fork_threaded.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Test that thread local data is handled correctly after forking without -// exec(). In this test leak checking is initiated from a non-main thread. -// RUN: %clangxx_lsan %s -o %t -// RUN: %run %t 2>&1 - -#include -#include -#include -#include -#include -#include - -__thread void *thread_local_var; - -void *exit_thread_func(void *arg) { - exit(0); -} - -void ExitFromThread() { - pthread_t tid; - int res; - res = pthread_create(&tid, 0, exit_thread_func, 0); - assert(res == 0); - pthread_join(tid, 0); -} - -int main() { - int status = 0; - thread_local_var = malloc(1337); - pid_t pid = fork(); - assert(pid >= 0); - if (pid > 0) { - waitpid(pid, &status, 0); - assert(WIFEXITED(status)); - return WEXITSTATUS(status); - } else { - // Spawn a thread and call exit() from there, to check that we track main - // thread's pid correctly even if leak checking is initiated from another - // thread. - ExitFromThread(); - } - return 0; -} diff --git a/test/lsan/TestCases/guard-page.c b/test/lsan/TestCases/guard-page.c deleted file mode 100644 index 25d63e272..000000000 --- a/test/lsan/TestCases/guard-page.c +++ /dev/null @@ -1,61 +0,0 @@ -// Check that if LSan finds that SP doesn't point into thread stack (e.g. -// if swapcontext is used), LSan will not hit the guard page. -// RUN: %clang_lsan %s -o %t && %run %t -#include -#include -#include -#include -#include -#include - -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -int ctxfunc_started = 0; - -static void die(const char* msg, int err) { - if (err == 0) - err = errno; - fprintf(stderr, "%s: %s\n", msg, strerror(err)); - exit(EXIT_FAILURE); -} - -static void ctxfunc() { - pthread_mutex_lock(&mutex); - ctxfunc_started = 1; - // printf("ctxfunc\n"); - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); - // Leave this context alive when the program exits. - for (;;); -} - -static void* thread(void* arg) { - (void)arg; - ucontext_t ctx; - void* stack; - - if (getcontext(&ctx) < 0) - die("getcontext", 0); - stack = malloc(1 << 11); - if (stack == NULL) - die("malloc", 0); - ctx.uc_stack.ss_sp = stack; - ctx.uc_stack.ss_size = 1 << 11; - makecontext(&ctx, ctxfunc, 0); - setcontext(&ctx); - die("setcontext", 0); - return NULL; -} - -int main() { - pthread_t tid; - int i; - - pthread_mutex_lock(&mutex); - i = pthread_create(&tid, NULL, thread, NULL); - if (i != 0) - die("pthread_create", i); - while (!ctxfunc_started) pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - return 0; -} diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc deleted file mode 100644 index 6af82d59e..000000000 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Test that dynamically allocated TLS space is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0" -// RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so -// RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux,arm - -#ifndef BUILD_DSO -#include -#include -#include -#include -#include -#include "sanitizer_common/print_address.h" - -int main(int argc, char *argv[]) { - std::string path = std::string(argv[0]) + "-so.so"; - - void *handle = dlopen(path.c_str(), RTLD_LAZY); - assert(handle != 0); - typedef void **(* store_t)(void *p); - store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS"); - assert(dlerror() == 0); - - void *p = malloc(1337); - // If we don't know about dynamic TLS, we will return a false leak above. - void **p_in_tls = StoreToTLS(p); - assert(*p_in_tls == p); - print_address("Test alloc: ", 1, p); - return 0; -} -// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: [[ADDR]] (1337 bytes) -// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: - -#else // BUILD_DSO -// A loadable module with a large thread local section, which would require -// allocation of a new TLS storage chunk when loaded with dlopen(). We use it -// to test the reachability of such chunks in LSan tests. - -// This must be large enough that it doesn't fit into preallocated static TLS -// space (see STATIC_TLS_SURPLUS in glibc). -__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT - -extern "C" void **StoreToTLS(void *p) { - huge_thread_local_array[0] = p; - return &huge_thread_local_array[0]; -} -#endif // BUILD_DSO diff --git a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc deleted file mode 100644 index f075d035a..000000000 --- a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Test that dynamically allocated thread-specific storage is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" -// RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 - -#include -#include -#include -#include -#include "sanitizer_common/print_address.h" - -// From glibc: this many keys are stored in the thread descriptor directly. -const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; - -int main() { - static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE; - int res; - pthread_key_t dummy_keys[kDummyKeysCount]; - for (unsigned i = 0; i < kDummyKeysCount; i++) { - res = pthread_key_create(&dummy_keys[i], NULL); - assert(res == 0); - } - pthread_key_t key; - res = pthread_key_create(&key, NULL); - assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE); - assert(res == 0); - void *p = malloc(1337); - res = pthread_setspecific(key, p); - assert(res == 0); - print_address("Test alloc: ", 1, p); - return 0; -} -// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: [[ADDR]] (1337 bytes) -// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/use_tls_pthread_specific_static.cc deleted file mode 100644 index d97abab41..000000000 --- a/test/lsan/TestCases/use_tls_pthread_specific_static.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Test that statically allocated thread-specific storage is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" -// RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 - -#include -#include -#include -#include -#include "sanitizer_common/print_address.h" - -// From glibc: this many keys are stored in the thread descriptor directly. -const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; - -int main() { - pthread_key_t key; - int res; - res = pthread_key_create(&key, NULL); - assert(res == 0); - assert(key < PTHREAD_KEY_2NDLEVEL_SIZE); - void *p = malloc(1337); - res = pthread_setspecific(key, p); - assert(res == 0); - print_address("Test alloc: ", 1, p); - return 0; -} -// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: [[ADDR]] (1337 bytes) -// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_static.cc b/test/lsan/TestCases/use_tls_static.cc deleted file mode 100644 index be34a3abf..000000000 --- a/test/lsan/TestCases/use_tls_static.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Test that statically allocated TLS space is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" -// RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 - -#include -#include -#include "sanitizer_common/print_address.h" - -__thread void *tls_var; - -int main() { - tls_var = malloc(1337); - print_address("Test alloc: ", 1, tls_var); - return 0; -} -// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: [[ADDR]] (1337 bytes) -// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: -- cgit v1.2.1 From 2d4035c4d492b18a4c7512bc2fea8d904628ec98 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 13 Apr 2017 20:14:15 +0000 Subject: Disable use of tls scanning on darwin leak sanitizer Summary: These checks appear linux-specific, disable them on darwin, at least for now. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32013 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300248 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 7 ++++++- lib/lsan/lsan_flags.inc | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index d15551072..022e73937 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -87,7 +87,12 @@ AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; } // Required on Linux for initialization of TLS behavior, but should not be // required on Darwin. -void InitializePlatformSpecificModules() {} +void InitializePlatformSpecificModules() { + if (flags()->use_tls) { + Report("use_tls=1 is not supported on Darwin.\n"); + Die(); + } +} // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { diff --git a/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc index e390e2ae5..8135bdcff 100644 --- a/lib/lsan/lsan_flags.inc +++ b/lib/lsan/lsan_flags.inc @@ -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, true, +LSAN_FLAG(bool, use_tls, !SANITIZER_MAC, "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().") -- cgit v1.2.1 From 0d5f39faf4caf6a65ba939bfe4d0a4755ff6670b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 13 Apr 2017 20:25:20 +0000 Subject: Revert "[msan] Fix msan_test broken after r299884." This does not fix the test, it still fails to bind. This reverts commit r300150. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300249 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 4e962e108..eebce5ee2 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -899,7 +899,7 @@ class SocketAddr4 : public SocketAddr { memset(&sai_, 0, sizeof(sai_)); sai_.sin_family = AF_INET; sai_.sin_port = port; - sai_.sin_addr.s_addr = htonl(INADDR_ANY); + sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } sockaddr *ptr() override { return reinterpret_cast(&sai_); } @@ -917,7 +917,7 @@ class SocketAddr6 : public SocketAddr { memset(&sai_, 0, sizeof(sai_)); sai_.sin6_family = AF_INET6; sai_.sin6_port = port; - sai_.sin6_addr = in6addr_any; + sai_.sin6_addr = in6addr_loopback; } sockaddr *ptr() override { return reinterpret_cast(&sai_); } -- cgit v1.2.1 From 3767ff9d5c16e25294c837e6e50dcf909d8e38b1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 13 Apr 2017 20:25:24 +0000 Subject: [msan] Fix msan_test.cc by checking bind results before assuming IPv6 supported. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300250 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index eebce5ee2..dd81c4d79 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -890,6 +890,9 @@ class SocketAddr { virtual ~SocketAddr() = default; virtual struct sockaddr *ptr() = 0; virtual size_t size() const = 0; + + template + static std::unique_ptr Create(int family, Args... args); }; class SocketAddr4 : public SocketAddr { @@ -928,6 +931,13 @@ class SocketAddr6 : public SocketAddr { sockaddr_in6 sai_; }; +template +std::unique_ptr SocketAddr::Create(int family, Args... args) { + if (family == AF_INET) + return std::unique_ptr(new SocketAddr4(args...)); + return std::unique_ptr(new SocketAddr6(args...)); +} + class MemorySanitizerIpTest : public ::testing::TestWithParam { public: void SetUp() override { @@ -936,9 +946,7 @@ class MemorySanitizerIpTest : public ::testing::TestWithParam { template std::unique_ptr CreateSockAddr(Args... args) const { - if (GetParam() == AF_INET) - return std::unique_ptr(new SocketAddr4(args...)); - return std::unique_ptr(new SocketAddr6(args...)); + return SocketAddr::Create(GetParam(), args...); } int CreateSocket(int socket_type) const { @@ -952,7 +960,8 @@ std::vector GetAvailableIpSocketFamilies() { for (int i : {AF_INET, AF_INET6}) { int s = socket(i, SOCK_STREAM, 0); if (s > 0) { - result.push_back(i); + auto sai = SocketAddr::Create(i, 0); + if (bind(s, sai->ptr(), sai->size()) == 0) result.push_back(i); close(s); } } -- cgit v1.2.1 From b97fb2e6b1a462c96974850432c4d6be01fa0285 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Thu, 13 Apr 2017 23:37:15 +0000 Subject: [Profile] PE binary coverage bug fix PR/32584 Differential Revision: https://reviews.llvm.org/D32023 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300278 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 67 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index 6ef1625d8..949a50c0b 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -246,6 +246,31 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \ /* COVMAP_HEADER end. */ +#ifdef INSTR_PROF_SECT_ENTRY +#define INSTR_PROF_DATA_DEFINED +INSTR_PROF_SECT_ENTRY(IPSK_data, INSTR_PROF_DATA_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_cnts, INSTR_PROF_CNTS_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_name, INSTR_PROF_NAME_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_vals, INSTR_PROF_VALS_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_vnodes, INSTR_PROF_VNODES_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,") +INSTR_PROF_SECT_ENTRY(IPSK_covmap, INSTR_PROF_COVMAP_SECT_NAME_STR, \ + INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \ + INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,") + +#undef INSTR_PROF_SECT_ENTRY +#endif + + #ifdef INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_DATA_DEFINED @@ -622,17 +647,47 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, * specified via command line. */ #define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename +/* section name strings common to all targets other + than WIN32 */ +#define INSTR_PROF_DATA_COMMON __llvm_prf_data +#define INSTR_PROF_NAME_COMMON __llvm_prf_names +#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts +#define INSTR_PROF_VALS_COMMON __llvm_prf_vals +#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds +#define INSTR_PROF_COVMAP_COMMON __llvm_covmap +/* Win32 */ +#define INSTR_PROF_DATA_COFF .lprfd +#define INSTR_PROF_NAME_COFF .lprfn +#define INSTR_PROF_CNTS_COFF .lprfc +#define INSTR_PROF_VALS_COFF .lprfv +#define INSTR_PROF_VNODES_COFF .lprfnd +#define INSTR_PROF_COVMAP_COFF .lcovmap + +#ifdef _WIN32 /* Runtime section names and name strings. */ -#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data -#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names -#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF /* Array of pointers. Each pointer points to a list * of value nodes associated with one value site. */ -#define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COFF /* Value profile nodes section. */ -#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds -#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF +#else +/* Runtime section names and name strings. */ +#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COMMON +#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COMMON +#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COMMON +/* Array of pointers. Each pointer points to a list + * of value nodes associated with one value site. + */ +#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COMMON +/* Value profile nodes section. */ +#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COMMON +#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COMMON +#endif #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) -- cgit v1.2.1 From 6d4c217ce48343d72a68f328f792d5bab487f192 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 14 Apr 2017 18:24:35 +0000 Subject: [ubsan] Use the correct tool name in diagnostics When using ASan and UBSan together, the common sanitizer tool name is set to "AddressSanitizer". That means that when a UBSan diagnostic is printed out, it looks like this: SUMMARY: AddressSanitizer: ... This can confuse users. Fix it so that we always use the correct tool name when printing out UBSan diagnostics. Differential Revision: https://reviews.llvm.org/D32066 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300358 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.cc | 13 +++++++------ lib/sanitizer_common/sanitizer_common.h | 10 +++++++--- lib/sanitizer_common/sanitizer_common_libcdep.cc | 5 +++-- lib/ubsan/ubsan_diag.cc | 6 +++--- lib/ubsan/ubsan_init.cc | 6 +++++- lib/ubsan/ubsan_init.h | 3 +++ test/ubsan/TestCases/Integer/summary.cpp | 4 ++-- 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 36f391118..3ef366f4f 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -199,23 +199,24 @@ const char *StripModuleName(const char *module) { return module; } -void ReportErrorSummary(const char *error_message) { +void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); - buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message); + buff.append("SUMMARY: %s: %s", + alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); __sanitizer_report_error_summary(buff.data()); } #if !SANITIZER_GO -void ReportErrorSummary(const char *error_type, const AddressInfo &info) { - if (!common_flags()->print_summary) - return; +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name) { + if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); buff.append("%s ", error_type); RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); - ReportErrorSummary(buff.data()); + ReportErrorSummary(buff.data(), alt_tool_name); } #endif diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index aa4d9e5ce..9d367ca80 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -392,12 +392,16 @@ const int kMaxSummaryLength = 1024; // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message // and pass it to __sanitizer_report_error_summary. -void ReportErrorSummary(const char *error_message); +// If alt_tool_name is provided, it's used in place of SanitizerToolName. +void ReportErrorSummary(const char *error_message, + const char *alt_tool_name = nullptr); // Same as above, but construct error_message as: // error_type file:line[:column][ function] -void ReportErrorSummary(const char *error_type, const AddressInfo &info); +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name = nullptr); // Same as above, but obtains AddressInfo by symbolizing top stack trace frame. -void ReportErrorSummary(const char *error_type, const StackTrace *trace); +void ReportErrorSummary(const char *error_type, const StackTrace *trace, + const char *alt_tool_name = nullptr); // Math #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 430318863..cf200512d 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -47,7 +47,8 @@ void SetSandboxingCallback(void (*f)()) { sandboxing_callback = f; } -void ReportErrorSummary(const char *error_type, const StackTrace *stack) { +void ReportErrorSummary(const char *error_type, const StackTrace *stack, + const char *alt_tool_name) { #if !SANITIZER_GO if (!common_flags()->print_summary) return; @@ -59,7 +60,7 @@ void ReportErrorSummary(const char *error_type, const StackTrace *stack) { // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); - ReportErrorSummary(error_type, frame->info); + ReportErrorSummary(error_type, frame->info, alt_tool_name); frame->ClearAll(); #endif } diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index c531c5f77..bbe1e0739 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -79,16 +79,16 @@ static void MaybeReportErrorSummary(Location Loc, ErrorType Type) { AI.line = SLoc.getLine(); AI.column = SLoc.getColumn(); AI.function = internal_strdup(""); // Avoid printing ?? as function name. - ReportErrorSummary(ErrorKind, AI); + ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); AI.Clear(); return; } } else if (Loc.isSymbolizedStack()) { const AddressInfo &AI = Loc.getSymbolizedStack()->info; - ReportErrorSummary(ErrorKind, AI); + ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); return; } - ReportErrorSummary(ErrorKind); + ReportErrorSummary(ErrorKind, GetSanititizerToolName()); } namespace { diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index b4f42c4b8..307bca376 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -23,6 +23,10 @@ using namespace __ubsan; +const char *__ubsan::GetSanititizerToolName() { + return "UndefinedBehaviorSanitizer"; +} + static enum { UBSAN_MODE_UNKNOWN = 0, UBSAN_MODE_STANDALONE, @@ -35,7 +39,7 @@ static void CommonInit() { } static void CommonStandaloneInit() { - SanitizerToolName = "UndefinedBehaviorSanitizer"; + SanitizerToolName = GetSanititizerToolName(); InitializeFlags(); CacheBinaryName(); __sanitizer_set_report_path(common_flags()->log_path); diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h index 103ae24d1..f12fc2ced 100644 --- a/lib/ubsan/ubsan_init.h +++ b/lib/ubsan/ubsan_init.h @@ -15,6 +15,9 @@ namespace __ubsan { +// Get the full tool name for UBSan. +const char *GetSanititizerToolName(); + // Initialize UBSan as a standalone tool. Typically should be called early // during initialization. void InitAsStandalone(); diff --git a/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp index e687afab4..8726c14c3 100644 --- a/test/ubsan/TestCases/Integer/summary.cpp +++ b/test/ubsan/TestCases/Integer/summary.cpp @@ -7,7 +7,7 @@ int main() { (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull)); - // CHECK-NOTYPE: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44 - // CHECK-TYPE: SUMMARY: AddressSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44 + // CHECK-NOTYPE: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44 + // CHECK-TYPE: SUMMARY: UndefinedBehaviorSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44 return 0; } -- cgit v1.2.1 From 55d98a136bfa537ea46891d0a7934ade91b91aac Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 15 Apr 2017 00:10:33 +0000 Subject: [profile] Sync up InstrProfData.inc (NFC) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300383 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index 949a50c0b..be0dd4ad0 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -248,22 +248,22 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \ #ifdef INSTR_PROF_SECT_ENTRY #define INSTR_PROF_DATA_DEFINED -INSTR_PROF_SECT_ENTRY(IPSK_data, INSTR_PROF_DATA_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_data, \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,") -INSTR_PROF_SECT_ENTRY(IPSK_cnts, INSTR_PROF_CNTS_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_cnts, \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,") -INSTR_PROF_SECT_ENTRY(IPSK_name, INSTR_PROF_NAME_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_name, \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,") -INSTR_PROF_SECT_ENTRY(IPSK_vals, INSTR_PROF_VALS_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_vals, \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,") -INSTR_PROF_SECT_ENTRY(IPSK_vnodes, INSTR_PROF_VNODES_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,") -INSTR_PROF_SECT_ENTRY(IPSK_covmap, INSTR_PROF_COVMAP_SECT_NAME_STR, \ +INSTR_PROF_SECT_ENTRY(IPSK_covmap, \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,") -- cgit v1.2.1 From 1bc70377e9230a971ce88ee7270a705ce306d103 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 17 Apr 2017 14:07:06 +0000 Subject: Scan Kernel Alloc Once page for global pointers Summary: libxpc stashes some pointers here. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32045 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300450 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 022e73937..d0ee181d0 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -22,6 +22,8 @@ #include +#include + namespace __lsan { typedef struct { @@ -113,8 +115,32 @@ void ProcessGlobalRegions(Frontier *frontier) { } } +// libxpc stashes some pointers in the Kernel Alloc Once page, +// make sure not to report those as leaks. void ProcessPlatformSpecificAllocations(Frontier *frontier) { - CHECK(0 && "unimplemented"); + mach_port_name_t port; + if (task_for_pid(mach_task_self(), internal_getpid(), &port) + != KERN_SUCCESS) { + return; + } + + unsigned depth = 1; + vm_size_t size = 0; + vm_address_t address = 0; + kern_return_t err = KERN_SUCCESS; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + while (err == KERN_SUCCESS) { + struct vm_region_submap_info_64 info; + err = vm_region_recurse_64(port, &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { + ScanRangeForPointers(address, address + size, frontier, + "GLOBAL", kReachable); + return; + } + address += size; + } } void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { -- cgit v1.2.1 From 9e60082e3f68e8619ffc917bbdaaf0636c3fcaa3 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 17 Apr 2017 16:34:38 +0000 Subject: Don't read non-readable address ranges during lsan pointer scanning Summary: This specifically addresses the Mach-O zero page, which we cannot read from. Reviewers: kubamracek, samsonov, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32044 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300456 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 2 +- lib/sanitizer_common/sanitizer_common.cc | 5 +++-- lib/sanitizer_common/sanitizer_common.h | 13 +++++++++---- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 4 +++- lib/sanitizer_common/sanitizer_procmaps_common.cc | 3 ++- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 3 ++- lib/sanitizer_common/sanitizer_win.cc | 3 ++- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index d0ee181d0..dfb5ab4cc 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -108,7 +108,7 @@ void ProcessGlobalRegions(Frontier *frontier) { for (const __sanitizer::LoadedModule::AddressRange &range : modules[i].ranges()) { - if (range.executable) continue; + if (range.executable || !range.readable) continue; ScanGlobalRange(range.beg, range.end, frontier); } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 3ef366f4f..471c3ded2 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -284,9 +284,10 @@ void LoadedModule::clear() { } } -void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { +void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, + bool readable) { void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = new(mem) AddressRange(beg, end, executable); + AddressRange *r = new(mem) AddressRange(beg, end, executable, readable); ranges_.push_back(r); if (executable && end > max_executable_address_) max_executable_address_ = end; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9d367ca80..313f0cfda 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -717,7 +717,7 @@ class LoadedModule { void set(const char *module_name, uptr base_address, ModuleArch arch, u8 uuid[kModuleUUIDSize], bool instrumented); void clear(); - void addAddressRange(uptr beg, uptr end, bool executable); + void addAddressRange(uptr beg, uptr end, bool executable, bool readable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } @@ -732,9 +732,14 @@ class LoadedModule { uptr beg; uptr end; bool executable; - - AddressRange(uptr beg, uptr end, bool executable) - : next(nullptr), beg(beg), end(end), executable(executable) {} + bool readable; + + AddressRange(uptr beg, uptr end, bool executable, bool readable) + : next(nullptr), + beg(beg), + end(end), + executable(executable), + readable(readable) {} }; const IntrusiveList &ranges() const { return ranges_; } diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 6fde671f8..25f1e12c0 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -447,7 +447,9 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; bool executable = phdr->p_flags & PF_X; - cur_module.addAddressRange(cur_beg, cur_end, executable); + bool readable = phdr->p_flags & PF_R; + cur_module.addAddressRange(cur_beg, cur_end, executable, + readable); } } data->modules->push_back(cur_module); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index fac3fbdad..67a659010 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -141,7 +141,8 @@ void MemoryMappingLayout::DumpListOfModules( uptr base_address = (i ? cur_beg : 0) - cur_offset; LoadedModule cur_module; cur_module.set(cur_name, base_address); - cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); + cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, + prot & kProtectionRead); modules->push_back(cur_module); } } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 2831f2869..be59b481f 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -262,7 +262,8 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(cur_name, cur_beg, cur_arch, cur_uuid, current_instrumented_); } - cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); + cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, + prot & kProtectionRead); } } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index b1a2a53a3..a8a8cd767 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -553,7 +553,8 @@ void ListOfModules::init() { LoadedModule cur_module; cur_module.set(module_name, adjusted_base); // We add the whole module as one single address range. - cur_module.addAddressRange(base_address, end_address, /*executable*/ true); + cur_module.addAddressRange(base_address, end_address, /*executable*/ true, + /*readable*/ true); modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -- cgit v1.2.1 From 0f9f15db742f9abe6141df0819cd0fd577c06a3d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 17 Apr 2017 18:17:38 +0000 Subject: [sanitizer] Introduce tid_t as a typedef for OS-provided thread IDs We seem to assume that OS-provided thread IDs are either uptr or int, neither of which is true on Darwin. This introduces a tid_t type, which holds a OS-provided thread ID (gettid on Linux, pthread_threadid_np on Darwin, pthread_self on FreeBSD). Differential Revision: https://reviews.llvm.org/D31774 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300473 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_thread.cc | 8 ++++---- lib/asan/asan_thread.h | 2 +- lib/lsan/lsan_common.cc | 2 +- lib/lsan/lsan_common.h | 4 ++-- lib/lsan/lsan_thread.cc | 6 +++--- lib/lsan/lsan_thread.h | 2 +- lib/sanitizer_common/sanitizer_common.h | 2 +- lib/sanitizer_common/sanitizer_internal_defs.h | 6 ++++++ lib/sanitizer_common/sanitizer_linux.cc | 2 +- lib/sanitizer_common/sanitizer_mac.cc | 5 ++--- lib/sanitizer_common/sanitizer_stoptheworld.h | 9 ++++----- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc | 6 ++---- lib/sanitizer_common/sanitizer_thread_registry.cc | 7 ++++--- lib/sanitizer_common/sanitizer_thread_registry.h | 8 ++++---- lib/sanitizer_common/sanitizer_win.cc | 2 +- lib/tsan/rtl/tsan_debugging.cc | 4 ++-- lib/tsan/rtl/tsan_interface.h | 5 +++-- lib/tsan/rtl/tsan_report.h | 2 +- lib/tsan/rtl/tsan_rtl.h | 2 +- lib/tsan/rtl/tsan_rtl_thread.cc | 2 +- test/tsan/Darwin/main_tid.mm | 4 ++-- test/tsan/debug_alloc_stack.cc | 6 +++--- test/tsan/debugging.cc | 4 ++-- 23 files changed, 52 insertions(+), 48 deletions(-) diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index aaa32d6ea..f41ee2df2 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -237,7 +237,7 @@ void AsanThread::Init() { } thread_return_t AsanThread::ThreadStart( - uptr os_id, atomic_uintptr_t *signal_thread_is_registered) { + tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { Init(); asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false, nullptr); @@ -395,7 +395,7 @@ void EnsureMainThreadIDIsCorrect() { context->os_id = GetTid(); } -__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { +__asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); if (!context) return nullptr; @@ -405,7 +405,7 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { -bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); @@ -421,7 +421,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, return true; } -void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, +void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (t && t->has_fake_stack()) diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index f53dfb712..424f9e68d 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -63,7 +63,7 @@ class AsanThread { void Destroy(); void Init(); // Should be called from the thread itself. - thread_return_t ThreadStart(uptr os_id, + thread_return_t ThreadStart(tid_t os_id, atomic_uintptr_t *signal_thread_is_registered); uptr stack_top(); diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 6cc737498..8ca0905d6 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -204,7 +204,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, uptr registers_begin = reinterpret_cast(registers.data()); uptr registers_end = registers_begin + registers.size(); for (uptr i = 0; i < suspended_threads.thread_count(); i++) { - uptr os_id = static_cast(suspended_threads.GetThreadID(i)); + tid_t os_id = static_cast(suspended_threads.GetThreadID(i)); LOG_THREADS("Processing thread %d.\n", os_id); uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; DTLS *dtls; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 919be0ec2..0bb575b29 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -193,10 +193,10 @@ bool WordIsPoisoned(uptr addr); // Wrappers for ThreadRegistry access. void LockThreadRegistry(); void UnlockThreadRegistry(); -bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls); -void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, +void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); // If called from the main thread, updates the main thread's TID in the thread // registry. We need this to handle processes that fork() without a subsequent diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index 09eeb9c24..0ea7a6e97 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { /* arg */ nullptr); } -void ThreadStart(u32 tid, uptr os_id) { +void ThreadStart(u32 tid, tid_t os_id) { OnStartedArgs args; uptr stack_size = 0; uptr tls_size = 0; @@ -127,7 +127,7 @@ void EnsureMainThreadIDIsCorrect() { ///// Interface to the common LSan module. ///// -bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { ThreadContext *context = static_cast( @@ -143,7 +143,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, return true; } -void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, +void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg) { } diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h index 10b7b5796..73e080e26 100644 --- a/lib/lsan/lsan_thread.h +++ b/lib/lsan/lsan_thread.h @@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase { void InitializeThreadRegistry(); -void ThreadStart(u32 tid, uptr os_id); +void ThreadStart(u32 tid, tid_t os_id); void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 313f0cfda..bbe7aebf3 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -72,7 +72,7 @@ INLINE uptr GetPageSizeCached() { uptr GetMmapGranularity(); uptr GetMaxVirtualAddress(); // Threads -uptr GetTid(); +tid_t GetTid(); uptr GetThreadSelf(); void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom); diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index ea5022e31..f35b095ee 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -152,6 +152,12 @@ typedef u32 operator_new_size_type; # endif #endif +#if SANITIZER_MAC +// On Darwin, thread IDs are 64-bit even on 32-bit systems. +typedef u64 tid_t; +#else +typedef uptr tid_t; +#endif // ----------- ATTENTION ------------- // This header should NOT include any other headers to avoid portability issues. diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 0b5473d95..fce78fe59 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -384,7 +384,7 @@ bool FileExists(const char *filename) { return S_ISREG(st.st_mode); } -uptr GetTid() { +tid_t GetTid() { #if SANITIZER_FREEBSD return (uptr)pthread_self(); #else diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 34af4e918..2f990b805 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -252,9 +252,8 @@ bool FileExists(const char *filename) { return S_ISREG(st.st_mode); } -uptr GetTid() { - // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes. - uint64_t tid; +tid_t GetTid() { + tid_t tid; pthread_threadid_np(nullptr, &tid); return tid; } diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h index 41752d8f6..f7ee018b6 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -18,7 +18,6 @@ #include "sanitizer_common.h" namespace __sanitizer { -typedef int SuspendedThreadID; enum PtraceRegistersStatus { REGISTERS_UNAVAILABLE_FATAL = -1, @@ -32,7 +31,7 @@ class SuspendedThreadsList { public: SuspendedThreadsList() : thread_ids_(1024) {} - SuspendedThreadID GetThreadID(uptr index) const { + tid_t GetThreadID(uptr index) const { CHECK_LT(index, thread_ids_.size()); return thread_ids_[index]; } @@ -41,19 +40,19 @@ class SuspendedThreadsList { // The buffer in GetRegistersAndSP should be at least this big. static uptr RegisterCount(); uptr thread_count() const { return thread_ids_.size(); } - bool Contains(SuspendedThreadID thread_id) const { + bool Contains(tid_t thread_id) const { for (uptr i = 0; i < thread_ids_.size(); i++) { if (thread_ids_[i] == thread_id) return true; } return false; } - void Append(SuspendedThreadID thread_id) { + void Append(tid_t thread_id) { thread_ids_.push_back(thread_id); } private: - InternalMmapVector thread_ids_; + InternalMmapVector thread_ids_; // Prohibit copy and assign. SuspendedThreadsList(const SuspendedThreadsList&); diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 6e4baeeca..91ce58c25 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -82,8 +82,6 @@ namespace __sanitizer { -COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t)); - // Structure for passing arguments into the tracer thread. struct TracerThreadArgument { StopTheWorldCallback callback; @@ -114,10 +112,10 @@ class ThreadSuspender { private: SuspendedThreadsList suspended_threads_list_; pid_t pid_; - bool SuspendThread(SuspendedThreadID thread_id); + bool SuspendThread(tid_t thread_id); }; -bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) { +bool ThreadSuspender::SuspendThread(tid_t tid) { // Are we already attached to this thread? // Currently this check takes linear time, however the number of threads is // usually small. diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc index c5b2e0946..439e33a08 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.cc +++ b/lib/sanitizer_common/sanitizer_thread_registry.cc @@ -59,7 +59,8 @@ void ThreadContextBase::SetFinished() { OnFinished(); } -void ThreadContextBase::SetStarted(uptr _os_id, bool _workerthread, void *arg) { +void ThreadContextBase::SetStarted(tid_t _os_id, bool _workerthread, + void *arg) { status = ThreadStatusRunning; os_id = _os_id; workerthread = _workerthread; @@ -193,7 +194,7 @@ static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, tctx->status != ThreadStatusDead); } -ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) { +ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { return FindThreadContextLocked(FindThreadContextByOsIdCallback, (void *)os_id); } @@ -267,7 +268,7 @@ void ThreadRegistry::FinishThread(u32 tid) { } } -void ThreadRegistry::StartThread(u32 tid, uptr os_id, bool workerthread, +void ThreadRegistry::StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg) { BlockingMutexLock l(&mtx_); running_threads_++; diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h index 17b1d5d90..9aae875c7 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/lib/sanitizer_common/sanitizer_thread_registry.h @@ -39,7 +39,7 @@ class ThreadContextBase { const u32 tid; // Thread ID. Main thread should have tid = 0. u64 unique_id; // Unique thread ID. u32 reuse_count; // Number of times this tid was reused. - uptr os_id; // PID (used for reporting). + tid_t os_id; // PID (used for reporting). uptr user_id; // Some opaque user thread id (e.g. pthread_t). char name[64]; // As annotated by user. @@ -55,7 +55,7 @@ class ThreadContextBase { void SetDead(); void SetJoined(void *arg); void SetFinished(); - void SetStarted(uptr _os_id, bool _workerthread, void *arg); + void SetStarted(tid_t _os_id, bool _workerthread, void *arg); void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, u32 _parent_tid, void *arg); void Reset(); @@ -109,14 +109,14 @@ class ThreadRegistry { // is found. ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, void *arg); - ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id); + ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); void SetThreadName(u32 tid, const char *name); void SetThreadNameByUserId(uptr user_id, const char *name); void DetachThread(u32 tid, void *arg); void JoinThread(u32 tid, void *arg); void FinishThread(u32 tid); - void StartThread(u32 tid, uptr os_id, bool workerthread, void *arg); + void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg); private: const ThreadContextFactory context_factory_; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a8a8cd767..1a454ba42 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -80,7 +80,7 @@ uptr internal_getpid() { // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. -uptr GetTid() { +tid_t GetTid() { return GetCurrentThreadId(); } diff --git a/lib/tsan/rtl/tsan_debugging.cc b/lib/tsan/rtl/tsan_debugging.cc index 06154bc13..a44b13632 100644 --- a/lib/tsan/rtl/tsan_debugging.cc +++ b/lib/tsan/rtl/tsan_debugging.cc @@ -151,7 +151,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, } SANITIZER_INTERFACE_ATTRIBUTE -int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id, +int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, int *running, const char **name, int *parent_tid, void **trace, uptr trace_size) { const ReportDesc *rep = (ReportDesc *)report; @@ -228,7 +228,7 @@ const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, SANITIZER_INTERFACE_ATTRIBUTE int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, - uptr *os_id) { + tid_t *os_id) { MBlock *b = 0; Allocator *a = allocator(); if (a->PointerIsMine((void *)addr)) { diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h index 496a8717f..71986283e 100644 --- a/lib/tsan/rtl/tsan_interface.h +++ b/lib/tsan/rtl/tsan_interface.h @@ -18,6 +18,7 @@ #include using __sanitizer::uptr; +using __sanitizer::tid_t; // This header should NOT include any other headers. // All functions in this header are extern "C" and start with __tsan_. @@ -143,7 +144,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, // Returns information about threads included in the report. SANITIZER_INTERFACE_ATTRIBUTE -int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id, +int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, int *running, const char **name, int *parent_tid, void **trace, uptr trace_size); @@ -160,7 +161,7 @@ const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, // Returns the allocation stack for a heap pointer. SANITIZER_INTERFACE_ATTRIBUTE int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, - uptr *os_id); + tid_t *os_id); #endif // SANITIZER_GO diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h index 8d8ae0fd8..a0473e8db 100644 --- a/lib/tsan/rtl/tsan_report.h +++ b/lib/tsan/rtl/tsan_report.h @@ -90,7 +90,7 @@ struct ReportLocation { struct ReportThread { int id; - uptr os_id; + tid_t os_id; bool running; bool workerthread; char *name; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 0d62af00a..3481c31eb 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -720,7 +720,7 @@ void FuncEntry(ThreadState *thr, uptr pc); void FuncExit(ThreadState *thr); int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); -void ThreadStart(ThreadState *thr, int tid, uptr os_id, bool workerthread); +void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread); void ThreadFinish(ThreadState *thr); int ThreadTid(ThreadState *thr, uptr pc, uptr uid); void ThreadJoin(ThreadState *thr, uptr pc, int tid); diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index 7357d97a2..6a0943c49 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -236,7 +236,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { return tid; } -void ThreadStart(ThreadState *thr, int tid, uptr os_id, bool workerthread) { +void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread) { uptr stk_addr = 0; uptr stk_size = 0; uptr tls_addr = 0; diff --git a/test/tsan/Darwin/main_tid.mm b/test/tsan/Darwin/main_tid.mm index af658e4b9..6dea58e53 100644 --- a/test/tsan/Darwin/main_tid.mm +++ b/test/tsan/Darwin/main_tid.mm @@ -8,7 +8,7 @@ extern "C" { void __tsan_on_report(void *report); int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, - unsigned long *os_id, int *running, + uint64_t *os_id, int *running, const char **name, int *parent_tid, void **trace, unsigned long trace_size); } @@ -17,7 +17,7 @@ void __tsan_on_report(void *report) { fprintf(stderr, "__tsan_on_report(%p)\n", report); int tid; - unsigned long os_id; + uint64_t os_id; int running; const char *name; int parent_tid; diff --git a/test/tsan/debug_alloc_stack.cc b/test/tsan/debug_alloc_stack.cc index 303c10320..ffe99e73a 100644 --- a/test/tsan/debug_alloc_stack.cc +++ b/test/tsan/debug_alloc_stack.cc @@ -15,7 +15,7 @@ #endif extern "C" int __tsan_get_alloc_stack(void *addr, void **trace, size_t size, - int *thread_id, void *os_id); + int *thread_id, uint64_t *os_id); char *mem; void alloc_func() { mem = (char *)malloc(10); } @@ -49,7 +49,7 @@ int main() { void *trace[100]; size_t num_frames = 100; int thread_id; - void *thread_os_id; + uint64_t *thread_os_id; num_frames = __tsan_get_alloc_stack(mem, trace, num_frames, &thread_id, &thread_os_id); @@ -58,7 +58,7 @@ int main() { // CHECK: alloc stack retval ok fprintf(stderr, "thread id = %d\n", thread_id); // CHECK: thread id = 1 - fprintf(stderr, "thread os id = 0x%llx\n", (uint64_t)thread_os_id); + fprintf(stderr, "thread os id = 0x%llx\n", thread_os_id); // CHECK: thread os id = [[THREAD_OS_ID]] fprintf(stderr, "%p\n", trace[0]); // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]] diff --git a/test/tsan/debugging.cc b/test/tsan/debugging.cc index 653364404..0a82f4460 100644 --- a/test/tsan/debugging.cc +++ b/test/tsan/debugging.cc @@ -20,7 +20,7 @@ int __tsan_get_report_mop(void *report, unsigned long idx, int *tid, void **addr, int *size, int *write, int *atomic, void **trace, unsigned long trace_size); int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, - unsigned long *os_id, int *running, + uint64_t *os_id, int *running, const char **name, int *parent_tid, void **trace, unsigned long trace_size); } @@ -90,7 +90,7 @@ void __tsan_on_report(void *report) { fprintf(stderr, "thread_count = %d\n", thread_count); // CHECK: thread_count = 2 - unsigned long os_id; + uint64_t os_id; int running; const char *name; int parent_tid; -- cgit v1.2.1 From cd07c23441ed62ecec244af61880ba05547d2a2a Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 17 Apr 2017 19:51:58 +0000 Subject: Fixup for r300473: Use %lu on Linux for tid_t in format strings. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300483 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 91ce58c25..81ff70963 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -126,10 +126,10 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { &pterrno)) { // Either the thread is dead, or something prevented us from attaching. // Log this event and move on. - VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno); + VReport(1, "Could not attach to thread %lu (errno %d).\n", tid, pterrno); return false; } else { - VReport(2, "Attached to thread %d.\n", tid); + VReport(2, "Attached to thread %lu.\n", tid); // The thread is not guaranteed to stop before ptrace returns, so we must // wait on it. Note: if the thread receives a signal concurrently, // we can get notification about the signal before notification about stop. @@ -147,7 +147,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { if (internal_iserror(waitpid_status, &wperrno)) { // Got a ECHILD error. I don't think this situation is possible, but it // doesn't hurt to report it. - VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n", + VReport(1, "Waiting on thread %lu failed, detaching (errno %d).\n", tid, wperrno); internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); return false; -- cgit v1.2.1 From a5928c107b50a7aa115fad424e3452766607fdb8 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Mon, 17 Apr 2017 19:55:12 +0000 Subject: [tsan] Add missing include for uint64_t in test. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300484 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/debugging.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tsan/debugging.cc b/test/tsan/debugging.cc index 0a82f4460..d9c7c6581 100644 --- a/test/tsan/debugging.cc +++ b/test/tsan/debugging.cc @@ -2,6 +2,7 @@ // RUN: %deflake %run %t 2>&1 | FileCheck %s #include +#include #include #include #include -- cgit v1.2.1 From 279da8dd05fbf8023dd0c434b01f6e7a5b09ca15 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 17 Apr 2017 20:29:38 +0000 Subject: Update suspended threads info to be compatible with darwin Summary: On Darwin, we need to track thread and tid as separate values. This patch splits out the implementation of the suspended threads list to be OS-specific. Reviewers: glider, kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31474 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300491 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 4 +- lib/sanitizer_common/sanitizer_stoptheworld.h | 32 ++++------- .../sanitizer_stoptheworld_linux_libcdep.cc | 55 ++++++++++++++---- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 65 ++++++++++++++++++++-- 4 files changed, 119 insertions(+), 37 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 8ca0905d6..e7eea6853 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -200,10 +200,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { - InternalScopedBuffer registers(SuspendedThreadsList::RegisterCount()); + InternalScopedBuffer registers(suspended_threads.RegisterCount()); uptr registers_begin = reinterpret_cast(registers.data()); uptr registers_end = registers_begin + registers.size(); - for (uptr i = 0; i < suspended_threads.thread_count(); i++) { + for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) { tid_t os_id = static_cast(suspended_threads.GetThreadID(i)); LOG_THREADS("Processing thread %d.\n", os_id); uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h index f7ee018b6..20b49ae78 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -29,31 +29,21 @@ enum PtraceRegistersStatus { // register contexts. class SuspendedThreadsList { public: - SuspendedThreadsList() - : thread_ids_(1024) {} - tid_t GetThreadID(uptr index) const { - CHECK_LT(index, thread_ids_.size()); - return thread_ids_[index]; + SuspendedThreadsList() = default; + + // Can't declare pure virtual functions in sanitizer runtimes: + // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead. + virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const { + UNIMPLEMENTED(); } - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; + // The buffer in GetRegistersAndSP should be at least this big. - static uptr RegisterCount(); - uptr thread_count() const { return thread_ids_.size(); } - bool Contains(tid_t thread_id) const { - for (uptr i = 0; i < thread_ids_.size(); i++) { - if (thread_ids_[i] == thread_id) - return true; - } - return false; - } - void Append(tid_t thread_id) { - thread_ids_.push_back(thread_id); - } + virtual uptr RegisterCount() const { UNIMPLEMENTED(); } + virtual uptr ThreadCount() const { UNIMPLEMENTED(); } + virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } private: - InternalMmapVector thread_ids_; - // Prohibit copy and assign. SuspendedThreadsList(const SuspendedThreadsList&); void operator=(const SuspendedThreadsList&); diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 81ff70963..91f798cd2 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -82,6 +82,23 @@ namespace __sanitizer { +class SuspendedThreadsListLinux : public SuspendedThreadsList { + public: + SuspendedThreadsListLinux() : thread_ids_(1024) {} + + tid_t GetThreadID(uptr index) const; + uptr ThreadCount() const; + bool ContainsTid(tid_t thread_id) const; + void Append(tid_t tid); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector thread_ids_; +}; + // Structure for passing arguments into the tracer thread. struct TracerThreadArgument { StopTheWorldCallback callback; @@ -105,12 +122,12 @@ class ThreadSuspender { bool SuspendAllThreads(); void ResumeAllThreads(); void KillAllThreads(); - SuspendedThreadsList &suspended_threads_list() { + SuspendedThreadsListLinux &suspended_threads_list() { return suspended_threads_list_; } TracerThreadArgument *arg; private: - SuspendedThreadsList suspended_threads_list_; + SuspendedThreadsListLinux suspended_threads_list_; pid_t pid_; bool SuspendThread(tid_t thread_id); }; @@ -119,8 +136,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { // Are we already attached to this thread? // Currently this check takes linear time, however the number of threads is // usually small. - if (suspended_threads_list_.Contains(tid)) - return false; + if (suspended_threads_list_.ContainsTid(tid)) return false; int pterrno; if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), &pterrno)) { @@ -165,7 +181,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { } void ThreadSuspender::ResumeAllThreads() { - for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) { + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) { pid_t tid = suspended_threads_list_.GetThreadID(i); int pterrno; if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), @@ -181,7 +197,7 @@ void ThreadSuspender::ResumeAllThreads() { } void ThreadSuspender::KillAllThreads() { - for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), nullptr, nullptr); } @@ -492,9 +508,28 @@ typedef _user_regs_struct regs_struct; #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) -PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +uptr SuspendedThreadsListLinux::ThreadCount() const { + return thread_ids_.size(); +} + +bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < thread_ids_.size(); i++) { + if (thread_ids_[i] == thread_id) return true; + } + return false; +} + +void SuspendedThreadsListLinux::Append(tid_t tid) { + thread_ids_.push_back(tid); +} + +PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( + uptr index, uptr *buffer, uptr *sp) const { pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; @@ -524,7 +559,7 @@ PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsList::RegisterCount() { +uptr SuspendedThreadsListLinux::RegisterCount() const { return sizeof(regs_struct) / sizeof(uptr); } } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 047472a65..f65065e27 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -16,21 +16,78 @@ #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ defined(__mips64) || defined(__i386)) +#include + #include "sanitizer_stoptheworld.h" namespace __sanitizer { +typedef struct { + tid_t tid; + thread_t thread; +} SuspendedThreadInfo; + +class SuspendedThreadsListMac : public SuspendedThreadsList { + public: + SuspendedThreadsListMac() : threads_(1024) {} + + tid_t GetThreadID(uptr index) const; + thread_t GetThread(uptr index) const; + uptr ThreadCount() const; + bool ContainsThread(thread_t thread) const; + void Append(thread_t thread); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector threads_; +}; + void StopTheWorld(StopTheWorldCallback callback, void *argument) { CHECK(0 && "unimplemented"); } -PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].tid; +} + +thread_t SuspendedThreadsListMac::GetThread(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].thread; +} + +uptr SuspendedThreadsListMac::ThreadCount() const { + return threads_.size(); +} + +bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { + for (uptr i = 0; i < threads_.size(); i++) { + if (threads_[i].thread == thread) return true; + } + return false; +} + +void SuspendedThreadsListMac::Append(thread_t thread) { + thread_identifier_info_data_t info; + mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, + (thread_info_t)&info, &info_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get thread ident for a thread\n"); + return; + } + threads_.push_back({info.thread_id, thread}); +} + +PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( + uptr index, uptr *buffer, uptr *sp) const { CHECK(0 && "unimplemented"); return REGISTERS_UNAVAILABLE_FATAL; } -uptr SuspendedThreadsList::RegisterCount() { +uptr SuspendedThreadsListMac::RegisterCount() const { CHECK(0 && "unimplemented"); return 0; } -- cgit v1.2.1 From b09b5174499e95167eb3df4059c3799b704d1779 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 18 Apr 2017 01:08:00 +0000 Subject: [asan] Fixup for r300483 (which is a fixup for r300473). Sanitizer Printf() does not know about %lu. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300521 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 91f798cd2..fb257fe0a 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -142,10 +142,11 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { &pterrno)) { // Either the thread is dead, or something prevented us from attaching. // Log this event and move on. - VReport(1, "Could not attach to thread %lu (errno %d).\n", tid, pterrno); + VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid, + pterrno); return false; } else { - VReport(2, "Attached to thread %lu.\n", tid); + VReport(2, "Attached to thread %zu.\n", (uptr)tid); // The thread is not guaranteed to stop before ptrace returns, so we must // wait on it. Note: if the thread receives a signal concurrently, // we can get notification about the signal before notification about stop. @@ -163,8 +164,8 @@ bool ThreadSuspender::SuspendThread(tid_t tid) { if (internal_iserror(waitpid_status, &wperrno)) { // Got a ECHILD error. I don't think this situation is possible, but it // doesn't hurt to report it. - VReport(1, "Waiting on thread %lu failed, detaching (errno %d).\n", - tid, wperrno); + VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n", + (uptr)tid, wperrno); internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); return false; } -- cgit v1.2.1 From 4f6879e409680205444ac3e366249f3032c63667 Mon Sep 17 00:00:00 2001 From: Douglas Yung Date: Tue, 18 Apr 2017 03:25:11 +0000 Subject: [XRay][compiler-rt] Use emulated TSC when CPU supports rdtscp, but cannot determine the CPU frequency A problem arises if a machine supports the rdtscp instruction, but the processor frequency cannot be determined by the function getTSCFrequency(). In this case, we want to use the emulated TSC instead. This patch implements that by adding a call to getTSCFrequency() from probeRequiredCPUFeatures(), and the function only returns true if both the processor supports rdtscp and the CPU frequency can be determined. This should fix PR32620. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32067 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300525 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 13 ++++++++++--- lib/xray/xray_inmemory_log.cc | 10 +++++++--- lib/xray/xray_x86_64.cc | 6 ++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index c5b63b0a5..e538b477a 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -118,11 +118,15 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { return Result; } + // Test for required CPU features and cache the cycle frequency + static bool TSCSupported = probeRequiredCPUFeatures(); + static uint64_t CycleFrequency = TSCSupported ? getTSCFrequency() + : __xray::NanosecondsPerSecond; + XRayFileHeader Header; Header.Version = 1; Header.Type = FileTypes::FDR_LOG; - Header.CycleFrequency = probeRequiredCPUFeatures() - ? getTSCFrequency() : __xray::NanosecondsPerSecond; + Header.CycleFrequency = CycleFrequency; // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc' // before setting the values in the header. Header.ConstantTSC = 1; @@ -196,7 +200,10 @@ void fdrLoggingHandleArg0(int32_t FuncId, unsigned char CPU; uint64_t TSC; - if(probeRequiredCPUFeatures()) { + // Test once for required CPU features + static bool TSCSupported = probeRequiredCPUFeatures(); + + if(TSCSupported) { TSC = __xray::readTSC(CPU); } else { // FIXME: This code needs refactoring as it appears in multiple locations diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc index cdaa6d1b5..83aecfaf7 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_inmemory_log.cc @@ -79,15 +79,19 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { int F = getLogFD(); if (F == -1) return -1; + + // Test for required CPU features and cache the cycle frequency + static bool TSCSupported = probeRequiredCPUFeatures(); + static uint64_t CycleFrequency = TSCSupported ? getTSCFrequency() + : __xray::NanosecondsPerSecond; + // Since we're here, we get to write the header. We set it up so that the // header will only be written once, at the start, and let the threads // logging do writes which just append. XRayFileHeader Header; Header.Version = 1; Header.Type = FileTypes::NAIVE_LOG; - Header.CycleFrequency = probeRequiredCPUFeatures() - ? getTSCFrequency() - : __xray::NanosecondsPerSecond; + Header.CycleFrequency = CycleFrequency; // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc' // before setting the values in the header. diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index 8c2a4e313..2e9a8d270 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -214,6 +214,12 @@ bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { Report("Missing rdtscp support.\n"); return false; } + // Also check whether we can determine the CPU frequency, since if we cannot, + // we should use the emulated TSC instead. + if (!getTSCFrequency()) { + Report("Unable to determine CPU frequency.\n"); + return false; + } return true; } -- cgit v1.2.1 From 385d9f6d5abb6b2d4ea27e59ac1e7b0e20d54f7c Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Tue, 18 Apr 2017 07:22:26 +0000 Subject: [sanitizer] Don't include in sanitizer_stoptheworld_linux_libcdep.cc on ARM Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turned out that adding defined(_arm_) in sanitizer_stoptheworld_linux_libcdep.cc breaks android arm with some toolchains. .../llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc:36:11: fatal error: 'linux/user.h' file not found # include // for pt_regs ^ 1 error generated. Context: #if SANITIZER_ANDROID && defined(__arm__) # include // for pt_regs #else This patch removes corresponding #if SANITIZER_ANDROID && defined(__arm__) and a bit rearranges adjacent сode. Differential Revision: https://reviews.llvm.org/D32128 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300531 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_stoptheworld_linux_libcdep.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index fb257fe0a..03f73ae88 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -32,17 +32,13 @@ #include // for pid_t #include // for iovec #include // for NT_PRSTATUS -#if SANITIZER_ANDROID && defined(__arm__) -# include // for pt_regs -#else -# ifdef __aarch64__ +#if defined(__aarch64__) && !SANITIZER_ANDROID // GLIBC 2.20+ sys/user does not include asm/ptrace.h -# include -# endif -# include // for user_regs_struct -# if SANITIZER_ANDROID && SANITIZER_MIPS -# include // for mips SP register in sys/user.h -# endif +# include +#endif +#include // for user_regs_struct +#if SANITIZER_ANDROID && SANITIZER_MIPS +# include // for mips SP register in sys/user.h #endif #include // for signal-related stuff -- cgit v1.2.1 From 73ac02fff7ce39a39f5228acb9ae14a9b79ebee6 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Apr 2017 20:56:56 +0000 Subject: Allow for setting of global platform-specific lsan options in the test suite Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32131 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300592 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c | 4 ++-- test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c | 2 +- test/lsan/TestCases/Linux/use_tls_dynamic.cc | 6 +++--- test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc | 6 +++--- test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc | 6 +++--- test/lsan/TestCases/Linux/use_tls_static.cc | 6 +++--- test/lsan/TestCases/disabler.c | 2 +- test/lsan/TestCases/disabler.cc | 2 +- test/lsan/TestCases/do_leak_check_override.cc | 4 ++-- test/lsan/TestCases/high_allocator_contention.cc | 2 +- test/lsan/TestCases/ignore_object.c | 2 +- test/lsan/TestCases/ignore_object_errors.cc | 2 +- test/lsan/TestCases/large_allocation_leak.cc | 2 +- test/lsan/TestCases/leak_check_at_exit.cc | 8 ++++---- test/lsan/TestCases/leak_check_before_thread_started.cc | 2 +- test/lsan/TestCases/link_turned_off.cc | 4 ++-- test/lsan/TestCases/pointer_to_self.cc | 2 +- test/lsan/TestCases/print_suppressions.cc | 8 ++++---- test/lsan/TestCases/recoverable_leak_check.cc | 4 ++-- test/lsan/TestCases/register_root_region.cc | 6 +++--- test/lsan/TestCases/stale_stack_leak.cc | 4 ++-- test/lsan/TestCases/suppressions_default.cc | 2 +- test/lsan/TestCases/suppressions_file.cc | 6 +++--- test/lsan/TestCases/swapcontext.cc | 4 ++-- test/lsan/TestCases/use_after_return.cc | 6 +++--- test/lsan/TestCases/use_globals_initialized.cc | 6 +++--- test/lsan/TestCases/use_globals_uninitialized.cc | 6 +++--- test/lsan/TestCases/use_poisoned_asan.cc | 4 ++-- test/lsan/TestCases/use_registers.cc | 6 +++--- test/lsan/TestCases/use_stacks.cc | 6 +++--- test/lsan/TestCases/use_stacks_threaded.cc | 6 +++--- test/lsan/TestCases/use_unaligned.cc | 4 ++-- test/lsan/lit.common.cfg | 8 ++++++++ 33 files changed, 78 insertions(+), 70 deletions(-) diff --git a/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c b/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c index 6da759563..cf080e4dd 100644 --- a/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c +++ b/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c @@ -5,8 +5,8 @@ // makes its best effort. // RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0" // RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %run %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:use_tls=1 %run %t +// RUN: %env_lsan_opts=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c b/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c index 4a3a7ac14..52819bb9f 100644 --- a/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c +++ b/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c @@ -1,7 +1,7 @@ // Regression test. Disabler should not depend on TSD validity. // RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1:use_ld_allocations=0" // RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t +// RUN: %env_lsan_opts=$LSAN_BASE %run %t #include #include diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index 6af82d59e..c81bcaed2 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -2,9 +2,9 @@ // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0" // RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 // UNSUPPORTED: i386-linux,i686-linux,arm #ifndef BUILD_DSO diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc index f075d035a..947a4ce24 100644 --- a/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc @@ -1,9 +1,9 @@ // Test that dynamically allocated thread-specific storage is included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc index d97abab41..8f5afc49a 100644 --- a/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc @@ -1,9 +1,9 @@ // Test that statically allocated thread-specific storage is included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/Linux/use_tls_static.cc b/test/lsan/TestCases/Linux/use_tls_static.cc index be34a3abf..e56f5e13a 100644 --- a/test/lsan/TestCases/Linux/use_tls_static.cc +++ b/test/lsan/TestCases/Linux/use_tls_static.cc @@ -1,9 +1,9 @@ // Test that statically allocated TLS space is included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/disabler.c b/test/lsan/TestCases/disabler.c index 1c4529df4..f8b7f0da1 100644 --- a/test/lsan/TestCases/disabler.c +++ b/test/lsan/TestCases/disabler.c @@ -1,7 +1,7 @@ // Test for __lsan_disable() / __lsan_enable(). // RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" // RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/disabler.cc b/test/lsan/TestCases/disabler.cc index 95e58f457..feabc36fa 100644 --- a/test/lsan/TestCases/disabler.cc +++ b/test/lsan/TestCases/disabler.cc @@ -1,7 +1,7 @@ // Test for ScopedDisabler. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/do_leak_check_override.cc b/test/lsan/TestCases/do_leak_check_override.cc index 3d191f861..bffcf6ef6 100644 --- a/test/lsan/TestCases/do_leak_check_override.cc +++ b/test/lsan/TestCases/do_leak_check_override.cc @@ -3,8 +3,8 @@ // "normal" mode (LSan runs in "strict" mode by default). // RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s #include #include diff --git a/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc index 322e61bde..8d8f9879b 100644 --- a/test/lsan/TestCases/high_allocator_contention.cc +++ b/test/lsan/TestCases/high_allocator_contention.cc @@ -2,7 +2,7 @@ // Usage: ./a.out number_of_threads total_number_of_allocations // RUN: LSAN_BASE="detect_leaks=1:use_ld_allocations=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 5 1000000 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE %run %t 5 1000000 2>&1 #include #include #include diff --git a/test/lsan/TestCases/ignore_object.c b/test/lsan/TestCases/ignore_object.c index 2aa4f14e2..53dea7594 100644 --- a/test/lsan/TestCases/ignore_object.c +++ b/test/lsan/TestCases/ignore_object.c @@ -1,7 +1,7 @@ // Test for __lsan_ignore_object(). // RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" // RUN: %clang_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc index 41603274a..76cd3bbf3 100644 --- a/test/lsan/TestCases/ignore_object_errors.cc +++ b/test/lsan/TestCases/ignore_object_errors.cc @@ -1,6 +1,6 @@ // Test for incorrect use of __lsan_ignore_object(). // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index c3da932a4..6bf593be1 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -1,7 +1,7 @@ // Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s // For 32 bit LSan it's pretty likely that large chunks are "reachable" from some // internal data structures (e.g. Glibc global data). diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc index 5659b3968..2e00cfb12 100644 --- a/test/lsan/TestCases/leak_check_at_exit.cc +++ b/test/lsan/TestCases/leak_check_at_exit.cc @@ -1,10 +1,10 @@ // Test for the leak_check_at_exit flag. // RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do -// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do -// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: %env_lsan_opts=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: %env_lsan_opts=$LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont #include #include diff --git a/test/lsan/TestCases/leak_check_before_thread_started.cc b/test/lsan/TestCases/leak_check_before_thread_started.cc index ca818e1e2..94084dcb5 100644 --- a/test/lsan/TestCases/leak_check_before_thread_started.cc +++ b/test/lsan/TestCases/leak_check_before_thread_started.cc @@ -1,7 +1,7 @@ // Regression test for http://llvm.org/bugs/show_bug.cgi?id=21621 // This test relies on timing between threads, so any failures will be flaky. // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS="log_pointers=1:log_threads=1" %run %t +// RUN: %env_lsan_opts="log_pointers=1:log_threads=1" %run %t #include #include #include diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index a425a6c2d..da848bbc3 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -1,8 +1,8 @@ // Test for disabling LSan at link-time. // RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s #include diff --git a/test/lsan/TestCases/pointer_to_self.cc b/test/lsan/TestCases/pointer_to_self.cc index ea1208dcf..4f34d8a8f 100644 --- a/test/lsan/TestCases/pointer_to_self.cc +++ b/test/lsan/TestCases/pointer_to_self.cc @@ -2,7 +2,7 @@ // object is indirectly leaked. Only external pointers count. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/print_suppressions.cc b/test/lsan/TestCases/print_suppressions.cc index 1a252e442..0f9147244 100644 --- a/test/lsan/TestCases/print_suppressions.cc +++ b/test/lsan/TestCases/print_suppressions.cc @@ -2,10 +2,10 @@ // matched. Default is print_suppressions=true. // RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print -// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print +// RUN: %env_lsan_opts=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: %env_lsan_opts=$LSAN_BASE:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print #include #include diff --git a/test/lsan/TestCases/recoverable_leak_check.cc b/test/lsan/TestCases/recoverable_leak_check.cc index 04686a561..be10a49dc 100644 --- a/test/lsan/TestCases/recoverable_leak_check.cc +++ b/test/lsan/TestCases/recoverable_leak_check.cc @@ -1,8 +1,8 @@ // Test for on-demand leak checking. // RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/register_root_region.cc b/test/lsan/TestCases/register_root_region.cc index a63b0cc62..6e3c8c1ce 100644 --- a/test/lsan/TestCases/register_root_region.cc +++ b/test/lsan/TestCases/register_root_region.cc @@ -1,9 +1,9 @@ // Test for __lsan_(un)register_root_region(). // RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:use_root_regions=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:use_root_regions=0 not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc index 8f7ab9c1c..0b33f26a4 100644 --- a/test/lsan/TestCases/stale_stack_leak.cc +++ b/test/lsan/TestCases/stale_stack_leak.cc @@ -1,8 +1,8 @@ // Test that out-of-scope local variables are ignored by LSan. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=1" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s // // x86 passes parameters through stack that may lead to false negatives // UNSUPPORTED: x86 diff --git a/test/lsan/TestCases/suppressions_default.cc b/test/lsan/TestCases/suppressions_default.cc index 6c0364e62..da240f200 100644 --- a/test/lsan/TestCases/suppressions_default.cc +++ b/test/lsan/TestCases/suppressions_default.cc @@ -1,6 +1,6 @@ // RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s #include #include diff --git a/test/lsan/TestCases/suppressions_file.cc b/test/lsan/TestCases/suppressions_file.cc index 1d8a06474..a14afc4d5 100644 --- a/test/lsan/TestCases/suppressions_file.cc +++ b/test/lsan/TestCases/suppressions_file.cc @@ -3,13 +3,13 @@ // RUN: rm -f %t.supp // RUN: touch %t.supp -// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s --check-prefix=NOSUPP +// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s --check-prefix=NOSUPP // RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp -// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s // RUN: echo "leak:%t" > %t.supp -// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp':symbolize=false" %run %t +// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%t.supp':symbolize=false" %run %t #include #include diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index f990526cf..b019067aa 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -3,8 +3,8 @@ // RUN: %clangxx_lsan %s -o %t // RUN: LSAN_BASE="detect_leaks=1" -// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 -// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s // UNSUPPORTED: arm #include diff --git a/test/lsan/TestCases/use_after_return.cc b/test/lsan/TestCases/use_after_return.cc index 413775276..6c00639c0 100644 --- a/test/lsan/TestCases/use_after_return.cc +++ b/test/lsan/TestCases/use_after_return.cc @@ -2,9 +2,9 @@ // in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -O2 -o %t -// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s -// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 -// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS="" %run %t 2>&1 +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_globals_initialized.cc b/test/lsan/TestCases/use_globals_initialized.cc index 996052d6e..07557ee8b 100644 --- a/test/lsan/TestCases/use_globals_initialized.cc +++ b/test/lsan/TestCases/use_globals_initialized.cc @@ -1,9 +1,9 @@ // Test that initialized globals are included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_globals_uninitialized.cc b/test/lsan/TestCases/use_globals_uninitialized.cc index 25ccacc7e..f42608662 100644 --- a/test/lsan/TestCases/use_globals_uninitialized.cc +++ b/test/lsan/TestCases/use_globals_uninitialized.cc @@ -1,9 +1,9 @@ // Test that uninitialized globals are included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_poisoned_asan.cc b/test/lsan/TestCases/use_poisoned_asan.cc index d9ef16a4e..164b0cf67 100644 --- a/test/lsan/TestCases/use_poisoned_asan.cc +++ b/test/lsan/TestCases/use_poisoned_asan.cc @@ -2,8 +2,8 @@ // REQUIRES: asan // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 2fe13318e..fe552e628 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -1,9 +1,9 @@ // Test that registers of running threads are included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0" // RUN: %clangxx_lsan -pthread %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_stacks.cc b/test/lsan/TestCases/use_stacks.cc index 95a01003b..656a78a79 100644 --- a/test/lsan/TestCases/use_stacks.cc +++ b/test/lsan/TestCases/use_stacks.cc @@ -1,9 +1,9 @@ // Test that stack of main thread is included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc index 310171feb..c0549b22e 100644 --- a/test/lsan/TestCases/use_stacks_threaded.cc +++ b/test/lsan/TestCases/use_stacks_threaded.cc @@ -1,9 +1,9 @@ // Test that stacks of non-main threads are included in the root set. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" // RUN: %clangxx_lsan -pthread %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 -// RUN: LSAN_OPTIONS="" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: %env_lsan_opts="" %run %t 2>&1 #include #include diff --git a/test/lsan/TestCases/use_unaligned.cc b/test/lsan/TestCases/use_unaligned.cc index 1179c15b7..1d680a51b 100644 --- a/test/lsan/TestCases/use_unaligned.cc +++ b/test/lsan/TestCases/use_unaligned.cc @@ -1,8 +1,8 @@ // Test that unaligned pointers are detected correctly. // RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=0" not %run %t 2>&1 | FileCheck %s -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %run %t 2>&1 +// RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=0" not %run %t 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=1" %run %t 2>&1 #include #include diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index b90c7ef48..3de341783 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -32,6 +32,14 @@ else: lit_config.fatal("Unknown LSan test mode: %r" % lsan_lit_test_mode) config.name += config.name_suffix +# Platform-specific default LSAN_OPTIONS for lit tests. +default_lsan_opts = '' +if default_lsan_opts: + config.environment['LSAN_OPTIONS'] = default_lsan_opts + default_lsan_opts += ':' +config.substitutions.append(('%env_lsan_opts=', + 'env LSAN_OPTIONS=' + default_lsan_opts)) + if lit.util.which('strace'): config.available_features.add('strace') -- cgit v1.2.1 From 5962f26bd374b50e7b2784696d3592471599549e Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Apr 2017 20:56:59 +0000 Subject: Don't use abort_on_error for lsan darwin test suite Summary: This option is disabled by our other test suites, and will cause failures when unit tests abort instead of failing with an error code. Will also prevent the test suite from being too slow. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32129 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300593 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/lit.common.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 3de341783..43ed02a4b 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -34,6 +34,13 @@ config.name += config.name_suffix # Platform-specific default LSAN_OPTIONS for lit tests. default_lsan_opts = '' +if config.host_os == 'Darwin': + # On Darwin, we default to `abort_on_error=1`, which would make tests run + # much slower. Let's override this and run lit tests with 'abort_on_error=0'. + # Also, make sure we do not overwhelm the syslog while testing. + default_lsan_opts = 'abort_on_error=0' + default_lsan_opts += ':log_to_syslog=0' + if default_lsan_opts: config.environment['LSAN_OPTIONS'] = default_lsan_opts default_lsan_opts += ':' -- cgit v1.2.1 From e73b4aa40949ba926c098eebb9f482a44b097432 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Apr 2017 21:05:09 +0000 Subject: Remove mips64 defines from darwin-specific file Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits, arichardson Differential Revision: https://reviews.llvm.org/D32183 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300598 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index f65065e27..70625a9f1 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ - defined(__mips64) || defined(__i386)) + defined(__i386)) #include @@ -94,4 +94,4 @@ uptr SuspendedThreadsListMac::RegisterCount() const { } // namespace __sanitizer #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || - // defined(__mips64) || defined(__i386)) + // defined(__i386)) -- cgit v1.2.1 From c895c98c3709dc9aed804b85a53d5ce0d6c3dc1c Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Apr 2017 21:05:11 +0000 Subject: Implement suspended thread register count for darwin Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32165 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300599 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 70625a9f1..ab33ba641 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -88,8 +88,7 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( } uptr SuspendedThreadsListMac::RegisterCount() const { - CHECK(0 && "unimplemented"); - return 0; + return MACHINE_THREAD_STATE_COUNT; } } // namespace __sanitizer -- cgit v1.2.1 From 85478c5f49a6379ca86edc08d84dae244128ecc2 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 18 Apr 2017 21:10:50 +0000 Subject: [sanitizer] Define lsan-x86 in tests for both i386 and i686. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300601 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index 2926edb12..da720a850 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -26,7 +26,7 @@ config.available_features.add(config.tool_name) if config.target_arch not in ['arm', 'armhf', 'aarch64']: config.available_features.add('stable-runtime') -if config.host_os == 'Linux' and config.target_arch == 'i386' and config.tool_name == "lsan": +if config.host_os == 'Linux' and config.tool_name == "lsan" and (config.target_arch == 'i386' or config.target_arch == 'i686'): config.available_features.add("lsan-x86") if config.host_os == 'Darwin': -- cgit v1.2.1 From 28c21763d3a76b17d367eba292a43df4baf33bbc Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 19 Apr 2017 05:37:14 +0000 Subject: [XRay][compiler-rt] Fix up CFI annotations and stack alignment Summary: Previously, we had been very undisciplined about CFI annotations with the XRay trampolines. This leads to runtime crashes due to mis-alined stack pointers that some function implementations may run into (i.e. those using instructions that require properly aligned addresses coming from the stack). This patch attempts to clean that up, as well as more accurately use the correct amounts of space on the stack for stashing and un-stashing registers. Reviewers: eugenis, kcc Subscribers: kpw, llvm-commits Differential Revision: https://reviews.llvm.org/D32202 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300660 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_trampoline_x86_64.S | 89 ++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index da0aae326..772eafbec 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -16,41 +16,41 @@ #include "../builtins/assembly.h" .macro SAVE_REGISTERS - subq $200, %rsp - movupd %xmm0, 184(%rsp) - movupd %xmm1, 168(%rsp) - movupd %xmm2, 152(%rsp) - movupd %xmm3, 136(%rsp) - movupd %xmm4, 120(%rsp) - movupd %xmm5, 104(%rsp) - movupd %xmm6, 88(%rsp) - movupd %xmm7, 72(%rsp) - movq %rdi, 64(%rsp) - movq %rax, 56(%rsp) - movq %rdx, 48(%rsp) - movq %rsi, 40(%rsp) - movq %rcx, 32(%rsp) - movq %r8, 24(%rsp) - movq %r9, 16(%rsp) + subq $184, %rsp + movupd %xmm0, 168(%rsp) + movupd %xmm1, 152(%rsp) + movupd %xmm2, 136(%rsp) + movupd %xmm3, 120(%rsp) + movupd %xmm4, 104(%rsp) + movupd %xmm5, 88(%rsp) + movupd %xmm6, 72(%rsp) + movupd %xmm7, 56(%rsp) + movq %rdi, 48(%rsp) + movq %rax, 40(%rsp) + movq %rdx, 32(%rsp) + movq %rsi, 24(%rsp) + movq %rcx, 16(%rsp) + movq %r8, 8(%rsp) + movq %r9, 0(%rsp) .endm .macro RESTORE_REGISTERS - movupd 184(%rsp), %xmm0 - movupd 168(%rsp), %xmm1 - movupd 152(%rsp), %xmm2 - movupd 136(%rsp), %xmm3 - movupd 120(%rsp), %xmm4 - movupd 104(%rsp), %xmm5 - movupd 88(%rsp) , %xmm6 - movupd 72(%rsp) , %xmm7 - movq 64(%rsp), %rdi - movq 56(%rsp), %rax - movq 48(%rsp), %rdx - movq 40(%rsp), %rsi - movq 32(%rsp), %rcx - movq 24(%rsp), %r8 - movq 16(%rsp), %r9 - addq $200, %rsp + movupd 168(%rsp), %xmm0 + movupd 152(%rsp), %xmm1 + movupd 136(%rsp), %xmm2 + movupd 120(%rsp), %xmm3 + movupd 104(%rsp), %xmm4 + movupd 88(%rsp), %xmm5 + movupd 72(%rsp) , %xmm6 + movupd 56(%rsp) , %xmm7 + movq 48(%rsp), %rdi + movq 40(%rsp), %rax + movq 32(%rsp), %rdx + movq 24(%rsp), %rsi + movq 16(%rsp), %rcx + movq 8(%rsp), %r8 + movq 0(%rsp), %r9 + addq $184, %rsp .endm .text @@ -67,6 +67,7 @@ __xray_FunctionEntry: pushq %rbp .cfi_def_cfa_offset 16 SAVE_REGISTERS + .cfi_def_cfa_offset 200 // This load has to be atomic, it's concurrent with __xray_patch(). // On x86/amd64, a simple (type-aligned) MOV instruction is enough. @@ -98,12 +99,12 @@ __xray_FunctionExit: // returning. pushq %rbp .cfi_def_cfa_offset 16 - subq $56, %rsp - .cfi_def_cfa_offset 32 - movupd %xmm0, 40(%rsp) - movupd %xmm1, 24(%rsp) - movq %rax, 16(%rsp) - movq %rdx, 8(%rsp) + subq $48, %rsp + .cfi_def_cfa_offset 64 + movupd %xmm0, 32(%rsp) + movupd %xmm1, 16(%rsp) + movq %rax, 8(%rsp) + movq %rdx, 0(%rsp) movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax testq %rax,%rax je .Ltmp2 @@ -113,11 +114,11 @@ __xray_FunctionExit: callq *%rax .Ltmp2: // Restore the important registers. - movupd 40(%rsp), %xmm0 - movupd 24(%rsp), %xmm1 - movq 16(%rsp), %rax - movq 8(%rsp), %rdx - addq $56, %rsp + movupd 32(%rsp), %xmm0 + movupd 16(%rsp), %xmm1 + movq 8(%rsp), %rax + movq 0(%rsp), %rdx + addq $48, %rsp popq %rbp retq .Ltmp3: @@ -138,6 +139,7 @@ __xray_FunctionTailExit: pushq %rbp .cfi_def_cfa_offset 16 SAVE_REGISTERS + .cfi_def_cfa_offset 200 movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax testq %rax,%rax @@ -165,6 +167,7 @@ __xray_ArgLoggerEntry: pushq %rbp .cfi_def_cfa_offset 16 SAVE_REGISTERS + .cfi_def_cfa_offset 200 // Again, these function pointer loads must be atomic; MOV is fine. movq _ZN6__xray13XRayArgLoggerE(%rip), %rax -- cgit v1.2.1 From 57da2deeb0e6cf80adb9d45218918c88966c01f7 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 19 Apr 2017 14:00:35 +0000 Subject: Move valid caller-pc checks out of platform-specific checks Summary: ProcessPlatformSpecificAllocations for linux leak sanitizer iterated over memory chunks and ran two checks concurrently: 1) Ensured the pc was valid 2) Checked whether it was a linker allocation All platforms will need the valid pc check, so it is moved out of the platform- specific file. To prevent code and logic duplication, the linker allocation check is moved as well, with the name of the linker supplied by the platform-specific module. In cases where we don't need to check for linker allocations (ie Darwin), this name will be a nullptr, and we'll only run the caller pc checks. Reviewers: kubamracek, alekseyshl, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32130 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300690 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 70 ++++++++++++++++++++++++++++++++++++++++++- lib/lsan/lsan_common.h | 4 +++ lib/lsan/lsan_common_linux.cc | 65 ++-------------------------------------- lib/lsan/lsan_common_mac.cc | 2 ++ 4 files changed, 77 insertions(+), 64 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index e7eea6853..9d65918aa 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -356,6 +356,72 @@ static void CollectIgnoredCb(uptr chunk, void *arg) { } } +static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) { + CHECK(stack_id); + StackTrace stack = map->Get(stack_id); + // The top frame is our malloc/calloc/etc. The next frame is the caller. + if (stack.size >= 2) + return stack.trace[1]; + return 0; +} + +struct InvalidPCParam { + Frontier *frontier; + StackDepotReverseMap *stack_depot_reverse_map; + bool skip_linker_allocations; +}; + +// ForEachChunk callback. If the caller pc is invalid or is within the linker, +// mark as reachable. Called by ProcessPlatformSpecificAllocations. +static void MarkInvalidPCCb(uptr chunk, void *arg) { + CHECK(arg); + InvalidPCParam *param = reinterpret_cast(arg); + chunk = GetUserBegin(chunk); + LsanMetadata m(chunk); + if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) { + u32 stack_id = m.stack_trace_id(); + uptr caller_pc = 0; + if (stack_id > 0) + caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map); + // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark + // it as reachable, as we can't properly report its allocation stack anyway. + if (caller_pc == 0 || (param->skip_linker_allocations && + GetLinker()->containsAddress(caller_pc))) { + m.set_tag(kReachable); + param->frontier->push_back(chunk); + } + } +} + +// On Linux, handles dynamically allocated TLS blocks by treating all chunks +// allocated from ld-linux.so as reachable. +// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. +// They are allocated with a __libc_memalign() call in allocate_and_init() +// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those +// blocks, but we can make sure they come from our own allocator by intercepting +// __libc_memalign(). On top of that, there is no easy way to reach them. Their +// addresses are stored in a dynamically allocated array (the DTV) which is +// referenced from the static TLS. Unfortunately, we can't just rely on the DTV +// being reachable from the static TLS, and the dynamic TLS being reachable from +// the DTV. This is because the initial DTV is allocated before our interception +// mechanism kicks in, and thus we don't recognize it as allocated memory. We +// can't special-case it either, since we don't know its size. +// Our solution is to include in the root set all allocations made from +// ld-linux.so (which is where allocate_and_init() is implemented). This is +// guaranteed to include all dynamic TLS blocks (and possibly other allocations +// which we don't care about). +// On all other platforms, this simply checks to ensure that the caller pc is +// valid before reporting chunks as leaked. +void ProcessPC(Frontier *frontier) { + StackDepotReverseMap stack_depot_reverse_map; + InvalidPCParam arg; + arg.frontier = frontier; + arg.stack_depot_reverse_map = &stack_depot_reverse_map; + arg.skip_linker_allocations = + flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr; + ForEachChunk(MarkInvalidPCCb, &arg); +} + // Sets the appropriate tag on each chunk. static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { // Holds the flood fill frontier. @@ -367,11 +433,13 @@ static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { ProcessRootRegions(&frontier); FloodFillTag(&frontier, kReachable); + CHECK_EQ(0, frontier.size()); + ProcessPC(&frontier); + // The check here is relatively expensive, so we do this in a separate flood // fill. That way we can skip the check for chunks that are reachable // otherwise. LOG_POINTERS("Processing platform-specific allocations.\n"); - CHECK_EQ(0, frontier.size()); ProcessPlatformSpecificAllocations(&frontier); FloodFillTag(&frontier, kReachable); diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 0bb575b29..88d5f1ca7 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -212,6 +212,10 @@ uptr PointsIntoChunk(void *p); uptr GetUserBegin(uptr chunk); // Helper for __lsan_ignore_object(). IgnoreObjectResult IgnoreObjectLocked(const void *p); + +// Return the linker module, if valid for the platform. +LoadedModule *GetLinker(); + // Wrapper for chunk metadata operations. class LsanMetadata { public: diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 0d1e998a5..fadd0263d 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -89,70 +89,9 @@ void ProcessGlobalRegions(Frontier *frontier) { dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier); } -static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) { - CHECK(stack_id); - StackTrace stack = map->Get(stack_id); - // The top frame is our malloc/calloc/etc. The next frame is the caller. - if (stack.size >= 2) - return stack.trace[1]; - return 0; -} +LoadedModule *GetLinker() { return linker; } -struct ProcessPlatformAllocParam { - Frontier *frontier; - StackDepotReverseMap *stack_depot_reverse_map; - bool skip_linker_allocations; -}; - -// ForEachChunk callback. Identifies unreachable chunks which must be treated as -// reachable. Marks them as reachable and adds them to the frontier. -static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) { - CHECK(arg); - ProcessPlatformAllocParam *param = - reinterpret_cast(arg); - chunk = GetUserBegin(chunk); - LsanMetadata m(chunk); - if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) { - u32 stack_id = m.stack_trace_id(); - uptr caller_pc = 0; - if (stack_id > 0) - caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map); - // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark - // it as reachable, as we can't properly report its allocation stack anyway. - if (caller_pc == 0 || (param->skip_linker_allocations && - linker->containsAddress(caller_pc))) { - m.set_tag(kReachable); - param->frontier->push_back(chunk); - } - } -} - -// Handles dynamically allocated TLS blocks by treating all chunks allocated -// from ld-linux.so as reachable. -// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. -// They are allocated with a __libc_memalign() call in allocate_and_init() -// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those -// blocks, but we can make sure they come from our own allocator by intercepting -// __libc_memalign(). On top of that, there is no easy way to reach them. Their -// addresses are stored in a dynamically allocated array (the DTV) which is -// referenced from the static TLS. Unfortunately, we can't just rely on the DTV -// being reachable from the static TLS, and the dynamic TLS being reachable from -// the DTV. This is because the initial DTV is allocated before our interception -// mechanism kicks in, and thus we don't recognize it as allocated memory. We -// can't special-case it either, since we don't know its size. -// Our solution is to include in the root set all allocations made from -// ld-linux.so (which is where allocate_and_init() is implemented). This is -// guaranteed to include all dynamic TLS blocks (and possibly other allocations -// which we don't care about). -void ProcessPlatformSpecificAllocations(Frontier *frontier) { - StackDepotReverseMap stack_depot_reverse_map; - ProcessPlatformAllocParam arg; - arg.frontier = frontier; - arg.stack_depot_reverse_map = &stack_depot_reverse_map; - arg.skip_linker_allocations = - flags()->use_tls && flags()->use_ld_allocations && linker != nullptr; - ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg); -} +void ProcessPlatformSpecificAllocations(Frontier *frontier) {} struct DoStopTheWorldParam { StopTheWorldCallback callback; diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index dfb5ab4cc..20ac389d5 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -87,6 +87,8 @@ void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; } +LoadedModule *GetLinker() { return nullptr; } + // Required on Linux for initialization of TLS behavior, but should not be // required on Darwin. void InitializePlatformSpecificModules() { -- cgit v1.2.1 From 02099e22a3330b4ce41d236b6c6af5dd6f70ffa9 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 19 Apr 2017 14:00:42 +0000 Subject: Implement function to get registers from suspended thread on darwin Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32182 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300691 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 45 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index ab33ba641..281db96f6 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -48,6 +48,29 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { CHECK(0 && "unimplemented"); } +#if defined(__x86_64__) +typedef x86_thread_state64_t regs_struct; + +#define SP_REG __rsp + +#elif defined(__aarch64__) +typedef arm_thread_state64_t regs_struct; + +# if __DARWIN_UNIX03 +# define SP_REG __sp +# else +# define SP_REG sp +# endif + +#elif defined(__i386) +typedef x86_thread_state32_t regs_struct; + +#define SP_REG __esp + +#else +#error "Unsupported architecture" +#endif + tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { CHECK_LT(index, threads_.size()); return threads_[index].tid; @@ -83,8 +106,26 @@ void SuspendedThreadsListMac::Append(thread_t thread) { PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( uptr index, uptr *buffer, uptr *sp) const { - CHECK(0 && "unimplemented"); - return REGISTERS_UNAVAILABLE_FATAL; + thread_t thread = GetThread(index); + regs_struct regs; + int err; + mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; + err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, + ®_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get registers for a thread\n"); + // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, + // or the thread does not exist. The other possible error case, + // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's + // still safe to proceed. + return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + internal_memcpy(buffer, ®s, sizeof(regs)); + *sp = regs.SP_REG; + + return REGISTERS_AVAILABLE; } uptr SuspendedThreadsListMac::RegisterCount() const { -- cgit v1.2.1 From 8b205e90b46fa52e41c48539776991c98c860670 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 19 Apr 2017 14:03:40 +0000 Subject: Let ubsan search UBSAN_SYMBOLIZER_PATH for llvm-symbolizer https://reviews.llvm.org/D27375 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300692 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_flags.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc index 3d404c1b7..8e1f40885 100644 --- a/lib/ubsan/ubsan_flags.cc +++ b/lib/ubsan/ubsan_flags.cc @@ -45,6 +45,7 @@ void InitializeFlags() { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.print_summary = false; + cf.external_symbolizer_path = GetEnv("UBSAN_SYMBOLIZER_PATH"); OverrideCommonFlags(cf); } -- cgit v1.2.1 From 88ccfa16b381f20856cb12a195b184a2e9e54f1b Mon Sep 17 00:00:00 2001 From: Keith Wyss Date: Wed, 19 Apr 2017 17:20:47 +0000 Subject: Skip tests that use 'llvm_xray' for standalone builds. Summary: Tests that generate output with compiler-rt and verify it with the llvm_xray command (built from the llvm tree) are extremely convenient, but compiler-rt can be built out of tree and llvm_xray is not built for every target. This change intends to disable tests for out of tree builds, but does nothing to detect whether llvm_xray can be found elsewhere on the path, is fresh enough, or is part of a build target for the in tree build. Tested: Tested that this didn't break check-xray. Haven't reproduced bots or standalone builds. Reviewers: dberris, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32150 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300716 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 1 + test/xray/TestCases/Linux/fdr-thread-order.cc | 2 ++ test/xray/lit.site.cfg.in | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index 9fb54ce7b..ae7ad863a 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -7,6 +7,7 @@ // RUN: rm fdr-unwrite-test-* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree #include "xray/xray_log_interface.h" #include diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 5edef2be2..814fb70b0 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -4,6 +4,8 @@ // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree + #include "xray/xray_log_interface.h" #include #include diff --git a/test/xray/lit.site.cfg.in b/test/xray/lit.site.cfg.in index ee0ffcad4..32d9f7f39 100644 --- a/test/xray/lit.site.cfg.in +++ b/test/xray/lit.site.cfg.in @@ -5,6 +5,10 @@ config.name_suffix = "@XRAY_TEST_CONFIG_SUFFIX@" config.xray_lit_source_dir = "@XRAY_LIT_SOURCE_DIR@" config.target_cflags = "@XRAY_TEST_TARGET_CFLAGS@" config.target_arch = "@XRAY_TEST_TARGET_ARCH@" +config.built_with_llvm = ("@COMPILER_RT_STANDALONE_BUILD@" == "FALSE") + +if config.built_with_llvm: + config.available_features.add('built-in-llvm-tree') # Load common config for all compiler-rt lit tests lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") -- cgit v1.2.1 From 7971e4d179df6069f7b3ffadd01d9a5cbee8df8a Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 19 Apr 2017 20:17:41 +0000 Subject: [sanitizer-coverage] remove run-time support for the deprecated -fsanitize-coverage=8bit-counters git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300745 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 19 ---- lib/dfsan/done_abilist.txt | 4 - .../sanitizer_coverage_interface.inc | 2 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 117 --------------------- test/asan/TestCases/coverage-levels.cc | 3 - 5 files changed, 145 deletions(-) diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index b44c5acde..c6ea0e674 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -45,25 +45,6 @@ extern "C" { // Set *data to the array of covered PCs and return the size of that array. // Some of the entries in *data will be zero. uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); - - // The coverage instrumentation may optionally provide imprecise counters. - // Rather than exposing the counter values to the user we instead map - // the counters to a bitset. - // Every counter is associated with 8 bits in the bitset. - // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+ - // The i-th bit is set to 1 if the counter value is in the i-th range. - // This counter-based coverage implementation is *not* thread-safe. - - // Returns the number of registered coverage counters. - uintptr_t __sanitizer_get_number_of_counters(); - // Updates the counter 'bitset', clears the counters and returns the number of - // new bits in 'bitset'. - // If 'bitset' is nullptr, only clears the counters. - // Otherwise 'bitset' should be at least - // __sanitizer_get_number_of_counters bytes long and 8-aligned. - uintptr_t - __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); - #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index a00dc5426..95a5af559 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -295,10 +295,6 @@ fun:__sanitizer_set_death_callback=uninstrumented fun:__sanitizer_set_death_callback=discard fun:__sanitizer_get_coverage_guards=uninstrumented fun:__sanitizer_get_coverage_guards=discard -fun:__sanitizer_get_number_of_counters=uninstrumented -fun:__sanitizer_get_number_of_counters=discard -fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented -fun:__sanitizer_update_counter_bitset_and_clear_counters=discard fun:__sanitizer_get_total_unique_coverage=uninstrumented fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_get_total_unique_coverage=uninstrumented diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index ae691bd9d..e92503d12 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -19,12 +19,10 @@ INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) -INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_FUNCTION(__sanitizer_reset_coverage) -INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_WEAK_FUNCTION(__sancov_default_options) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index e934af3ed..931ab0778 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -95,7 +95,6 @@ class CoverageData { void DumpCallerCalleePairs(); void DumpTrace(); void DumpAsBitSet(); - void DumpCounters(); void DumpOffsets(); void DumpAll(); @@ -105,10 +104,7 @@ class CoverageData { void InitializeGuardArray(s32 *guards); void InitializeGuards(s32 *guards, uptr n, const char *module_name, uptr caller_pc); - void InitializeCounters(u8 *counters, uptr n); void ReinitializeGuards(); - uptr GetNumberOf8bitCounters(); - uptr Update8bitCounterBitsetAndClearCounters(u8 *bitset); uptr *data(); uptr size() const; @@ -150,14 +146,6 @@ class CoverageData { InternalMmapVectorNoCtor comp_unit_name_vec; InternalMmapVectorNoCtor module_name_vec; - struct CounterAndSize { - u8 *counters; - uptr n; - }; - - InternalMmapVectorNoCtor counters_vec; - uptr num_8bit_counters; - // Caller-Callee (cc) array, size and current index. static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24); uptr **cc_array; @@ -232,8 +220,6 @@ void CoverageData::Enable() { GetMmapGranularity()); tr_event_array_size = kTrEventArrayMaxSize; tr_event_pointer = tr_event_array; - - num_8bit_counters = 0; } void CoverageData::InitializeGuardArray(s32 *guards) { @@ -341,15 +327,6 @@ void CoverageData::Extend(uptr npcs) { atomic_store(&pc_array_size, size, memory_order_release); } -void CoverageData::InitializeCounters(u8 *counters, uptr n) { - if (!counters) return; - CHECK_EQ(reinterpret_cast(counters) % 16, 0); - n = RoundUpTo(n, 16); // The compiler must ensure that counters is 16-aligned. - SpinMutexLock l(&mu); - counters_vec.push_back({counters, n}); - num_8bit_counters += n; -} - void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end) { auto sym = Symbolizer::GetOrInit(); @@ -458,64 +435,6 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], } } -uptr CoverageData::GetNumberOf8bitCounters() { - return num_8bit_counters; -} - -// Map every 8bit counter to a 8-bit bitset and clear the counter. -uptr CoverageData::Update8bitCounterBitsetAndClearCounters(u8 *bitset) { - uptr num_new_bits = 0; - uptr cur = 0; - // For better speed we map 8 counters to 8 bytes of bitset at once. - static const uptr kBatchSize = 8; - CHECK_EQ(reinterpret_cast(bitset) % kBatchSize, 0); - for (uptr i = 0, len = counters_vec.size(); i < len; i++) { - u8 *c = counters_vec[i].counters; - uptr n = counters_vec[i].n; - CHECK_EQ(n % 16, 0); - CHECK_EQ(cur % kBatchSize, 0); - CHECK_EQ(reinterpret_cast(c) % kBatchSize, 0); - if (!bitset) { - internal_bzero_aligned16(c, n); - cur += n; - continue; - } - for (uptr j = 0; j < n; j += kBatchSize, cur += kBatchSize) { - CHECK_LT(cur, num_8bit_counters); - u64 *pc64 = reinterpret_cast(c + j); - u64 *pb64 = reinterpret_cast(bitset + cur); - u64 c64 = *pc64; - u64 old_bits_64 = *pb64; - u64 new_bits_64 = old_bits_64; - if (c64) { - *pc64 = 0; - for (uptr k = 0; k < kBatchSize; k++) { - u64 x = (c64 >> (8 * k)) & 0xff; - if (x) { - u64 bit = 0; - /**/ if (x >= 128) bit = 128; - else if (x >= 32) bit = 64; - else if (x >= 16) bit = 32; - else if (x >= 8) bit = 16; - else if (x >= 4) bit = 8; - else if (x >= 3) bit = 4; - else if (x >= 2) bit = 2; - else if (x >= 1) bit = 1; - u64 mask = bit << (8 * k); - if (!(new_bits_64 & mask)) { - num_new_bits++; - new_bits_64 |= mask; - } - } - } - *pb64 = new_bits_64; - } - } - } - CHECK_EQ(cur, num_8bit_counters); - return num_new_bits; -} - uptr *CoverageData::data() { return pc_array; } @@ -698,30 +617,6 @@ void CoverageData::TraceBasicBlock(u32 *id) { tr_event_pointer++; } -void CoverageData::DumpCounters() { - if (!common_flags()->coverage_counters) return; - uptr n = coverage_data.GetNumberOf8bitCounters(); - if (!n) return; - InternalScopedBuffer bitset(n); - coverage_data.Update8bitCounterBitsetAndClearCounters(bitset.data()); - InternalScopedString path(kMaxPathLength); - - for (uptr m = 0; m < module_name_vec.size(); m++) { - auto r = module_name_vec[m]; - CHECK(r.copied_module_name); - CHECK_LE(r.beg, r.end); - CHECK_LE(r.end, size()); - const char *base_name = StripModuleName(r.copied_module_name); - fd_t fd = - CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov"); - if (fd == kInvalidFd) return; - WriteToFile(fd, bitset.data() + r.beg, r.end - r.beg); - CloseFile(fd); - VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg, - base_name); - } -} - void CoverageData::DumpAsBitSet() { if (!common_flags()->coverage_bitset) return; if (!size()) return; @@ -869,7 +764,6 @@ void CoverageData::DumpAll() { if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) return; DumpAsBitSet(); - DumpCounters(); DumpTrace(); DumpOffsets(); DumpCallerCalleePairs(); @@ -964,7 +858,6 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters, const char *comp_unit_name) { coverage_data.InitializeGuards(guards, npcs, comp_unit_name, GET_CALLER_PC()); - coverage_data.InitializeCounters(counters, npcs); if (!common_flags()->coverage_direct) return; if (SANITIZER_ANDROID && coverage_enabled) { // dlopen/dlclose interceptors do not work on Android, so we rely on @@ -1011,16 +904,6 @@ uptr __sanitizer_get_coverage_guards(uptr **data) { return coverage_data.size(); } -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_number_of_counters() { - return coverage_data.GetNumberOf8bitCounters(); -} - -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) { - return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset); -} - // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} diff --git a/test/asan/TestCases/coverage-levels.cc b/test/asan/TestCases/coverage-levels.cc index 83f7cf6f7..ae9ac4841 100644 --- a/test/asan/TestCases/coverage-levels.cc +++ b/test/asan/TestCases/coverage-levels.cc @@ -8,8 +8,6 @@ // RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 // RUN: %clangxx_asan -O1 -fsanitize-coverage=edge -mllvm -sanitizer-coverage-block-threshold=0 %s -o %t // RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 -// RUN: %clangxx_asan -O1 -fsanitize-coverage=edge,8bit-counters %s -o %t -// RUN: %env_asan_opts=coverage=1:coverage_counters=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK_COUNTERS // RUN: %env_asan_opts=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET @@ -31,4 +29,3 @@ int main(int argc, char **argv) { // CHECK3: 2 PCs written // CHECK3_NOBITSET-NOT: bitset of // CHECK3_NOPCS-NOT: PCs written -// CHECK_COUNTERS: CovDump: 3 counters written for -- cgit v1.2.1 From 70d9e16a1361333d4e5ae2433515f9084dc74c0b Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 19 Apr 2017 20:39:09 +0000 Subject: Turn symbolization on for ASan unit test. Summary: On PowerPC and ARM (possibly, need to verify), couple tests involving pthread_exit fail due to leaks detected by LSan. pthread_exit tries to perform unwinding that leads to dlopen'ing libgcc_s.so. dlopen mallocs "libgcc_s.so" string which confuses LSan, it fails to realize that this allocation happens in dynamic linker and should be ignored. Symbolized leak report is required to define a suppression for this known problem. Reviewers: eugenis Subscribers: aemerson, rengolin, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32194 Turn symbolization on for PPC and Thumb only to do not slow down other platforms. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300748 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test_main.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/asan/tests/asan_test_main.cc b/lib/asan/tests/asan_test_main.cc index 1071d4474..4b72f0aea 100644 --- a/lib/asan/tests/asan_test_main.cc +++ b/lib/asan/tests/asan_test_main.cc @@ -13,15 +13,26 @@ #include "asan_test_utils.h" #include "sanitizer_common/sanitizer_platform.h" -// Default ASAN_OPTIONS for the unit tests. Let's turn symbolication off to -// speed up testing (unit tests don't use it anyway). +// Default ASAN_OPTIONS for the unit tests. extern "C" const char* __asan_default_options() { #if SANITIZER_MAC // On Darwin, we default to `abort_on_error=1`, which would make tests run - // much slower. Let's override this and run lit tests with 'abort_on_error=0'. - // Also, make sure we do not overwhelm the syslog while testing. + // much slower. Let's override this and run lit tests with 'abort_on_error=0' + // and make sure we do not overwhelm the syslog while testing. Also, let's + // turn symbolization off to speed up testing, especially when not running + // with llvm-symbolizer but with atos. return "symbolize=false:abort_on_error=0:log_to_syslog=0"; +#elif SANITIZER_PPC || defined(__thumb__) + // On PowerPC and ARM Thumb, a couple tests involving pthread_exit fail due to + // leaks detected by LSan. pthread_exit tries to perform unwinding that leads + // to dlopen'ing libgcc_s.so. dlopen mallocs "libgcc_s.so" string which + // confuses LSan, it fails to realize that this allocation happens in dynamic + // linker and should be ignored. Symbolized leak report is required to define + // a suppression for this known problem. + return ""; #else + // Let's turn symbolization off to speed up testing (more than 3 times speedup + // observed). return "symbolize=false"; #endif } -- cgit v1.2.1 From 223b56caae57fb066c4fb29b31528d27e01b843a Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 19 Apr 2017 21:11:07 +0000 Subject: Implement StopTheWorld for Darwin Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32189 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300759 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 2 +- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 47 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 20ac389d5..a158b6512 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -146,7 +146,7 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { } void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { - CHECK(0 && "unimplemented"); + StopTheWorld(callback, argument); } } // namespace __lsan diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 281db96f6..20b876093 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -17,6 +17,8 @@ defined(__i386)) #include +#include +#include #include "sanitizer_stoptheworld.h" @@ -44,8 +46,51 @@ class SuspendedThreadsListMac : public SuspendedThreadsList { InternalMmapVector threads_; }; +struct RunThreadArgs { + StopTheWorldCallback callback; + void *argument; +}; + +void RunThread(void *arg) { + struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; + SuspendedThreadsListMac suspended_threads_list; + + mach_port_t task; + kern_return_t err = task_for_pid(mach_task_self(), internal_getpid(), &task); + if (err != KERN_SUCCESS) { + VReport(1, "Getting task from pid failed (errno %d).\n", err); + return; + } + + thread_array_t threads; + mach_msg_type_number_t num_threads; + + err = task_threads(task, &threads, &num_threads); + if (err != KERN_SUCCESS) { + VReport(1, "Failed to get threads for task (errno %d).\n", err); + return; + } + + thread_t thread_self = mach_thread_self(); + for (unsigned int i = 0; i < num_threads; ++i) { + if (threads[i] == thread_self) continue; + + thread_suspend(threads[i]); + suspended_threads_list.Append(threads[i]); + } + + run_args->callback(suspended_threads_list, run_args->argument); + + uptr num_suspended = suspended_threads_list.ThreadCount(); + for (unsigned int i = 0; i < num_suspended; ++i) { + thread_resume(suspended_threads_list.GetThread(i)); + } +} + void StopTheWorld(StopTheWorldCallback callback, void *argument) { - CHECK(0 && "unimplemented"); + struct RunThreadArgs arg = {callback, argument}; + pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); + internal_join_thread(run_thread); } #if defined(__x86_64__) -- cgit v1.2.1 From 60ceca6311c5611167f1b4639db19a83359c3674 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 19 Apr 2017 21:11:08 +0000 Subject: Make sure to scan mmap'd memory regions for root pointers on OS X Summary: In the general case, we only need to check for root regions inside the memory map returned by procmaps. However, on Darwin, we also need to check inside mmap'd regions, which aren't returned in the list of modules we get from procmaps. This patch refactors memory region scanning on darwin to reduce code duplication with the kernel alloc once page scan. Reviewers: kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32190 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300760 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 47 +++++++++++++++++++++++---------------------- lib/lsan/lsan_common.h | 9 +++++++++ lib/lsan/lsan_common_mac.cc | 31 ++++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 9d65918aa..d3385df7f 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -83,13 +83,10 @@ static SuppressionContext *GetSuppressionContext() { return suppression_ctx; } -struct RootRegion { - const void *begin; - uptr size; -}; - InternalMmapVector *root_regions; +InternalMmapVector const *GetRootRegions() { return root_regions; } + void InitializeRootRegions() { CHECK(!root_regions); ALIGNED(64) static char placeholder[sizeof(InternalMmapVector)]; @@ -291,23 +288,29 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } } -static void ProcessRootRegion(Frontier *frontier, uptr root_begin, - uptr root_end) { - MemoryMappingLayout proc_maps(/*cache_enabled*/true); +void ScanRootRegion(Frontier *frontier, RootRegion const &root_region, + uptr region_begin, uptr region_end, uptr prot) { + uptr intersection_begin = Max(root_region.begin, region_begin); + uptr intersection_end = Min(region_end, root_region.begin + root_region.size); + if (intersection_begin >= intersection_end) return; + bool is_readable = prot & MemoryMappingLayout::kProtectionRead; + LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", + root_region.begin, root_region.begin + root_region.size, + region_begin, region_end, + is_readable ? "readable" : "unreadable"); + if (is_readable) + ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT", + kReachable); +} + +static void ProcessRootRegion(Frontier *frontier, + RootRegion const &root_region) { + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); uptr begin, end, prot; while (proc_maps.Next(&begin, &end, /*offset*/ nullptr, /*filename*/ nullptr, /*filename_size*/ 0, &prot)) { - uptr intersection_begin = Max(root_begin, begin); - uptr intersection_end = Min(end, root_end); - if (intersection_begin >= intersection_end) continue; - bool is_readable = prot & MemoryMappingLayout::kProtectionRead; - LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", - root_begin, root_end, begin, end, - is_readable ? "readable" : "unreadable"); - if (is_readable) - ScanRangeForPointers(intersection_begin, intersection_end, frontier, - "ROOT", kReachable); + ScanRootRegion(frontier, root_region, begin, end, prot); } } @@ -316,9 +319,7 @@ static void ProcessRootRegions(Frontier *frontier) { if (!flags()->use_root_regions) return; CHECK(root_regions); for (uptr i = 0; i < root_regions->size(); i++) { - RootRegion region = (*root_regions)[i]; - uptr begin_addr = reinterpret_cast(region.begin); - ProcessRootRegion(frontier, begin_addr, begin_addr + region.size); + ProcessRootRegion(frontier, (*root_regions)[i]); } } @@ -775,7 +776,7 @@ void __lsan_register_root_region(const void *begin, uptr size) { #if CAN_SANITIZE_LEAKS BlockingMutexLock l(&global_mutex); CHECK(root_regions); - RootRegion region = {begin, size}; + RootRegion region = {reinterpret_cast(begin), size}; root_regions->push_back(region); VReport(1, "Registered root region at %p of size %llu\n", begin, size); #endif // CAN_SANITIZE_LEAKS @@ -789,7 +790,7 @@ void __lsan_unregister_root_region(const void *begin, uptr size) { bool removed = false; for (uptr i = 0; i < root_regions->size(); i++) { RootRegion region = (*root_regions)[i]; - if (region.begin == begin && region.size == size) { + if (region.begin == reinterpret_cast(begin) && region.size == size) { removed = true; uptr last_index = root_regions->size() - 1; (*root_regions)[i] = (*root_regions)[last_index]; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 88d5f1ca7..121b9c082 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -118,6 +118,15 @@ typedef InternalMmapVector Frontier; void InitializePlatformSpecificModules(); void ProcessGlobalRegions(Frontier *frontier); void ProcessPlatformSpecificAllocations(Frontier *frontier); + +struct RootRegion { + uptr begin; + uptr size; +}; + +InternalMmapVector const *GetRootRegions(); +void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, + uptr region_begin, uptr region_end, uptr prot); // Run stoptheworld while holding any platform-specific locks. void DoStopTheWorld(StopTheWorldCallback callback, void* argument); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index a158b6512..a9adcdfff 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -117,8 +117,6 @@ void ProcessGlobalRegions(Frontier *frontier) { } } -// libxpc stashes some pointers in the Kernel Alloc Once page, -// make sure not to report those as leaks. void ProcessPlatformSpecificAllocations(Frontier *frontier) { mach_port_name_t port; if (task_for_pid(mach_task_self(), internal_getpid(), &port) @@ -132,16 +130,37 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { kern_return_t err = KERN_SUCCESS; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + InternalMmapVector const *root_regions = GetRootRegions(); + while (err == KERN_SUCCESS) { struct vm_region_submap_info_64 info; err = vm_region_recurse_64(port, &address, &size, &depth, (vm_region_info_t)&info, &count); + + uptr end_address = address + size; + + // libxpc stashes some pointers in the Kernel Alloc Once page, + // make sure not to report those as leaks. if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { - ScanRangeForPointers(address, address + size, frontier, - "GLOBAL", kReachable); - return; + ScanRangeForPointers(address, end_address, frontier, "GLOBAL", + kReachable); } - address += size; + + // This additional root region scan is required on Darwin in order to + // detect root regions contained within mmap'd memory regions, because + // the Darwin implementation of sanitizer_procmaps traverses images + // as loaded by dyld, and not the complete set of all memory regions. + // + // TODO(fjricci) - remove this once sanitizer_procmaps_mac has the same + // behavior as sanitizer_procmaps_linux and traverses all memory regions + if (flags()->use_root_regions) { + for (uptr i = 0; i < root_regions->size(); i++) { + ScanRootRegion(frontier, (*root_regions)[i], address, end_address, + info.protection); + } + } + + address = end_address; } } -- cgit v1.2.1 From 42bd2ce3de6931f43cca12c5471aef1a64d31b79 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 19 Apr 2017 21:25:06 +0000 Subject: Fixup style from r300760 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300765 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index d3385df7f..3523049d3 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -83,7 +83,7 @@ static SuppressionContext *GetSuppressionContext() { return suppression_ctx; } -InternalMmapVector *root_regions; +static InternalMmapVector *root_regions; InternalMmapVector const *GetRootRegions() { return root_regions; } @@ -288,7 +288,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } } -void ScanRootRegion(Frontier *frontier, RootRegion const &root_region, +void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, uptr region_begin, uptr region_end, uptr prot) { uptr intersection_begin = Max(root_region.begin, region_begin); uptr intersection_end = Min(region_end, root_region.begin + root_region.size); @@ -304,7 +304,7 @@ void ScanRootRegion(Frontier *frontier, RootRegion const &root_region, } static void ProcessRootRegion(Frontier *frontier, - RootRegion const &root_region) { + const RootRegion &root_region) { MemoryMappingLayout proc_maps(/*cache_enabled*/ true); uptr begin, end, prot; while (proc_maps.Next(&begin, &end, -- cgit v1.2.1 From 2409e866b62af4d24a0aa743e4e3b8bd7d8a4484 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 19 Apr 2017 21:30:46 +0000 Subject: [sanitizer-coverage] remove run-time support for -fsanitize-coverage=trace-bb git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300766 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_coverage_interface.inc | 2 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 111 --------------------- test/asan/TestCases/coverage-tracing.cc | 51 ---------- 3 files changed, 164 deletions(-) delete mode 100644 test/asan/TestCases/coverage-tracing.cc diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index e92503d12..04726f5b2 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -13,8 +13,6 @@ INTERFACE_FUNCTION(__sanitizer_cov_dump) INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) INTERFACE_FUNCTION(__sanitizer_cov_init) INTERFACE_FUNCTION(__sanitizer_cov_module_init) -INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) -INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 931ab0778..c056b0668 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -93,14 +93,10 @@ class CoverageData { void IndirCall(uptr caller, uptr callee, uptr callee_cache[], uptr cache_size); void DumpCallerCalleePairs(); - void DumpTrace(); void DumpAsBitSet(); void DumpOffsets(); void DumpAll(); - ALWAYS_INLINE - void TraceBasicBlock(u32 *id); - void InitializeGuardArray(s32 *guards); void InitializeGuards(s32 *guards, uptr n, const char *module_name, uptr caller_pc); @@ -152,23 +148,6 @@ class CoverageData { atomic_uintptr_t cc_array_index; atomic_uintptr_t cc_array_size; - // Tracing event array, size and current pointer. - // We record all events (basic block entries) in a global buffer of u32 - // values. Each such value is the index in pc_array. - // So far the tracing is highly experimental: - // - not thread-safe; - // - does not support long traces; - // - not tuned for performance. - // Windows doesn't do overcommit (committed virtual memory costs swap), so - // programs can't reliably map such large amounts of virtual memory. - // TODO(etienneb): Find a way to support coverage of larger executable -static const uptr kTrEventArrayMaxSize = - (SANITIZER_WORDSIZE == 32 || SANITIZER_WINDOWS) ? 1 << 22 : 1 << 30; - u32 *tr_event_array; - uptr tr_event_array_size; - u32 *tr_event_pointer; - static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); - StaticSpinMutex mu; }; @@ -210,16 +189,6 @@ void CoverageData::Enable() { sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed); atomic_store(&cc_array_index, 0, memory_order_relaxed); - - // Allocate tr_event_array with a guard page at the end. - tr_event_array = reinterpret_cast(MmapNoReserveOrDie( - sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(), - "CovInit::tr_event_array")); - MprotectNoAccess( - reinterpret_cast(&tr_event_array[kTrEventArrayMaxSize]), - GetMmapGranularity()); - tr_event_array_size = kTrEventArrayMaxSize; - tr_event_pointer = tr_event_array; } void CoverageData::InitializeGuardArray(s32 *guards) { @@ -241,13 +210,6 @@ void CoverageData::Disable() { UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize); cc_array = nullptr; } - if (tr_event_array) { - UnmapOrDie(tr_event_array, - sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + - GetMmapGranularity()); - tr_event_array = nullptr; - tr_event_pointer = nullptr; - } if (pc_fd != kInvalidFd) { CloseFile(pc_fd); pc_fd = kInvalidFd; @@ -515,55 +477,6 @@ static fd_t CovOpenFile(InternalScopedString *path, bool packed, return fd; } -// Dump trace PCs and trace events into two separate files. -void CoverageData::DumpTrace() { - uptr max_idx = tr_event_pointer - tr_event_array; - if (!max_idx) return; - auto sym = Symbolizer::GetOrInit(); - if (!sym) - return; - InternalScopedString out(32 << 20); - for (uptr i = 0, n = size(); i < n; i++) { - const char *module_name = ""; - uptr module_address = 0; - sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name, - &module_address); - out.append("%s 0x%zx\n", module_name, module_address); - } - InternalScopedString path(kMaxPathLength); - fd_t fd = CovOpenFile(&path, false, "trace-points"); - if (fd == kInvalidFd) return; - WriteToFile(fd, out.data(), out.length()); - CloseFile(fd); - - fd = CovOpenFile(&path, false, "trace-compunits"); - if (fd == kInvalidFd) return; - out.clear(); - for (uptr i = 0; i < comp_unit_name_vec.size(); i++) - out.append("%s\n", comp_unit_name_vec[i].copied_module_name); - WriteToFile(fd, out.data(), out.length()); - CloseFile(fd); - - fd = CovOpenFile(&path, false, "trace-events"); - if (fd == kInvalidFd) return; - uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]); - u8 *event_bytes = reinterpret_cast(tr_event_array); - // The trace file could be huge, and may not be written with a single syscall. - while (bytes_to_write) { - uptr actually_written; - if (WriteToFile(fd, event_bytes, bytes_to_write, &actually_written) && - actually_written <= bytes_to_write) { - bytes_to_write -= actually_written; - event_bytes += actually_written; - } else { - break; - } - } - CloseFile(fd); - VReport(1, " CovDump: Trace: %zd PCs written\n", size()); - VReport(1, " CovDump: Trace: %zd Events written\n", max_idx); -} - // This function dumps the caller=>callee pairs into a file as a sequence of // lines like "module_name offset". void CoverageData::DumpCallerCalleePairs() { @@ -604,19 +517,6 @@ void CoverageData::DumpCallerCalleePairs() { VReport(1, " CovDump: %zd caller-callee pairs written\n", total); } -// Record the current PC into the event buffer. -// Every event is a u32 value (index in tr_pc_array_index) so we compute -// it once and then cache in the provided 'cache' storage. -// -// This function will eventually be inlined by the compiler. -void CoverageData::TraceBasicBlock(u32 *id) { - // Will trap here if - // 1. coverage is not enabled at run-time. - // 2. The array tr_event_array is full. - *tr_event_pointer = *id - 1; - tr_event_pointer++; -} - void CoverageData::DumpAsBitSet() { if (!common_flags()->coverage_bitset) return; if (!size()) return; @@ -764,7 +664,6 @@ void CoverageData::DumpAll() { if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) return; DumpAsBitSet(); - DumpTrace(); DumpOffsets(); DumpCallerCalleePairs(); } @@ -880,16 +779,6 @@ uptr __sanitizer_get_total_unique_caller_callee_pairs() { return atomic_load(&caller_callee_counter, memory_order_relaxed); } -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_func_enter(u32 *id) { - __sanitizer_cov_with_check(id); - coverage_data.TraceBasicBlock(id); -} -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_basic_block(u32 *id) { - __sanitizer_cov_with_check(id); - coverage_data.TraceBasicBlock(id); -} SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_reset_coverage() { ResetGlobalCounters(); diff --git a/test/asan/TestCases/coverage-tracing.cc b/test/asan/TestCases/coverage-tracing.cc deleted file mode 100644 index 278cfb141..000000000 --- a/test/asan/TestCases/coverage-tracing.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Test -fsanitize-coverage=trace-bb -// -// RUN: %clangxx_asan -O1 -fsanitize-coverage=func,trace-bb %s -o %t -// RUN: rm -rf %T/coverage-tracing -// RUN: mkdir %T/coverage-tracing -// RUN: cd %T/coverage-tracing -// RUN: A=x; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK1; mv trace-points.*.sancov $A.points -// RUN: A=f; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points -// RUN: A=b; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points -// RUN: A=bf; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points -// RUN: A=fb; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points -// RUN: A=ffb; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points -// RUN: A=fff; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points -// RUN: A=bbf; %env_asan_opts=coverage=1:verbosity=1 %run %t $A 100 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK301; mv trace-points.*.sancov $A.points -// RUN: diff f.points fff.points -// RUN: diff bf.points fb.points -// RUN: diff bf.points ffb.points -// RUN: diff bf.points bbf.points -// RUN: not diff x.points f.points -// RUN: not diff x.points b.points -// RUN: not diff x.points bf.points -// RUN: not diff f.points b.points -// RUN: not diff f.points bf.points -// RUN: not diff b.points bf.points -// RUN: rm -rf %T/coverage-tracing -// -// REQUIRES: asan-64-bits, shell -// UNSUPPORTED: android - -#include -volatile int sink; -__attribute__((noinline)) void foo() { sink++; } -__attribute__((noinline)) void bar() { sink++; } - -int main(int argc, char **argv) { - if (argc != 3) return 0; - int n = strtol(argv[2], 0, 10); - while (n-- > 0) { - for (int i = 0; argv[1][i]; i++) { - if (argv[1][i] == 'f') foo(); - else if (argv[1][i] == 'b') bar(); - } - } -} - -// CHECK: CovDump: Trace: 3 PCs written -// CHECK1: CovDump: Trace: 1 Events written -// CHECK2: CovDump: Trace: 2 Events written -// CHECK3: CovDump: Trace: 3 Events written -// CHECK4: CovDump: Trace: 4 Events written -// CHECK301: CovDump: Trace: 301 Events written -- cgit v1.2.1 From 104db270df900d2465b8e448292ff90fee6269a0 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 19 Apr 2017 22:24:03 +0000 Subject: [sanitizer-coverage] remove run-time support for -fsanitize-coverage=indirect-calls git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300775 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 2 - lib/dfsan/done_abilist.txt | 4 - .../sanitizer_coverage_interface.inc | 2 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 105 --------------------- .../asan/TestCases/Posix/coverage-caller-callee.cc | 75 --------------- .../coverage-caller-callee-total-count.cc | 42 --------- 6 files changed, 230 deletions(-) delete mode 100644 test/asan/TestCases/Posix/coverage-caller-callee.cc delete mode 100644 test/asan/TestCases/coverage-caller-callee-total-count.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index c6ea0e674..adf0960d2 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -35,8 +35,6 @@ extern "C" { // Get the number of unique covered blocks (or edges). // This can be useful for coverage-directed in-process fuzzers. uintptr_t __sanitizer_get_total_unique_coverage(); - // Get the number of unique indirect caller-callee pairs. - uintptr_t __sanitizer_get_total_unique_caller_callee_pairs(); // Reset the basic-block (edge) coverage to the initial state. // Useful for in-process fuzzing to start collecting coverage from scratch. diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index 95a5af559..d3ac553db 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -285,10 +285,6 @@ fun:__sanitizer_cov_module_init=uninstrumented fun:__sanitizer_cov_module_init=discard fun:__sanitizer_cov_with_check=uninstrumented fun:__sanitizer_cov_with_check=discard -fun:__sanitizer_cov_indir_call16=uninstrumented -fun:__sanitizer_cov_indir_call16=discard -fun:__sanitizer_cov_indir_call16=uninstrumented -fun:__sanitizer_cov_indir_call16=discard fun:__sanitizer_reset_coverage=uninstrumented fun:__sanitizer_reset_coverage=discard fun:__sanitizer_set_death_callback=uninstrumented diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 04726f5b2..139a8b989 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -10,14 +10,12 @@ //===----------------------------------------------------------------------===// INTERFACE_FUNCTION(__sanitizer_cov) INTERFACE_FUNCTION(__sanitizer_cov_dump) -INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) INTERFACE_FUNCTION(__sanitizer_cov_init) INTERFACE_FUNCTION(__sanitizer_cov_module_init) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) -INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_FUNCTION(__sanitizer_reset_coverage) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index c056b0668..d3447a553 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -57,11 +57,9 @@ static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32; static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. static atomic_uintptr_t coverage_counter; -static atomic_uintptr_t caller_callee_counter; static void ResetGlobalCounters() { return atomic_store(&coverage_counter, 0, memory_order_relaxed); - return atomic_store(&caller_callee_counter, 0, memory_order_relaxed); } // pc_array is the array containing the covered PCs. @@ -90,9 +88,6 @@ class CoverageData { void AfterFork(int child_pid); void Extend(uptr npcs); void Add(uptr pc, u32 *guard); - void IndirCall(uptr caller, uptr callee, uptr callee_cache[], - uptr cache_size); - void DumpCallerCalleePairs(); void DumpAsBitSet(); void DumpOffsets(); void DumpAll(); @@ -142,12 +137,6 @@ class CoverageData { InternalMmapVectorNoCtor comp_unit_name_vec; InternalMmapVectorNoCtor module_name_vec; - // Caller-Callee (cc) array, size and current index. - static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24); - uptr **cc_array; - atomic_uintptr_t cc_array_index; - atomic_uintptr_t cc_array_size; - StaticSpinMutex mu; }; @@ -184,11 +173,6 @@ void CoverageData::Enable() { } else { atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); } - - cc_array = reinterpret_cast(MmapNoReserveOrDie( - sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); - atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed); - atomic_store(&cc_array_index, 0, memory_order_relaxed); } void CoverageData::InitializeGuardArray(s32 *guards) { @@ -206,10 +190,6 @@ void CoverageData::Disable() { UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize); pc_array = nullptr; } - if (cc_array) { - UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize); - cc_array = nullptr; - } if (pc_fd != kInvalidFd) { CloseFile(pc_fd); pc_fd = kInvalidFd; @@ -363,40 +343,6 @@ void CoverageData::Add(uptr pc, u32 *guard) { pc_array[idx] = BundlePcAndCounter(pc, counter); } -// Registers a pair caller=>callee. -// When a given caller is seen for the first time, the callee_cache is added -// to the global array cc_array, callee_cache[0] is set to caller and -// callee_cache[1] is set to cache_size. -// Then we are trying to add callee to callee_cache [2,cache_size) if it is -// not there yet. -// If the cache is full we drop the callee (may want to fix this later). -void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], - uptr cache_size) { - if (!cc_array) return; - atomic_uintptr_t *atomic_callee_cache = - reinterpret_cast(callee_cache); - uptr zero = 0; - if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller, - memory_order_seq_cst)) { - uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed); - CHECK_LT(idx * sizeof(uptr), - atomic_load(&cc_array_size, memory_order_acquire)); - callee_cache[1] = cache_size; - cc_array[idx] = callee_cache; - } - CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller); - for (uptr i = 2; i < cache_size; i++) { - uptr was = 0; - if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee, - memory_order_seq_cst)) { - atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed); - return; - } - if (was == callee) // Already have this callee. - return; - } -} - uptr *CoverageData::data() { return pc_array; } @@ -477,46 +423,6 @@ static fd_t CovOpenFile(InternalScopedString *path, bool packed, return fd; } -// This function dumps the caller=>callee pairs into a file as a sequence of -// lines like "module_name offset". -void CoverageData::DumpCallerCalleePairs() { - uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed); - if (!max_idx) return; - auto sym = Symbolizer::GetOrInit(); - if (!sym) - return; - InternalScopedString out(32 << 20); - uptr total = 0; - for (uptr i = 0; i < max_idx; i++) { - uptr *cc_cache = cc_array[i]; - CHECK(cc_cache); - uptr caller = cc_cache[0]; - uptr n_callees = cc_cache[1]; - const char *caller_module_name = ""; - uptr caller_module_address = 0; - sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name, - &caller_module_address); - for (uptr j = 2; j < n_callees; j++) { - uptr callee = cc_cache[j]; - if (!callee) break; - total++; - const char *callee_module_name = ""; - uptr callee_module_address = 0; - sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name, - &callee_module_address); - out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name, - caller_module_address, callee_module_name, - callee_module_address); - } - } - InternalScopedString path(kMaxPathLength); - fd_t fd = CovOpenFile(&path, false, "caller-callee"); - if (fd == kInvalidFd) return; - WriteToFile(fd, out.data(), out.length()); - CloseFile(fd); - VReport(1, " CovDump: %zd caller-callee pairs written\n", total); -} - void CoverageData::DumpAsBitSet() { if (!common_flags()->coverage_bitset) return; if (!size()) return; @@ -665,7 +571,6 @@ void CoverageData::DumpAll() { return; DumpAsBitSet(); DumpOffsets(); - DumpCallerCalleePairs(); } void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -739,11 +644,6 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) { coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), guard); } -SANITIZER_INTERFACE_ATTRIBUTE void -__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) { - coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), - callee, callee_cache16, 16); -} SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { coverage_enabled = true; coverage_dir = common_flags()->coverage_dir; @@ -774,11 +674,6 @@ uptr __sanitizer_get_total_unique_coverage() { return atomic_load(&coverage_counter, memory_order_relaxed); } -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_total_unique_caller_callee_pairs() { - return atomic_load(&caller_callee_counter, memory_order_relaxed); -} - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_reset_coverage() { ResetGlobalCounters(); diff --git a/test/asan/TestCases/Posix/coverage-caller-callee.cc b/test/asan/TestCases/Posix/coverage-caller-callee.cc deleted file mode 100644 index fb8b9bf92..000000000 --- a/test/asan/TestCases/Posix/coverage-caller-callee.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Test caller-callee coverage with large number of threads -// and various numbers of callers and callees. - -// RUN: %clangxx_asan -fsanitize-coverage=edge,indirect-calls %s -o %t -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-10-1 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 9 2 2>&1 | FileCheck %s --check-prefix=CHECK-9-2 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 7 3 2>&1 | FileCheck %s --check-prefix=CHECK-7-3 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 17 1 2>&1 | FileCheck %s --check-prefix=CHECK-17-1 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 15 2 2>&1 | FileCheck %s --check-prefix=CHECK-15-2 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 18 3 2>&1 | FileCheck %s --check-prefix=CHECK-18-3 -// RUN: rm -f caller-callee*.sancov -// -// REQUIRES: asan-64-bits -// UNSUPPORTED: android -// -// CHECK-10-1: CovDump: 10 caller-callee pairs written -// CHECK-9-2: CovDump: 18 caller-callee pairs written -// CHECK-7-3: CovDump: 21 caller-callee pairs written -// CHECK-17-1: CovDump: 14 caller-callee pairs written -// CHECK-15-2: CovDump: 28 caller-callee pairs written -// CHECK-18-3: CovDump: 42 caller-callee pairs written - -#include -#include -#include -int P = 0; -struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}}; -struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo3 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo4 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo5 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo6 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo7 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo8 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo9 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo10 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo11 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo12 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo13 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo14 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo15 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo16 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo17 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo18 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo19 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; - -Foo *foo[20] = { - new Foo, new Foo1, new Foo2, new Foo3, new Foo4, new Foo5, new Foo6, - new Foo7, new Foo8, new Foo9, new Foo10, new Foo11, new Foo12, new Foo13, - new Foo14, new Foo15, new Foo16, new Foo17, new Foo18, new Foo19, -}; - -int n_functions = 10; -int n_callers = 2; - -void *Thread(void *arg) { - if (n_callers >= 1) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); - if (n_callers >= 2) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); - if (n_callers >= 3) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); - return arg; -} - -int main(int argc, char **argv) { - if (argc >= 2) - n_functions = atoi(argv[1]); - if (argc >= 3) - n_callers = atoi(argv[2]); - const int kNumThreads = 16; - pthread_t t[kNumThreads]; - for (int i = 0; i < kNumThreads; i++) - pthread_create(&t[i], 0, Thread, 0); - for (int i = 0; i < kNumThreads; i++) - pthread_join(t[i], 0); -} diff --git a/test/asan/TestCases/coverage-caller-callee-total-count.cc b/test/asan/TestCases/coverage-caller-callee-total-count.cc deleted file mode 100644 index 955ffe5a9..000000000 --- a/test/asan/TestCases/coverage-caller-callee-total-count.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Test __sanitizer_get_total_unique_coverage for caller-callee coverage - -// RUN: %clangxx_asan -fsanitize-coverage=edge,indirect-calls %s -o %t -// RUN: %env_asan_opts=coverage=1 %run %t -// RUN: rm -f caller-callee*.sancov -// -// REQUIRES: asan-64-bits - -#include -#include -#include -int P = 0; -struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}}; -struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; -struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; - -Foo *foo[3] = {new Foo, new Foo1, new Foo2}; - -uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) { - uintptr_t new_total = __sanitizer_get_total_unique_caller_callee_pairs(); - fprintf(stderr, "Caller-Callee: old %zd new %zd\n", old_total, new_total); - assert(new_total > old_total); - return new_total; -} - -int main(int argc, char **argv) { - uintptr_t total = __sanitizer_get_total_unique_caller_callee_pairs(); - foo[0]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); - foo[1]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); - foo[2]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); - // Ok, called every function once. - // Now call them again from another call site. Should get new coverage. - foo[0]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); - foo[1]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); - foo[2]->f(); - total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); -} -- cgit v1.2.1 From 00e8357e522e7327483bfd438f4db4ee17ffa544 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 19 Apr 2017 23:05:53 +0000 Subject: [sanitizer-coverage] remove more unused code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300780 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 8 --- lib/dfsan/done_abilist.txt | 6 --- .../sanitizer_coverage_interface.inc | 2 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 18 ------- test/asan/TestCases/coverage-reset.cc | 63 ---------------------- 5 files changed, 97 deletions(-) delete mode 100644 test/asan/TestCases/coverage-reset.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index adf0960d2..911a3e854 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -35,14 +35,6 @@ extern "C" { // Get the number of unique covered blocks (or edges). // This can be useful for coverage-directed in-process fuzzers. uintptr_t __sanitizer_get_total_unique_coverage(); - - // Reset the basic-block (edge) coverage to the initial state. - // Useful for in-process fuzzing to start collecting coverage from scratch. - // Experimental, will likely not work for multi-threaded process. - void __sanitizer_reset_coverage(); - // Set *data to the array of covered PCs and return the size of that array. - // Some of the entries in *data will be zero. - uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index d3ac553db..cbbedbc33 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -285,14 +285,8 @@ fun:__sanitizer_cov_module_init=uninstrumented fun:__sanitizer_cov_module_init=discard fun:__sanitizer_cov_with_check=uninstrumented fun:__sanitizer_cov_with_check=discard -fun:__sanitizer_reset_coverage=uninstrumented -fun:__sanitizer_reset_coverage=discard fun:__sanitizer_set_death_callback=uninstrumented fun:__sanitizer_set_death_callback=discard -fun:__sanitizer_get_coverage_guards=uninstrumented -fun:__sanitizer_get_coverage_guards=discard -fun:__sanitizer_get_total_unique_coverage=uninstrumented -fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_get_total_unique_coverage=uninstrumented fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 139a8b989..42b4d3aba 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -15,10 +15,8 @@ INTERFACE_FUNCTION(__sanitizer_cov_module_init) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) -INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) -INTERFACE_FUNCTION(__sanitizer_reset_coverage) INTERFACE_WEAK_FUNCTION(__sancov_default_options) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index d3447a553..bb59c344e 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -58,10 +58,6 @@ static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. static atomic_uintptr_t coverage_counter; -static void ResetGlobalCounters() { - return atomic_store(&coverage_counter, 0, memory_order_relaxed); -} - // pc_array is the array containing the covered PCs. // To make the pc_array thread- and async-signal-safe it has to be large enough. // 128M counters "ought to be enough for anybody" (4M on 32-bit). @@ -674,20 +670,6 @@ uptr __sanitizer_get_total_unique_coverage() { return atomic_load(&coverage_counter, memory_order_relaxed); } -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_reset_coverage() { - ResetGlobalCounters(); - coverage_data.ReinitializeGuards(); - internal_bzero_aligned16( - coverage_data.data(), - RoundUpTo(coverage_data.size() * sizeof(coverage_data.data()[0]), 16)); -} -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_coverage_guards(uptr **data) { - *data = coverage_data.data(); - return coverage_data.size(); -} - // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} diff --git a/test/asan/TestCases/coverage-reset.cc b/test/asan/TestCases/coverage-reset.cc deleted file mode 100644 index 11c5ef66e..000000000 --- a/test/asan/TestCases/coverage-reset.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Test __sanitizer_reset_coverage(). - -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -// RUN: %env_asan_opts=coverage=1 %run %t - -// https://github.com/google/sanitizers/issues/618 -// UNSUPPORTED: android - -#include -#include -#include -static volatile int sink; -__attribute__((noinline)) void bar() { sink = 2; } -__attribute__((noinline)) void foo() { sink = 1; } - -// In MSVC 2015, printf is an inline function, which causes this test to fail as -// it introduces an extra coverage point. Define away printf on that platform to -// avoid the issue. -#if _MSC_VER >= 1900 -# define printf(arg, ...) -#endif - -#define GET_AND_PRINT_COVERAGE() \ - bitset = 0; \ - for (size_t i = 0; i < n_guards; i++) \ - if (guards[i]) bitset |= 1U << i; \ - printf("line %d: bitset %zd total: %zd\n", __LINE__, bitset, \ - __sanitizer_get_total_unique_coverage()); - -#define IS_POWER_OF_TWO(a) ((a & ((a) - 1)) == 0) - -int main() { - size_t *guards = 0; - size_t bitset; - size_t n_guards = __sanitizer_get_coverage_guards(&guards); - - GET_AND_PRINT_COVERAGE(); - size_t main_bit = bitset; - assert(IS_POWER_OF_TWO(main_bit)); - - foo(); - GET_AND_PRINT_COVERAGE(); - size_t foo_bit = bitset & ~main_bit; - assert(IS_POWER_OF_TWO(foo_bit)); - - bar(); - GET_AND_PRINT_COVERAGE(); - size_t bar_bit = bitset & ~(main_bit | foo_bit); - assert(IS_POWER_OF_TWO(bar_bit)); - - __sanitizer_reset_coverage(); - assert(__sanitizer_get_total_unique_coverage() == 0); - GET_AND_PRINT_COVERAGE(); - assert(bitset == 0); - - foo(); - GET_AND_PRINT_COVERAGE(); - assert(bitset == foo_bit); - - bar(); - GET_AND_PRINT_COVERAGE(); - assert(bitset == (foo_bit | bar_bit)); -} -- cgit v1.2.1 From ea443214cce6273e3310755a56e5bb22087eae6f Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 20 Apr 2017 03:26:04 +0000 Subject: [XRay][compiler-rt] Cleanup CFI/CFA annotations on trampolines Summary: This is a follow-up to D32202. While the previous change (D32202) did fix the stack alignment issue, we were still at a weird state in terms of the CFI/CFA directives (as the offsets were wrong). This change cleans up the SAVE/RESTORE macros for the trampoline, accounting the stack pointer adjustments with less instructions and with some clearer math. We note that the offsets will be different on the exit trampolines, because we don't typically 'call' into this trampoline and we only ever jump into them (i.e. treated as a tail call that's patched in at runtime). Reviewers: eugenis, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32214 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300815 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_trampoline_x86_64.S | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index 772eafbec..847ecef8d 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -16,7 +16,12 @@ #include "../builtins/assembly.h" .macro SAVE_REGISTERS - subq $184, %rsp + subq $192, %rsp + .cfi_def_cfa_offset 200 + // At this point, the stack pointer should be aligned to an 8-byte boundary, + // because any call instructions that come after this will add another 8 + // bytes and therefore align it to 16-bytes. + movq %rbp, 184(%rsp) movupd %xmm0, 168(%rsp) movupd %xmm1, 152(%rsp) movupd %xmm2, 136(%rsp) @@ -35,6 +40,7 @@ .endm .macro RESTORE_REGISTERS + movq 184(%rsp), %rbp movupd 168(%rsp), %xmm0 movupd 152(%rsp), %xmm1 movupd 136(%rsp), %xmm2 @@ -50,7 +56,8 @@ movq 16(%rsp), %rcx movq 8(%rsp), %r8 movq 0(%rsp), %r9 - addq $184, %rsp + addq $192, %rsp + .cfi_def_cfa_offset 8 .endm .text @@ -64,10 +71,7 @@ __xray_FunctionEntry: .cfi_startproc - pushq %rbp - .cfi_def_cfa_offset 16 SAVE_REGISTERS - .cfi_def_cfa_offset 200 // This load has to be atomic, it's concurrent with __xray_patch(). // On x86/amd64, a simple (type-aligned) MOV instruction is enough. @@ -81,7 +85,6 @@ __xray_FunctionEntry: callq *%rax .Ltmp0: RESTORE_REGISTERS - popq %rbp retq .Ltmp1: .size __xray_FunctionEntry, .Ltmp1-__xray_FunctionEntry @@ -97,10 +100,9 @@ __xray_FunctionExit: // Save the important registers first. Since we're assuming that this // function is only jumped into, we only preserve the registers for // returning. - pushq %rbp - .cfi_def_cfa_offset 16 - subq $48, %rsp + subq $56, %rsp .cfi_def_cfa_offset 64 + movq %rbp, 48(%rsp) movupd %xmm0, 32(%rsp) movupd %xmm1, 16(%rsp) movq %rax, 8(%rsp) @@ -114,12 +116,13 @@ __xray_FunctionExit: callq *%rax .Ltmp2: // Restore the important registers. + movq 48(%rsp), %rbp movupd 32(%rsp), %xmm0 movupd 16(%rsp), %xmm1 movq 8(%rsp), %rax movq 0(%rsp), %rdx - addq $48, %rsp - popq %rbp + addq $56, %rsp + .cfi_def_cfa_offset 8 retq .Ltmp3: .size __xray_FunctionExit, .Ltmp3-__xray_FunctionExit @@ -136,10 +139,7 @@ __xray_FunctionTailExit: // this is an exit. In the future, we will introduce a new entry type that // differentiates between a normal exit and a tail exit, but we'd have to do // this and increment the version number for the header. - pushq %rbp - .cfi_def_cfa_offset 16 SAVE_REGISTERS - .cfi_def_cfa_offset 200 movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax testq %rax,%rax @@ -151,7 +151,6 @@ __xray_FunctionTailExit: .Ltmp4: RESTORE_REGISTERS - popq %rbp retq .Ltmp5: .size __xray_FunctionTailExit, .Ltmp5-__xray_FunctionTailExit @@ -164,10 +163,7 @@ __xray_FunctionTailExit: .type __xray_ArgLoggerEntry,@function __xray_ArgLoggerEntry: .cfi_startproc - pushq %rbp - .cfi_def_cfa_offset 16 SAVE_REGISTERS - .cfi_def_cfa_offset 200 // Again, these function pointer loads must be atomic; MOV is fine. movq _ZN6__xray13XRayArgLoggerE(%rip), %rax @@ -187,7 +183,6 @@ __xray_ArgLoggerEntry: .Larg1entryFail: RESTORE_REGISTERS - popq %rbp retq .Larg1entryEnd: -- cgit v1.2.1 From 35ad9be15fc08a4ebcf312ba30becb8cc788a555 Mon Sep 17 00:00:00 2001 From: Keith Wyss Date: Thu, 20 Apr 2017 05:59:26 +0000 Subject: [XRay] [compiler-rt] - Fix standalone and non-deterministic test issue Summary: The thread order test fails sometimes my machine independently of standalone build. From testing both standalone and in-tree build, I see I configured it wrong. The other hypothesis for an issue is that cold starts can interfere with whether record unwriting happens. Once this happens more than once, we can naively FileCheck on the wrong test output, which compounds the issue. While "rm blah.* || true" will print to stderr if the glob can't expand, this is mostly harmless and makes sure earlier failing tests don't sabotage us. Example failure: --- header: version: 1 type: 1 constant-tsc: true nonstop-tsc: true cycle-frequency: 3800000000 records: - { type: 0, func-id: 1, function: 'f1()', cpu: 9, thread: 21377, kind: function-enter, tsc: 2413745203147228 } - { type: 0, func-id: 1, function: 'f1()', cpu: 9, thread: 21377, kind: function-exit, tsc: 2413745203304238 } ... The CMAKE related change fixes the expectation that COMPILER_RT_STANDALONE_BUILD will be explicitly FALSE instead of empty string when it is not "TRUE". Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32259 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300822 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-mode.cc | 2 ++ test/xray/TestCases/Linux/fdr-thread-order.cc | 3 ++- test/xray/lit.site.cfg.in | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index ae7ad863a..f1e087673 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -1,4 +1,6 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm fdr-logging-test-* || true +// RUN: rm fdr-unwrite-test-* || true // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-unwrite-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=5000" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix=TRACE diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 814fb70b0..b43a0fe40 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -1,5 +1,6 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s +// RUN: rm fdr-thread-order.* || true +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s // RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. diff --git a/test/xray/lit.site.cfg.in b/test/xray/lit.site.cfg.in index 32d9f7f39..73c4eff6e 100644 --- a/test/xray/lit.site.cfg.in +++ b/test/xray/lit.site.cfg.in @@ -5,8 +5,11 @@ config.name_suffix = "@XRAY_TEST_CONFIG_SUFFIX@" config.xray_lit_source_dir = "@XRAY_LIT_SOURCE_DIR@" config.target_cflags = "@XRAY_TEST_TARGET_CFLAGS@" config.target_arch = "@XRAY_TEST_TARGET_ARCH@" -config.built_with_llvm = ("@COMPILER_RT_STANDALONE_BUILD@" == "FALSE") +config.built_with_llvm = ("@COMPILER_RT_STANDALONE_BUILD@" != "TRUE") +# TODO: Look into whether we can run a capability test on the standalone build to +# see whether it can run 'llvm-xray convert' instead of turning off tests for a +# standalone build. if config.built_with_llvm: config.available_features.add('built-in-llvm-tree') -- cgit v1.2.1 From ac9e6ea23b96de782d512ffd7a0dd71e88c0798d Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 20 Apr 2017 15:11:00 +0000 Subject: [scudo] Minor changes and refactoring Summary: This is part of D31947 that is being split into several smaller changes. This one deals with all the minor changes, more specifically: - Rename some variables and functions to make their purpose clearer; - Reorder some code; - Mark the hot termination incurring checks as `UNLIKELY`; if they happen, the program will die anyway; - Add a `getScudoChunk` method; - Add an `eraseHeader` method to ScudoChunk that will clear a header with 0s; - Add a parameter to `allocate` to know if the allocated chunk should be filled with zeros. This allows `calloc` to not have to call `GetActuallyAllocatedSize`; more changes to get rid of this function on the hot paths will follow; - reallocate was missing a check to verify that the pointer is properly aligned on `MinAlignment`; - The `Stats` in the secondary have to be protected by a mutex as the `Add` and `Sub` methods are actually not atomic; - The software CRC32 function was moved to the header to allow for inlining. Reviewers: dvyukov, alekseyshl, kcc Reviewed By: dvyukov Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32242 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300846 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 203 +++++++++++++++++----------------- lib/scudo/scudo_allocator.h | 3 +- lib/scudo/scudo_allocator_secondary.h | 17 ++- lib/scudo/scudo_utils.cpp | 54 --------- lib/scudo/scudo_utils.h | 56 +++++++++- 5 files changed, 171 insertions(+), 162 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index dab6abedc..6bf2fa1e5 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -22,8 +22,7 @@ #include #include - -#include +#include namespace __scudo { @@ -60,9 +59,9 @@ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap, typedef SizeClassAllocatorLocalCache AllocatorCache; typedef ScudoLargeMmapAllocator SecondaryAllocator; typedef CombinedAllocator - ScudoAllocator; + ScudoBackendAllocator; -static ScudoAllocator &getAllocator(); +static ScudoBackendAllocator &getBackendAllocator(); static thread_local Xorshift128Plus Prng; // Global static cookie, initialized at start-up. @@ -101,9 +100,10 @@ struct ScudoChunk : UnpackedHeader { // Returns the usable size for a chunk, meaning the amount of bytes from the // beginning of the user data to the end of the backend allocated chunk. uptr getUsableSize(UnpackedHeader *Header) { - uptr Size = getAllocator().GetActuallyAllocatedSize(getAllocBeg(Header)); + uptr Size = getBackendAllocator().GetActuallyAllocatedSize( + getAllocBeg(Header)); if (Size == 0) - return Size; + return 0; return Size - AlignedChunkHeaderSize - (Header->Offset << MinAlignmentLog); } @@ -120,7 +120,8 @@ struct ScudoChunk : UnpackedHeader { return static_cast(Crc); } - // Checks the validity of a chunk by verifying its checksum. + // Checks the validity of a chunk by verifying its checksum. It doesn't + // incur termination in the event of an invalid chunk. bool isValid() { UnpackedHeader NewUnpackedHeader; const AtomicPackedHeader *AtomicHeader = @@ -130,13 +131,27 @@ struct ScudoChunk : UnpackedHeader { return (NewUnpackedHeader.Checksum == computeChecksum(&NewUnpackedHeader)); } + // Nulls out a chunk header. When returning the chunk to the backend, there + // is no need to store a valid ChunkAvailable header, as this would be + // computationally expensive. Zeroing out serves the same purpose by making + // the header invalid. In the extremely rare event where 0 would be a valid + // checksum for the chunk, the state of the chunk is ChunkAvailable anyway. + COMPILER_CHECK(ChunkAvailable == 0); + void eraseHeader() { + PackedHeader NullPackedHeader = 0; + AtomicPackedHeader *AtomicHeader = + reinterpret_cast(this); + atomic_store_relaxed(AtomicHeader, NullPackedHeader); + } + // Loads and unpacks the header, verifying the checksum in the process. void loadHeader(UnpackedHeader *NewUnpackedHeader) const { const AtomicPackedHeader *AtomicHeader = reinterpret_cast(this); PackedHeader NewPackedHeader = atomic_load_relaxed(AtomicHeader); *NewUnpackedHeader = bit_cast(NewPackedHeader); - if (NewUnpackedHeader->Checksum != computeChecksum(NewUnpackedHeader)) { + if (UNLIKELY(NewUnpackedHeader->Checksum != + computeChecksum(NewUnpackedHeader))) { dieWithMessage("ERROR: corrupted chunk header at address %p\n", this); } } @@ -160,15 +175,19 @@ struct ScudoChunk : UnpackedHeader { PackedHeader OldPackedHeader = bit_cast(*OldUnpackedHeader); AtomicPackedHeader *AtomicHeader = reinterpret_cast(this); - if (!atomic_compare_exchange_strong(AtomicHeader, - &OldPackedHeader, - NewPackedHeader, - memory_order_relaxed)) { + if (UNLIKELY(!atomic_compare_exchange_strong(AtomicHeader, + &OldPackedHeader, + NewPackedHeader, + memory_order_relaxed))) { dieWithMessage("ERROR: race on chunk header at address %p\n", this); } } }; +ScudoChunk *getScudoChunk(uptr UserBeg) { + return reinterpret_cast(UserBeg - AlignedChunkHeaderSize); +} + static bool ScudoInitIsRunning = false; static pthread_once_t GlobalInited = PTHREAD_ONCE_INIT; @@ -190,7 +209,7 @@ static void teardownThread(void *p) { return; } drainQuarantine(); - getAllocator().DestroyCache(&Cache); + getBackendAllocator().DestroyCache(&Cache); ThreadTornDown = true; } @@ -223,7 +242,7 @@ static void initGlobal() { static void NOINLINE initThread() { pthread_once(&GlobalInited, initGlobal); pthread_setspecific(PThreadKey, reinterpret_cast(1)); - getAllocator().InitCache(&Cache); + getBackendAllocator().InitCache(&Cache); ThreadInited = true; } @@ -235,38 +254,31 @@ struct QuarantineCallback { void Recycle(ScudoChunk *Chunk) { UnpackedHeader Header; Chunk->loadHeader(&Header); - if (Header.State != ChunkQuarantine) { + if (UNLIKELY(Header.State != ChunkQuarantine)) { dieWithMessage("ERROR: invalid chunk state when recycling address %p\n", Chunk); } + Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(&Header); - getAllocator().Deallocate(Cache_, Ptr); + getBackendAllocator().Deallocate(Cache_, Ptr); } /// Internal quarantine allocation and deallocation functions. void *Allocate(uptr Size) { - // The internal quarantine memory cannot be protected by us. But the only - // structures allocated are QuarantineBatch, that are 8KB for x64. So we - // will use mmap for those, and given that Deallocate doesn't pass a size - // in, we enforce the size of the allocation to be sizeof(QuarantineBatch). - // TODO(kostyak): switching to mmap impacts greatly performances, we have - // to find another solution - // CHECK_EQ(Size, sizeof(QuarantineBatch)); - // return MmapOrDie(Size, "QuarantineBatch"); - return getAllocator().Allocate(Cache_, Size, 1, false); + // TODO(kostyak): figure out the best way to protect the batches. + return getBackendAllocator().Allocate(Cache_, Size, MinAlignment); } void Deallocate(void *Ptr) { - // UnmapOrDie(Ptr, sizeof(QuarantineBatch)); - getAllocator().Deallocate(Cache_, Ptr); + getBackendAllocator().Deallocate(Cache_, Ptr); } AllocatorCache *Cache_; }; typedef Quarantine ScudoQuarantine; -typedef ScudoQuarantine::Cache QuarantineCache; -static thread_local QuarantineCache ThreadQuarantineCache; +typedef ScudoQuarantine::Cache ScudoQuarantineCache; +static thread_local ScudoQuarantineCache ThreadQuarantineCache; void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) { MayReturnNull = cf->allocator_may_return_null; @@ -288,11 +300,11 @@ void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const { f->ZeroContents = ZeroContents; } -struct Allocator { +struct ScudoAllocator { static const uptr MaxAllowedMallocSize = FIRST_32_SECOND_64(2UL << 30, 1ULL << 40); - ScudoAllocator BackendAllocator; + ScudoBackendAllocator BackendAllocator; ScudoQuarantine AllocatorQuarantine; // The fallback caches are used when the thread local caches have been @@ -300,13 +312,13 @@ struct Allocator { // be accessed by different threads. StaticSpinMutex FallbackMutex; AllocatorCache FallbackAllocatorCache; - QuarantineCache FallbackQuarantineCache; + ScudoQuarantineCache FallbackQuarantineCache; bool DeallocationTypeMismatch; bool ZeroContents; bool DeleteSizeMismatch; - explicit Allocator(LinkerInitialized) + explicit ScudoAllocator(LinkerInitialized) : AllocatorQuarantine(LINKER_INITIALIZED), FallbackQuarantineCache(LINKER_INITIALIZED) {} @@ -349,37 +361,37 @@ struct Allocator { static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); BackendAllocator.InitCache(&FallbackAllocatorCache); - Cookie = Prng.Next(); + Cookie = Prng.getNext(); } - // Helper function that checks for a valid Scudo chunk. + // Helper function that checks for a valid Scudo chunk. nullptr isn't. bool isValidPointer(const void *UserPtr) { if (UNLIKELY(!ThreadInited)) initThread(); - uptr ChunkBeg = reinterpret_cast(UserPtr); - if (!IsAligned(ChunkBeg, MinAlignment)) { + if (!UserPtr) return false; - } - ScudoChunk *Chunk = - reinterpret_cast(ChunkBeg - AlignedChunkHeaderSize); - return Chunk->isValid(); + uptr UserBeg = reinterpret_cast(UserPtr); + if (!IsAligned(UserBeg, MinAlignment)) + return false; + return getScudoChunk(UserBeg)->isValid(); } // Allocates a chunk. - void *allocate(uptr Size, uptr Alignment, AllocType Type) { + void *allocate(uptr Size, uptr Alignment, AllocType Type, + bool ForceZeroContents = false) { if (UNLIKELY(!ThreadInited)) initThread(); - if (!IsPowerOfTwo(Alignment)) { + if (UNLIKELY(!IsPowerOfTwo(Alignment))) { dieWithMessage("ERROR: alignment is not a power of 2\n"); } if (Alignment > MaxAlignment) return BackendAllocator.ReturnNullOrDieOnBadRequest(); if (Alignment < MinAlignment) Alignment = MinAlignment; - if (Size == 0) - Size = 1; if (Size >= MaxAllowedMallocSize) return BackendAllocator.ReturnNullOrDieOnBadRequest(); + if (Size == 0) + Size = 1; uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize; if (Alignment > MinAlignment) @@ -395,13 +407,13 @@ struct Allocator { bool FromPrimary = PrimaryAllocator::CanAllocate(NeededSize, MinAlignment); void *Ptr; + uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; if (LIKELY(!ThreadTornDown)) { - Ptr = BackendAllocator.Allocate(&Cache, NeededSize, - FromPrimary ? MinAlignment : Alignment); + Ptr = BackendAllocator.Allocate(&Cache, NeededSize, AllocationAlignment); } else { SpinMutexLock l(&FallbackMutex); Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, NeededSize, - FromPrimary ? MinAlignment : Alignment); + AllocationAlignment); } if (!Ptr) return BackendAllocator.ReturnNullOrDieOnOOM(); @@ -419,27 +431,23 @@ struct Allocator { uptr ActuallyAllocatedSize = BackendAllocator.GetActuallyAllocatedSize( reinterpret_cast(AllocBeg)); // If requested, we will zero out the entire contents of the returned chunk. - if (ZeroContents && FromPrimary) + if ((ForceZeroContents || ZeroContents) && FromPrimary) memset(Ptr, 0, ActuallyAllocatedSize); - uptr ChunkBeg = AllocBeg + AlignedChunkHeaderSize; - if (!IsAligned(ChunkBeg, Alignment)) - ChunkBeg = RoundUpTo(ChunkBeg, Alignment); - CHECK_LE(ChunkBeg + Size, AllocBeg + NeededSize); - ScudoChunk *Chunk = - reinterpret_cast(ChunkBeg - AlignedChunkHeaderSize); + uptr UserBeg = AllocBeg + AlignedChunkHeaderSize; + if (!IsAligned(UserBeg, Alignment)) + UserBeg = RoundUpTo(UserBeg, Alignment); + CHECK_LE(UserBeg + Size, AllocBeg + NeededSize); UnpackedHeader Header = {}; Header.State = ChunkAllocated; - uptr Offset = ChunkBeg - AlignedChunkHeaderSize - AllocBeg; + uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg; Header.Offset = Offset >> MinAlignmentLog; Header.AllocType = Type; Header.UnusedBytes = ActuallyAllocatedSize - Offset - AlignedChunkHeaderSize - Size; - Header.Salt = static_cast(Prng.Next()); - Chunk->storeHeader(&Header); - void *UserPtr = reinterpret_cast(ChunkBeg); - // TODO(kostyak): hooks sound like a terrible idea security wise but might - // be needed for things to work properly? + Header.Salt = static_cast(Prng.getNext()); + getScudoChunk(UserBeg)->storeHeader(&Header); + void *UserPtr = reinterpret_cast(UserBeg); // if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(UserPtr, Size); return UserPtr; } @@ -449,45 +457,44 @@ struct Allocator { void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { if (UNLIKELY(!ThreadInited)) initThread(); - // TODO(kostyak): see hook comment above // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr); if (!UserPtr) return; - uptr ChunkBeg = reinterpret_cast(UserPtr); - if (!IsAligned(ChunkBeg, MinAlignment)) { + uptr UserBeg = reinterpret_cast(UserPtr); + if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) { dieWithMessage("ERROR: attempted to deallocate a chunk not properly " "aligned at address %p\n", UserPtr); } - ScudoChunk *Chunk = - reinterpret_cast(ChunkBeg - AlignedChunkHeaderSize); + ScudoChunk *Chunk = getScudoChunk(UserBeg); UnpackedHeader OldHeader; Chunk->loadHeader(&OldHeader); - if (OldHeader.State != ChunkAllocated) { + if (UNLIKELY(OldHeader.State != ChunkAllocated)) { dieWithMessage("ERROR: invalid chunk state when deallocating address " "%p\n", UserPtr); } - uptr UsableSize = Chunk->getUsableSize(&OldHeader); - UnpackedHeader NewHeader = OldHeader; - NewHeader.State = ChunkQuarantine; - Chunk->compareExchangeHeader(&NewHeader, &OldHeader); if (DeallocationTypeMismatch) { // The deallocation type has to match the allocation one. - if (NewHeader.AllocType != Type) { + if (OldHeader.AllocType != Type) { // With the exception of memalign'd Chunks, that can be still be free'd. - if (NewHeader.AllocType != FromMemalign || Type != FromMalloc) { + if (OldHeader.AllocType != FromMemalign || Type != FromMalloc) { dieWithMessage("ERROR: allocation type mismatch on address %p\n", - Chunk); + UserPtr); } } } + uptr UsableSize = Chunk->getUsableSize(&OldHeader); uptr Size = UsableSize - OldHeader.UnusedBytes; if (DeleteSizeMismatch) { if (DeleteSize && DeleteSize != Size) { dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", - Chunk); + UserPtr); } } + UnpackedHeader NewHeader = OldHeader; + NewHeader.State = ChunkQuarantine; + Chunk->compareExchangeHeader(&NewHeader, &OldHeader); + if (LIKELY(!ThreadTornDown)) { AllocatorQuarantine.Put(&ThreadQuarantineCache, QuarantineCallback(&Cache), Chunk, UsableSize); @@ -504,24 +511,27 @@ struct Allocator { void *reallocate(void *OldPtr, uptr NewSize) { if (UNLIKELY(!ThreadInited)) initThread(); - uptr ChunkBeg = reinterpret_cast(OldPtr); - ScudoChunk *Chunk = - reinterpret_cast(ChunkBeg - AlignedChunkHeaderSize); + uptr UserBeg = reinterpret_cast(OldPtr); + if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) { + dieWithMessage("ERROR: attempted to reallocate a chunk not properly " + "aligned at address %p\n", OldPtr); + } + ScudoChunk *Chunk = getScudoChunk(UserBeg); UnpackedHeader OldHeader; Chunk->loadHeader(&OldHeader); - if (OldHeader.State != ChunkAllocated) { + if (UNLIKELY(OldHeader.State != ChunkAllocated)) { dieWithMessage("ERROR: invalid chunk state when reallocating address " "%p\n", OldPtr); } - uptr Size = Chunk->getUsableSize(&OldHeader); - if (OldHeader.AllocType != FromMalloc) { + if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { dieWithMessage("ERROR: invalid chunk type when reallocating address %p\n", - Chunk); + OldPtr); } + uptr UsableSize = Chunk->getUsableSize(&OldHeader); UnpackedHeader NewHeader = OldHeader; // The new size still fits in the current chunk. - if (NewSize <= Size) { - NewHeader.UnusedBytes = Size - NewSize; + if (NewSize <= UsableSize) { + NewHeader.UnusedBytes = UsableSize - NewSize; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); return OldPtr; } @@ -529,18 +539,18 @@ struct Allocator { // old one. void *NewPtr = allocate(NewSize, MinAlignment, FromMalloc); if (NewPtr) { - uptr OldSize = Size - OldHeader.UnusedBytes; + uptr OldSize = UsableSize - OldHeader.UnusedBytes; memcpy(NewPtr, OldPtr, Min(NewSize, OldSize)); NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); if (LIKELY(!ThreadTornDown)) { AllocatorQuarantine.Put(&ThreadQuarantineCache, - QuarantineCallback(&Cache), Chunk, Size); + QuarantineCallback(&Cache), Chunk, UsableSize); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, QuarantineCallback(&FallbackAllocatorCache), - Chunk, Size); + Chunk, UsableSize); } } return NewPtr; @@ -552,13 +562,12 @@ struct Allocator { initThread(); if (!Ptr) return 0; - uptr ChunkBeg = reinterpret_cast(Ptr); - ScudoChunk *Chunk = - reinterpret_cast(ChunkBeg - AlignedChunkHeaderSize); + uptr UserBeg = reinterpret_cast(Ptr); + ScudoChunk *Chunk = getScudoChunk(UserBeg); UnpackedHeader Header; Chunk->loadHeader(&Header); // Getting the usable size of a chunk only makes sense if it's allocated. - if (Header.State != ChunkAllocated) { + if (UNLIKELY(Header.State != ChunkAllocated)) { dieWithMessage("ERROR: invalid chunk state when sizing address %p\n", Ptr); } @@ -569,13 +578,9 @@ struct Allocator { if (UNLIKELY(!ThreadInited)) initThread(); uptr Total = NMemB * Size; - if (Size != 0 && Total / Size != NMemB) // Overflow check + if (Size != 0 && Total / Size != NMemB) // Overflow check return BackendAllocator.ReturnNullOrDieOnBadRequest(); - void *Ptr = allocate(Total, MinAlignment, FromMalloc); - // If ZeroContents, the content of the chunk has already been zero'd out. - if (!ZeroContents && Ptr && BackendAllocator.FromPrimary(Ptr)) - memset(Ptr, 0, getUsableSize(Ptr)); - return Ptr; + return allocate(Total, MinAlignment, FromMalloc, true); } void drainQuarantine() { @@ -592,9 +597,9 @@ struct Allocator { } }; -static Allocator Instance(LINKER_INITIALIZED); +static ScudoAllocator Instance(LINKER_INITIALIZED); -static ScudoAllocator &getAllocator() { +static ScudoBackendAllocator &getBackendAllocator() { return Instance.BackendAllocator; } diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 5f5225b36..1696e1389 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -41,8 +41,7 @@ enum ChunkState : u8 { // using functions such as GetBlockBegin, that is fairly costly. Our first // implementation used the MetaData as well, which offers the advantage of // being stored away from the chunk itself, but accessing it was costly as -// well. The header will be atomically loaded and stored using the 16-byte -// primitives offered by the platform (likely requires cmpxchg16b support). +// well. The header will be atomically loaded and stored. typedef u64 PackedHeader; struct UnpackedHeader { u64 Checksum : 16; diff --git a/lib/scudo/scudo_allocator_secondary.h b/lib/scudo/scudo_allocator_secondary.h index b984f0db4..fbc7f247d 100644 --- a/lib/scudo/scudo_allocator_secondary.h +++ b/lib/scudo/scudo_allocator_secondary.h @@ -88,8 +88,11 @@ class ScudoLargeMmapAllocator { // The primary adds the whole class size to the stats when allocating a // chunk, so we will do something similar here. But we will not account for // the guard pages. - Stats->Add(AllocatorStatAllocated, MapSize - 2 * PageSize); - Stats->Add(AllocatorStatMapped, MapSize - 2 * PageSize); + { + SpinMutexLock l(&StatsMutex); + Stats->Add(AllocatorStatAllocated, MapSize - 2 * PageSize); + Stats->Add(AllocatorStatMapped, MapSize - 2 * PageSize); + } return reinterpret_cast(UserBeg); } @@ -112,8 +115,11 @@ class ScudoLargeMmapAllocator { void Deallocate(AllocatorStats *Stats, void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); - Stats->Sub(AllocatorStatAllocated, Header->MapSize - 2 * PageSize); - Stats->Sub(AllocatorStatMapped, Header->MapSize - 2 * PageSize); + { + SpinMutexLock l(&StatsMutex); + Stats->Sub(AllocatorStatAllocated, Header->MapSize - 2 * PageSize); + Stats->Sub(AllocatorStatMapped, Header->MapSize - 2 * PageSize); + } UnmapOrDie(reinterpret_cast(Header->MapBeg), Header->MapSize); } @@ -127,7 +133,7 @@ class ScudoLargeMmapAllocator { uptr GetActuallyAllocatedSize(void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); - // Deduct PageSize as MapEnd includes the trailing guard page. + // Deduct PageSize as MapSize includes the trailing guard page. uptr MapEnd = Header->MapBeg + Header->MapSize - PageSize; return MapEnd - reinterpret_cast(Ptr); } @@ -182,6 +188,7 @@ class ScudoLargeMmapAllocator { const uptr SecondaryHeaderSize = sizeof(SecondaryHeader); const uptr HeadersSize = SecondaryHeaderSize + AlignedChunkHeaderSize; uptr PageSize; + SpinMutex StatsMutex; atomic_uint8_t MayReturnNull; }; diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index 4e2f6e08e..98bd591aa 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -159,58 +159,4 @@ Xorshift128Plus::Xorshift128Plus() { fillRandom(reinterpret_cast(State), sizeof(State)); } -const static u32 CRC32Table[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -u32 computeSoftwareCRC32(u32 Crc, uptr Data) { - for (uptr i = 0; i < sizeof(Data); i++) { - Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8); - Data >>= 8; - } - return Crc; -} - } // namespace __scudo diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index 5082d79f6..f30c86125 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -41,7 +41,7 @@ bool testCPUFeature(CPUFeature feature); struct Xorshift128Plus { public: Xorshift128Plus(); - u64 Next() { + u64 getNext() { u64 x = State[0]; const u64 y = State[1]; State[0] = y; @@ -58,7 +58,59 @@ enum : u8 { CRC32Hardware = 1, }; -u32 computeSoftwareCRC32(u32 Crc, uptr Data); +const static u32 CRC32Table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +INLINE u32 computeSoftwareCRC32(u32 Crc, uptr Data) { + for (uptr i = 0; i < sizeof(Data); i++) { + Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8); + Data >>= 8; + } + return Crc; +} } // namespace __scudo -- cgit v1.2.1 From ba4bcb3734311880844d4802a46333de9040d996 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 20 Apr 2017 18:07:17 +0000 Subject: [scudo] Remove GetActuallyAllocatedSize calls from the fast path Summary: GetActuallyAllocatedSize is actually expensive. In order to avoid calling this function in the malloc/free fast path, we change the Scudo chunk header to store the size of the chunk, if from the Primary, or the amount of unused bytes if from the Secondary. This way, we only have to call the culprit function for Secondary backed allocations (and still in realloc). The performance gain on a singly threaded pure malloc/free benchmark exercising the Primary allocator is above 5%. Reviewers: alekseyshl, kcc, dvyukov Reviewed By: dvyukov Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32299 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300861 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 59 ++++++++++++++++++++++++++++--------------- lib/scudo/scudo_allocator.h | 20 ++++++++------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 6bf2fa1e5..9812fc0f5 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -341,14 +341,14 @@ struct ScudoAllocator { dieWithMessage("ERROR: the maximum possible offset doesn't fit in the " "header\n"); } - // Verify that we can fit the maximum amount of unused bytes in the header. - // Given that the Secondary fits the allocation to a page, the worst case - // scenario happens in the Primary. It will depend on the second to last - // and last class sizes, as well as the dynamic base for the Primary. The - // following is an over-approximation that works for our needs. - uptr MaxUnusedBytes = SizeClassMap::kMaxSize - 1 - AlignedChunkHeaderSize; - Header.UnusedBytes = MaxUnusedBytes; - if (Header.UnusedBytes != MaxUnusedBytes) { + // Verify that we can fit the maximum size or amount of unused bytes in the + // header. Given that the Secondary fits the allocation to a page, the worst + // case scenario happens in the Primary. It will depend on the second to + // last and last class sizes, as well as the dynamic base for the Primary. + // The following is an over-approximation that works for our needs. + uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1; + Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes; + if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) { dieWithMessage("ERROR: the maximum possible unused bytes doesn't fit in " "the header\n"); } @@ -428,11 +428,9 @@ struct ScudoAllocator { NeededSize -= Alignment; } - uptr ActuallyAllocatedSize = BackendAllocator.GetActuallyAllocatedSize( - reinterpret_cast(AllocBeg)); // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && FromPrimary) - memset(Ptr, 0, ActuallyAllocatedSize); + memset(Ptr, 0, BackendAllocator.GetActuallyAllocatedSize(Ptr)); uptr UserBeg = AllocBeg + AlignedChunkHeaderSize; if (!IsAligned(UserBeg, Alignment)) @@ -443,8 +441,18 @@ struct ScudoAllocator { uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg; Header.Offset = Offset >> MinAlignmentLog; Header.AllocType = Type; - Header.UnusedBytes = ActuallyAllocatedSize - Offset - - AlignedChunkHeaderSize - Size; + if (FromPrimary) { + Header.FromPrimary = FromPrimary; + Header.SizeOrUnusedBytes = Size; + } else { + // The secondary fits the allocations to a page, so the amount of unused + // bytes is the difference between the end of the user allocation and the + // next page boundary. + uptr PageSize = GetPageSizeCached(); + uptr TrailingBytes = (UserBeg + Size) & (PageSize - 1); + if (TrailingBytes) + Header.SizeOrUnusedBytes = PageSize - TrailingBytes; + } Header.Salt = static_cast(Prng.getNext()); getScudoChunk(UserBeg)->storeHeader(&Header); void *UserPtr = reinterpret_cast(UserBeg); @@ -482,8 +490,8 @@ struct ScudoAllocator { } } } - uptr UsableSize = Chunk->getUsableSize(&OldHeader); - uptr Size = UsableSize - OldHeader.UnusedBytes; + uptr Size = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : + Chunk->getUsableSize(&OldHeader) - OldHeader.SizeOrUnusedBytes; if (DeleteSizeMismatch) { if (DeleteSize && DeleteSize != Size) { dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", @@ -495,14 +503,19 @@ struct ScudoAllocator { NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); + // If a small memory amount was allocated with a larger alignment, we want + // to take that into account. Otherwise the Quarantine would be filled with + // tiny chunks, taking a lot of VA memory. This an approximation of the + // usable size, that allows us to not call GetActuallyAllocatedSize. + uptr LiableSize = Size + (OldHeader.Offset << MinAlignment); if (LIKELY(!ThreadTornDown)) { AllocatorQuarantine.Put(&ThreadQuarantineCache, - QuarantineCallback(&Cache), Chunk, UsableSize); + QuarantineCallback(&Cache), Chunk, LiableSize); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, QuarantineCallback(&FallbackAllocatorCache), - Chunk, UsableSize); + Chunk, LiableSize); } } @@ -529,9 +542,12 @@ struct ScudoAllocator { } uptr UsableSize = Chunk->getUsableSize(&OldHeader); UnpackedHeader NewHeader = OldHeader; - // The new size still fits in the current chunk. - if (NewSize <= UsableSize) { - NewHeader.UnusedBytes = UsableSize - NewSize; + // The new size still fits in the current chunk, and the size difference + // is reasonable. + if (NewSize <= UsableSize && + (UsableSize - NewSize) < (SizeClassMap::kMaxSize / 2)) { + NewHeader.SizeOrUnusedBytes = + OldHeader.FromPrimary ? NewSize : UsableSize - NewSize; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); return OldPtr; } @@ -539,7 +555,8 @@ struct ScudoAllocator { // old one. void *NewPtr = allocate(NewSize, MinAlignment, FromMalloc); if (NewPtr) { - uptr OldSize = UsableSize - OldHeader.UnusedBytes; + uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : + UsableSize - OldHeader.SizeOrUnusedBytes; memcpy(NewPtr, OldPtr, Min(NewSize, OldSize)); NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 1696e1389..e7428f170 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -44,15 +44,17 @@ enum ChunkState : u8 { // well. The header will be atomically loaded and stored. typedef u64 PackedHeader; struct UnpackedHeader { - u64 Checksum : 16; - u64 UnusedBytes : 20; // Needed for reallocation purposes. - u64 State : 2; // available, allocated, or quarantined - u64 AllocType : 2; // malloc, new, new[], or memalign - u64 Offset : 16; // Offset from the beginning of the backend - // allocation to the beginning of the chunk itself, - // in multiples of MinAlignment. See comment about - // its maximum value and test in init(). - u64 Salt : 8; + u64 Checksum : 16; + u64 SizeOrUnusedBytes : 19; // Size for Primary backed allocations, amount of + // unused bytes in the chunk for Secondary ones. + u64 FromPrimary : 1; + u64 State : 2; // available, allocated, or quarantined + u64 AllocType : 2; // malloc, new, new[], or memalign + u64 Offset : 16; // Offset from the beginning of the backend + // allocation to the beginning of the chunk + // itself, in multiples of MinAlignment. See + /// comment about its maximum value and in init(). + u64 Salt : 8; }; typedef atomic_uint64_t AtomicPackedHeader; -- cgit v1.2.1 From 4491af204031a352be69227e28142ed55a90c04d Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 20 Apr 2017 20:54:19 +0000 Subject: Define a suppression for known leaks on pthread_exit call. Summary: Refer to D32194 for the context. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32303 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300886 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test_main.cc | 9 +++------ lib/lsan/lsan_common.cc | 6 ++++++ lib/sanitizer_common/sanitizer_platform.h | 11 +++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/asan/tests/asan_test_main.cc b/lib/asan/tests/asan_test_main.cc index 4b72f0aea..0c1b93c7f 100644 --- a/lib/asan/tests/asan_test_main.cc +++ b/lib/asan/tests/asan_test_main.cc @@ -22,13 +22,10 @@ extern "C" const char* __asan_default_options() { // turn symbolization off to speed up testing, especially when not running // with llvm-symbolizer but with atos. return "symbolize=false:abort_on_error=0:log_to_syslog=0"; -#elif SANITIZER_PPC || defined(__thumb__) +#elif SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // On PowerPC and ARM Thumb, a couple tests involving pthread_exit fail due to - // leaks detected by LSan. pthread_exit tries to perform unwinding that leads - // to dlopen'ing libgcc_s.so. dlopen mallocs "libgcc_s.so" string which - // confuses LSan, it fails to realize that this allocation happens in dynamic - // linker and should be ignored. Symbolized leak report is required to define - // a suppression for this known problem. + // leaks detected by LSan. Symbolized leak report is required to apply a + // suppression for this known problem. return ""; #else // Let's turn symbolization off to speed up testing (more than 3 times speedup diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 3523049d3..d54f56958 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -848,7 +848,13 @@ int __lsan_is_turned_off() { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *__lsan_default_suppressions() { +#if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // The actual string allocation happens here (for more details refer to the + // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition). + return "leak:*_dl_map_object_deps*"; +#else return ""; +#endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT } #endif } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 1a6410878..49732aa32 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -259,4 +259,15 @@ # define SANITIZER_GO 0 #endif +// On PowerPC and ARM Thumb, calling pthread_exit() causes LSan to detect leaks. +// pthread_exit() performs unwinding that leads to dlopen'ing libgcc_s.so. +// dlopen mallocs "libgcc_s.so" string which confuses LSan, it fails to realize +// that this allocation happens in dynamic linker and should be ignored. +#if SANITIZER_PPC || defined(__thumb__) +# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 1 +#else +# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 +#endif + + #endif // SANITIZER_PLATFORM_H -- cgit v1.2.1 From b1a6993d25052b1d3eb0a4862f21380bada69c72 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 20 Apr 2017 20:54:22 +0000 Subject: Define standard suppressions for LSan, start with this one. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300887 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index d54f56958..200f16a59 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -68,6 +68,14 @@ ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; static SuppressionContext *suppression_ctx = nullptr; static const char kSuppressionLeak[] = "leak"; static const char *kSuppressionTypes[] = { kSuppressionLeak }; +static const char kStdSuppressions[] = +#if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // The actual string allocation happens here (for more details refer to the + // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition). + "leak:*_dl_map_object_deps*"; +#else + ""; +#endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); @@ -76,6 +84,7 @@ void InitializeSuppressions() { suppression_ctx->ParseFromFile(flags()->suppressions); if (&__lsan_default_suppressions) suppression_ctx->Parse(__lsan_default_suppressions()); + suppression_ctx->Parse(kStdSuppressions); } static SuppressionContext *GetSuppressionContext() { @@ -848,13 +857,7 @@ int __lsan_is_turned_off() { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *__lsan_default_suppressions() { -#if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // The actual string allocation happens here (for more details refer to the - // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition). - return "leak:*_dl_map_object_deps*"; -#else return ""; -#endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT } #endif } // extern "C" -- cgit v1.2.1 From 8be3b047030f4ac34cf7e72e7e610e91181fe65a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Apr 2017 20:59:37 +0000 Subject: [asan] Optimize strchr for strict_string_checks=false Summary: strchr interceptor does not need to call strlen if strict_string_checks is not enabled. Unnecessary strlen calls affect python parser performance. Reviewers: eugenis, kcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D32264 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300889 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 22 ++++++------- test/asan/TestCases/Posix/strchr.c | 36 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 test/asan/TestCases/Posix/strchr.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7b4e6d27d..d1c793c55 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -139,12 +139,9 @@ bool PlatformHasDifferentMemcpyAndMemmove(); #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) #endif -#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \ - COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ - common_flags()->strict_string_checks ? (len) + 1 : (n) ) - #define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ - COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) ) #ifndef COMMON_INTERCEPTOR_ON_DLOPEN #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ @@ -450,8 +447,7 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1, const char *s2) { uptr len1 = REAL(strlen)(s1); uptr len2 = REAL(strlen)(s2); - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1, - r ? r - s1 + len2 : len1 + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); } #endif @@ -577,10 +573,11 @@ INTERCEPTOR(char*, strchr, const char *s, int c) { return internal_strchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); char *result = REAL(strchr)(s, c); - uptr len = internal_strlen(s); - uptr n = result ? result - s + 1 : len + 1; - if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n); + if (common_flags()->intercept_strchr) { + // Keep strlen as macro argument, as macro may ignore it. + COMMON_INTERCEPTOR_READ_STRING(ctx, s, + (result ? result - s : REAL(strlen)(s)) + 1); + } return result; } #define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) @@ -609,9 +606,8 @@ INTERCEPTOR(char*, strrchr, const char *s, int c) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strrchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); - uptr len = internal_strlen(s); if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); return REAL(strrchr)(s, c); } #define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c new file mode 100644 index 000000000..df854d79e --- /dev/null +++ b/test/asan/TestCases/Posix/strchr.c @@ -0,0 +1,36 @@ +// Test strchr for strict_string_checks=false does not look beyond necessary +// char. +// RUN: %clang_asan %s -o %t +// RUN: %env_asan_opts=strict_string_checks=false %run %t 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + size_t page_size = sysconf(_SC_PAGE_SIZE); + size_t size = 2 * page_size; + char *s = (char *)mmap(0, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(s); + assert(((uintptr_t)s & (page_size - 1)) == 0); + memset(s, 'o', size); + s[size - 1] = 0; + + char *p = s + page_size - 1; + *p = 'x'; + + if (mprotect(p + 1, 1, PROT_NONE)) + return 1; + char *r = strchr(s, 'x'); + // CHECK: AddressSanitizer: SEGV on unknown address + // CHECK: The signal is caused by a READ memory access + // CHECK: strchr.c:[[@LINE-3]] + assert(r == p); + + return 0; +} -- cgit v1.2.1 From 90b4b2c3c0f6a64a5b793e089c77a906acdf40c3 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 20 Apr 2017 21:00:02 +0000 Subject: make detect_leaks=1 the default for the lsan test suite Summary: This already appears to be the case in all .cc test files, it was probably left out of the .c test files accidentally. Make it a global default, instead of manually adding it to each individual test. This is needed to force leak detection for Darwin tests, where leak detection is disabled by default. Reviewers: m.ostapenko, kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32297 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300890 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/Linux/use_tls_dynamic.cc | 2 +- test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc | 2 +- test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc | 2 +- test/lsan/TestCases/Linux/use_tls_static.cc | 2 +- test/lsan/TestCases/disabler.cc | 2 +- test/lsan/TestCases/do_leak_check_override.cc | 2 +- test/lsan/TestCases/high_allocator_contention.cc | 2 +- test/lsan/TestCases/large_allocation_leak.cc | 2 +- test/lsan/TestCases/leak_check_at_exit.cc | 2 +- test/lsan/TestCases/link_turned_off.cc | 2 +- test/lsan/TestCases/pointer_to_self.cc | 2 +- test/lsan/TestCases/print_suppressions.cc | 2 +- test/lsan/TestCases/recoverable_leak_check.cc | 2 +- test/lsan/TestCases/register_root_region.cc | 2 +- test/lsan/TestCases/stale_stack_leak.cc | 2 +- test/lsan/TestCases/suppressions_default.cc | 2 +- test/lsan/TestCases/suppressions_file.cc | 2 +- test/lsan/TestCases/swapcontext.cc | 5 ++--- test/lsan/TestCases/use_after_return.cc | 2 +- test/lsan/TestCases/use_globals_initialized.cc | 2 +- test/lsan/TestCases/use_globals_uninitialized.cc | 2 +- test/lsan/TestCases/use_poisoned_asan.cc | 2 +- test/lsan/TestCases/use_registers.cc | 2 +- test/lsan/TestCases/use_stacks.cc | 2 +- test/lsan/TestCases/use_stacks_threaded.cc | 2 +- test/lsan/TestCases/use_unaligned.cc | 2 +- test/lsan/lit.common.cfg | 4 ++-- 27 files changed, 29 insertions(+), 30 deletions(-) diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index c81bcaed2..d60dec08f 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -1,5 +1,5 @@ // Test that dynamically allocated TLS space is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0" // RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc index 947a4ce24..650e6ad20 100644 --- a/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cc @@ -1,5 +1,5 @@ // Test that dynamically allocated thread-specific storage is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc index 8f5afc49a..cafe40f06 100644 --- a/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc +++ b/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cc @@ -1,5 +1,5 @@ // Test that statically allocated thread-specific storage is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/Linux/use_tls_static.cc b/test/lsan/TestCases/Linux/use_tls_static.cc index e56f5e13a..84cc6c99f 100644 --- a/test/lsan/TestCases/Linux/use_tls_static.cc +++ b/test/lsan/TestCases/Linux/use_tls_static.cc @@ -1,5 +1,5 @@ // Test that statically allocated TLS space is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/disabler.cc b/test/lsan/TestCases/disabler.cc index feabc36fa..c5ffdb0bf 100644 --- a/test/lsan/TestCases/disabler.cc +++ b/test/lsan/TestCases/disabler.cc @@ -1,5 +1,5 @@ // Test for ScopedDisabler. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/do_leak_check_override.cc b/test/lsan/TestCases/do_leak_check_override.cc index bffcf6ef6..40a97635c 100644 --- a/test/lsan/TestCases/do_leak_check_override.cc +++ b/test/lsan/TestCases/do_leak_check_override.cc @@ -1,7 +1,7 @@ // Test for __lsan_do_leak_check(). We test it by making the leak check run // before global destructors, which also tests compatibility with HeapChecker's // "normal" mode (LSan runs in "strict" mode by default). -// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s diff --git a/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc index 8d8f9879b..cbe592c4f 100644 --- a/test/lsan/TestCases/high_allocator_contention.cc +++ b/test/lsan/TestCases/high_allocator_contention.cc @@ -1,6 +1,6 @@ // A benchmark that executes malloc/free pairs in parallel. // Usage: ./a.out number_of_threads total_number_of_allocations -// RUN: LSAN_BASE="detect_leaks=1:use_ld_allocations=0" +// RUN: LSAN_BASE="use_ld_allocations=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t 5 1000000 2>&1 #include diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index 6bf593be1..66f364fff 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -1,5 +1,5 @@ // Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc index 2e00cfb12..8a8ff8245 100644 --- a/test/lsan/TestCases/leak_check_at_exit.cc +++ b/test/lsan/TestCases/leak_check_at_exit.cc @@ -1,5 +1,5 @@ // Test for the leak_check_at_exit flag. -// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index da848bbc3..b8458de63 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -1,5 +1,5 @@ // Test for disabling LSan at link-time. -// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/pointer_to_self.cc b/test/lsan/TestCases/pointer_to_self.cc index 4f34d8a8f..62683a215 100644 --- a/test/lsan/TestCases/pointer_to_self.cc +++ b/test/lsan/TestCases/pointer_to_self.cc @@ -1,6 +1,6 @@ // Regression test: pointers to self should not confuse LSan into thinking the // object is indirectly leaked. Only external pointers count. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/print_suppressions.cc b/test/lsan/TestCases/print_suppressions.cc index 0f9147244..2fa199d5d 100644 --- a/test/lsan/TestCases/print_suppressions.cc +++ b/test/lsan/TestCases/print_suppressions.cc @@ -1,6 +1,6 @@ // Print matched suppressions only if print_suppressions=1 AND at least one is // matched. Default is print_suppressions=true. -// RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0" +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print // RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print diff --git a/test/lsan/TestCases/recoverable_leak_check.cc b/test/lsan/TestCases/recoverable_leak_check.cc index be10a49dc..909698561 100644 --- a/test/lsan/TestCases/recoverable_leak_check.cc +++ b/test/lsan/TestCases/recoverable_leak_check.cc @@ -1,5 +1,5 @@ // Test for on-demand leak checking. -// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/register_root_region.cc b/test/lsan/TestCases/register_root_region.cc index 6e3c8c1ce..b73b56b52 100644 --- a/test/lsan/TestCases/register_root_region.cc +++ b/test/lsan/TestCases/register_root_region.cc @@ -1,5 +1,5 @@ // Test for __lsan_(un)register_root_region(). -// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc index 0b33f26a4..635d73814 100644 --- a/test/lsan/TestCases/stale_stack_leak.cc +++ b/test/lsan/TestCases/stale_stack_leak.cc @@ -1,5 +1,5 @@ // Test that out-of-scope local variables are ignored by LSan. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=1" +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s diff --git a/test/lsan/TestCases/suppressions_default.cc b/test/lsan/TestCases/suppressions_default.cc index da240f200..9a660e610 100644 --- a/test/lsan/TestCases/suppressions_default.cc +++ b/test/lsan/TestCases/suppressions_default.cc @@ -1,4 +1,4 @@ -// RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0" +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s diff --git a/test/lsan/TestCases/suppressions_file.cc b/test/lsan/TestCases/suppressions_file.cc index a14afc4d5..33cf0202d 100644 --- a/test/lsan/TestCases/suppressions_file.cc +++ b/test/lsan/TestCases/suppressions_file.cc @@ -1,4 +1,4 @@ -// RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0" +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t // RUN: rm -f %t.supp diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index b019067aa..f46897a97 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -2,9 +2,8 @@ // memory. Make sure we don't report these leaks. // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_BASE="detect_leaks=1" -// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 -// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// RUN: %env_lsan_opts= %run %t 2>&1 +// RUN: %env_lsan_opts= not %run %t foo 2>&1 | FileCheck %s // UNSUPPORTED: arm #include diff --git a/test/lsan/TestCases/use_after_return.cc b/test/lsan/TestCases/use_after_return.cc index 6c00639c0..5c60ec60f 100644 --- a/test/lsan/TestCases/use_after_return.cc +++ b/test/lsan/TestCases/use_after_return.cc @@ -1,6 +1,6 @@ // Test that fake stack (introduced by ASan's use-after-return mode) is included // in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -O2 -o %t // RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s // RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_globals_initialized.cc b/test/lsan/TestCases/use_globals_initialized.cc index 07557ee8b..8664618eb 100644 --- a/test/lsan/TestCases/use_globals_initialized.cc +++ b/test/lsan/TestCases/use_globals_initialized.cc @@ -1,5 +1,5 @@ // Test that initialized globals are included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_globals_uninitialized.cc b/test/lsan/TestCases/use_globals_uninitialized.cc index f42608662..ef8f8e1f3 100644 --- a/test/lsan/TestCases/use_globals_uninitialized.cc +++ b/test/lsan/TestCases/use_globals_uninitialized.cc @@ -1,5 +1,5 @@ // Test that uninitialized globals are included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_poisoned_asan.cc b/test/lsan/TestCases/use_poisoned_asan.cc index 164b0cf67..780792e95 100644 --- a/test/lsan/TestCases/use_poisoned_asan.cc +++ b/test/lsan/TestCases/use_poisoned_asan.cc @@ -1,6 +1,6 @@ // ASan-poisoned memory should be ignored if use_poisoned is false. // REQUIRES: asan -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index fe552e628..5d5ede5ce 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -1,5 +1,5 @@ // Test that registers of running threads are included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0" // RUN: %clangxx_lsan -pthread %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_stacks.cc b/test/lsan/TestCases/use_stacks.cc index 656a78a79..855a8e4ed 100644 --- a/test/lsan/TestCases/use_stacks.cc +++ b/test/lsan/TestCases/use_stacks.cc @@ -1,5 +1,5 @@ // Test that stack of main thread is included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc index c0549b22e..579dcffb2 100644 --- a/test/lsan/TestCases/use_stacks_threaded.cc +++ b/test/lsan/TestCases/use_stacks_threaded.cc @@ -1,5 +1,5 @@ // Test that stacks of non-main threads are included in the root set. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_registers=0" // RUN: %clangxx_lsan -pthread %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 diff --git a/test/lsan/TestCases/use_unaligned.cc b/test/lsan/TestCases/use_unaligned.cc index 1d680a51b..26afc2d8a 100644 --- a/test/lsan/TestCases/use_unaligned.cc +++ b/test/lsan/TestCases/use_unaligned.cc @@ -1,5 +1,5 @@ // Test that unaligned pointers are detected correctly. -// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0" +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=1" %run %t 2>&1 diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 43ed02a4b..7020bd847 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -33,12 +33,12 @@ else: config.name += config.name_suffix # Platform-specific default LSAN_OPTIONS for lit tests. -default_lsan_opts = '' +default_lsan_opts = 'detect_leaks=1' if config.host_os == 'Darwin': # On Darwin, we default to `abort_on_error=1`, which would make tests run # much slower. Let's override this and run lit tests with 'abort_on_error=0'. # Also, make sure we do not overwhelm the syslog while testing. - default_lsan_opts = 'abort_on_error=0' + default_lsan_opts += ':abort_on_error=0' default_lsan_opts += ':log_to_syslog=0' if default_lsan_opts: -- cgit v1.2.1 From 08d91460ea4a2141a1b0051cba4082207c90f992 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 20 Apr 2017 21:27:25 +0000 Subject: Enable lsan test suite on Darwin x86_64 builds Reviewers: kubamracek, alekseyshl Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D32191 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300897 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/asan/lit.cfg | 9 ++++++++- test/lsan/lit.common.cfg | 6 ++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 60cb39a93..ae2a262a1 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -476,7 +476,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD") + OS_NAME MATCHES "Darwin|Linux|FreeBSD") set(COMPILER_RT_HAS_LSAN TRUE) else() set(COMPILER_RT_HAS_LSAN FALSE) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 7d684a1ae..0a5a2d2ed 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -38,6 +38,11 @@ if config.host_os == 'Darwin': # Also, make sure we do not overwhelm the syslog while testing. default_asan_opts = 'abort_on_error=0' default_asan_opts += ':log_to_syslog=0' + + # On Darwin, leak checking is not enabled by default. Enable for x86_64 + # tests to prevent regressions + if config.target_arch == 'x86_64': + default_asan_opts += ':detect_leaks=1' elif config.android: # The same as on Darwin, we default to "abort_on_error=1" which slows down # testing. Also, all existing tests are using "not" instead of "not --crash" @@ -217,7 +222,9 @@ if re.search('mthumb', config.target_cflags) is not None: config.available_features.add('fast-unwinder-works') # Turn on leak detection on 64-bit Linux. -if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): +leak_detection_linux = (config.host_os == 'Linux') and (config.target_arch == 'x86_64' or config.target_arch == 'i386') +leak_detection_mac = (config.host_os == 'Darwin') and (config.target_arch == 'x86_64') +if leak_detection_linux or leak_detection_mac: config.available_features.add('leak-detection') # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 7020bd847..f484f9339 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,8 +67,10 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: +# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin +supported_linux = config.host_os in ['Linux'] and config.host_arch in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l'] +supported_darwin = config.host_os is 'Darwin' and config.target_arch is 'x86_64' +if not (supported_linux or supported_darwin): config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 71895e0fe75900d8b8767304d5d9c611f9c69e5b Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 20 Apr 2017 21:44:35 +0000 Subject: [cfi] Move one test under cross-dso/icall. The test is using indirect calls. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300900 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/cross-dso/dlopen.cpp | 147 ------------------------------------ test/cfi/cross-dso/icall/dlopen.cpp | 147 ++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 147 deletions(-) delete mode 100644 test/cfi/cross-dso/dlopen.cpp create mode 100644 test/cfi/cross-dso/icall/dlopen.cpp diff --git a/test/cfi/cross-dso/dlopen.cpp b/test/cfi/cross-dso/dlopen.cpp deleted file mode 100644 index ee4dae2b5..000000000 --- a/test/cfi/cross-dso/dlopen.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so -// RUN: %clangxx_cfi_dso %s -o %t1 -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t1 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s -// RUN: %expect_crash %t1 dlclose 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so -// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t2 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s -// RUN: %expect_crash %t2 dlclose 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so -// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t3 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s -// RUN: %expect_crash %t3 dlclose 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so -// RUN: %clangxx_cfi_dso -DBM %s -o %t4 -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t4 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s -// RUN: %expect_crash %t4 dlclose 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx -g -DBM -DSHARED_LIB -DNOCFI %s -fPIC -shared -o %t5-so.so -// RUN: %clangxx -g -DBM -DNOCFI %s -ldl -o %t5 -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t5 cast 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t5 dlclose 2>&1 | FileCheck --check-prefix=NCFI %s - -// Test that calls to uninstrumented library are unchecked. -// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t6-so.so -// RUN: %clangxx_cfi_dso -DBM %s -o %t6 -// RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t6 cast 2>&1 | FileCheck --check-prefix=NCFI %s - -// Call-after-dlclose is checked on the caller side. -// RUN: %expect_crash %t6 dlclose 2>&1 | FileCheck --check-prefix=CFI %s - -// Tests calls into dlopen-ed library. -// REQUIRES: cxxabi - -#include -#include -#include -#include -#include -#include - -#include - -struct A { - virtual void f(); -}; - -#ifdef SHARED_LIB - -#include "../utils.h" -struct B { - virtual void f(); -}; -void B::f() {} - -extern "C" void *create_B() { - create_derivers(); - return (void *)(new B()); -} - -extern "C" __attribute__((aligned(4096))) void do_nothing() {} - -#else - -void A::f() {} - -static const int kCodeAlign = 4096; -static const int kCodeSize = 4096; -static char saved_code[kCodeSize]; -static char *real_start; - -static void save_code(char *p) { - real_start = (char *)(((uintptr_t)p) & ~(kCodeAlign - 1)); - memcpy(saved_code, real_start, kCodeSize); -} - -static void restore_code() { - char *code = (char *)mmap(real_start, kCodeSize, PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); - assert(code == real_start); - memcpy(code, saved_code, kCodeSize); -} - -int main(int argc, char *argv[]) { - const bool test_cast = argc > 1 && strcmp(argv[1], "cast") == 0; - const bool test_dlclose = argc > 1 && strcmp(argv[1], "dlclose") == 0; - - std::string name = std::string(argv[0]) + "-so.so"; - void *handle = dlopen(name.c_str(), RTLD_NOW); - assert(handle); - void *(*create_B)() = (void *(*)())dlsym(handle, "create_B"); - assert(create_B); - - void *p = create_B(); - A *a; - - // CFI: =0= - // CFI-CAST: =0= - // NCFI: =0= - fprintf(stderr, "=0=\n"); - - if (test_cast) { - // Test cast. BOOM. - a = (A*)p; - } else { - // Invisible to CFI. Test virtual call later. - memcpy(&a, &p, sizeof(a)); - } - - // CFI: =1= - // CFI-CAST-NOT: =1= - // NCFI: =1= - fprintf(stderr, "=1=\n"); - - if (test_dlclose) { - // Imitate an attacker sneaking in an executable page where a dlclose()d - // library was loaded. This needs to pass w/o CFI, so for the testing - // purpose, we just copy the bytes of a "void f() {}" function back and - // forth. - void (*do_nothing)() = (void (*)())dlsym(handle, "do_nothing"); - assert(do_nothing); - save_code((char *)do_nothing); - - int res = dlclose(handle); - assert(res == 0); - - restore_code(); - - do_nothing(); // UB here - } else { - a->f(); // UB here - } - - // CFI-NOT: =2= - // CFI-CAST-NOT: =2= - // NCFI: =2= - fprintf(stderr, "=2=\n"); -} -#endif diff --git a/test/cfi/cross-dso/icall/dlopen.cpp b/test/cfi/cross-dso/icall/dlopen.cpp new file mode 100644 index 000000000..d238a7ace --- /dev/null +++ b/test/cfi/cross-dso/icall/dlopen.cpp @@ -0,0 +1,147 @@ +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so +// RUN: %clangxx_cfi_dso %s -o %t1 +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t1 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s +// RUN: %expect_crash %t1 dlclose 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so +// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t2 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s +// RUN: %expect_crash %t2 dlclose 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so +// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t3 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s +// RUN: %expect_crash %t3 dlclose 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so +// RUN: %clangxx_cfi_dso -DBM %s -o %t4 +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t4 cast 2>&1 | FileCheck --check-prefix=CFI-CAST %s +// RUN: %expect_crash %t4 dlclose 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -g -DBM -DSHARED_LIB -DNOCFI %s -fPIC -shared -o %t5-so.so +// RUN: %clangxx -g -DBM -DNOCFI %s -ldl -o %t5 +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 cast 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 dlclose 2>&1 | FileCheck --check-prefix=NCFI %s + +// Test that calls to uninstrumented library are unchecked. +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t6-so.so +// RUN: %clangxx_cfi_dso -DBM %s -o %t6 +// RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t6 cast 2>&1 | FileCheck --check-prefix=NCFI %s + +// Call-after-dlclose is checked on the caller side. +// RUN: %expect_crash %t6 dlclose 2>&1 | FileCheck --check-prefix=CFI %s + +// Tests calls into dlopen-ed library. +// REQUIRES: cxxabi + +#include +#include +#include +#include +#include +#include + +#include + +struct A { + virtual void f(); +}; + +#ifdef SHARED_LIB + +#include "../../utils.h" +struct B { + virtual void f(); +}; +void B::f() {} + +extern "C" void *create_B() { + create_derivers(); + return (void *)(new B()); +} + +extern "C" __attribute__((aligned(4096))) void do_nothing() {} + +#else + +void A::f() {} + +static const int kCodeAlign = 4096; +static const int kCodeSize = 4096; +static char saved_code[kCodeSize]; +static char *real_start; + +static void save_code(char *p) { + real_start = (char *)(((uintptr_t)p) & ~(kCodeAlign - 1)); + memcpy(saved_code, real_start, kCodeSize); +} + +static void restore_code() { + char *code = (char *)mmap(real_start, kCodeSize, PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); + assert(code == real_start); + memcpy(code, saved_code, kCodeSize); +} + +int main(int argc, char *argv[]) { + const bool test_cast = argc > 1 && strcmp(argv[1], "cast") == 0; + const bool test_dlclose = argc > 1 && strcmp(argv[1], "dlclose") == 0; + + std::string name = std::string(argv[0]) + "-so.so"; + void *handle = dlopen(name.c_str(), RTLD_NOW); + assert(handle); + void *(*create_B)() = (void *(*)())dlsym(handle, "create_B"); + assert(create_B); + + void *p = create_B(); + A *a; + + // CFI: =0= + // CFI-CAST: =0= + // NCFI: =0= + fprintf(stderr, "=0=\n"); + + if (test_cast) { + // Test cast. BOOM. + a = (A*)p; + } else { + // Invisible to CFI. Test virtual call later. + memcpy(&a, &p, sizeof(a)); + } + + // CFI: =1= + // CFI-CAST-NOT: =1= + // NCFI: =1= + fprintf(stderr, "=1=\n"); + + if (test_dlclose) { + // Imitate an attacker sneaking in an executable page where a dlclose()d + // library was loaded. This needs to pass w/o CFI, so for the testing + // purpose, we just copy the bytes of a "void f() {}" function back and + // forth. + void (*do_nothing)() = (void (*)())dlsym(handle, "do_nothing"); + assert(do_nothing); + save_code((char *)do_nothing); + + int res = dlclose(handle); + assert(res == 0); + + restore_code(); + + do_nothing(); // UB here + } else { + a->f(); // UB here + } + + // CFI-NOT: =2= + // CFI-CAST-NOT: =2= + // NCFI: =2= + fprintf(stderr, "=2=\n"); +} +#endif -- cgit v1.2.1 From c779240ba489671a8706357aa8bf09188d5ed634 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 20 Apr 2017 21:44:37 +0000 Subject: [cfi] Add explicit -flto in create-derivers test. This is necessary to run the test suite in ThinLTO mode - otherwise opt complains about an input file containing several modules. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300901 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/create-derivers.test | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/cfi/create-derivers.test b/test/cfi/create-derivers.test index a67562b1a..8b569d001 100644 --- a/test/cfi/create-derivers.test +++ b/test/cfi/create-derivers.test @@ -1,20 +1,21 @@ REQUIRES: asserts -RUN: %clangxx_cfi -c -o %t1.o %S/simple-fail.cpp +%% Explicit -flto to override possible -flto=thin in %clangxx_cfi +RUN: %clangxx_cfi -flto -c -o %t1.o %S/simple-fail.cpp RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t1.o 2>&1 | FileCheck --check-prefix=B0 %s B0: {{1B|B@@}}: {{.*}} size 1 -RUN: %clangxx_cfi -DB32 -c -o %t2.o %S/simple-fail.cpp +RUN: %clangxx_cfi -DB32 -flto -c -o %t2.o %S/simple-fail.cpp RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t2.o 2>&1 | FileCheck --check-prefix=B32 %s B32: {{1B|B@@}}: {{.*}} size 24 B32-NOT: all-ones -RUN: %clangxx_cfi -DB64 -c -o %t3.o %S/simple-fail.cpp +RUN: %clangxx_cfi -DB64 -flto -c -o %t3.o %S/simple-fail.cpp RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t3.o 2>&1 | FileCheck --check-prefix=B64 %s B64: {{1B|B@@}}: {{.*}} size 54 B64-NOT: all-ones -RUN: %clangxx_cfi -DBM -c -o %t4.o %S/simple-fail.cpp +RUN: %clangxx_cfi -DBM -flto -c -o %t4.o %S/simple-fail.cpp RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t4.o 2>&1 | FileCheck --check-prefix=BM %s BM: {{1B|B@@}}: {{.*}} size 84 BM-NOT: all-ones -- cgit v1.2.1 From 9bde122566bdf9d7fdffce80b58cc2d112892e3f Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 20 Apr 2017 21:56:36 +0000 Subject: Enable LSan on PowerPC64. Summary: Re-landing reverted D31995 with suppressions defined in D32303. Reviewers: eugenis Subscribers: nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D32314 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300903 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 2 +- lib/lsan/lsan_common.h | 3 ++- test/lsan/lit.common.cfg | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index e5def17d4..fad5adb01 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> PrimaryAllocator; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__powerpc64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; static const uptr kSpaceSize = 0x40000000000ULL; // 4T. diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 121b9c082..beb31d6f4 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -32,7 +32,8 @@ // new architecture inside sanitizer library. #if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ + defined(__powerpc64__)) #define CAN_SANITIZE_LEAKS 1 #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index f484f9339..216559eb3 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,8 +67,8 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin -supported_linux = config.host_os in ['Linux'] and config.host_arch in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l'] +# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin +supported_linux = config.host_os in ['Linux'] and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l'] supported_darwin = config.host_os is 'Darwin' and config.target_arch is 'x86_64' if not (supported_linux or supported_darwin): config.unsupported = True -- cgit v1.2.1 From d8d3de1d7f213ec5f7579e825e6c237cc0aa892a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Apr 2017 21:58:18 +0000 Subject: [asan] Match BUS and SIGV to fix test on Darwin git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300906 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/strchr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c index df854d79e..76d96da47 100644 --- a/test/asan/TestCases/Posix/strchr.c +++ b/test/asan/TestCases/Posix/strchr.c @@ -27,7 +27,7 @@ int main(int argc, char **argv) { if (mprotect(p + 1, 1, PROT_NONE)) return 1; char *r = strchr(s, 'x'); - // CHECK: AddressSanitizer: SEGV on unknown address + // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address // CHECK: The signal is caused by a READ memory access // CHECK: strchr.c:[[@LINE-3]] assert(r == p); -- cgit v1.2.1 From 1082bc6658c1027897b2769e7de89bb69f81322c Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 20 Apr 2017 23:38:10 +0000 Subject: sanitizer: fix crash with textdomain(NULL) interceptor Summary: The textdomain function accepts a NULL parameter (and should then return the current message domain). Add a check for this and include ASAN tests. Link: https://github.com/google/sanitizers/issues/787 Reviewers: m.guseva, kcc Reviewed By: kcc Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D32318 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300924 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_interceptors.inc | 2 +- test/asan/TestCases/textdomain.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 test/asan/TestCases/textdomain.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index d1c793c55..9da1822f3 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -304,7 +304,7 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname); - COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0); + if (domainname) COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0); char *domain = REAL(textdomain)(domainname); if (domain) { COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1); diff --git a/test/asan/TestCases/textdomain.c b/test/asan/TestCases/textdomain.c new file mode 100644 index 000000000..31e5139c9 --- /dev/null +++ b/test/asan/TestCases/textdomain.c @@ -0,0 +1,10 @@ +// RUN: %clang_asan -O0 -g %s -o %t +// RUN: %env_asan_opts=strict_string_checks=1 %run %t + +#include +#include + +int main() { + textdomain(NULL); + return 0; +} -- cgit v1.2.1 From e12d8a2107050e4d566791de7d27ecbaecbfb31e Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 20 Apr 2017 23:57:44 +0000 Subject: [asan] move textdomain.c to Linux dir, as the test is Linux-specific git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300926 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/textdomain.c | 10 ++++++++++ test/asan/TestCases/textdomain.c | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 test/asan/TestCases/Linux/textdomain.c delete mode 100644 test/asan/TestCases/textdomain.c diff --git a/test/asan/TestCases/Linux/textdomain.c b/test/asan/TestCases/Linux/textdomain.c new file mode 100644 index 000000000..31e5139c9 --- /dev/null +++ b/test/asan/TestCases/Linux/textdomain.c @@ -0,0 +1,10 @@ +// RUN: %clang_asan -O0 -g %s -o %t +// RUN: %env_asan_opts=strict_string_checks=1 %run %t + +#include +#include + +int main() { + textdomain(NULL); + return 0; +} diff --git a/test/asan/TestCases/textdomain.c b/test/asan/TestCases/textdomain.c deleted file mode 100644 index 31e5139c9..000000000 --- a/test/asan/TestCases/textdomain.c +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang_asan -O0 -g %s -o %t -// RUN: %env_asan_opts=strict_string_checks=1 %run %t - -#include -#include - -int main() { - textdomain(NULL); - return 0; -} -- cgit v1.2.1 From b6eb475185726d40e2ff6d47e246e565c17237eb Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Fri, 21 Apr 2017 00:00:59 +0000 Subject: Revert "Enable lsan test suite on Darwin x86_64 builds" This reverts commit r300897. Most LSan/ASan tests are failing on darwin bots. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300929 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/asan/lit.cfg | 9 +-------- test/lsan/lit.common.cfg | 6 ++---- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index ae2a262a1..60cb39a93 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -476,7 +476,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD") + OS_NAME MATCHES "Linux|FreeBSD") set(COMPILER_RT_HAS_LSAN TRUE) else() set(COMPILER_RT_HAS_LSAN FALSE) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 0a5a2d2ed..7d684a1ae 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -38,11 +38,6 @@ if config.host_os == 'Darwin': # Also, make sure we do not overwhelm the syslog while testing. default_asan_opts = 'abort_on_error=0' default_asan_opts += ':log_to_syslog=0' - - # On Darwin, leak checking is not enabled by default. Enable for x86_64 - # tests to prevent regressions - if config.target_arch == 'x86_64': - default_asan_opts += ':detect_leaks=1' elif config.android: # The same as on Darwin, we default to "abort_on_error=1" which slows down # testing. Also, all existing tests are using "not" instead of "not --crash" @@ -222,9 +217,7 @@ if re.search('mthumb', config.target_cflags) is not None: config.available_features.add('fast-unwinder-works') # Turn on leak detection on 64-bit Linux. -leak_detection_linux = (config.host_os == 'Linux') and (config.target_arch == 'x86_64' or config.target_arch == 'i386') -leak_detection_mac = (config.host_os == 'Darwin') and (config.target_arch == 'x86_64') -if leak_detection_linux or leak_detection_mac: +if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): config.available_features.add('leak-detection') # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 216559eb3..3441f6fdd 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,10 +67,8 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin -supported_linux = config.host_os in ['Linux'] and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l'] -supported_darwin = config.host_os is 'Darwin' and config.target_arch is 'x86_64' -if not (supported_linux or supported_darwin): +# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, and mips64 Linux only. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 2c94915622b5855125f9042814c39e50aa1b1e74 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 21 Apr 2017 00:36:29 +0000 Subject: Disable LSan on ppc64, some tests are failing. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300933 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 2 +- lib/lsan/lsan_common.h | 3 +-- test/lsan/lit.common.cfg | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index fad5adb01..e5def17d4 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> PrimaryAllocator; -#elif defined(__x86_64__) || defined(__powerpc64__) +#elif defined(__x86_64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; static const uptr kSpaceSize = 0x40000000000ULL; // 4T. diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index beb31d6f4..121b9c082 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -32,8 +32,7 @@ // new architecture inside sanitizer library. #if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ - defined(__powerpc64__)) + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) #define CAN_SANITIZE_LEAKS 1 #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 3441f6fdd..888ed424d 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,8 +67,8 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l']: +# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux, and mips64 Linux only. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 5cc53833e7c80dc00ec0b41c8a94cda6d6141d81 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 21 Apr 2017 00:48:43 +0000 Subject: [asan] Fix test on ppc64le-linux by checking "UNKNOWN memory access" git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300935 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/strchr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c index 76d96da47..a986cb16f 100644 --- a/test/asan/TestCases/Posix/strchr.c +++ b/test/asan/TestCases/Posix/strchr.c @@ -28,7 +28,7 @@ int main(int argc, char **argv) { return 1; char *r = strchr(s, 'x'); // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address - // CHECK: The signal is caused by a READ memory access + // CHECK: The signal is caused by a {{READ|UNKNOWN}} memory access // CHECK: strchr.c:[[@LINE-3]] assert(r == p); -- cgit v1.2.1 From cf2441775576329d5f0300b66f766884a228a47e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 21 Apr 2017 01:16:58 +0000 Subject: [asan] Fix test by removing "The signal is caused" check. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300939 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/strchr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c index a986cb16f..d5683d524 100644 --- a/test/asan/TestCases/Posix/strchr.c +++ b/test/asan/TestCases/Posix/strchr.c @@ -28,8 +28,7 @@ int main(int argc, char **argv) { return 1; char *r = strchr(s, 'x'); // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address - // CHECK: The signal is caused by a {{READ|UNKNOWN}} memory access - // CHECK: strchr.c:[[@LINE-3]] + // CHECK: strchr.c:[[@LINE-2]] assert(r == p); return 0; -- cgit v1.2.1 From efc456638526dd3ae3fe8ae1435f9cb87ef80d37 Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Fri, 21 Apr 2017 08:21:56 +0000 Subject: Revert r300889, r300906, r300935, r300939 At least one of the ARM bots is still broken: Command Output (stderr): -- /home/buildslave/buildslave/clang-cmake-armv7-a15-full/llvm/projects/compiler-rt/test/asan/TestCases/Posix/strchr.c:31:12: error: expected string not found in input // CHECK: strchr.c:[[@LINE-2]] ^ :3:59: note: scanning from here ==16297==ERROR: AddressSanitizer: SEGV on unknown address 0xb5add000 (pc 0xb6dccaa4 bp 0xbe8c19c8 sp 0xbe8c1570 T0) ^ :3:59: note: with expression "@LINE-2" equal to "29" ==16297==ERROR: AddressSanitizer: SEGV on unknown address 0xb5add000 (pc 0xb6dccaa4 bp 0xbe8c19c8 sp 0xbe8c1570 T0) ^ :5:57: note: possible intended match here #0 0xb6dccaa3 in strlen /build/glibc-f8FFOS/glibc-2.23/string/../sysdeps/arm/armv6t2/strlen.S:82 Try to fix by reverting r300889 and subsequent fixes: Revert "[asan] Fix test by removing "The signal is caused" check." Revert "[asan] Fix test on ppc64le-linux by checking "UNKNOWN memory access"" Revert "[asan] Match BUS and SIGV to fix test on Darwin" Revert "[asan] Optimize strchr for strict_string_checks=false" git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300955 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 22 ++++++++------ test/asan/TestCases/Posix/strchr.c | 35 ---------------------- 2 files changed, 13 insertions(+), 44 deletions(-) delete mode 100644 test/asan/TestCases/Posix/strchr.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9da1822f3..38cb3c2c2 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -139,9 +139,12 @@ bool PlatformHasDifferentMemcpyAndMemmove(); #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) #endif -#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ +#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ - common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) ) + common_flags()->strict_string_checks ? (len) + 1 : (n) ) + +#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ + COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) #ifndef COMMON_INTERCEPTOR_ON_DLOPEN #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ @@ -447,7 +450,8 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1, const char *s2) { uptr len1 = REAL(strlen)(s1); uptr len2 = REAL(strlen)(s2); - COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); + COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1, + r ? r - s1 + len2 : len1 + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); } #endif @@ -573,11 +577,10 @@ INTERCEPTOR(char*, strchr, const char *s, int c) { return internal_strchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); char *result = REAL(strchr)(s, c); - if (common_flags()->intercept_strchr) { - // Keep strlen as macro argument, as macro may ignore it. - COMMON_INTERCEPTOR_READ_STRING(ctx, s, - (result ? result - s : REAL(strlen)(s)) + 1); - } + uptr len = internal_strlen(s); + uptr n = result ? result - s + 1 : len + 1; + if (common_flags()->intercept_strchr) + COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n); return result; } #define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) @@ -606,8 +609,9 @@ INTERCEPTOR(char*, strrchr, const char *s, int c) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strrchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); + uptr len = internal_strlen(s); if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); + COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1); return REAL(strrchr)(s, c); } #define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c deleted file mode 100644 index d5683d524..000000000 --- a/test/asan/TestCases/Posix/strchr.c +++ /dev/null @@ -1,35 +0,0 @@ -// Test strchr for strict_string_checks=false does not look beyond necessary -// char. -// RUN: %clang_asan %s -o %t -// RUN: %env_asan_opts=strict_string_checks=false %run %t 2>&1 -// RUN: %env_asan_opts=strict_string_checks=true not %run %t 2>&1 | FileCheck %s - -#include -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - size_t page_size = sysconf(_SC_PAGE_SIZE); - size_t size = 2 * page_size; - char *s = (char *)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - assert(s); - assert(((uintptr_t)s & (page_size - 1)) == 0); - memset(s, 'o', size); - s[size - 1] = 0; - - char *p = s + page_size - 1; - *p = 'x'; - - if (mprotect(p + 1, 1, PROT_NONE)) - return 1; - char *r = strchr(s, 'x'); - // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address - // CHECK: strchr.c:[[@LINE-2]] - assert(r == p); - - return 0; -} -- cgit v1.2.1 From cc599619a08deaae432a0a62212de6cc7dca490d Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 16:44:27 +0000 Subject: [tsan] Don't report bugs from interceptors called from libignored modules This patch make sure we don't report deadlocks and other bug types when we're inside an interceptor that was called from a noninstrumented module (when ignore_noninstrumented_modules=1 is set). Adding a testcase that shows that deadlock detection still works on Darwin (to make sure we're not silencing too many reports). Differential Revision: https://reviews.llvm.org/D31449 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300998 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 2 ++ lib/tsan/rtl/tsan_rtl.h | 1 + lib/tsan/rtl/tsan_rtl_report.cc | 2 +- test/tsan/Darwin/deadlock.mm | 47 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/tsan/Darwin/deadlock.mm diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index d0fd91aec..5ad7a5909 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -269,6 +269,7 @@ ScopedInterceptor::~ScopedInterceptor() { void ScopedInterceptor::EnableIgnores() { if (ignoring_) { ThreadIgnoreBegin(thr_, pc_, false); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; if (in_ignored_lib_) { DCHECK(!thr_->in_ignored_lib); thr_->in_ignored_lib = true; @@ -279,6 +280,7 @@ void ScopedInterceptor::EnableIgnores() { void ScopedInterceptor::DisableIgnores() { if (ignoring_) { ThreadIgnoreEnd(thr_, pc_); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--; if (in_ignored_lib_) { DCHECK(thr_->in_ignored_lib); thr_->in_ignored_lib = false; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 3481c31eb..09c97a3a4 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -381,6 +381,7 @@ struct ThreadState { // for better performance. int ignore_reads_and_writes; int ignore_sync; + int suppress_reports; // Go does not support ignores. #if !SANITIZER_GO IgnoreSet mop_ignore_set; diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index 31b9e9789..5cd93a184 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -500,7 +500,7 @@ static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], } bool OutputReport(ThreadState *thr, const ScopedReport &srep) { - if (!flags()->report_bugs) + if (!flags()->report_bugs || thr->suppress_reports) return false; atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); const ReportDesc *rep = srep.GetReport(); diff --git a/test/tsan/Darwin/deadlock.mm b/test/tsan/Darwin/deadlock.mm new file mode 100644 index 000000000..36ddfad54 --- /dev/null +++ b/test/tsan/Darwin/deadlock.mm @@ -0,0 +1,47 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#import + +#import "../test.h" + +pthread_mutex_t m1; +pthread_mutex_t m2; + +int main(int argc, const char *argv[]) { + barrier_init(&barrier, 2); + fprintf(stderr, "Hello world.\n"); + + pthread_mutex_init(&m1, NULL); + pthread_mutex_init(&m2, NULL); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + + barrier_wait(&barrier); + }); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + barrier_wait(&barrier); + + pthread_mutex_lock(&m2); + pthread_mutex_lock(&m1); + pthread_mutex_unlock(&m1); + pthread_mutex_unlock(&m2); + + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + }); + + CFRunLoopRun(); + + fprintf(stderr, "Done.\n"); + return 0; +} + +// CHECK: Hello world. +// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) +// CHECK: Done. -- cgit v1.2.1 From 0a039ecbdab95ae1274a6e0ec484c2a1c2419bdd Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 17:18:14 +0000 Subject: [tsan] Ignore memory accesses for libignored modules for "external" races On Darwin, the setting ignore_noninstrumented_modules is used to suppress false positives in code that users don't have control of. The recently added "external" API (which can be used to detect races on objects provided by system libraries, but the race is actually user's fault) ignores this flag and it can report issues in non-instrumented modules. This patch fixes that. Differential Revision: https://reviews.llvm.org/D31553 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301000 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_external.cc | 19 ++++-- lib/tsan/rtl/tsan_interceptors.cc | 2 +- lib/tsan/rtl/tsan_interceptors.h | 2 + .../tsan/Darwin/external-ignore-noninstrumented.cc | 19 ++++++ test/tsan/Darwin/external-lib.cc | 68 ++++++++++++++++++++++ .../tsan/Darwin/external-noninstrumented-module.cc | 27 +++++++++ test/tsan/Darwin/external.cc | 66 +-------------------- 7 files changed, 133 insertions(+), 70 deletions(-) create mode 100644 test/tsan/Darwin/external-ignore-noninstrumented.cc create mode 100644 test/tsan/Darwin/external-lib.cc create mode 100644 test/tsan/Darwin/external-noninstrumented-module.cc diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc index dc8ec6232..971d1a01b 100644 --- a/lib/tsan/rtl/tsan_external.cc +++ b/lib/tsan/rtl/tsan_external.cc @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "tsan_rtl.h" +#include "tsan_interceptors.h" namespace __tsan { @@ -57,9 +58,12 @@ void __tsan_external_read(void *addr, void *caller_pc, void *tag) { CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); ThreadState *thr = cur_thread(); thr->external_tag = (uptr)tag; - FuncEntry(thr, (uptr)caller_pc); - MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog8); - FuncExit(thr); + if (caller_pc) FuncEntry(thr, (uptr)caller_pc); + bool in_ignored_lib; + if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { + MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog8); + } + if (caller_pc) FuncExit(thr); thr->external_tag = 0; } @@ -68,9 +72,12 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag) { CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); ThreadState *thr = cur_thread(); thr->external_tag = (uptr)tag; - FuncEntry(thr, (uptr)caller_pc); - MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog8); - FuncExit(thr); + if (caller_pc) FuncEntry(thr, (uptr)caller_pc); + bool in_ignored_lib; + if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { + MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog8); + } + if (caller_pc) FuncExit(thr); thr->external_tag = 0; } } // extern "C" diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 5ad7a5909..334cc326d 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -210,7 +210,7 @@ struct ThreadSignalContext { // The object is 64-byte aligned, because we want hot data to be located in // a single cache line if possible (it's accessed in every interceptor). static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)]; -static LibIgnore *libignore() { +LibIgnore *libignore() { return reinterpret_cast(&libignore_placeholder[0]); } diff --git a/lib/tsan/rtl/tsan_interceptors.h b/lib/tsan/rtl/tsan_interceptors.h index 72534f4a2..de4746650 100644 --- a/lib/tsan/rtl/tsan_interceptors.h +++ b/lib/tsan/rtl/tsan_interceptors.h @@ -19,6 +19,8 @@ class ScopedInterceptor { bool ignoring_; }; +LibIgnore *libignore(); + } // namespace __tsan #define SCOPED_INTERCEPTOR_RAW(func, ...) \ diff --git a/test/tsan/Darwin/external-ignore-noninstrumented.cc b/test/tsan/Darwin/external-ignore-noninstrumented.cc new file mode 100644 index 000000000..d2acaf54b --- /dev/null +++ b/test/tsan/Darwin/external-ignore-noninstrumented.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_tsan -shared %p/external-lib.cc -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \ +// RUN: -o %t-lib.dylib -install_name @rpath/`basename %t-lib.dylib` + +// RUN: %clangxx_tsan -shared %p/external-noninstrumented-module.cc %t-lib.dylib -fno-sanitize=thread \ +// RUN: -o %t-module.dylib -install_name @rpath/`basename %t-module.dylib` + +// RUN: %clangxx_tsan %s %t-module.dylib -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include + +extern "C" void NonInstrumentedModule(); +int main(int argc, char *argv[]) { + NonInstrumentedModule(); + fprintf(stderr, "Done.\n"); +} + +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. diff --git a/test/tsan/Darwin/external-lib.cc b/test/tsan/Darwin/external-lib.cc new file mode 100644 index 000000000..f0afdf1dc --- /dev/null +++ b/test/tsan/Darwin/external-lib.cc @@ -0,0 +1,68 @@ +// This file is used from other tests. +// RUN: true + +#include +#include +#include + +struct MyObject; +typedef MyObject *MyObjectRef; +extern "C" { + void InitializeLibrary(); + MyObject *ObjectCreate(); + long ObjectRead(MyObject *); + void ObjectWrite(MyObject *, long); + void ObjectWriteAnother(MyObject *, long); +} + +struct MyObject { + long _val; + long _another; +}; + +#if defined(USE_TSAN_CALLBACKS) +static void *tag; +void *(*callback_register_tag)(const char *object_type); +void *(*callback_assign_tag)(void *addr, void *tag); +void (*callback_read)(void *addr, void *caller_pc, void *tag); +void (*callback_write)(void *addr, void *caller_pc, void *tag); +#endif + +void InitializeLibrary() { +#if defined(USE_TSAN_CALLBACKS) + callback_register_tag = (decltype(callback_register_tag))dlsym(RTLD_DEFAULT, "__tsan_external_register_tag"); + callback_assign_tag = (decltype(callback_assign_tag))dlsym(RTLD_DEFAULT, "__tsan_external_assign_tag"); + callback_read = (decltype(callback_read))dlsym(RTLD_DEFAULT, "__tsan_external_read"); + callback_write = (decltype(callback_write))dlsym(RTLD_DEFAULT, "__tsan_external_write"); + tag = callback_register_tag("MyLibrary::MyObject"); +#endif +} + +MyObject *ObjectCreate() { + MyObject *ref = (MyObject *)malloc(sizeof(MyObject)); +#if defined(USE_TSAN_CALLBACKS) + callback_assign_tag(ref, tag); +#endif + return ref; +} + +long ObjectRead(MyObject *ref) { +#if defined(USE_TSAN_CALLBACKS) + callback_read(ref, __builtin_return_address(0), tag); +#endif + return ref->_val; +} + +void ObjectWrite(MyObject *ref, long val) { +#if defined(USE_TSAN_CALLBACKS) + callback_write(ref, __builtin_return_address(0), tag); +#endif + ref->_val = val; +} + +void ObjectWriteAnother(MyObject *ref, long val) { +#if defined(USE_TSAN_CALLBACKS) + callback_write(ref, __builtin_return_address(0), tag); +#endif + ref->_another = val; +} diff --git a/test/tsan/Darwin/external-noninstrumented-module.cc b/test/tsan/Darwin/external-noninstrumented-module.cc new file mode 100644 index 000000000..ce6597083 --- /dev/null +++ b/test/tsan/Darwin/external-noninstrumented-module.cc @@ -0,0 +1,27 @@ +// This file is used from other tests. +// RUN: true + +#include + +#include +#include + +struct MyObject; +typedef MyObject *MyObjectRef; +extern "C" { + void InitializeLibrary(); + MyObject *ObjectCreate(); + long ObjectRead(MyObject *); + void ObjectWrite(MyObject *, long); + void ObjectWriteAnother(MyObject *, long); +} + +extern "C" void NonInstrumentedModule() { + InitializeLibrary(); + + MyObjectRef ref = ObjectCreate(); + std::thread t1([ref]{ ObjectWrite(ref, 42); }); + std::thread t2([ref]{ ObjectWrite(ref, 43); }); + t1.join(); + t2.join(); +} diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc index 2605480d7..66881d3e5 100644 --- a/test/tsan/Darwin/external.cc +++ b/test/tsan/Darwin/external.cc @@ -1,12 +1,12 @@ -// RUN: %clangxx_tsan %s -shared -DSHARED_LIB \ +// RUN: %clangxx_tsan %p/external-lib.cc -shared \ // RUN: -o %t-lib-instrumented.dylib \ // RUN: -install_name @rpath/`basename %t-lib-instrumented.dylib` -// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread \ +// RUN: %clangxx_tsan %p/external-lib.cc -shared -fno-sanitize=thread \ // RUN: -o %t-lib-noninstrumented.dylib \ // RUN: -install_name @rpath/`basename %t-lib-noninstrumented.dylib` -// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \ +// RUN: %clangxx_tsan %p/external-lib.cc -shared -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \ // RUN: -o %t-lib-noninstrumented-callbacks.dylib \ // RUN: -install_name @rpath/`basename %t-lib-noninstrumented-callbacks.dylib` @@ -23,8 +23,6 @@ #include -#include -#include #include #include @@ -38,62 +36,6 @@ extern "C" { void ObjectWriteAnother(MyObject *, long); } -#if defined(SHARED_LIB) - -struct MyObject { - long _val; - long _another; -}; - -#if defined(USE_TSAN_CALLBACKS) -static void *tag; -void *(*callback_register_tag)(const char *object_type); -void *(*callback_assign_tag)(void *addr, void *tag); -void (*callback_read)(void *addr, void *caller_pc, void *tag); -void (*callback_write)(void *addr, void *caller_pc, void *tag); -#endif - -void InitializeLibrary() { -#if defined(USE_TSAN_CALLBACKS) - callback_register_tag = (decltype(callback_register_tag))dlsym(RTLD_DEFAULT, "__tsan_external_register_tag"); - callback_assign_tag = (decltype(callback_assign_tag))dlsym(RTLD_DEFAULT, "__tsan_external_assign_tag"); - callback_read = (decltype(callback_read))dlsym(RTLD_DEFAULT, "__tsan_external_read"); - callback_write = (decltype(callback_write))dlsym(RTLD_DEFAULT, "__tsan_external_write"); - tag = callback_register_tag("MyLibrary::MyObject"); -#endif -} - -MyObject *ObjectCreate() { - MyObject *ref = (MyObject *)malloc(sizeof(MyObject)); -#if defined(USE_TSAN_CALLBACKS) - callback_assign_tag(ref, tag); -#endif - return ref; -} - -long ObjectRead(MyObject *ref) { -#if defined(USE_TSAN_CALLBACKS) - callback_read(ref, __builtin_return_address(0), tag); -#endif - return ref->_val; -} - -void ObjectWrite(MyObject *ref, long val) { -#if defined(USE_TSAN_CALLBACKS) - callback_write(ref, __builtin_return_address(0), tag); -#endif - ref->_val = val; -} - -void ObjectWriteAnother(MyObject *ref, long val) { -#if defined(USE_TSAN_CALLBACKS) - callback_write(ref, __builtin_return_address(0), tag); -#endif - ref->_another = val; -} - -#else // defined(SHARED_LIB) - int main(int argc, char *argv[]) { InitializeLibrary(); @@ -159,5 +101,3 @@ int main(int argc, char *argv[]) { fprintf(stderr, "WW test done\n"); // CHECK: WW test done } - -#endif // defined(SHARED_LIB) -- cgit v1.2.1 From 58a4814ee329cf97331e7af3c3a3a1d6d60fd521 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 17:21:18 +0000 Subject: [tsan] Track external API accesses as 1-byte accesses (instead of 8-byte) It doesn't really make sense to track them as 8-byte accesses. Differential Revision: https://reviews.llvm.org/D32359 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301001 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_external.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc index 971d1a01b..d89d8f4f9 100644 --- a/lib/tsan/rtl/tsan_external.cc +++ b/lib/tsan/rtl/tsan_external.cc @@ -61,7 +61,7 @@ void __tsan_external_read(void *addr, void *caller_pc, void *tag) { if (caller_pc) FuncEntry(thr, (uptr)caller_pc); bool in_ignored_lib; if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { - MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog8); + MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog1); } if (caller_pc) FuncExit(thr); thr->external_tag = 0; @@ -75,7 +75,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag) { if (caller_pc) FuncEntry(thr, (uptr)caller_pc); bool in_ignored_lib; if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { - MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog8); + MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog1); } if (caller_pc) FuncExit(thr); thr->external_tag = 0; -- cgit v1.2.1 From 35ad53db387d998a574dec72ae43d98d677ac616 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 17:25:47 +0000 Subject: [tsan] Publish the TSan external API in tsan_interface.h Let's make the TSan external API available and commented in the public header: void *__tsan_external_register_tag(const char *object_type); void __tsan_external_assign_tag(void *addr, void *tag); void __tsan_external_read(void *addr, void *caller_pc, void *tag); void __tsan_external_write(void *addr, void *caller_pc, void *tag); Differential Revision: https://reviews.llvm.org/D32358 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301003 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/tsan_interface.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h index 34b74d537..45e54f758 100644 --- a/include/sanitizer/tsan_interface.h +++ b/include/sanitizer/tsan_interface.h @@ -114,6 +114,21 @@ void __tsan_mutex_post_signal(void *addr, unsigned flags); void __tsan_mutex_pre_divert(void *addr, unsigned flags); void __tsan_mutex_post_divert(void *addr, unsigned flags); +// External race detection API. +// Can be used by non-instrumented libraries to detect when their objects are +// being used in an unsafe manner. +// - __tsan_external_read/__tsan_external_write annotates the logical reads +// and writes of the object at the specified address. 'caller_pc' should +// be the PC of the library user, which the library can obtain with e.g. +// `__builtin_return_address(0)`. +// - __tsan_external_register_tag registers a 'tag' with the specified name, +// which is later used in read/write annotations to denote the object type +// - __tsan_external_assign_tag can optionally mark a heap object with a tag +void *__tsan_external_register_tag(const char *object_type); +void __tsan_external_assign_tag(void *addr, void *tag); +void __tsan_external_read(void *addr, void *caller_pc, void *tag); +void __tsan_external_write(void *addr, void *caller_pc, void *tag); + #ifdef __cplusplus } // extern "C" #endif -- cgit v1.2.1 From 65382e6212a3432756b51b149421769dc29e261e Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 17:41:01 +0000 Subject: [tsan] Refactor __tsan_external_read/__tsan_external_write to avoid code duplication Let's introduce a ExternalAccess function that has the shared code only once. Differential Revision: https://reviews.llvm.org/D32360 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301008 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_external.cc | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc index d89d8f4f9..88468e406 100644 --- a/lib/tsan/rtl/tsan_external.cc +++ b/lib/tsan/rtl/tsan_external.cc @@ -30,6 +30,20 @@ const char *GetObjectTypeFromTag(uptr tag) { return registered_tags[tag]; } +typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int); +void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) { + CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); + ThreadState *thr = cur_thread(); + thr->external_tag = (uptr)tag; + if (caller_pc) FuncEntry(thr, (uptr)caller_pc); + bool in_ignored_lib; + if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { + access(thr, CALLERPC, (uptr)addr, kSizeLog1); + } + if (caller_pc) FuncExit(thr); + thr->external_tag = 0; +} + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void *__tsan_external_register_tag(const char *object_type) { @@ -55,30 +69,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) { SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_read(void *addr, void *caller_pc, void *tag) { - CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); - ThreadState *thr = cur_thread(); - thr->external_tag = (uptr)tag; - if (caller_pc) FuncEntry(thr, (uptr)caller_pc); - bool in_ignored_lib; - if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { - MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog1); - } - if (caller_pc) FuncExit(thr); - thr->external_tag = 0; + ExternalAccess(addr, caller_pc, tag, MemoryRead); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_write(void *addr, void *caller_pc, void *tag) { - CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); - ThreadState *thr = cur_thread(); - thr->external_tag = (uptr)tag; - if (caller_pc) FuncEntry(thr, (uptr)caller_pc); - bool in_ignored_lib; - if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { - MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog1); - } - if (caller_pc) FuncExit(thr); - thr->external_tag = 0; + ExternalAccess(addr, caller_pc, tag, MemoryWrite); } } // extern "C" -- cgit v1.2.1 From f94bfbbbbb7189d9e50ddf589a7567770859d0c0 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Apr 2017 17:49:19 +0000 Subject: [tsan] Add a test for "external" API that checks the dup suppression is based on the caller PC We need to make sure that the "external" API isn't dup'ing all data races into a single one (because the stack might look the same) and suppressing all external races. This works now, so just adding a test for that. Differential Revision: https://reviews.llvm.org/D31734 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301011 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/external-dups.cc | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/tsan/Darwin/external-dups.cc diff --git a/test/tsan/Darwin/external-dups.cc b/test/tsan/Darwin/external-dups.cc new file mode 100644 index 000000000..b276977d4 --- /dev/null +++ b/test/tsan/Darwin/external-dups.cc @@ -0,0 +1,66 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#include + +#import "../test.h" + +extern "C" { +void *__tsan_external_register_tag(const char *object_type); +void *__tsan_external_assign_tag(void *addr, void *tag); +void __tsan_external_read(void *addr, void *caller_pc, void *tag); +void __tsan_external_write(void *addr, void *caller_pc, void *tag); +void __tsan_write8(void *addr); +} + +void *tag; + +__attribute__((no_sanitize("thread"))) +void ExternalWrite(void *addr) { + __tsan_external_write(addr, __builtin_return_address(0), tag); +} + +int main(int argc, char *argv[]) { + barrier_init(&barrier, 2); + tag = __tsan_external_register_tag("HelloWorld"); + fprintf(stderr, "Start.\n"); + // CHECK: Start. + + for (int i = 0; i < 4; i++) { + void *opaque_object = malloc(16); + std::thread t1([opaque_object] { + ExternalWrite(opaque_object); + barrier_wait(&barrier); + }); + std::thread t2([opaque_object] { + barrier_wait(&barrier); + ExternalWrite(opaque_object); + }); + // CHECK: WARNING: ThreadSanitizer: race on a library object + t1.join(); + t2.join(); + } + + fprintf(stderr, "First phase done.\n"); + // CHECK: First phase done. + + for (int i = 0; i < 4; i++) { + void *opaque_object = malloc(16); + std::thread t1([opaque_object] { + ExternalWrite(opaque_object); + barrier_wait(&barrier); + }); + std::thread t2([opaque_object] { + barrier_wait(&barrier); + ExternalWrite(opaque_object); + }); + // CHECK: WARNING: ThreadSanitizer: race on a library object + t1.join(); + t2.join(); + } + + fprintf(stderr, "Second phase done.\n"); + // CHECK: Second phase done. +} + +// CHECK: ThreadSanitizer: reported 2 warnings -- cgit v1.2.1 From 9cb198789f2eb9672fdc0e22e1abb89d1ed8132a Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 21 Apr 2017 18:10:53 +0000 Subject: [scudo] Bypass Quarantine if its size is set to 0 Summary: In the current state of things, the deallocation path puts a chunk in the Quarantine whether it's enabled or not (size of 0). When the Quarantine is disabled, this results in the header being loaded (and checked) twice, and stored (and checksummed) once, in `deallocate` and `Recycle`. This change introduces a `quarantineOrDeallocateChunk` function that has a fast path to deallocation if the Quarantine is disabled. Even though this is not the preferred configuration security-wise, this change saves a sizeable amount of processing for that particular situation (which could be adopted by low memory devices). Additionally this simplifies a bit `deallocate` and `reallocate`. Reviewers: dvyukov, kcc, alekseyshl Reviewed By: dvyukov Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32310 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301015 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 62 +++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 9812fc0f5..e89e09223 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -460,6 +460,38 @@ struct ScudoAllocator { return UserPtr; } + // Place a chunk in the quarantine. In the event of a zero-sized quarantine, + // we directly deallocate the chunk, otherwise the flow would lead to the + // chunk being checksummed twice, once before Put and once in Recycle, with + // no additional security value. + void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header, + uptr Size) { + bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0); + if (BypassQuarantine) { + Chunk->eraseHeader(); + void *Ptr = Chunk->getAllocBeg(Header); + if (LIKELY(!ThreadTornDown)) { + getBackendAllocator().Deallocate(&Cache, Ptr); + } else { + SpinMutexLock Lock(&FallbackMutex); + getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr); + } + } else { + UnpackedHeader NewHeader = *Header; + NewHeader.State = ChunkQuarantine; + Chunk->compareExchangeHeader(&NewHeader, Header); + if (LIKELY(!ThreadTornDown)) { + AllocatorQuarantine.Put(&ThreadQuarantineCache, + QuarantineCallback(&Cache), Chunk, Size); + } else { + SpinMutexLock l(&FallbackMutex); + AllocatorQuarantine.Put(&FallbackQuarantineCache, + QuarantineCallback(&FallbackAllocatorCache), + Chunk, Size); + } + } + } + // Deallocates a Chunk, which means adding it to the delayed free list (or // Quarantine). void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { @@ -499,24 +531,12 @@ struct ScudoAllocator { } } - UnpackedHeader NewHeader = OldHeader; - NewHeader.State = ChunkQuarantine; - Chunk->compareExchangeHeader(&NewHeader, &OldHeader); - // If a small memory amount was allocated with a larger alignment, we want // to take that into account. Otherwise the Quarantine would be filled with - // tiny chunks, taking a lot of VA memory. This an approximation of the + // tiny chunks, taking a lot of VA memory. This is an approximation of the // usable size, that allows us to not call GetActuallyAllocatedSize. uptr LiableSize = Size + (OldHeader.Offset << MinAlignment); - if (LIKELY(!ThreadTornDown)) { - AllocatorQuarantine.Put(&ThreadQuarantineCache, - QuarantineCallback(&Cache), Chunk, LiableSize); - } else { - SpinMutexLock l(&FallbackMutex); - AllocatorQuarantine.Put(&FallbackQuarantineCache, - QuarantineCallback(&FallbackAllocatorCache), - Chunk, LiableSize); - } + quarantineOrDeallocateChunk(Chunk, &OldHeader, LiableSize); } // Reallocates a chunk. We can save on a new allocation if the new requested @@ -541,11 +561,11 @@ struct ScudoAllocator { OldPtr); } uptr UsableSize = Chunk->getUsableSize(&OldHeader); - UnpackedHeader NewHeader = OldHeader; // The new size still fits in the current chunk, and the size difference // is reasonable. if (NewSize <= UsableSize && (UsableSize - NewSize) < (SizeClassMap::kMaxSize / 2)) { + UnpackedHeader NewHeader = OldHeader; NewHeader.SizeOrUnusedBytes = OldHeader.FromPrimary ? NewSize : UsableSize - NewSize; Chunk->compareExchangeHeader(&NewHeader, &OldHeader); @@ -558,17 +578,7 @@ struct ScudoAllocator { uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : UsableSize - OldHeader.SizeOrUnusedBytes; memcpy(NewPtr, OldPtr, Min(NewSize, OldSize)); - NewHeader.State = ChunkQuarantine; - Chunk->compareExchangeHeader(&NewHeader, &OldHeader); - if (LIKELY(!ThreadTornDown)) { - AllocatorQuarantine.Put(&ThreadQuarantineCache, - QuarantineCallback(&Cache), Chunk, UsableSize); - } else { - SpinMutexLock l(&FallbackMutex); - AllocatorQuarantine.Put(&FallbackQuarantineCache, - QuarantineCallback(&FallbackAllocatorCache), - Chunk, UsableSize); - } + quarantineOrDeallocateChunk(Chunk, &OldHeader, UsableSize); } return NewPtr; } -- cgit v1.2.1 From fa7f48480d5f954ef590b92da1b8544b9ff95705 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 21 Apr 2017 18:11:23 +0000 Subject: [cfi] Run tests with and without lld and thinlto. Run tests in all configurations: (standalone, with devirtualization) * (gold, lld) * (lto, thinlto) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301016 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/fuse-lld.cc | 2 +- test/cfi/CMakeLists.txt | 62 +++++++++++++++++++++++++-------- test/cfi/cross-dso/icall/lit.local.cfg | 3 ++ test/cfi/cross-dso/stats.cpp | 4 +++ test/cfi/icall/lit.local.cfg | 3 ++ test/cfi/lit.cfg | 4 +-- test/cfi/lit.site.cfg.in | 3 ++ test/lit.common.cfg | 16 ++++++++- test/lit.common.configured.in | 2 ++ test/safestack/lit.cfg | 2 +- 10 files changed, 81 insertions(+), 20 deletions(-) diff --git a/test/asan/TestCases/Windows/fuse-lld.cc b/test/asan/TestCases/Windows/fuse-lld.cc index 7fa5d4e8a..c20e5ff6c 100644 --- a/test/asan/TestCases/Windows/fuse-lld.cc +++ b/test/asan/TestCases/Windows/fuse-lld.cc @@ -1,6 +1,6 @@ // If we have LLD, see that things more or less work. // -// REQUIRES: lld +// REQUIRES: lld-available // // FIXME: Use -fuse-ld=lld after the old COFF linker is removed. // FIXME: Test will fail until we add flags for requesting dwarf or cv. diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index c3123a820..17266e5c0 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -1,14 +1,48 @@ -set(CFI_LIT_TEST_MODE Standalone) -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/Standalone/lit.site.cfg - ) +set(CFI_TESTSUITES) -set(CFI_LIT_TEST_MODE Devirt) -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/Devirt/lit.site.cfg - ) +macro (add_cfi_test_suites lld thinlto) + set(suffix) + if (${lld}) + set(suffix ${suffix}-lld) + endif() + if (${thinlto}) + set(suffix ${suffix}-thinlto) + endif() + + set(CFI_TEST_USE_LLD ${lld}) + set(CFI_TEST_USE_THINLTO ${thinlto}) + + set(CFI_LIT_TEST_MODE Standalone) + set(CFI_TEST_CONFIG_SUFFIX -standalone${suffix}) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Standalone${suffix}/lit.site.cfg + ) + list(APPEND CFI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Standalone${suffix}) + + set(CFI_LIT_TEST_MODE Devirt) + set(CFI_TEST_CONFIG_SUFFIX -devirt${suffix}) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Devirt${suffix}/lit.site.cfg + ) + list(APPEND CFI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Devirt${suffix}) +endmacro() + +if (APPLE) + add_cfi_test_suites(False False) + add_cfi_test_suites(False True) +elif (WINDOWS) + add_cfi_test_suites(True False) + add_cfi_test_suites(True True) +else() + add_cfi_test_suites(False False) + add_cfi_test_suites(False True) + if (COMPILER_RT_HAS_LLD) + add_cfi_test_suites(True False) + add_cfi_test_suites(True True) + endif() +endif() set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) list(APPEND CFI_TEST_DEPS @@ -34,7 +68,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LTO ) endif() - if(WIN32 AND COMPILER_RT_HAS_LLD) + if(NOT APPLE AND COMPILER_RT_HAS_LLD) list(APPEND CFI_TEST_DEPS lld ) @@ -42,13 +76,11 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) endif() add_lit_testsuite(check-cfi "Running the cfi regression tests" - ${CMAKE_CURRENT_BINARY_DIR}/Standalone - ${CMAKE_CURRENT_BINARY_DIR}/Devirt + ${CFI_TESTSUITES} DEPENDS ${CFI_TEST_DEPS}) add_lit_target(check-cfi-and-supported "Running the cfi regression tests" - ${CMAKE_CURRENT_BINARY_DIR}/Standalone - ${CMAKE_CURRENT_BINARY_DIR}/Devirt + ${CFI_TESTSUITES} PARAMS check_supported=1 DEPENDS ${CFI_TEST_DEPS}) diff --git a/test/cfi/cross-dso/icall/lit.local.cfg b/test/cfi/cross-dso/icall/lit.local.cfg index db08765a2..322b287a6 100644 --- a/test/cfi/cross-dso/icall/lit.local.cfg +++ b/test/cfi/cross-dso/icall/lit.local.cfg @@ -1,3 +1,6 @@ # The cfi-icall checker is only supported on x86 and x86_64 for now. if config.root.host_arch not in ['x86', 'x86_64']: config.unsupported = True + +if config.root.use_thinlto: + config.unsupported = True diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp index 6566ea2fc..fb98a50a3 100644 --- a/test/cfi/cross-dso/stats.cpp +++ b/test/cfi/cross-dso/stats.cpp @@ -3,6 +3,10 @@ // RUN: env SANITIZER_STATS_PATH=%t.stats %t // RUN: sanstats %t.stats | FileCheck %s +// CFI-icall is not implemented in thinlto mode => ".cfi" suffixes are missing +// in sanstats output. +// XFAIL: thinlto + struct ABase {}; struct A : ABase { diff --git a/test/cfi/icall/lit.local.cfg b/test/cfi/icall/lit.local.cfg index db08765a2..44891c5e2 100644 --- a/test/cfi/icall/lit.local.cfg +++ b/test/cfi/icall/lit.local.cfg @@ -1,3 +1,6 @@ # The cfi-icall checker is only supported on x86 and x86_64 for now. if config.root.host_arch not in ['x86', 'x86_64']: config.unsupported = True + +if config.use_thinlto: + config.unsupported = True diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index 3c0250632..314ba5ce9 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -1,7 +1,7 @@ import lit.formats import os -config.name = 'cfi' +config.name = 'cfi' + config.name_suffix config.suffixes = ['.c', '.cpp', '.test'] config.test_source_root = os.path.dirname(__file__) @@ -10,7 +10,7 @@ clangxx = ' '.join([config.clang] + config.cxx_mode_flags) config.substitutions.append((r"%clang ", ' '.join([config.clang]) + ' ')) config.substitutions.append((r"%clangxx ", clangxx + ' ')) if config.lto_supported: - clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=cfi ']) + clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=cfi ']) if config.cfi_lit_test_mode == "Devirt": config.available_features.add('devirt') diff --git a/test/cfi/lit.site.cfg.in b/test/cfi/lit.site.cfg.in index 87e5b51e7..63611f659 100644 --- a/test/cfi/lit.site.cfg.in +++ b/test/cfi/lit.site.cfg.in @@ -1,6 +1,9 @@ @LIT_SITE_CFG_IN_HEADER@ +config.name_suffix = "@CFI_TEST_CONFIG_SUFFIX@" config.cfi_lit_test_mode = "@CFI_LIT_TEST_MODE@" +config.use_lld = @CFI_TEST_USE_LLD@ +config.use_thinlto = @CFI_TEST_USE_THINLTO@ lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/test/lit.common.cfg b/test/lit.common.cfg index d59d7d668..4b03a5504 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -129,6 +129,9 @@ if sanitizer_can_use_cxxabi: config.available_features.add('cxxabi') if config.has_lld: + config.available_features.add('lld-available') + +if config.use_lld: config.available_features.add('lld') if config.can_symbolize: @@ -180,6 +183,9 @@ def is_darwin_lto_supported(): return os.path.exists(os.path.join(config.llvm_shlib_dir, 'libLTO.dylib')) def is_linux_lto_supported(): + if config.use_lld: + return True + if not os.path.exists(os.path.join(config.llvm_shlib_dir, 'LLVMgold.so')): return False @@ -202,7 +208,10 @@ if config.host_os == 'Darwin' and is_darwin_lto_supported(): elif config.host_os == 'Linux' and is_linux_lto_supported(): config.lto_supported = True config.lto_launch = [] - config.lto_flags = ["-fuse-ld=gold"] + if config.use_lld: + config.lto_flags = ["-fuse-ld=lld"] + else: + config.lto_flags = ["-fuse-ld=gold"] elif config.host_os == 'Windows' and is_windows_lto_supported(): config.lto_supported = True config.lto_launch = [] @@ -213,6 +222,11 @@ else: if config.lto_supported: config.available_features.add('lto') + if config.use_thinlto: + config.available_features.add('thinlto') + config.lto_flags += ["-flto=thin"] + else: + config.lto_flags += ["-flto"] # Ask llvm-config about assertion mode. try: diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 387f4d4a7..0ad03a180 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -28,6 +28,8 @@ set_default("emulator", "@COMPILER_RT_EMULATOR@") set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) +set_default("use_lld", False) +set_default("use_thinlto", False) config.available_features.add('target-is-%s' % config.target_arch) # LLVM tools dir can be passed in lit parameters, so try to diff --git a/test/safestack/lit.cfg b/test/safestack/lit.cfg index d4ec73ce7..fb5672936 100644 --- a/test/safestack/lit.cfg +++ b/test/safestack/lit.cfg @@ -16,7 +16,7 @@ config.substitutions.append( ("%clang_nosafestack ", config.clang + " -O0 -fno-s config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsanitize=safe-stack ") ) if config.lto_supported: - config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=safe-stack ']))) + config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=safe-stack ']))) # SafeStack tests are currently supported on Linux, FreeBSD and Darwin only. if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']: -- cgit v1.2.1 From 6d68f82042320a09156b04a41bbfc1a10e695d4a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 21 Apr 2017 19:22:15 +0000 Subject: [cfi] Replace elif with elseif in cmake. Apparently, elif() is deprecated. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301022 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 17266e5c0..aa6c8214c 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -32,7 +32,7 @@ endmacro() if (APPLE) add_cfi_test_suites(False False) add_cfi_test_suites(False True) -elif (WINDOWS) +elseif(WINDOWS) add_cfi_test_suites(True False) add_cfi_test_suites(True True) else() -- cgit v1.2.1 From c8d70402d14b60b77a8ab84fd1dac4153a0bdeb7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 21 Apr 2017 19:39:46 +0000 Subject: [asan] Optimize strchr for strict_string_checks=false Summary: strchr interceptor does not need to call strlen if strict_string_checks is not enabled. Unnecessary strlen calls affect python parser performance. Reviewers: eugenis, kcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D32264 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301027 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 22 ++++++-------- test/asan/TestCases/Posix/strchr.c | 34 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 test/asan/TestCases/Posix/strchr.c diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 38cb3c2c2..9da1822f3 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -139,12 +139,9 @@ bool PlatformHasDifferentMemcpyAndMemmove(); #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) #endif -#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \ - COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ - common_flags()->strict_string_checks ? (len) + 1 : (n) ) - #define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ - COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) ) #ifndef COMMON_INTERCEPTOR_ON_DLOPEN #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ @@ -450,8 +447,7 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1, const char *s2) { uptr len1 = REAL(strlen)(s1); uptr len2 = REAL(strlen)(s2); - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1, - r ? r - s1 + len2 : len1 + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); } #endif @@ -577,10 +573,11 @@ INTERCEPTOR(char*, strchr, const char *s, int c) { return internal_strchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); char *result = REAL(strchr)(s, c); - uptr len = internal_strlen(s); - uptr n = result ? result - s + 1 : len + 1; - if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n); + if (common_flags()->intercept_strchr) { + // Keep strlen as macro argument, as macro may ignore it. + COMMON_INTERCEPTOR_READ_STRING(ctx, s, + (result ? result - s : REAL(strlen)(s)) + 1); + } return result; } #define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) @@ -609,9 +606,8 @@ INTERCEPTOR(char*, strrchr, const char *s, int c) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strrchr(s, c); COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); - uptr len = internal_strlen(s); if (common_flags()->intercept_strchr) - COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); return REAL(strrchr)(s, c); } #define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c new file mode 100644 index 000000000..7086e1374 --- /dev/null +++ b/test/asan/TestCases/Posix/strchr.c @@ -0,0 +1,34 @@ +// Test strchr for strict_string_checks=false does not look beyond necessary +// char. +// RUN: %clang_asan %s -o %t +// RUN: %env_asan_opts=strict_string_checks=false %run %t 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + size_t page_size = sysconf(_SC_PAGE_SIZE); + size_t size = 2 * page_size; + char *s = (char *)mmap(0, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(s); + assert(((uintptr_t)s & (page_size - 1)) == 0); + memset(s, 'o', size); + s[size - 1] = 0; + + char *p = s + page_size - 1; + *p = 'x'; + + if (mprotect(p + 1, 1, PROT_NONE)) + return 1; + char *r = strchr(s, 'x'); + // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address + assert(r == p); + + return 0; +} -- cgit v1.2.1 From ba68c62d8b58b511859fd87a2b870e4a18e9b3b1 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 21 Apr 2017 21:34:37 +0000 Subject: Suppress DTLS leak happening in some glibc versions. Summary: Refer to https://sourceware.org/bugzilla/show_bug.cgi?id=12650 for the context. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32377 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301043 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 200f16a59..5a4cb454e 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -72,10 +72,11 @@ static const char kStdSuppressions[] = #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // The actual string allocation happens here (for more details refer to the // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition). - "leak:*_dl_map_object_deps*"; -#else - ""; + "leak:*_dl_map_object_deps*\n" #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // TLS leak in some glibc versions, described in + // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. + "leak:*tls_get_addr_tail*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); -- cgit v1.2.1 From bed4c80fce1fa61c55bb53fc7338cf628655fe1d Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 21 Apr 2017 21:59:53 +0000 Subject: [lsan] Enable LSan on PowerPC64. Summary: Re-landing reverted D31995 with suppressions defined in D32303 and D32377. Reviewers: eugenis Subscribers: nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D32379 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301048 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 2 +- lib/lsan/lsan_common.h | 3 ++- test/lsan/lit.common.cfg | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index e5def17d4..fad5adb01 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> PrimaryAllocator; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__powerpc64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; static const uptr kSpaceSize = 0x40000000000ULL; // 4T. diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 121b9c082..beb31d6f4 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -32,7 +32,8 @@ // new architecture inside sanitizer library. #if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ + defined(__powerpc64__)) #define CAN_SANITIZE_LEAKS 1 #elif defined(__i386__) && \ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 888ed424d..da439d4c0 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,8 +67,9 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux, and mips64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']: +# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, and mips64 Linux only. +supported_linux = config.host_os is 'Linux' and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l'] +if not (supported_linux): config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 5386ce5171f419d6307004c545bca6232358bdcc Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Sat, 22 Apr 2017 00:07:47 +0000 Subject: [cfi] Disable thinlto tests on Darwin. These were added in r301016, but they're failing, because -fsanitize=cfi seemingly causes -flto=thin to emit raw bitcode objects, rather than the mach-o-wrapped bitcode we emit with -flto=thin alone. That causes all tests to fail with ld64 errors. Filed PR32741. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301065 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index aa6c8214c..ee2ac5566 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -31,7 +31,6 @@ endmacro() if (APPLE) add_cfi_test_suites(False False) - add_cfi_test_suites(False True) elseif(WINDOWS) add_cfi_test_suites(True False) add_cfi_test_suites(True True) -- cgit v1.2.1 From 1d5d795baf398e19b1f687190fbdb0a89d14f220 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 22 Apr 2017 18:45:17 +0000 Subject: [builtins] Implement emulated TLS on Windows. Summary: LLVM JIT needs to be able to use emulated TLS on all platforms, and this provides a reference one can compile to enable emutls for Linux/Mac/Windows. Reviewers: chh, howard.hinnant Reviewed By: chh Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D30787 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301089 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 9 +- lib/builtins/emutls.c | 280 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 222 insertions(+), 67 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 161487e70..c30d9b363 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -164,7 +164,8 @@ set(GENERIC_SOURCES udivti3.c umoddi3.c umodsi3.c - umodti3.c) + umodti3.c + emutls.c) option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" @@ -187,12 +188,6 @@ if(APPLE) atomic_thread_fence.c) endif() -if(NOT WIN32 OR MINGW) - set(GENERIC_SOURCES - ${GENERIC_SOURCES} - emutls.c) -endif() - if (HAVE_UNWIND_H) set(GENERIC_SOURCES ${GENERIC_SOURCES} diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index eccbf5336..c884e9040 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -7,7 +7,7 @@ * * ===----------------------------------------------------------------------=== */ -#include + #include #include #include @@ -15,6 +15,23 @@ #include "int_lib.h" #include "int_util.h" +typedef struct emutls_address_array { + uintptr_t size; /* number of elements in the 'data' array */ + void* data[]; +} emutls_address_array; + +static void emutls_shutdown(emutls_address_array *array); + +#ifndef _WIN32 + +#include + +static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t emutls_pthread_key; + +typedef unsigned int gcc_word __attribute__((mode(word))); +typedef unsigned int gcc_pointer __attribute__((mode(pointer))); + /* Default is not to use posix_memalign, so systems like Android * can use thread local data without heavier POSIX memory allocators. */ @@ -22,26 +39,6 @@ #define EMUTLS_USE_POSIX_MEMALIGN 0 #endif -/* For every TLS variable xyz, - * there is one __emutls_control variable named __emutls_v.xyz. - * If xyz has non-zero initial value, __emutls_v.xyz's "value" - * will point to __emutls_t.xyz, which has the initial value. - */ -typedef unsigned int gcc_word __attribute__((mode(word))); -typedef struct __emutls_control { - /* Must use gcc_word here, instead of size_t, to match GCC. When - gcc_word is larger than size_t, the upper extra bits are all - zeros. We can use variables of size_t to operate on size and - align. */ - gcc_word size; /* size of the object in bytes */ - gcc_word align; /* alignment of the object in bytes */ - union { - uintptr_t index; /* data[index-1] is the object address */ - void* address; /* object address, when in single thread env */ - } object; - void* value; /* null or non-zero initial value for the object */ -} __emutls_control; - static __inline void *emutls_memalign_alloc(size_t align, size_t size) { void *base; #if EMUTLS_USE_POSIX_MEMALIGN @@ -50,7 +47,7 @@ static __inline void *emutls_memalign_alloc(size_t align, size_t size) { #else #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*)) char* object; - if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) + if ((object = (char*)malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) abort(); base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) & ~(uintptr_t)(align - 1)); @@ -69,10 +66,192 @@ static __inline void emutls_memalign_free(void *base) { #endif } +static void emutls_key_destructor(void* ptr) { + emutls_shutdown((emutls_address_array*)ptr); + free(ptr); +} + +static __inline void emutls_init(void) { + if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) + abort(); +} + +static __inline void emutls_init_once(void) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, emutls_init); +} + +static __inline void emutls_lock() { + pthread_mutex_lock(&emutls_mutex); +} + +static __inline void emutls_unlock() { + pthread_mutex_unlock(&emutls_mutex); +} + +static __inline void emutls_setspecific(emutls_address_array *value) { + pthread_setspecific(emutls_pthread_key, (void*) value); +} + +static __inline emutls_address_array* emutls_getspecific() { + return (emutls_address_array*) pthread_getspecific(emutls_pthread_key); +} + +#else + +#include +#include +#include +#include +#include + +static LPCRITICAL_SECTION emutls_mutex; +static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES; + +typedef uintptr_t gcc_word; +typedef void * gcc_pointer; + +static void win_error(DWORD last_err, const char *hint) { + char *buffer = NULL; + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) { + fprintf(stderr, "Windows error: %s\n", buffer); + } else { + fprintf(stderr, "Unkown Windows error: %s\n", hint); + } + LocalFree(buffer); +} + +static __inline void win_abort(DWORD last_err, const char *hint) { + win_error(last_err, hint); + abort(); +} + +static __inline void *emutls_memalign_alloc(size_t align, size_t size) { + void *base = _aligned_malloc(size, align); + if (!base) + win_abort(GetLastError(), "_aligned_malloc"); + return base; +} + +static __inline void emutls_memalign_free(void *base) { + _aligned_free(base); +} + +static void emutls_exit(void) { + if (emutls_mutex) { + DeleteCriticalSection(emutls_mutex); + _aligned_free(emutls_mutex); + emutls_mutex = NULL; + } + if (emutls_tls_index != TLS_OUT_OF_INDEXES) { + emutls_shutdown((emutls_address_array*)TlsGetValue(emutls_tls_index)); + TlsFree(emutls_tls_index); + emutls_tls_index = TLS_OUT_OF_INDEXES; + } +} + +#pragma warning (push) +#pragma warning (disable : 4100) +static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) { + emutls_mutex = (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16); + if (!emutls_mutex) { + win_error(GetLastError(), "_aligned_malloc"); + return FALSE; + } + InitializeCriticalSection(emutls_mutex); + + emutls_tls_index = TlsAlloc(); + if (emutls_tls_index == TLS_OUT_OF_INDEXES) { + emutls_exit(); + win_error(GetLastError(), "TlsAlloc"); + return FALSE; + } + atexit(&emutls_exit); + return TRUE; +} + +static __inline void emutls_init_once(void) { + static INIT_ONCE once; + InitOnceExecuteOnce(&once, emutls_init, NULL, NULL); +} + +static __inline void emutls_lock() { + EnterCriticalSection(emutls_mutex); +} + +static __inline void emutls_unlock() { + LeaveCriticalSection(emutls_mutex); +} + +static __inline void emutls_setspecific(emutls_address_array *value) { + if (TlsSetValue(emutls_tls_index, (LPVOID) value) == 0) + win_abort(GetLastError(), "TlsSetValue"); +} + +static __inline emutls_address_array* emutls_getspecific() { + LPVOID value = TlsGetValue(emutls_tls_index); + if (value == NULL) { + const DWORD err = GetLastError(); + if (err != ERROR_SUCCESS) + win_abort(err, "TlsGetValue"); + } + return (emutls_address_array*) value; +} + +enum { __ATOMIC_ACQUIRE, __ATOMIC_RELEASE }; + +static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) { + assert(type == __ATOMIC_ACQUIRE); + return (uintptr_t) _load_be_u64(ptr); +} + +static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) { + assert(type == __ATOMIC_RELEASE); + _store_be_u64(ptr, val); +} +#pragma warning (pop) + +#endif + +static size_t emutls_num_object = 0; /* number of allocated TLS objects */ + +/* Free the allocated TLS data + */ +static void emutls_shutdown(emutls_address_array *array) { + if (array) { + uintptr_t i; + for (i = 0; i < array->size; ++i) { + if (array->data[i]) + emutls_memalign_free(array->data[i]); + } + } +} + +/* For every TLS variable xyz, + * there is one __emutls_control variable named __emutls_v.xyz. + * If xyz has non-zero initial value, __emutls_v.xyz's "value" + * will point to __emutls_t.xyz, which has the initial value. + */ +typedef struct __emutls_control { + /* Must use gcc_word here, instead of size_t, to match GCC. When + gcc_word is larger than size_t, the upper extra bits are all + zeros. We can use variables of size_t to operate on size and + align. */ + gcc_word size; /* size of the object in bytes */ + gcc_word align; /* alignment of the object in bytes */ + union { + uintptr_t index; /* data[index-1] is the object address */ + void* address; /* object address, when in single thread env */ + } object; + void* value; /* null or non-zero initial value for the object */ +} __emutls_control; + /* Emulated TLS objects are always allocated at run-time. */ static __inline void *emutls_allocate_object(__emutls_control *control) { /* Use standard C types, check with gcc's emutls.o. */ - typedef unsigned int gcc_pointer __attribute__((mode(pointer))); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer)); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*)); @@ -93,45 +272,19 @@ static __inline void *emutls_allocate_object(__emutls_control *control) { return base; } -static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; - -static size_t emutls_num_object = 0; /* number of allocated TLS objects */ - -typedef struct emutls_address_array { - uintptr_t size; /* number of elements in the 'data' array */ - void* data[]; -} emutls_address_array; - -static pthread_key_t emutls_pthread_key; - -static void emutls_key_destructor(void* ptr) { - emutls_address_array* array = (emutls_address_array*)ptr; - uintptr_t i; - for (i = 0; i < array->size; ++i) { - if (array->data[i]) - emutls_memalign_free(array->data[i]); - } - free(ptr); -} - -static void emutls_init(void) { - if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) - abort(); -} /* Returns control->object.index; set index if not allocated yet. */ static __inline uintptr_t emutls_get_index(__emutls_control *control) { uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE); if (!index) { - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, emutls_init); - pthread_mutex_lock(&emutls_mutex); + emutls_init_once(); + emutls_lock(); index = control->object.index; if (!index) { index = ++emutls_num_object; __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE); } - pthread_mutex_unlock(&emutls_mutex); + emutls_unlock(); } return index; } @@ -142,7 +295,7 @@ static __inline void emutls_check_array_set_size(emutls_address_array *array, if (array == NULL) abort(); array->size = size; - pthread_setspecific(emutls_pthread_key, (void*)array); + emutls_setspecific(array); } /* Returns the new 'data' array size, number of elements, @@ -156,22 +309,29 @@ static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) { return ((index + 1 + 15) & ~((uintptr_t)15)) - 1; } +/* Returns the size in bytes required for an emutls_address_array with + * N number of elements for data field. + */ +static __inline uintptr_t emutls_asize(uintptr_t N) { + return N * sizeof(void *) + sizeof(emutls_address_array); +} + /* Returns the thread local emutls_address_array. * Extends its size if necessary to hold address at index. */ static __inline emutls_address_array * emutls_get_address_array(uintptr_t index) { - emutls_address_array* array = pthread_getspecific(emutls_pthread_key); + emutls_address_array* array = emutls_getspecific(); if (array == NULL) { uintptr_t new_size = emutls_new_data_array_size(index); - array = malloc(new_size * sizeof(void *) + sizeof(emutls_address_array)); + array = (emutls_address_array*) malloc(emutls_asize(new_size)); if (array) memset(array->data, 0, new_size * sizeof(void*)); emutls_check_array_set_size(array, new_size); } else if (index > array->size) { uintptr_t orig_size = array->size; uintptr_t new_size = emutls_new_data_array_size(index); - array = realloc(array, new_size * sizeof(void *) + sizeof(emutls_address_array)); + array = (emutls_address_array*) realloc(array, emutls_asize(new_size)); if (array) memset(array->data + orig_size, 0, (new_size - orig_size) * sizeof(void*)); @@ -182,8 +342,8 @@ emutls_get_address_array(uintptr_t index) { void* __emutls_get_address(__emutls_control* control) { uintptr_t index = emutls_get_index(control); - emutls_address_array* array = emutls_get_address_array(index); - if (array->data[index - 1] == NULL) - array->data[index - 1] = emutls_allocate_object(control); - return array->data[index - 1]; + emutls_address_array* array = emutls_get_address_array(index--); + if (array->data[index] == NULL) + array->data[index] = emutls_allocate_object(control); + return array->data[index]; } -- cgit v1.2.1 From c88db7d06d5c489e19e7454638b9ddda7991ca2a Mon Sep 17 00:00:00 2001 From: Sagar Thakur Date: Mon, 24 Apr 2017 04:29:44 +0000 Subject: [scudo] Enabling MIPS support for Scudo Adding MIPS 32-bit and 64-bit support for Scudo. Reviewed by cryptoad Differential: D31803 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301158 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/scudo/random_shuffle.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 60cb39a93..255761db2 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -179,7 +179,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64}) set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) -set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}) +set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le) if(APPLE) diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 41e67ded6..05a432615 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From 6711394c339fd776d1aaec16da8be461e32a93d7 Mon Sep 17 00:00:00 2001 From: Sagar Thakur Date: Mon, 24 Apr 2017 11:02:36 +0000 Subject: Revert [scudo] Enabling MIPS support for Scudo This patch broke the buildbot clang-cmake-mips. Investigating the issue. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301173 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/scudo/random_shuffle.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 255761db2..60cb39a93 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -179,7 +179,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64}) set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) -set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}) +set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le) if(APPLE) diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 05a432615..41e67ded6 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From 4ba77b58fd117d808570d5bd57471bba154e2778 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 24 Apr 2017 14:53:38 +0000 Subject: [sanitizer] Cache SizeClassForTransferBatch in the 32-bit local cache Summary: `SizeClassForTransferBatch` is expensive and is called for every `CreateBatch` and `DestroyBatch`. Caching it means `kNumClasses` calls in `InitCache` instead. This should be a performance gain if more than `kNumClasses / 2` batches are created and destroyed during the lifetime of the local cache. I have chosen to fully remove the function and putting the code in `InitCache`, which is a debatable choice. In single threaded benchmarks leveraging primary backed allocations, this turns out to be a sizeable gain in performances (greater than 5%). In multithreaded benchmarks leveraging everything, it is less significant but still an improvement (about 1%). Reviewers: kcc, dvyukov, alekseyshl Reviewed By: dvyukov Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32365 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301184 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index d6c66604e..b3729bf55 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -180,6 +180,7 @@ struct SizeClassAllocator32LocalCache { uptr count; uptr max_count; uptr class_size; + uptr class_id_for_transfer_batch; void *batch[2 * TransferBatch::kMaxNumCached]; }; PerClass per_class_[kNumClasses]; @@ -188,32 +189,31 @@ struct SizeClassAllocator32LocalCache { void InitCache() { if (per_class_[1].max_count) return; + // TransferBatch class is declared in SizeClassAllocator. + uptr class_id_for_transfer_batch = + SizeClassMap::ClassID(sizeof(TransferBatch)); for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; - c->max_count = 2 * TransferBatch::MaxCached(i); + uptr max_cached = TransferBatch::MaxCached(i); + c->max_count = 2 * max_cached; c->class_size = Allocator::ClassIdToSize(i); + // We transfer chunks between central and thread-local free lists in + // batches. For small size classes we allocate batches separately. For + // large size classes we may use one of the chunks to store the batch. + // sizeof(TransferBatch) must be a power of 2 for more efficient + // allocation. + c->class_id_for_transfer_batch = (c->class_size < + TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ? + class_id_for_transfer_batch : 0; } } - // TransferBatch class is declared in SizeClassAllocator. - // We transfer chunks between central and thread-local free lists in batches. - // For small size classes we allocate batches separately. - // For large size classes we may use one of the chunks to store the batch. - // sizeof(TransferBatch) must be a power of 2 for more efficient allocation. - static uptr SizeClassForTransferBatch(uptr class_id) { - if (Allocator::ClassIdToSize(class_id) < - TransferBatch::AllocationSizeRequiredForNElements( - TransferBatch::MaxCached(class_id))) - return SizeClassMap::ClassID(sizeof(TransferBatch)); - return 0; - } - // Returns a TransferBatch suitable for class_id. // For small size classes allocates the batch from the allocator. // For large size classes simply returns b. TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, TransferBatch *b) { - if (uptr batch_class_id = SizeClassForTransferBatch(class_id)) + if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch) return (TransferBatch*)Allocate(allocator, batch_class_id); return b; } @@ -223,7 +223,7 @@ struct SizeClassAllocator32LocalCache { // Does notthing for large size classes. void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, TransferBatch *b) { - if (uptr batch_class_id = SizeClassForTransferBatch(class_id)) + if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch) Deallocate(allocator, batch_class_id, b); } -- cgit v1.2.1 From b4626e22fe9d8d54f24c164168dcc7ac7e8f7c5b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 24 Apr 2017 16:42:29 +0000 Subject: [tsan] Remove the extra word "object" from description of external races Differential Revision: https://reviews.llvm.org/D32383 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301189 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_report.cc | 4 ++-- test/tsan/Darwin/external.cc | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 7de00840c..af5fe6176 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -169,7 +169,7 @@ static void PrintMop(const ReportMop *mop, bool first) { MopDesc(first, mop->write, mop->atomic), mop->size, (void *)mop->addr, thread_name(thrbuf, mop->tid)); } else { - Printf(" %s access of object %s at %p by %s", + Printf(" %s access of %s at %p by %s", ExternalMopDesc(first, mop->write), object_type, (void *)mop->addr, thread_name(thrbuf, mop->tid)); } @@ -202,7 +202,7 @@ static void PrintLocation(const ReportLocation *loc) { loc->heap_chunk_size, loc->heap_chunk_start, thread_name(thrbuf, loc->tid)); } else { - Printf(" Location is %s object of size %zu at %p allocated by %s:\n", + Printf(" Location is %s of size %zu at %p allocated by %s:\n", object_type, loc->heap_chunk_size, loc->heap_chunk_start, thread_name(thrbuf, loc->tid)); } diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc index 66881d3e5..211694ab7 100644 --- a/test/tsan/Darwin/external.cc +++ b/test/tsan/Darwin/external.cc @@ -68,11 +68,11 @@ int main(int argc, char *argv[]) { // TEST2-NOT: WARNING: ThreadSanitizer // TEST3: WARNING: ThreadSanitizer: race on a library object - // TEST3: {{Mutating|read-only}} access of object MyLibrary::MyObject at + // TEST3: {{Mutating|read-only}} access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectRead}} - // TEST3: Previous {{mutating|read-only}} access of object MyLibrary::MyObject at + // TEST3: Previous {{mutating|read-only}} access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectRead}} - // TEST3: Location is MyLibrary::MyObject object of size 16 at + // TEST3: Location is MyLibrary::MyObject of size 16 at // TEST3: {{ObjectCreate}} fprintf(stderr, "RW test done\n"); @@ -91,11 +91,11 @@ int main(int argc, char *argv[]) { // TEST2-NOT: WARNING: ThreadSanitizer // TEST3: WARNING: ThreadSanitizer: race on a library object - // TEST3: Mutating access of object MyLibrary::MyObject at + // TEST3: Mutating access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectWriteAnother}} - // TEST3: Previous mutating access of object MyLibrary::MyObject at + // TEST3: Previous mutating access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectWriteAnother}} - // TEST3: Location is MyLibrary::MyObject object of size 16 at + // TEST3: Location is MyLibrary::MyObject of size 16 at // TEST3: {{ObjectCreate}} fprintf(stderr, "WW test done\n"); -- cgit v1.2.1 From 537070f680fce3fdae6a15a0bf7f25c57960db39 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 24 Apr 2017 16:48:30 +0000 Subject: [tsan] Include __tsan_external_* API from a header file instead of declaring them manually. NFC. Differential Revision: https://reviews.llvm.org/D32384 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301190 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/debug_external.cc | 2 -- test/tsan/Darwin/external-dups.cc | 8 -------- test/tsan/test.h | 2 ++ test/tsan/unaligned_race.cc | 23 +++++++---------------- 4 files changed, 9 insertions(+), 26 deletions(-) diff --git a/test/tsan/Darwin/debug_external.cc b/test/tsan/Darwin/debug_external.cc index 217690fc5..2418a271b 100644 --- a/test/tsan/Darwin/debug_external.cc +++ b/test/tsan/Darwin/debug_external.cc @@ -17,8 +17,6 @@ int __tsan_get_report_loc(void *report, unsigned long idx, const char **type, unsigned long trace_size); int __tsan_get_report_loc_object_type(void *report, unsigned long idx, const char **object_type); -void *__tsan_external_register_tag(const char *object_type); -void __tsan_external_assign_tag(void *addr, void *tag); } void *Thread(void *arg) { diff --git a/test/tsan/Darwin/external-dups.cc b/test/tsan/Darwin/external-dups.cc index b276977d4..79432bac4 100644 --- a/test/tsan/Darwin/external-dups.cc +++ b/test/tsan/Darwin/external-dups.cc @@ -5,14 +5,6 @@ #import "../test.h" -extern "C" { -void *__tsan_external_register_tag(const char *object_type); -void *__tsan_external_assign_tag(void *addr, void *tag); -void __tsan_external_read(void *addr, void *caller_pc, void *tag); -void __tsan_external_write(void *addr, void *caller_pc, void *tag); -void __tsan_write8(void *addr); -} - void *tag; __attribute__((no_sanitize("thread"))) diff --git a/test/tsan/test.h b/test/tsan/test.h index 6b981c09f..bc4f7aad5 100644 --- a/test/tsan/test.h +++ b/test/tsan/test.h @@ -8,6 +8,8 @@ #include #include "sanitizer_common/print_address.h" +#include + #ifdef __APPLE__ #include #endif diff --git a/test/tsan/unaligned_race.cc b/test/tsan/unaligned_race.cc index 030642a4d..5850b2154 100644 --- a/test/tsan/unaligned_race.cc +++ b/test/tsan/unaligned_race.cc @@ -6,31 +6,22 @@ volatile uint64_t objs[8*2*(2 + 4 + 8)][2]; -extern "C" { -uint16_t __sanitizer_unaligned_load16(volatile void *addr); -uint32_t __sanitizer_unaligned_load32(volatile void *addr); -uint64_t __sanitizer_unaligned_load64(volatile void *addr); -void __sanitizer_unaligned_store16(volatile void *addr, uint16_t v); -void __sanitizer_unaligned_store32(volatile void *addr, uint32_t v); -void __sanitizer_unaligned_store64(volatile void *addr, uint64_t v); -} - // All this mess is to generate unique stack for each race, // otherwise tsan will suppress similar stacks. -static NOINLINE void access(volatile char *p, int sz, int rw) { +static NOINLINE void access(volatile void *p, int sz, int rw) { if (rw) { switch (sz) { - case 0: __sanitizer_unaligned_store16(p, 0); break; - case 1: __sanitizer_unaligned_store32(p, 0); break; - case 2: __sanitizer_unaligned_store64(p, 0); break; + case 0: __sanitizer_unaligned_store16((void *)p, 0); break; + case 1: __sanitizer_unaligned_store32((void *)p, 0); break; + case 2: __sanitizer_unaligned_store64((void *)p, 0); break; default: exit(1); } } else { switch (sz) { - case 0: __sanitizer_unaligned_load16(p); break; - case 1: __sanitizer_unaligned_load32(p); break; - case 2: __sanitizer_unaligned_load64(p); break; + case 0: __sanitizer_unaligned_load16((void *)p); break; + case 1: __sanitizer_unaligned_load32((void *)p); break; + case 2: __sanitizer_unaligned_load64((void *)p); break; default: exit(1); } } -- cgit v1.2.1 From 6733410e1c98cb475feaa5de52dcf32c6c2796eb Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 24 Apr 2017 19:52:51 +0000 Subject: [cfi] Disable ThinLTO + CFI tests on Windows. PR32770. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301235 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index ee2ac5566..6bad910d4 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -30,10 +30,11 @@ macro (add_cfi_test_suites lld thinlto) endmacro() if (APPLE) + # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 add_cfi_test_suites(False False) elseif(WINDOWS) + # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32770 add_cfi_test_suites(True False) - add_cfi_test_suites(True True) else() add_cfi_test_suites(False False) add_cfi_test_suites(False True) -- cgit v1.2.1 From 46a48e5918ab64e40ed8b929fdb8d2ff4117cfa1 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 24 Apr 2017 20:25:39 +0000 Subject: [asan] Use posix strerror_r interceptor on android. This fixes a regression in r297315. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301243 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_interceptors.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9da1822f3..4fe1ac8f9 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3330,7 +3330,7 @@ INTERCEPTOR(char *, strerror, int errnum) { // * GNU version returns message pointer, which points to either buf or some // static storage. #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ - SANITIZER_MAC + SANITIZER_MAC || SANITIZER_ANDROID // POSIX version. Spec is not clear on whether buf is NULL-terminated. // At least on OSX, buf contents are valid even when the call fails. INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { -- cgit v1.2.1 From abff16288109c49485d7539fde5bb3d9f953b9df Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 24 Apr 2017 21:27:45 +0000 Subject: [asan] Remove asanwrapper from Android test harness. It is only necessary for pre-L and creates problems on newer builds. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301256 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/android_commands/android_run.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py index f4ea52bec..7e599453d 100755 --- a/test/asan/android_commands/android_run.py +++ b/test/asan/android_commands/android_run.py @@ -18,15 +18,14 @@ def build_env(): return ' '.join(args) is_64bit = (subprocess.check_output(['file', sys.argv[0] + '.real']).find('64-bit') != -1) -asanwrapper = "" if is_64bit else "asanwrapper " device_env = build_env() device_args = ' '.join(sys.argv[1:]) # FIXME: escape? device_stdout = device_binary + '.stdout' device_stderr = device_binary + '.stderr' device_exitcode = device_binary + '.exitcode' -ret = adb(['shell', 'cd %s && %s %s%s %s >%s 2>%s ; echo $? >%s' % - (ANDROID_TMPDIR, device_env, asanwrapper, device_binary, device_args, +ret = adb(['shell', 'cd %s && %s %s %s >%s 2>%s ; echo $? >%s' % + (ANDROID_TMPDIR, device_env, device_binary, device_args, device_stdout, device_stderr, device_exitcode)]) if ret != 0: sys.exit(ret) -- cgit v1.2.1 From 2192b71415ee3f3b5894a66f36585c01a87cbc7f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 24 Apr 2017 21:27:47 +0000 Subject: [cfi] Fix wrong CMake condition for WIN32. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301257 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 6bad910d4..fb45f2f40 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -32,7 +32,7 @@ endmacro() if (APPLE) # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 add_cfi_test_suites(False False) -elseif(WINDOWS) +elseif(WIN32) # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32770 add_cfi_test_suites(True False) else() -- cgit v1.2.1 From 518a5aca006fc207818c1d5c657a527749b7006f Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 24 Apr 2017 22:20:22 +0000 Subject: Mark a test as requiring a shell. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301265 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/read_binary_name_regtest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/TestCases/Linux/read_binary_name_regtest.c b/test/asan/TestCases/Linux/read_binary_name_regtest.c index b09096c89..413025677 100644 --- a/test/asan/TestCases/Linux/read_binary_name_regtest.c +++ b/test/asan/TestCases/Linux/read_binary_name_regtest.c @@ -3,6 +3,7 @@ // This test uses seccomp-BPF to restrict the readlink() system call and makes // sure ASan is still able to // RUN: not ls /usr/include/linux/seccomp.h || ( %clang_asan %s -o %t && not %run %t 2>&1 | FileCheck %s ) +// REQUIRES: shell // UNSUPPORTED: android #include -- cgit v1.2.1 From 43a355662c1a51ed4e1802b53cd79639ac7dded0 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 24 Apr 2017 23:13:47 +0000 Subject: [asan] Fix Windows global dead stripping tests Pass /Gw to clang-cl which is equivalent to -fdata-sections. This is now necessary. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301272 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/dll_global_dead_strip.c | 4 ++-- test/asan/TestCases/Windows/global_dead_strip.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/asan/TestCases/Windows/dll_global_dead_strip.c b/test/asan/TestCases/Windows/dll_global_dead_strip.c index 2664f5baf..15cfd5a7d 100644 --- a/test/asan/TestCases/Windows/dll_global_dead_strip.c +++ b/test/asan/TestCases/Windows/dll_global_dead_strip.c @@ -1,8 +1,8 @@ // RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t // -// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %clang_cl_asan /Gw -LD -O0 %s -Fe%t.dll // RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=NOSTRIP -// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll -link -opt:ref +// RUN: %clang_cl_asan /Gw -LD -O2 %s -Fe%t.dll -link -opt:ref // RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=STRIP #include diff --git a/test/asan/TestCases/Windows/global_dead_strip.c b/test/asan/TestCases/Windows/global_dead_strip.c index e68549050..2121392d9 100644 --- a/test/asan/TestCases/Windows/global_dead_strip.c +++ b/test/asan/TestCases/Windows/global_dead_strip.c @@ -1,6 +1,6 @@ -// RUN: %clang_cl_asan /O0 %s /Fe%t.exe +// RUN: %clang_cl_asan /Gw /O0 %s /Fe%t.exe // RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=NOSTRIP -// RUN: %clang_cl_asan /O2 %s /Fe%t.exe -link -opt:ref +// RUN: %clang_cl_asan /Gw /O2 %s /Fe%t.exe -link -opt:ref // RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=STRIP #include -- cgit v1.2.1 From efd746c9a96411e02fa96426dfdb25cae807aadd Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Mon, 24 Apr 2017 23:16:49 +0000 Subject: Revert r301089 "[builtins] Implement emulated TLS on Windows." This broke the self-host build on Windows (PR32777). Original commit message: > [builtins] Implement emulated TLS on Windows. > > Summary: > LLVM JIT needs to be able to use emulated TLS on all platforms, and this provides a reference one can compile to enable emutls for Linux/Mac/Windows. > > Reviewers: chh, howard.hinnant > > Reviewed By: chh > > Subscribers: mgorny, llvm-commits > > Differential Revision: https://reviews.llvm.org/D30787 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301274 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 9 +- lib/builtins/emutls.c | 280 ++++++++++---------------------------------- 2 files changed, 67 insertions(+), 222 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index c30d9b363..161487e70 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -164,8 +164,7 @@ set(GENERIC_SOURCES udivti3.c umoddi3.c umodsi3.c - umodti3.c - emutls.c) + umodti3.c) option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" @@ -188,6 +187,12 @@ if(APPLE) atomic_thread_fence.c) endif() +if(NOT WIN32 OR MINGW) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} + emutls.c) +endif() + if (HAVE_UNWIND_H) set(GENERIC_SOURCES ${GENERIC_SOURCES} diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index c884e9040..eccbf5336 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -7,7 +7,7 @@ * * ===----------------------------------------------------------------------=== */ - +#include #include #include #include @@ -15,23 +15,6 @@ #include "int_lib.h" #include "int_util.h" -typedef struct emutls_address_array { - uintptr_t size; /* number of elements in the 'data' array */ - void* data[]; -} emutls_address_array; - -static void emutls_shutdown(emutls_address_array *array); - -#ifndef _WIN32 - -#include - -static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_key_t emutls_pthread_key; - -typedef unsigned int gcc_word __attribute__((mode(word))); -typedef unsigned int gcc_pointer __attribute__((mode(pointer))); - /* Default is not to use posix_memalign, so systems like Android * can use thread local data without heavier POSIX memory allocators. */ @@ -39,6 +22,26 @@ typedef unsigned int gcc_pointer __attribute__((mode(pointer))); #define EMUTLS_USE_POSIX_MEMALIGN 0 #endif +/* For every TLS variable xyz, + * there is one __emutls_control variable named __emutls_v.xyz. + * If xyz has non-zero initial value, __emutls_v.xyz's "value" + * will point to __emutls_t.xyz, which has the initial value. + */ +typedef unsigned int gcc_word __attribute__((mode(word))); +typedef struct __emutls_control { + /* Must use gcc_word here, instead of size_t, to match GCC. When + gcc_word is larger than size_t, the upper extra bits are all + zeros. We can use variables of size_t to operate on size and + align. */ + gcc_word size; /* size of the object in bytes */ + gcc_word align; /* alignment of the object in bytes */ + union { + uintptr_t index; /* data[index-1] is the object address */ + void* address; /* object address, when in single thread env */ + } object; + void* value; /* null or non-zero initial value for the object */ +} __emutls_control; + static __inline void *emutls_memalign_alloc(size_t align, size_t size) { void *base; #if EMUTLS_USE_POSIX_MEMALIGN @@ -47,7 +50,7 @@ static __inline void *emutls_memalign_alloc(size_t align, size_t size) { #else #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*)) char* object; - if ((object = (char*)malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) + if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) abort(); base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) & ~(uintptr_t)(align - 1)); @@ -66,192 +69,10 @@ static __inline void emutls_memalign_free(void *base) { #endif } -static void emutls_key_destructor(void* ptr) { - emutls_shutdown((emutls_address_array*)ptr); - free(ptr); -} - -static __inline void emutls_init(void) { - if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) - abort(); -} - -static __inline void emutls_init_once(void) { - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, emutls_init); -} - -static __inline void emutls_lock() { - pthread_mutex_lock(&emutls_mutex); -} - -static __inline void emutls_unlock() { - pthread_mutex_unlock(&emutls_mutex); -} - -static __inline void emutls_setspecific(emutls_address_array *value) { - pthread_setspecific(emutls_pthread_key, (void*) value); -} - -static __inline emutls_address_array* emutls_getspecific() { - return (emutls_address_array*) pthread_getspecific(emutls_pthread_key); -} - -#else - -#include -#include -#include -#include -#include - -static LPCRITICAL_SECTION emutls_mutex; -static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES; - -typedef uintptr_t gcc_word; -typedef void * gcc_pointer; - -static void win_error(DWORD last_err, const char *hint) { - char *buffer = NULL; - if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) { - fprintf(stderr, "Windows error: %s\n", buffer); - } else { - fprintf(stderr, "Unkown Windows error: %s\n", hint); - } - LocalFree(buffer); -} - -static __inline void win_abort(DWORD last_err, const char *hint) { - win_error(last_err, hint); - abort(); -} - -static __inline void *emutls_memalign_alloc(size_t align, size_t size) { - void *base = _aligned_malloc(size, align); - if (!base) - win_abort(GetLastError(), "_aligned_malloc"); - return base; -} - -static __inline void emutls_memalign_free(void *base) { - _aligned_free(base); -} - -static void emutls_exit(void) { - if (emutls_mutex) { - DeleteCriticalSection(emutls_mutex); - _aligned_free(emutls_mutex); - emutls_mutex = NULL; - } - if (emutls_tls_index != TLS_OUT_OF_INDEXES) { - emutls_shutdown((emutls_address_array*)TlsGetValue(emutls_tls_index)); - TlsFree(emutls_tls_index); - emutls_tls_index = TLS_OUT_OF_INDEXES; - } -} - -#pragma warning (push) -#pragma warning (disable : 4100) -static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) { - emutls_mutex = (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16); - if (!emutls_mutex) { - win_error(GetLastError(), "_aligned_malloc"); - return FALSE; - } - InitializeCriticalSection(emutls_mutex); - - emutls_tls_index = TlsAlloc(); - if (emutls_tls_index == TLS_OUT_OF_INDEXES) { - emutls_exit(); - win_error(GetLastError(), "TlsAlloc"); - return FALSE; - } - atexit(&emutls_exit); - return TRUE; -} - -static __inline void emutls_init_once(void) { - static INIT_ONCE once; - InitOnceExecuteOnce(&once, emutls_init, NULL, NULL); -} - -static __inline void emutls_lock() { - EnterCriticalSection(emutls_mutex); -} - -static __inline void emutls_unlock() { - LeaveCriticalSection(emutls_mutex); -} - -static __inline void emutls_setspecific(emutls_address_array *value) { - if (TlsSetValue(emutls_tls_index, (LPVOID) value) == 0) - win_abort(GetLastError(), "TlsSetValue"); -} - -static __inline emutls_address_array* emutls_getspecific() { - LPVOID value = TlsGetValue(emutls_tls_index); - if (value == NULL) { - const DWORD err = GetLastError(); - if (err != ERROR_SUCCESS) - win_abort(err, "TlsGetValue"); - } - return (emutls_address_array*) value; -} - -enum { __ATOMIC_ACQUIRE, __ATOMIC_RELEASE }; - -static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) { - assert(type == __ATOMIC_ACQUIRE); - return (uintptr_t) _load_be_u64(ptr); -} - -static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) { - assert(type == __ATOMIC_RELEASE); - _store_be_u64(ptr, val); -} -#pragma warning (pop) - -#endif - -static size_t emutls_num_object = 0; /* number of allocated TLS objects */ - -/* Free the allocated TLS data - */ -static void emutls_shutdown(emutls_address_array *array) { - if (array) { - uintptr_t i; - for (i = 0; i < array->size; ++i) { - if (array->data[i]) - emutls_memalign_free(array->data[i]); - } - } -} - -/* For every TLS variable xyz, - * there is one __emutls_control variable named __emutls_v.xyz. - * If xyz has non-zero initial value, __emutls_v.xyz's "value" - * will point to __emutls_t.xyz, which has the initial value. - */ -typedef struct __emutls_control { - /* Must use gcc_word here, instead of size_t, to match GCC. When - gcc_word is larger than size_t, the upper extra bits are all - zeros. We can use variables of size_t to operate on size and - align. */ - gcc_word size; /* size of the object in bytes */ - gcc_word align; /* alignment of the object in bytes */ - union { - uintptr_t index; /* data[index-1] is the object address */ - void* address; /* object address, when in single thread env */ - } object; - void* value; /* null or non-zero initial value for the object */ -} __emutls_control; - /* Emulated TLS objects are always allocated at run-time. */ static __inline void *emutls_allocate_object(__emutls_control *control) { /* Use standard C types, check with gcc's emutls.o. */ + typedef unsigned int gcc_pointer __attribute__((mode(pointer))); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer)); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*)); @@ -272,19 +93,45 @@ static __inline void *emutls_allocate_object(__emutls_control *control) { return base; } +static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; + +static size_t emutls_num_object = 0; /* number of allocated TLS objects */ + +typedef struct emutls_address_array { + uintptr_t size; /* number of elements in the 'data' array */ + void* data[]; +} emutls_address_array; + +static pthread_key_t emutls_pthread_key; + +static void emutls_key_destructor(void* ptr) { + emutls_address_array* array = (emutls_address_array*)ptr; + uintptr_t i; + for (i = 0; i < array->size; ++i) { + if (array->data[i]) + emutls_memalign_free(array->data[i]); + } + free(ptr); +} + +static void emutls_init(void) { + if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) + abort(); +} /* Returns control->object.index; set index if not allocated yet. */ static __inline uintptr_t emutls_get_index(__emutls_control *control) { uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE); if (!index) { - emutls_init_once(); - emutls_lock(); + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, emutls_init); + pthread_mutex_lock(&emutls_mutex); index = control->object.index; if (!index) { index = ++emutls_num_object; __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE); } - emutls_unlock(); + pthread_mutex_unlock(&emutls_mutex); } return index; } @@ -295,7 +142,7 @@ static __inline void emutls_check_array_set_size(emutls_address_array *array, if (array == NULL) abort(); array->size = size; - emutls_setspecific(array); + pthread_setspecific(emutls_pthread_key, (void*)array); } /* Returns the new 'data' array size, number of elements, @@ -309,29 +156,22 @@ static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) { return ((index + 1 + 15) & ~((uintptr_t)15)) - 1; } -/* Returns the size in bytes required for an emutls_address_array with - * N number of elements for data field. - */ -static __inline uintptr_t emutls_asize(uintptr_t N) { - return N * sizeof(void *) + sizeof(emutls_address_array); -} - /* Returns the thread local emutls_address_array. * Extends its size if necessary to hold address at index. */ static __inline emutls_address_array * emutls_get_address_array(uintptr_t index) { - emutls_address_array* array = emutls_getspecific(); + emutls_address_array* array = pthread_getspecific(emutls_pthread_key); if (array == NULL) { uintptr_t new_size = emutls_new_data_array_size(index); - array = (emutls_address_array*) malloc(emutls_asize(new_size)); + array = malloc(new_size * sizeof(void *) + sizeof(emutls_address_array)); if (array) memset(array->data, 0, new_size * sizeof(void*)); emutls_check_array_set_size(array, new_size); } else if (index > array->size) { uintptr_t orig_size = array->size; uintptr_t new_size = emutls_new_data_array_size(index); - array = (emutls_address_array*) realloc(array, emutls_asize(new_size)); + array = realloc(array, new_size * sizeof(void *) + sizeof(emutls_address_array)); if (array) memset(array->data + orig_size, 0, (new_size - orig_size) * sizeof(void*)); @@ -342,8 +182,8 @@ emutls_get_address_array(uintptr_t index) { void* __emutls_get_address(__emutls_control* control) { uintptr_t index = emutls_get_index(control); - emutls_address_array* array = emutls_get_address_array(index--); - if (array->data[index] == NULL) - array->data[index] = emutls_allocate_object(control); - return array->data[index]; + emutls_address_array* array = emutls_get_address_array(index); + if (array->data[index - 1] == NULL) + array->data[index - 1] = emutls_allocate_object(control); + return array->data[index - 1]; } -- cgit v1.2.1 From e80e955171a57aa3be9a9d03404a7e9652b8a78d Mon Sep 17 00:00:00 2001 From: Nitesh Jain Date: Tue, 25 Apr 2017 13:25:40 +0000 Subject: [Compiler-rt][MIPS] Fix assert introduce with commit rl301171. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301307 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform_limits_posix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index c2d9f2cd3..c6f6a2115 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -83,7 +83,7 @@ namespace __sanitizer { #elif defined(__mips__) const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) : - FIRST_32_SECOND_64(144, 216); + FIRST_32_SECOND_64(160, 216); const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390__) && !defined(__s390x__) const unsigned struct_kernel_stat_sz = 64; -- cgit v1.2.1 From ad42fb978f5423083dfcf84ce70d8f1cbdcbfe6e Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 25 Apr 2017 17:24:27 +0000 Subject: [lsan] When necessary, define LSan suppression for pthread_exit. Summary: Generalize already defined LSan suppression for the leak on pthread_exit, some envs do not have the entire call stack symbolized, so we have to be less specific. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32497 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301335 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 5a4cb454e..1f4734c85 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -70,9 +70,9 @@ static const char kSuppressionLeak[] = "leak"; static const char *kSuppressionTypes[] = { kSuppressionLeak }; static const char kStdSuppressions[] = #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // The actual string allocation happens here (for more details refer to the - // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition). - "leak:*_dl_map_object_deps*\n" + // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // definition. + "leak:*pthread_exit*\n" #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. -- cgit v1.2.1 From 12df869c06b0e5728765618e04b3b1b78f8dd28c Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Tue, 25 Apr 2017 19:04:19 +0000 Subject: [builtins] Implement emulated TLS on Windows. Summary: LLVM JIT needs to be able to use emulated TLS on all platforms, and this provides a reference one can compile to enable emutls for Linux/Mac/Windows. Reviewers: chh, howard.hinnant Reviewed By: chh Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D30787 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301350 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 9 +- lib/builtins/emutls.c | 294 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 236 insertions(+), 67 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 161487e70..c30d9b363 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -164,7 +164,8 @@ set(GENERIC_SOURCES udivti3.c umoddi3.c umodsi3.c - umodti3.c) + umodti3.c + emutls.c) option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" @@ -187,12 +188,6 @@ if(APPLE) atomic_thread_fence.c) endif() -if(NOT WIN32 OR MINGW) - set(GENERIC_SOURCES - ${GENERIC_SOURCES} - emutls.c) -endif() - if (HAVE_UNWIND_H) set(GENERIC_SOURCES ${GENERIC_SOURCES} diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index eccbf5336..e8d5ddb22 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -7,7 +7,6 @@ * * ===----------------------------------------------------------------------=== */ -#include #include #include #include @@ -15,6 +14,23 @@ #include "int_lib.h" #include "int_util.h" +typedef struct emutls_address_array { + uintptr_t size; /* number of elements in the 'data' array */ + void* data[]; +} emutls_address_array; + +static void emutls_shutdown(emutls_address_array *array); + +#ifndef _WIN32 + +#include + +static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t emutls_pthread_key; + +typedef unsigned int gcc_word __attribute__((mode(word))); +typedef unsigned int gcc_pointer __attribute__((mode(pointer))); + /* Default is not to use posix_memalign, so systems like Android * can use thread local data without heavier POSIX memory allocators. */ @@ -22,26 +38,6 @@ #define EMUTLS_USE_POSIX_MEMALIGN 0 #endif -/* For every TLS variable xyz, - * there is one __emutls_control variable named __emutls_v.xyz. - * If xyz has non-zero initial value, __emutls_v.xyz's "value" - * will point to __emutls_t.xyz, which has the initial value. - */ -typedef unsigned int gcc_word __attribute__((mode(word))); -typedef struct __emutls_control { - /* Must use gcc_word here, instead of size_t, to match GCC. When - gcc_word is larger than size_t, the upper extra bits are all - zeros. We can use variables of size_t to operate on size and - align. */ - gcc_word size; /* size of the object in bytes */ - gcc_word align; /* alignment of the object in bytes */ - union { - uintptr_t index; /* data[index-1] is the object address */ - void* address; /* object address, when in single thread env */ - } object; - void* value; /* null or non-zero initial value for the object */ -} __emutls_control; - static __inline void *emutls_memalign_alloc(size_t align, size_t size) { void *base; #if EMUTLS_USE_POSIX_MEMALIGN @@ -50,7 +46,7 @@ static __inline void *emutls_memalign_alloc(size_t align, size_t size) { #else #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*)) char* object; - if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) + if ((object = (char*)malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) abort(); base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) & ~(uintptr_t)(align - 1)); @@ -69,10 +65,207 @@ static __inline void emutls_memalign_free(void *base) { #endif } +static void emutls_key_destructor(void* ptr) { + emutls_shutdown((emutls_address_array*)ptr); + free(ptr); +} + +static __inline void emutls_init(void) { + if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) + abort(); +} + +static __inline void emutls_init_once(void) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, emutls_init); +} + +static __inline void emutls_lock() { + pthread_mutex_lock(&emutls_mutex); +} + +static __inline void emutls_unlock() { + pthread_mutex_unlock(&emutls_mutex); +} + +static __inline void emutls_setspecific(emutls_address_array *value) { + pthread_setspecific(emutls_pthread_key, (void*) value); +} + +static __inline emutls_address_array* emutls_getspecific() { + return (emutls_address_array*) pthread_getspecific(emutls_pthread_key); +} + +#else + +#include +#include +#include +#include +#include + +static LPCRITICAL_SECTION emutls_mutex; +static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES; + +typedef uintptr_t gcc_word; +typedef void * gcc_pointer; + +static void win_error(DWORD last_err, const char *hint) { + char *buffer = NULL; + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) { + fprintf(stderr, "Windows error: %s\n", buffer); + } else { + fprintf(stderr, "Unkown Windows error: %s\n", hint); + } + LocalFree(buffer); +} + +static __inline void win_abort(DWORD last_err, const char *hint) { + win_error(last_err, hint); + abort(); +} + +static __inline void *emutls_memalign_alloc(size_t align, size_t size) { + void *base = _aligned_malloc(size, align); + if (!base) + win_abort(GetLastError(), "_aligned_malloc"); + return base; +} + +static __inline void emutls_memalign_free(void *base) { + _aligned_free(base); +} + +static void emutls_exit(void) { + if (emutls_mutex) { + DeleteCriticalSection(emutls_mutex); + _aligned_free(emutls_mutex); + emutls_mutex = NULL; + } + if (emutls_tls_index != TLS_OUT_OF_INDEXES) { + emutls_shutdown((emutls_address_array*)TlsGetValue(emutls_tls_index)); + TlsFree(emutls_tls_index); + emutls_tls_index = TLS_OUT_OF_INDEXES; + } +} + +#pragma warning (push) +#pragma warning (disable : 4100) +static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) { + emutls_mutex = (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16); + if (!emutls_mutex) { + win_error(GetLastError(), "_aligned_malloc"); + return FALSE; + } + InitializeCriticalSection(emutls_mutex); + + emutls_tls_index = TlsAlloc(); + if (emutls_tls_index == TLS_OUT_OF_INDEXES) { + emutls_exit(); + win_error(GetLastError(), "TlsAlloc"); + return FALSE; + } + atexit(&emutls_exit); + return TRUE; +} + +static __inline void emutls_init_once(void) { + static INIT_ONCE once; + InitOnceExecuteOnce(&once, emutls_init, NULL, NULL); +} + +static __inline void emutls_lock() { + EnterCriticalSection(emutls_mutex); +} + +static __inline void emutls_unlock() { + LeaveCriticalSection(emutls_mutex); +} + +static __inline void emutls_setspecific(emutls_address_array *value) { + if (TlsSetValue(emutls_tls_index, (LPVOID) value) == 0) + win_abort(GetLastError(), "TlsSetValue"); +} + +static __inline emutls_address_array* emutls_getspecific() { + LPVOID value = TlsGetValue(emutls_tls_index); + if (value == NULL) { + const DWORD err = GetLastError(); + if (err != ERROR_SUCCESS) + win_abort(err, "TlsGetValue"); + } + return (emutls_address_array*) value; +} + +/* Provide atomic load/store functions for emutls_get_index if built with MSVC. + */ +#if !defined(__ATOMIC_RELEASE) + +enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 }; + +static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) { + assert(type == __ATOMIC_ACQUIRE); +#ifdef _WIN64 + return (uintptr_t) _load_be_u64(ptr); +#else + return (uintptr_t) _load_be_u32(ptr); +#endif +} + +static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) { + assert(type == __ATOMIC_RELEASE); +#ifdef _WIN64 + _store_be_u64(ptr, val); +#else + _store_be_u32(ptr, val); +#endif +} + +#endif + +#pragma warning (pop) + +#endif + +static size_t emutls_num_object = 0; /* number of allocated TLS objects */ + +/* Free the allocated TLS data + */ +static void emutls_shutdown(emutls_address_array *array) { + if (array) { + uintptr_t i; + for (i = 0; i < array->size; ++i) { + if (array->data[i]) + emutls_memalign_free(array->data[i]); + } + } +} + +/* For every TLS variable xyz, + * there is one __emutls_control variable named __emutls_v.xyz. + * If xyz has non-zero initial value, __emutls_v.xyz's "value" + * will point to __emutls_t.xyz, which has the initial value. + */ +typedef struct __emutls_control { + /* Must use gcc_word here, instead of size_t, to match GCC. When + gcc_word is larger than size_t, the upper extra bits are all + zeros. We can use variables of size_t to operate on size and + align. */ + gcc_word size; /* size of the object in bytes */ + gcc_word align; /* alignment of the object in bytes */ + union { + uintptr_t index; /* data[index-1] is the object address */ + void* address; /* object address, when in single thread env */ + } object; + void* value; /* null or non-zero initial value for the object */ +} __emutls_control; + /* Emulated TLS objects are always allocated at run-time. */ static __inline void *emutls_allocate_object(__emutls_control *control) { /* Use standard C types, check with gcc's emutls.o. */ - typedef unsigned int gcc_pointer __attribute__((mode(pointer))); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer)); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*)); @@ -93,45 +286,19 @@ static __inline void *emutls_allocate_object(__emutls_control *control) { return base; } -static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; - -static size_t emutls_num_object = 0; /* number of allocated TLS objects */ - -typedef struct emutls_address_array { - uintptr_t size; /* number of elements in the 'data' array */ - void* data[]; -} emutls_address_array; - -static pthread_key_t emutls_pthread_key; - -static void emutls_key_destructor(void* ptr) { - emutls_address_array* array = (emutls_address_array*)ptr; - uintptr_t i; - for (i = 0; i < array->size; ++i) { - if (array->data[i]) - emutls_memalign_free(array->data[i]); - } - free(ptr); -} - -static void emutls_init(void) { - if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) - abort(); -} /* Returns control->object.index; set index if not allocated yet. */ static __inline uintptr_t emutls_get_index(__emutls_control *control) { uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE); if (!index) { - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, emutls_init); - pthread_mutex_lock(&emutls_mutex); + emutls_init_once(); + emutls_lock(); index = control->object.index; if (!index) { index = ++emutls_num_object; __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE); } - pthread_mutex_unlock(&emutls_mutex); + emutls_unlock(); } return index; } @@ -142,7 +309,7 @@ static __inline void emutls_check_array_set_size(emutls_address_array *array, if (array == NULL) abort(); array->size = size; - pthread_setspecific(emutls_pthread_key, (void*)array); + emutls_setspecific(array); } /* Returns the new 'data' array size, number of elements, @@ -156,22 +323,29 @@ static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) { return ((index + 1 + 15) & ~((uintptr_t)15)) - 1; } +/* Returns the size in bytes required for an emutls_address_array with + * N number of elements for data field. + */ +static __inline uintptr_t emutls_asize(uintptr_t N) { + return N * sizeof(void *) + sizeof(emutls_address_array); +} + /* Returns the thread local emutls_address_array. * Extends its size if necessary to hold address at index. */ static __inline emutls_address_array * emutls_get_address_array(uintptr_t index) { - emutls_address_array* array = pthread_getspecific(emutls_pthread_key); + emutls_address_array* array = emutls_getspecific(); if (array == NULL) { uintptr_t new_size = emutls_new_data_array_size(index); - array = malloc(new_size * sizeof(void *) + sizeof(emutls_address_array)); + array = (emutls_address_array*) malloc(emutls_asize(new_size)); if (array) memset(array->data, 0, new_size * sizeof(void*)); emutls_check_array_set_size(array, new_size); } else if (index > array->size) { uintptr_t orig_size = array->size; uintptr_t new_size = emutls_new_data_array_size(index); - array = realloc(array, new_size * sizeof(void *) + sizeof(emutls_address_array)); + array = (emutls_address_array*) realloc(array, emutls_asize(new_size)); if (array) memset(array->data + orig_size, 0, (new_size - orig_size) * sizeof(void*)); @@ -182,8 +356,8 @@ emutls_get_address_array(uintptr_t index) { void* __emutls_get_address(__emutls_control* control) { uintptr_t index = emutls_get_index(control); - emutls_address_array* array = emutls_get_address_array(index); - if (array->data[index - 1] == NULL) - array->data[index - 1] = emutls_allocate_object(control); - return array->data[index - 1]; + emutls_address_array* array = emutls_get_address_array(index--); + if (array->data[index] == NULL) + array->data[index] = emutls_allocate_object(control); + return array->data[index]; } -- cgit v1.2.1 From 9b8267f708fe852f22a50a3f8f5ff21f9c7f318f Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Wed, 26 Apr 2017 07:35:36 +0000 Subject: [test] Build sanitizer/xray tests only if COMPILER_RT_BUILD_* is on Cover the sanitizer tests with COMPILER_RT_BUILD_SANITIZERS conditional, and add COMPILER_RT_BUILD_XRAY conditional to the xray tests. This makes it possible to do a pure-builtins build with tests enabled. Differential Revision: https://reviews.llvm.org/D32489 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301387 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 82 +++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index addc57997..7685fb3f4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,47 +41,49 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) if(COMPILER_RT_BUILD_BUILTINS) add_subdirectory(builtins) endif() - if(COMPILER_RT_HAS_ASAN) - add_subdirectory(asan) - endif() - if(COMPILER_RT_HAS_DFSAN) - add_subdirectory(dfsan) - endif() - if (COMPILER_RT_HAS_INTERCEPTION) - add_subdirectory(interception) - endif() - if(COMPILER_RT_HAS_LSAN) - add_subdirectory(lsan) - endif() - if(COMPILER_RT_HAS_MSAN) - add_subdirectory(msan) - endif() - if(COMPILER_RT_HAS_PROFILE) - add_subdirectory(profile) - endif() - if(COMPILER_RT_HAS_SANITIZER_COMMON) - add_subdirectory(sanitizer_common) - endif() - if(COMPILER_RT_HAS_TSAN) - add_subdirectory(tsan) - endif() - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(ubsan) - endif() - # CFI tests require diagnostic mode, which is implemented in UBSan. - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(cfi) - endif() - if(COMPILER_RT_HAS_SAFESTACK) - add_subdirectory(safestack) - endif() - if(COMPILER_RT_HAS_ESAN) - add_subdirectory(esan) - endif() - if(COMPILER_RT_HAS_SCUDO) - add_subdirectory(scudo) + if(COMPILER_RT_BUILD_SANITIZERS) + if(COMPILER_RT_HAS_ASAN) + add_subdirectory(asan) + endif() + if(COMPILER_RT_HAS_DFSAN) + add_subdirectory(dfsan) + endif() + if (COMPILER_RT_HAS_INTERCEPTION) + add_subdirectory(interception) + endif() + if(COMPILER_RT_HAS_LSAN) + add_subdirectory(lsan) + endif() + if(COMPILER_RT_HAS_MSAN) + add_subdirectory(msan) + endif() + if(COMPILER_RT_HAS_PROFILE) + add_subdirectory(profile) + endif() + if(COMPILER_RT_HAS_SANITIZER_COMMON) + add_subdirectory(sanitizer_common) + endif() + if(COMPILER_RT_HAS_TSAN) + add_subdirectory(tsan) + endif() + if(COMPILER_RT_HAS_UBSAN) + add_subdirectory(ubsan) + endif() + # CFI tests require diagnostic mode, which is implemented in UBSan. + if(COMPILER_RT_HAS_UBSAN) + add_subdirectory(cfi) + endif() + if(COMPILER_RT_HAS_SAFESTACK) + add_subdirectory(safestack) + endif() + if(COMPILER_RT_HAS_ESAN) + add_subdirectory(esan) + endif() + if(COMPILER_RT_HAS_SCUDO) + add_subdirectory(scudo) + endif() endif() - if(COMPILER_RT_HAS_XRAY) + if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY) add_subdirectory(xray) endif() endif() -- cgit v1.2.1 From 775df7943e0715df4cca8298d85803e055a62675 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 26 Apr 2017 17:13:31 +0000 Subject: [lsan] When necessary, define LSan suppression for tls_get_addr. Summary: Generalize already defined LSan suppression for the leak on tls_get_addr, some envs do not have the entire call stack symbolized, so we have to be less specific. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32545 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301434 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 1f4734c85..a6b3453f5 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -76,7 +76,7 @@ static const char kStdSuppressions[] = #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*tls_get_addr_tail*\n"; + "leak:*tls_get_addr*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); -- cgit v1.2.1 From fcf0ff11cde6226ebeb7ccf7225802e747ba3ca0 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 18:59:22 +0000 Subject: [asan] Add support for running lit tests in the iOS Simulator This patch adds a basic support for running the ASan lit test suite against an iOS Simulator. This is done by generating more lit.site.cfg configurations into subdirectories such as IOSSimI386Config and IOSSimX86_64Config. These test suites are not added into "check-all" or into "check-asan", they have to be run manually. Differential Revision: https://reviews.llvm.org/D31477 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301443 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 8 ++++ test/asan/CMakeLists.txt | 49 ++++++++++++++++++++++++ test/asan/lit.site.cfg.in | 2 + test/lit.common.cfg | 11 +++++- test/lit.common.configured.in | 2 + test/sanitizer_common/ios_commands/iossim_env.py | 17 ++++++++ test/sanitizer_common/ios_commands/iossim_run.py | 17 ++++++++ 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 test/sanitizer_common/ios_commands/iossim_env.py create mode 100644 test/sanitizer_common/ios_commands/iossim_run.py diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index b64eb4246..bc5fb9ff7 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -210,6 +210,14 @@ function(add_compiler_rt_runtime name type) set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "") set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib") endif() + if(APPLE) + # Ad-hoc sign the dylibs + add_custom_command(TARGET ${libname} + POST_BUILD + COMMAND codesign --sign - $ + WORKING_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR} + ) + endif() endif() install(TARGETS ${libname} ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR} diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 4b4fdf19d..944588333 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -41,6 +41,12 @@ foreach(arch ${ASAN_TEST_ARCH}) else() set(ASAN_TEST_TARGET_ARCH ${arch}) endif() + + set(ASAN_TEST_IOS "0") + pythonize_bool(ASAN_TEST_IOS) + set(ASAN_TEST_IOSSIM "0") + pythonize_bool(ASAN_TEST_IOSSIM) + string(TOLOWER "-${arch}-${OS_NAME}" ASAN_TEST_CONFIG_SUFFIX) get_bits_for_arch(${arch} ASAN_TEST_BITS) get_test_cc_for_arch(${arch} ASAN_TEST_TARGET_CC ASAN_TEST_TARGET_CFLAGS) @@ -69,6 +75,49 @@ foreach(arch ${ASAN_TEST_ARCH}) endif() endforeach() +# iOS and iOS simulator test suites +# These are not added into "check-all", in order to run these tests, you have to +# manually call (from the build directory). They also require that an extra env +# variable to select which iOS device or simulator to use, e.g.: +# $ SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER=BBE44C1C-8AAA-4000-8D06-91C89ED58172 +# $ ./bin/llvm-lit ./projects/compiler-rt/test/asan/IOSSimI386Config +if(APPLE) + set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) + set(ASAN_TEST_IOS "1") + pythonize_bool(ASAN_TEST_IOS) + set(ASAN_TEST_DYNAMIC True) + + foreach(arch ${DARWIN_iossim_ARCHS}) + set(ASAN_TEST_IOSSIM "1") + pythonize_bool(ASAN_TEST_IOSSIM) + set(ASAN_TEST_TARGET_ARCH ${arch}) + set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_iossim_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") + set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-iossim") + get_bits_for_arch(${arch} ASAN_TEST_BITS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME "IOSSim${ARCH_UPPER_CASE}Config") + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg + ) + endforeach() + + foreach (arch ${DARWIN_ios_ARCHS}) + set(ASAN_TEST_IOSSIM "0") + pythonize_bool(ASAN_TEST_IOSSIM) + set(ASAN_TEST_TARGET_ARCH ${arch}) + set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") + set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-ios") + get_bits_for_arch(${arch} ASAN_TEST_BITS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config") + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg + ) + endforeach() +endif() + # Add unit tests. if(COMPILER_RT_INCLUDE_TESTS) set(ASAN_TEST_DYNAMIC False) diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in index 1b6fed2cb..100592db2 100644 --- a/test/asan/lit.site.cfg.in +++ b/test/asan/lit.site.cfg.in @@ -7,6 +7,8 @@ config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@" config.clang = "@ASAN_TEST_TARGET_CC@" config.bits = "@ASAN_TEST_BITS@" config.android = "@ANDROID@" +config.ios = @ASAN_TEST_IOS_PYBOOL@ +config.iossim = @ASAN_TEST_IOSSIM_PYBOOL@ config.asan_dynamic = @ASAN_TEST_DYNAMIC@ config.target_arch = "@ASAN_TEST_TARGET_ARCH@" diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 4b03a5504..2f0dd6351 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -94,7 +94,16 @@ config.substitutions.append( instead define '%clangXXX' substitution in lit config. ***\n\n""") ) # Allow tests to be executed on a simulator or remotely. -config.substitutions.append( ('%run', config.emulator) ) +if config.emulator: + config.substitutions.append( ('%run', config.emulator) ) +elif config.ios: + device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER" + if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env] + ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands") + run_wrapper = os.path.join(ios_commands_dir, "iossim_run.py" if config.iossim else "ios_run.py") + config.substitutions.append(('%run', run_wrapper)) +else: + config.substitutions.append( ('%run', "") ) # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 0ad03a180..dc3081d6a 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -25,6 +25,8 @@ set_default("python_executable", "@PYTHON_EXECUTABLE@") set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@) set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@") set_default("emulator", "@COMPILER_RT_EMULATOR@") +set_default("ios", False) +set_default("iossim", False) set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) diff --git a/test/sanitizer_common/ios_commands/iossim_env.py b/test/sanitizer_common/ios_commands/iossim_env.py new file mode 100644 index 000000000..28f626900 --- /dev/null +++ b/test/sanitizer_common/ios_commands/iossim_env.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import os, sys, subprocess + + +idx = 1 +for arg in sys.argv[1:]: + if not "=" in arg: + break + idx += 1 + (argname, argval) = arg.split("=") + os.environ["SIMCTL_CHILD_" + argname] = argval + +exitcode = subprocess.call(sys.argv[idx:]) +if exitcode > 125: + exitcode = 126 +sys.exit(exitcode) diff --git a/test/sanitizer_common/ios_commands/iossim_run.py b/test/sanitizer_common/ios_commands/iossim_run.py new file mode 100644 index 000000000..732880f35 --- /dev/null +++ b/test/sanitizer_common/ios_commands/iossim_run.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import os, sys, subprocess + + +if not "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" in os.environ: + raise EnvironmentError("Specify SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER to select which simulator to use.") + +device_id = os.environ["SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER"] + +if "ASAN_OPTIONS" in os.environ: + os.environ["SIMCTL_CHILD_ASAN_OPTIONS"] = os.environ["ASAN_OPTIONS"] + +exitcode = subprocess.call(["xcrun", "simctl", "spawn", device_id] + sys.argv[1:]) +if exitcode > 125: + exitcode = 126 +sys.exit(exitcode) -- cgit v1.2.1 From 0e741b9733da7898fdc1850183b2582f2b63dc97 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 19:43:56 +0000 Subject: Follow-up for r301443: The python scrips need to be executable. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301448 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/ios_commands/iossim_env.py | 0 test/sanitizer_common/ios_commands/iossim_run.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/sanitizer_common/ios_commands/iossim_env.py mode change 100644 => 100755 test/sanitizer_common/ios_commands/iossim_run.py diff --git a/test/sanitizer_common/ios_commands/iossim_env.py b/test/sanitizer_common/ios_commands/iossim_env.py old mode 100644 new mode 100755 diff --git a/test/sanitizer_common/ios_commands/iossim_run.py b/test/sanitizer_common/ios_commands/iossim_run.py old mode 100644 new mode 100755 -- cgit v1.2.1 From ca256e1217bb9d0a7a0910a2afed86101b6ce5ae Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:02:14 +0000 Subject: Fix the typo in strtok.c testcase: There was a missing space in %run expansion. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301451 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/strtok.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/strtok.c b/test/asan/TestCases/strtok.c index e1eee89ee..c7b261777 100644 --- a/test/asan/TestCases/strtok.c +++ b/test/asan/TestCases/strtok.c @@ -4,7 +4,7 @@ // RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK1 -// RUN: %env_asan_opts=intercept_strtok=false%run %t test1 2>&1 +// RUN: %env_asan_opts=intercept_strtok=false %run %t test1 2>&1 // RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK2 // RUN: %env_asan_opts=intercept_strtok=false %run %t test2 2>&1 -- cgit v1.2.1 From 9553ac23b8a5c0be8eb81e4d802962c9098ba5bf Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:20:35 +0000 Subject: Add a missing "%run" expansion to fread_fwrite.cc test case to support testing on iOS simulator. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301455 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/fread_fwrite.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/fread_fwrite.cc b/test/asan/TestCases/Posix/fread_fwrite.cc index 97d44b752..c06292604 100644 --- a/test/asan/TestCases/Posix/fread_fwrite.cc +++ b/test/asan/TestCases/Posix/fread_fwrite.cc @@ -1,6 +1,6 @@ // RUN: %clangxx_asan -g %s -o %t -// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE -// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE +// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD #include #include -- cgit v1.2.1 From 1282f851dfdd700076d50da8e65023c82489a9c0 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:23:23 +0000 Subject: Mark the asan-sigbus.cpp ASan testcase as unsupported on iOS. We don't handle propagating crashes from/to iOS well. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301456 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/asan-sigbus.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/asan/TestCases/Posix/asan-sigbus.cpp b/test/asan/TestCases/Posix/asan-sigbus.cpp index e07392b4c..a7d032ace 100644 --- a/test/asan/TestCases/Posix/asan-sigbus.cpp +++ b/test/asan/TestCases/Posix/asan-sigbus.cpp @@ -4,6 +4,8 @@ // RUN: not %run %t %T/file 2>&1 | FileCheck %s -check-prefix=CHECK-BUS // RUN: %env_asan_opts=handle_sigbus=false not --crash %run %t %T/file 2>&1 | FileCheck %s +// UNSUPPORTED: ios + #include #include #include -- cgit v1.2.1 From fcedc089e038b20c8dcfcc6cfd527094ee04ddf5 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:27:06 +0000 Subject: Fix the dump_registers.cc ASan testcase on iOS to allow both SIGSEGV and SIGBUS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301458 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/dump_registers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Darwin/dump_registers.cc b/test/asan/TestCases/Darwin/dump_registers.cc index 884ad2ed4..42db446ff 100644 --- a/test/asan/TestCases/Darwin/dump_registers.cc +++ b/test/asan/TestCases/Darwin/dump_registers.cc @@ -18,7 +18,7 @@ int main() { assert(0 && "Your computer is weird."); char c = *ptr; // BOOM - // CHECK: ERROR: AddressSanitizer: SEGV + // CHECK: ERROR: AddressSanitizer: {{SEGV|BUS}} // CHECK: Register values: // CHECK: {{0x55555555|0x6666666666666666}} fprintf(stderr, "World\n"); -- cgit v1.2.1 From f760d1b915dbdb8b4eae3f7b261ed141029bcd0b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:29:30 +0000 Subject: XFAIL the TSan XPC tests on iOS. XPC isn't available on iOS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301459 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/xpc-cancel.mm | 2 ++ test/tsan/Darwin/xpc-race.mm | 2 ++ test/tsan/Darwin/xpc.mm | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test/tsan/Darwin/xpc-cancel.mm b/test/tsan/Darwin/xpc-cancel.mm index 5e326b7e4..91dafc3ea 100644 --- a/test/tsan/Darwin/xpc-cancel.mm +++ b/test/tsan/Darwin/xpc-cancel.mm @@ -1,6 +1,8 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %run %t 2>&1 | FileCheck %s +// XFAIL: ios + #import #import diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm index eaef4e06c..4b037e170 100644 --- a/test/tsan/Darwin/xpc-race.mm +++ b/test/tsan/Darwin/xpc-race.mm @@ -1,6 +1,8 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %deflake %run %t 2>&1 | FileCheck %s +// XFAIL: ios + #import #import diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm index 2d6de269b..c5e78a577 100644 --- a/test/tsan/Darwin/xpc.mm +++ b/test/tsan/Darwin/xpc.mm @@ -1,6 +1,8 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %run %t 2>&1 | FileCheck %s +// XFAIL: ios + #import #import -- cgit v1.2.1 From 5f3af083734d665b271b5602d44e8238b2419ac2 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 20:38:24 +0000 Subject: [asan] Allow propagating env variables when testing on iOS Simulator This patch adds "%env" as a way to express that the environment variable should be set on the target device/simulator. This fixes some test failures when testing on iOS/Simulator. Differential Revision: https://reviews.llvm.org/D32556 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301462 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/scribble.cc | 2 +- test/lit.common.cfg | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc index 0ddee6b5e..8303cf316 100644 --- a/test/asan/TestCases/Darwin/scribble.cc +++ b/test/asan/TestCases/Darwin/scribble.cc @@ -1,6 +1,6 @@ // RUN: %clang_asan -O2 %s -o %t // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s -// RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s +// RUN: %env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s // RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s #include diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 2f0dd6351..cca41a0a0 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -96,14 +96,18 @@ config.substitutions.append( # Allow tests to be executed on a simulator or remotely. if config.emulator: config.substitutions.append( ('%run', config.emulator) ) + config.substitutions.append( ('%env ', "env ") ) elif config.ios: device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER" if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env] ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands") run_wrapper = os.path.join(ios_commands_dir, "iossim_run.py" if config.iossim else "ios_run.py") config.substitutions.append(('%run', run_wrapper)) + env_wrapper = os.path.join(ios_commands_dir, "iossim_env.py" if config.iossim else "ios_env.py") + config.substitutions.append(('%env ', env_wrapper + " ")) else: config.substitutions.append( ('%run', "") ) + config.substitutions.append( ('%env ', "env ") ) # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) -- cgit v1.2.1 From 2c89e2b50ee487d350b386936bdfe41123d23914 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 26 Apr 2017 21:34:18 +0000 Subject: Mark two tests (dead-strip.c, initialization-bug.cc) as unsupported on iOS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301478 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/dead-strip.c | 1 + test/asan/TestCases/initialization-bug.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/test/asan/TestCases/Darwin/dead-strip.c b/test/asan/TestCases/Darwin/dead-strip.c index f87a5e52b..8165fcd08 100644 --- a/test/asan/TestCases/Darwin/dead-strip.c +++ b/test/asan/TestCases/Darwin/dead-strip.c @@ -6,6 +6,7 @@ // runtime is able to register globals in the __DATA,__asan_globals section. // REQUIRES: osx-ld64-live_support +// UNSUPPORTED: ios // RUN: %clang_asan -mmacosx-version-min=10.11 -Xlinker -dead_strip -o %t %s // RUN: llvm-nm -format=posix %t | FileCheck --check-prefix NM-CHECK %s // RUN: not %run %t 2>&1 | FileCheck --check-prefix ASAN-CHECK %s diff --git a/test/asan/TestCases/initialization-bug.cc b/test/asan/TestCases/initialization-bug.cc index b28174f59..6ecc6c836 100644 --- a/test/asan/TestCases/initialization-bug.cc +++ b/test/asan/TestCases/initialization-bug.cc @@ -10,6 +10,7 @@ // The test is expected to fail on OS X Yosemite and older // UNSUPPORTED: osx-no-ld64-live_support +// UNSUPPORTED: ios #include -- cgit v1.2.1 From b87de18ec4041bdc75319a4917633dd0b71bdf25 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 27 Apr 2017 13:32:09 +0000 Subject: Add missing FileCheck, update CHECK lines and avoid subshell. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301541 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-fork-direct.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/asan/TestCases/Posix/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc index c19671953..27c3e436a 100644 --- a/test/asan/TestCases/Posix/coverage-fork-direct.cc +++ b/test/asan/TestCases/Posix/coverage-fork-direct.cc @@ -1,8 +1,10 @@ // RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t // RUN: rm -rf %T/coverage-fork-direct // RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct -// RUN: (%env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t; \ -// RUN: %sancov rawunpack *.sancov.raw; %sancov print *.sancov) 2>&1 +// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t > %t.log 2>&1 +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >> %t.log 2>&1 +// RUN: FileCheck %s < %t.log // // XFAIL: android @@ -34,5 +36,7 @@ int main(int argc, char **argv) { // CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] // CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] -// CHECK-DAG: read 3 PCs from {{.*}}.[[ParentPID]].sancov -// CHECK-DAG: read 1 PCs from {{.*}}.[[ChildPID]].sancov +// CHECK-DAG: read 3 64-bit PCs from {{.*}}.[[ParentPID]].sancov + +// FIXME: this is missing +// XCHECK-DAG: read 1 64-bit PCs from {{.*}}.[[ChildPID]].sancov -- cgit v1.2.1 From 59674c69de7dcd222da9bc9749989fa0dbbe316e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 27 Apr 2017 14:21:09 +0000 Subject: Also match the output on 32 bit systems. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301543 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-fork-direct.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc index 27c3e436a..dba0cb022 100644 --- a/test/asan/TestCases/Posix/coverage-fork-direct.cc +++ b/test/asan/TestCases/Posix/coverage-fork-direct.cc @@ -36,7 +36,7 @@ int main(int argc, char **argv) { // CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] // CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] -// CHECK-DAG: read 3 64-bit PCs from {{.*}}.[[ParentPID]].sancov +// CHECK-DAG: read 3 {{64|32}}-bit PCs from {{.*}}.[[ParentPID]].sancov // FIXME: this is missing -// XCHECK-DAG: read 1 64-bit PCs from {{.*}}.[[ChildPID]].sancov +// XCHECK-DAG: read 1 {{64|32}}-bit PCs from {{.*}}.[[ChildPID]].sancov -- cgit v1.2.1 From 77bdfc0add1da8988f0117f7c3fb13781202c42d Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Thu, 27 Apr 2017 16:21:50 +0000 Subject: TSan: update line number after XFAIL on iOS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301560 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/xpc-race.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm index 4b037e170..2e965e4a0 100644 --- a/test/tsan/Darwin/xpc-race.mm +++ b/test/tsan/Darwin/xpc-race.mm @@ -76,8 +76,8 @@ int main(int argc, const char *argv[]) { // CHECK: Hello world. // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 8 -// CHECK: #0 {{.*}}xpc-race.mm:34 +// CHECK: #0 {{.*}}xpc-race.mm:36 // CHECK: Previous write of size 8 -// CHECK: #0 {{.*}}xpc-race.mm:34 +// CHECK: #0 {{.*}}xpc-race.mm:36 // CHECK: Location is global 'global' // CHECK: Done. -- cgit v1.2.1 From e3b4fb5e69a146811df9a27a9b3716e1ea4f3092 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 27 Apr 2017 20:21:16 +0000 Subject: [scudo] Move thread local variables into their own files Summary: This change introduces scudo_tls.h & scudo_tls_linux.cpp, where we move the thread local variables used by the allocator, namely the cache, quarantine cache & prng. `ScudoThreadContext` will hold those. This patch doesn't introduce any new platform support yet, this will be the object of a later patch. This also changes the PRNG so that the structure can be POD. Reviewers: kcc, dvyukov, alekseyshl Reviewed By: dvyukov, alekseyshl Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D32440 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301584 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/CMakeLists.txt | 1 + lib/scudo/scudo_allocator.cpp | 217 ++++++++++++++++++------------------------ lib/scudo/scudo_allocator.h | 55 +++++++---- lib/scudo/scudo_tls.h | 40 ++++++++ lib/scudo/scudo_tls_linux.cpp | 62 ++++++++++++ lib/scudo/scudo_tls_linux.h | 48 ++++++++++ lib/scudo/scudo_utils.cpp | 4 +- lib/scudo/scudo_utils.h | 2 +- 8 files changed, 286 insertions(+), 143 deletions(-) create mode 100644 lib/scudo/scudo_tls.h create mode 100644 lib/scudo/scudo_tls_linux.cpp create mode 100644 lib/scudo/scudo_tls_linux.h diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index ba5e8acd8..3a8f4ae4f 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -14,6 +14,7 @@ set(SCUDO_SOURCES scudo_interceptors.cpp scudo_new_delete.cpp scudo_termination.cpp + scudo_tls_linux.cpp scudo_utils.cpp) # Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available. diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index e89e09223..2ccdcd903 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "scudo_allocator.h" +#include "scudo_tls.h" #include "scudo_utils.h" #include "sanitizer_common/sanitizer_allocator_interface.h" @@ -26,44 +27,6 @@ namespace __scudo { -#if SANITIZER_CAN_USE_ALLOCATOR64 -const uptr AllocatorSpace = ~0ULL; -const uptr AllocatorSize = 0x40000000000ULL; -typedef DefaultSizeClassMap SizeClassMap; -struct AP { - static const uptr kSpaceBeg = AllocatorSpace; - static const uptr kSpaceSize = AllocatorSize; - static const uptr kMetadataSize = 0; - typedef __scudo::SizeClassMap SizeClassMap; - typedef NoOpMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = - SizeClassAllocator64FlagMasks::kRandomShuffleChunks; -}; -typedef SizeClassAllocator64 PrimaryAllocator; -#else -// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the -// security improvements brought to the 64-bit one. This makes the 32-bit -// version of Scudo slightly less toughened. -static const uptr RegionSizeLog = 20; -static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog; -# if SANITIZER_WORDSIZE == 32 -typedef FlatByteMap ByteMap; -# elif SANITIZER_WORDSIZE == 64 -typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap; -# endif // SANITIZER_WORDSIZE -typedef DefaultSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap, - RegionSizeLog, ByteMap> PrimaryAllocator; -#endif // SANITIZER_CAN_USE_ALLOCATOR64 - -typedef SizeClassAllocatorLocalCache AllocatorCache; -typedef ScudoLargeMmapAllocator SecondaryAllocator; -typedef CombinedAllocator - ScudoBackendAllocator; - -static ScudoBackendAllocator &getBackendAllocator(); - -static thread_local Xorshift128Plus Prng; // Global static cookie, initialized at start-up. static uptr Cookie; @@ -88,6 +51,8 @@ INLINE u32 computeCRC32(u32 Crc, uptr Data, u8 HashType) { #endif // defined(__SSE4_2__) } +static ScudoBackendAllocator &getBackendAllocator(); + struct ScudoChunk : UnpackedHeader { // We can't use the offset member of the chunk itself, as we would double // fetch it without any warranty that it wouldn't have been tampered. To @@ -188,32 +153,44 @@ ScudoChunk *getScudoChunk(uptr UserBeg) { return reinterpret_cast(UserBeg - AlignedChunkHeaderSize); } -static bool ScudoInitIsRunning = false; +struct AllocatorOptions { + u32 QuarantineSizeMb; + u32 ThreadLocalQuarantineSizeKb; + bool MayReturnNull; + s32 ReleaseToOSIntervalMs; + bool DeallocationTypeMismatch; + bool DeleteSizeMismatch; + bool ZeroContents; -static pthread_once_t GlobalInited = PTHREAD_ONCE_INIT; -static pthread_key_t PThreadKey; - -static thread_local bool ThreadInited = false; -static thread_local bool ThreadTornDown = false; -static thread_local AllocatorCache Cache; - -static void teardownThread(void *p) { - uptr v = reinterpret_cast(p); - // 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 (v < PTHREAD_DESTRUCTOR_ITERATIONS) { - pthread_setspecific(PThreadKey, reinterpret_cast(v + 1)); - return; - } - drainQuarantine(); - getBackendAllocator().DestroyCache(&Cache); - ThreadTornDown = true; + void setFrom(const Flags *f, const CommonFlags *cf); + void copyTo(Flags *f, CommonFlags *cf) const; +}; + +void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) { + MayReturnNull = cf->allocator_may_return_null; + ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms; + QuarantineSizeMb = f->QuarantineSizeMb; + ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb; + DeallocationTypeMismatch = f->DeallocationTypeMismatch; + DeleteSizeMismatch = f->DeleteSizeMismatch; + ZeroContents = f->ZeroContents; +} + +void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const { + cf->allocator_may_return_null = MayReturnNull; + cf->allocator_release_to_os_interval_ms = ReleaseToOSIntervalMs; + f->QuarantineSizeMb = QuarantineSizeMb; + f->ThreadLocalQuarantineSizeKb = ThreadLocalQuarantineSizeKb; + f->DeallocationTypeMismatch = DeallocationTypeMismatch; + f->DeleteSizeMismatch = DeleteSizeMismatch; + f->ZeroContents = ZeroContents; } -static void initInternal() { +static void initScudoInternal(const AllocatorOptions &Options); + +static bool ScudoInitIsRunning = false; + +void initScudo() { SanitizerToolName = "Scudo"; CHECK(!ScudoInitIsRunning && "Scudo init calls itself!"); ScudoInitIsRunning = true; @@ -227,25 +204,13 @@ static void initInternal() { AllocatorOptions Options; Options.setFrom(getFlags(), common_flags()); - initAllocator(Options); + initScudoInternal(Options); - MaybeStartBackgroudThread(); + // TODO(kostyak): determine if MaybeStartBackgroudThread could be of some use. ScudoInitIsRunning = false; } -static void initGlobal() { - pthread_key_create(&PThreadKey, teardownThread); - initInternal(); -} - -static void NOINLINE initThread() { - pthread_once(&GlobalInited, initGlobal); - pthread_setspecific(PThreadKey, reinterpret_cast(1)); - getBackendAllocator().InitCache(&Cache); - ThreadInited = true; -} - struct QuarantineCallback { explicit QuarantineCallback(AllocatorCache *Cache) : Cache_(Cache) {} @@ -278,26 +243,20 @@ struct QuarantineCallback { typedef Quarantine ScudoQuarantine; typedef ScudoQuarantine::Cache ScudoQuarantineCache; -static thread_local ScudoQuarantineCache ThreadQuarantineCache; +COMPILER_CHECK(sizeof(ScudoQuarantineCache) <= + sizeof(ScudoThreadContext::QuarantineCachePlaceHolder)); -void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) { - MayReturnNull = cf->allocator_may_return_null; - ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms; - QuarantineSizeMb = f->QuarantineSizeMb; - ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb; - DeallocationTypeMismatch = f->DeallocationTypeMismatch; - DeleteSizeMismatch = f->DeleteSizeMismatch; - ZeroContents = f->ZeroContents; +AllocatorCache *getAllocatorCache(ScudoThreadContext *ThreadContext) { + return &ThreadContext->Cache; } -void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const { - cf->allocator_may_return_null = MayReturnNull; - cf->allocator_release_to_os_interval_ms = ReleaseToOSIntervalMs; - f->QuarantineSizeMb = QuarantineSizeMb; - f->ThreadLocalQuarantineSizeKb = ThreadLocalQuarantineSizeKb; - f->DeallocationTypeMismatch = DeallocationTypeMismatch; - f->DeleteSizeMismatch = DeleteSizeMismatch; - f->ZeroContents = ZeroContents; +ScudoQuarantineCache *getQuarantineCache(ScudoThreadContext *ThreadContext) { + return reinterpret_cast< + ScudoQuarantineCache *>(ThreadContext->QuarantineCachePlaceHolder); +} + +Xorshift128Plus *getPrng(ScudoThreadContext *ThreadContext) { + return &ThreadContext->Prng; } struct ScudoAllocator { @@ -313,6 +272,7 @@ struct ScudoAllocator { StaticSpinMutex FallbackMutex; AllocatorCache FallbackAllocatorCache; ScudoQuarantineCache FallbackQuarantineCache; + Xorshift128Plus FallbackPrng; bool DeallocationTypeMismatch; bool ZeroContents; @@ -361,13 +321,13 @@ struct ScudoAllocator { static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); BackendAllocator.InitCache(&FallbackAllocatorCache); - Cookie = Prng.getNext(); + FallbackPrng.initFromURandom(); + Cookie = FallbackPrng.getNext(); } // Helper function that checks for a valid Scudo chunk. nullptr isn't. bool isValidPointer(const void *UserPtr) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); if (!UserPtr) return false; uptr UserBeg = reinterpret_cast(UserPtr); @@ -379,8 +339,7 @@ struct ScudoAllocator { // Allocates a chunk. void *allocate(uptr Size, uptr Alignment, AllocType Type, bool ForceZeroContents = false) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); if (UNLIKELY(!IsPowerOfTwo(Alignment))) { dieWithMessage("ERROR: alignment is not a power of 2\n"); } @@ -407,11 +366,16 @@ struct ScudoAllocator { bool FromPrimary = PrimaryAllocator::CanAllocate(NeededSize, MinAlignment); void *Ptr; + uptr Salt; uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; - if (LIKELY(!ThreadTornDown)) { - Ptr = BackendAllocator.Allocate(&Cache, NeededSize, AllocationAlignment); + ScudoThreadContext *ThreadContext = getThreadContext(); + if (LIKELY(ThreadContext)) { + Salt = getPrng(ThreadContext)->getNext(); + Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), + NeededSize, AllocationAlignment); } else { SpinMutexLock l(&FallbackMutex); + Salt = FallbackPrng.getNext(); Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, NeededSize, AllocationAlignment); } @@ -453,7 +417,7 @@ struct ScudoAllocator { if (TrailingBytes) Header.SizeOrUnusedBytes = PageSize - TrailingBytes; } - Header.Salt = static_cast(Prng.getNext()); + Header.Salt = static_cast(Salt); getScudoChunk(UserBeg)->storeHeader(&Header); void *UserPtr = reinterpret_cast(UserBeg); // if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(UserPtr, Size); @@ -462,16 +426,17 @@ struct ScudoAllocator { // Place a chunk in the quarantine. In the event of a zero-sized quarantine, // we directly deallocate the chunk, otherwise the flow would lead to the - // chunk being checksummed twice, once before Put and once in Recycle, with - // no additional security value. + // chunk being loaded (and checked) twice, and stored (and checksummed) once, + // with no additional security value. void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header, uptr Size) { bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0); if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); - if (LIKELY(!ThreadTornDown)) { - getBackendAllocator().Deallocate(&Cache, Ptr); + ScudoThreadContext *ThreadContext = getThreadContext(); + if (LIKELY(ThreadContext)) { + getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr); } else { SpinMutexLock Lock(&FallbackMutex); getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr); @@ -480,9 +445,12 @@ struct ScudoAllocator { UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); - if (LIKELY(!ThreadTornDown)) { - AllocatorQuarantine.Put(&ThreadQuarantineCache, - QuarantineCallback(&Cache), Chunk, Size); + ScudoThreadContext *ThreadContext = getThreadContext(); + if (LIKELY(ThreadContext)) { + AllocatorQuarantine.Put(getQuarantineCache(ThreadContext), + QuarantineCallback( + getAllocatorCache(ThreadContext)), + Chunk, Size); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, @@ -495,8 +463,7 @@ struct ScudoAllocator { // Deallocates a Chunk, which means adding it to the delayed free list (or // Quarantine). void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr); if (!UserPtr) return; @@ -542,8 +509,7 @@ struct ScudoAllocator { // Reallocates a chunk. We can save on a new allocation if the new requested // size still fits in the chunk. void *reallocate(void *OldPtr, uptr NewSize) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); uptr UserBeg = reinterpret_cast(OldPtr); if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) { dieWithMessage("ERROR: attempted to reallocate a chunk not properly " @@ -585,8 +551,7 @@ struct ScudoAllocator { // Helper function that returns the actual usable size of a chunk. uptr getUsableSize(const void *Ptr) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); if (!Ptr) return 0; uptr UserBeg = reinterpret_cast(Ptr); @@ -602,22 +567,22 @@ struct ScudoAllocator { } void *calloc(uptr NMemB, uptr Size) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); uptr Total = NMemB * Size; if (Size != 0 && Total / Size != NMemB) // Overflow check return BackendAllocator.ReturnNullOrDieOnBadRequest(); return allocate(Total, MinAlignment, FromMalloc, true); } - void drainQuarantine() { - AllocatorQuarantine.Drain(&ThreadQuarantineCache, - QuarantineCallback(&Cache)); + void commitBack(ScudoThreadContext *ThreadContext) { + AllocatorCache *Cache = getAllocatorCache(ThreadContext); + AllocatorQuarantine.Drain(getQuarantineCache(ThreadContext), + QuarantineCallback(Cache)); + BackendAllocator.DestroyCache(Cache); } uptr getStats(AllocatorStat StatType) { - if (UNLIKELY(!ThreadInited)) - initThread(); + initThreadMaybe(); uptr stats[AllocatorStatCount]; BackendAllocator.GetStats(stats); return stats[StatType]; @@ -630,12 +595,18 @@ static ScudoBackendAllocator &getBackendAllocator() { return Instance.BackendAllocator; } -void initAllocator(const AllocatorOptions &Options) { +static void initScudoInternal(const AllocatorOptions &Options) { Instance.init(Options); } -void drainQuarantine() { - Instance.drainQuarantine(); +void ScudoThreadContext::init() { + getBackendAllocator().InitCache(&Cache); + Prng.initFromURandom(); + memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder)); +} + +void ScudoThreadContext::commitBack() { + Instance.commitBack(this); } void *scudoMalloc(uptr Size, AllocType Type) { diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index e7428f170..2cac2de71 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -53,7 +53,7 @@ struct UnpackedHeader { u64 Offset : 16; // Offset from the beginning of the backend // allocation to the beginning of the chunk // itself, in multiples of MinAlignment. See - /// comment about its maximum value and in init(). + // comment about its maximum value and in init(). u64 Salt : 8; }; @@ -62,7 +62,7 @@ COMPILER_CHECK(sizeof(UnpackedHeader) == sizeof(PackedHeader)); // Minimum alignment of 8 bytes for 32-bit, 16 for 64-bit const uptr MinAlignmentLog = FIRST_32_SECOND_64(3, 4); -const uptr MaxAlignmentLog = 24; // 16 MB +const uptr MaxAlignmentLog = 24; // 16 MB const uptr MinAlignment = 1 << MinAlignmentLog; const uptr MaxAlignment = 1 << MaxAlignmentLog; @@ -70,21 +70,44 @@ const uptr ChunkHeaderSize = sizeof(PackedHeader); const uptr AlignedChunkHeaderSize = (ChunkHeaderSize + MinAlignment - 1) & ~(MinAlignment - 1); -struct AllocatorOptions { - u32 QuarantineSizeMb; - u32 ThreadLocalQuarantineSizeKb; - bool MayReturnNull; - s32 ReleaseToOSIntervalMs; - bool DeallocationTypeMismatch; - bool DeleteSizeMismatch; - bool ZeroContents; - - void setFrom(const Flags *f, const CommonFlags *cf); - void copyTo(Flags *f, CommonFlags *cf) const; +#if SANITIZER_CAN_USE_ALLOCATOR64 +const uptr AllocatorSpace = ~0ULL; +const uptr AllocatorSize = 0x40000000000ULL; // 4TB. +typedef DefaultSizeClassMap SizeClassMap; +struct AP { + static const uptr kSpaceBeg = AllocatorSpace; + static const uptr kSpaceSize = AllocatorSize; + static const uptr kMetadataSize = 0; + typedef __scudo::SizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = + SizeClassAllocator64FlagMasks::kRandomShuffleChunks; }; +typedef SizeClassAllocator64 PrimaryAllocator; +#else +// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the +// security improvements brought to the 64-bit one. This makes the 32-bit +// version of Scudo slightly less toughened. +static const uptr RegionSizeLog = 20; +static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog; +# if SANITIZER_WORDSIZE == 32 +typedef FlatByteMap ByteMap; +# elif SANITIZER_WORDSIZE == 64 +typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap; +# endif // SANITIZER_WORDSIZE +typedef DefaultSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap, + RegionSizeLog, ByteMap> PrimaryAllocator; +#endif // SANITIZER_CAN_USE_ALLOCATOR64 -void initAllocator(const AllocatorOptions &options); -void drainQuarantine(); +#include "scudo_allocator_secondary.h" + +typedef SizeClassAllocatorLocalCache AllocatorCache; +typedef ScudoLargeMmapAllocator SecondaryAllocator; +typedef CombinedAllocator + ScudoBackendAllocator; + +void initScudo(); void *scudoMalloc(uptr Size, AllocType Type); void scudoFree(void *Ptr, AllocType Type); @@ -98,8 +121,6 @@ int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size); void *scudoAlignedAlloc(uptr Alignment, uptr Size); uptr scudoMallocUsableSize(void *Ptr); -#include "scudo_allocator_secondary.h" - } // namespace __scudo #endif // SCUDO_ALLOCATOR_H_ diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h new file mode 100644 index 000000000..0d7d1bffd --- /dev/null +++ b/lib/scudo/scudo_tls.h @@ -0,0 +1,40 @@ +//===-- scudo_tls.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure definition. +/// Implementation will differ based on the thread local storage primitives +/// offered by the underlying platform. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_H_ +#define SCUDO_TLS_H_ + +#include "scudo_allocator.h" +#include "scudo_utils.h" + +namespace __scudo { + +struct ALIGNED(64) ScudoThreadContext { + public: + AllocatorCache Cache; + Xorshift128Plus Prng; + uptr QuarantineCachePlaceHolder[4]; + void init(); + void commitBack(); +}; + +void initThread(); + +// Fastpath functions are defined in the following platform specific headers. +#include "scudo_tls_linux.h" + +} // namespace __scudo + +#endif // SCUDO_TLS_H_ diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp new file mode 100644 index 000000000..3453367f8 --- /dev/null +++ b/lib/scudo/scudo_tls_linux.cpp @@ -0,0 +1,62 @@ +//===-- scudo_tls_linux.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure implementation for platforms supporting +/// thread_local. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_LINUX + +#include "scudo_tls.h" + +#include +#include + +namespace __scudo { + +static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; +static pthread_key_t PThreadKey; + +thread_local ThreadState ScudoThreadState = ThreadNotInitialized; +thread_local ScudoThreadContext ThreadLocalContext; + +static void teardownThread(void *Ptr) { + uptr Iteration = reinterpret_cast(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(Iteration + 1)); + return; + } + ThreadLocalContext.commitBack(); + ScudoThreadState = ThreadTornDown; +} + + +static void initOnce() { + CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0); + initScudo(); +} + +void initThread() { + pthread_once(&GlobalInitialized, initOnce); + pthread_setspecific(PThreadKey, reinterpret_cast(1)); + ThreadLocalContext.init(); + ScudoThreadState = ThreadInitialized; +} + +} // namespace __scudo + +#endif // SANITIZER_LINUX diff --git a/lib/scudo/scudo_tls_linux.h b/lib/scudo/scudo_tls_linux.h new file mode 100644 index 000000000..0994f2d7b --- /dev/null +++ b/lib/scudo/scudo_tls_linux.h @@ -0,0 +1,48 @@ +//===-- scudo_tls_linux.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure fastpath functions implementation for platforms +/// supporting thread_local. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_LINUX_H_ +#define SCUDO_TLS_LINUX_H_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_LINUX + +enum ThreadState : u8 { + ThreadNotInitialized = 0, + ThreadInitialized, + ThreadTornDown, +}; +extern thread_local ThreadState ScudoThreadState; +extern thread_local ScudoThreadContext ThreadLocalContext; + +ALWAYS_INLINE void initThreadMaybe() { + if (LIKELY(ScudoThreadState != ThreadNotInitialized)) + return; + initThread(); +} + +ALWAYS_INLINE ScudoThreadContext *getThreadContext() { + if (UNLIKELY(ScudoThreadState == ThreadTornDown)) + return nullptr; + return &ThreadLocalContext; +} + +#endif // SANITIZER_LINUX + +#endif // SCUDO_TLS_LINUX_H_ diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index 98bd591aa..31c391946 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -153,9 +153,9 @@ static void fillRandom(u8 *Data, ssize_t Size) { } } -// Default constructor for Xorshift128Plus seeds the state with /dev/urandom. +// Seeds the xorshift state with /dev/urandom. // TODO(kostyak): investigate using getrandom() if available. -Xorshift128Plus::Xorshift128Plus() { +void Xorshift128Plus::initFromURandom() { fillRandom(reinterpret_cast(State), sizeof(State)); } diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index f30c86125..484b0c859 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -40,7 +40,7 @@ bool testCPUFeature(CPUFeature feature); // The state (128 bits) will be stored in thread local storage. struct Xorshift128Plus { public: - Xorshift128Plus(); + void initFromURandom(); u64 getNext() { u64 x = State[0]; const u64 y = State[1]; -- cgit v1.2.1 From 57470fcc23ff27e2dbbcc2a04254a3879977d9ce Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 27 Apr 2017 20:27:33 +0000 Subject: [asan] Fix dead stripping of globals on Linux (compiler-rt). Third attempt. See the description of the corresponding commit in LLVM for more details. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301588 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 20 ++++++++++++++++++++ lib/asan/asan_interface.inc | 2 ++ lib/asan/asan_interface_internal.h | 5 +++++ test/asan/CMakeLists.txt | 2 +- test/asan/TestCases/Linux/global-overflow-bfd.cc | 18 ++++++++++++++++++ test/asan/TestCases/Linux/global-overflow-lld.cc | 19 +++++++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections-lld.cc | 15 +++++++++++++++ test/asan/TestCases/Linux/globals-gc-sections.cc | 13 ------------- 8 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 test/asan/TestCases/Linux/global-overflow-bfd.cc create mode 100644 test/asan/TestCases/Linux/global-overflow-lld.cc create mode 100644 test/asan/TestCases/Linux/globals-gc-sections-lld.cc delete mode 100644 test/asan/TestCases/Linux/globals-gc-sections.cc diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index b72330673..eebada804 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -332,6 +332,26 @@ void __asan_unregister_image_globals(uptr *flag) { *flag = 0; } +void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { + if (*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_register_globals(globals_start, globals_stop - globals_start); + *flag = 1; +} + +void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { + if (!*flag) return; + if (!start) return; + CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); + __asan_global *globals_start = (__asan_global*)start; + __asan_global *globals_stop = (__asan_global*)stop; + __asan_unregister_globals(globals_start, globals_stop - globals_start); + *flag = 0; +} + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc index 351be4da5..e65f61722 100644 --- a/lib/asan/asan_interface.inc +++ b/lib/asan/asan_interface.inc @@ -64,6 +64,7 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_print_accumulated_stats) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_register_globals) +INTERFACE_FUNCTION(__asan_register_elf_globals) INTERFACE_FUNCTION(__asan_register_image_globals) INTERFACE_FUNCTION(__asan_report_error) INTERFACE_FUNCTION(__asan_report_exp_load1) @@ -149,6 +150,7 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) +INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index b18c31548..b974c0cc4 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -67,6 +67,11 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_elf_globals(uptr *flag, void *start, void *stop); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop); + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 944588333..b8e365227 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -22,7 +22,7 @@ endmacro() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) - if(WIN32 AND COMPILER_RT_HAS_LLD) + if(NOT APPLE AND COMPILER_RT_HAS_LLD) list(APPEND ASAN_TEST_DEPS lld ) diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc new file mode 100644 index 000000000..117a761af --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-bfd.cc @@ -0,0 +1,18 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the BFD linker. +// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc new file mode 100644 index 000000000..f4d0bc977 --- /dev/null +++ b/test/asan/TestCases/Linux/global-overflow-lld.cc @@ -0,0 +1,19 @@ +// Test that gc-sections-friendly instrumentation of globals does not introduce +// false negatives with the LLD linker. +// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: lld + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at}} + // CHECK: {{located 0 bytes to the right of global variable}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc new file mode 100644 index 000000000..0d8bcdd1c --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// REQUIRES: lld + +int undefined(); + +// On i386 clang adds --export-dynamic when linking with ASan, which adds all +// non-hidden globals to GC roots. +__attribute__((visibility("hidden"))) int (*unused)() = undefined; + +int main() { + return 0; +} diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc deleted file mode 100644 index 72a9e9498..000000000 --- a/test/asan/TestCases/Linux/globals-gc-sections.cc +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 -// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 - -// https://code.google.com/p/address-sanitizer/issues/detail?id=260 -// XFAIL: * - -int undefined(); - -int (*unused)() = undefined; - -int main() { - return 0; -} -- cgit v1.2.1 From 33780624aebb9e414150ca504b734742552e6f7a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 27 Apr 2017 20:48:17 +0000 Subject: [ubsan] Make the cast overflow message less redundant git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301589 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 2 +- test/ubsan/TestCases/Float/cast-overflow.cpp | 20 ++++++++++---------- test/ubsan/TestCases/Misc/log-path_test.cc | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 4e025a8dd..de13ab893 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -390,7 +390,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From, ScopedReport R(Opts, Loc, ET); Diag(Loc, DL_Error, - "value %0 is outside the range of representable values of type %2") + "%0 is outside the range of representable values of type %2") << Value(*FromType, From) << *FromType << *ToType; } diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp index 5f51553f4..85c5049b4 100644 --- a/test/ubsan/TestCases/Float/cast-overflow.cpp +++ b/test/ubsan/TestCases/Float/cast-overflow.cpp @@ -86,42 +86,42 @@ int main(int argc, char **argv) { case '0': { // Note that values between 0x7ffffe00 and 0x80000000 may or may not // successfully round-trip, depending on the rounding mode. - // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int' + // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: 2.14748{{.*}} is outside the range of representable values of type 'int' static int test_int = MaxFloatRepresentableAsInt + 0x80; // CHECK-0: SUMMARY: {{.*}}Sanitizer: float-cast-overflow {{.*}}cast-overflow.cpp:[[@LINE-1]] return 0; } case '1': { - // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int' + // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: -2.14748{{.*}} is outside the range of representable values of type 'int' static int test_int = MinFloatRepresentableAsInt - 0x100; return 0; } case '2': { - // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: value -1 is outside the range of representable values of type 'unsigned int' + // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: -1 is outside the range of representable values of type 'unsigned int' volatile float f = -1.0; volatile unsigned u = (unsigned)f; return 0; } case '3': { - // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int' + // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: 4.2949{{.*}} is outside the range of representable values of type 'unsigned int' static int test_int = (unsigned)(MaxFloatRepresentableAsUInt + 0x100); return 0; } case '4': { - // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int' + // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int' static int test_int = Inf; return 0; } case '5': { - // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int' + // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int' static int test_int = NaN; return 0; } // Integer -> floating point overflow. case '6': { - // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}} + // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}} #if defined(__SIZEOF_INT128__) && !defined(_WIN32) static int test_int = (float)(FloatMaxAsUInt128 + 1); return 0; @@ -135,16 +135,16 @@ int main(int argc, char **argv) { // FIXME: The backend cannot lower __fp16 operations on x86 yet. //case '7': // (__fp16)65504; // ok - // // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16' + // // CHECK-7: runtime error: 65505 is outside the range of representable values of type '__fp16' // return (__fp16)65505; // Floating point -> floating point overflow. case '8': - // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: value 1e+39 is outside the range of representable values of type 'float' + // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: 1e+39 is outside the range of representable values of type 'float' return (float)1e39; case '9': volatile long double ld = 300.0; - // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: value 300 is outside the range of representable values of type 'char' + // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: 300 is outside the range of representable values of type 'char' char c = ld; return c; } diff --git a/test/ubsan/TestCases/Misc/log-path_test.cc b/test/ubsan/TestCases/Misc/log-path_test.cc index 5b45f0b6f..40bb35a06 100644 --- a/test/ubsan/TestCases/Misc/log-path_test.cc +++ b/test/ubsan/TestCases/Misc/log-path_test.cc @@ -32,5 +32,5 @@ int main(int argc, char *argv[]) { return 0; } -// CHECK-ERROR: runtime error: value -4 is outside the range of representable values of type 'unsigned int' +// CHECK-ERROR: runtime error: -4 is outside the range of representable values of type 'unsigned int' -- cgit v1.2.1 From d53a2b5d96571c4120c1bd69ab5d406926acd5f1 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 28 Apr 2017 04:55:35 +0000 Subject: [asan] Add a compilation wrapper that codesigns shared libraries to support iOS simulator testing Tests that run on the iOS simulator require the dlopen'd dylibs are codesigned. This patch adds the "iossim_compile.py" wrapper that codesigns any produces dylib. Differential Revision: https://reviews.llvm.org/D32561 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301617 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 6 ++-- test/lit.common.cfg | 6 ++++ .../ios_commands/iossim_compile.py | 32 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100755 test/sanitizer_common/ios_commands/iossim_compile.py diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 7d684a1ae..b433a91e8 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -108,14 +108,12 @@ if platform.system() == 'Windows': asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir") if config.android == "1": config.available_features.add('android') - clang_wrapper = os.path.join(asan_lit_source_dir, - "android_commands", "android_compile.py") + " " + compile_wrapper = os.path.join(asan_lit_source_dir, "android_commands", "android_compile.py") + " " else: config.available_features.add('not-android') - clang_wrapper = "" def build_invocation(compile_flags): - return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " # Clang driver link 'x86' (i686) architecture to 'i386'. target_arch = config.target_arch diff --git a/test/lit.common.cfg b/test/lit.common.cfg index cca41a0a0..6080edca4 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -97,7 +97,10 @@ config.substitutions.append( if config.emulator: config.substitutions.append( ('%run', config.emulator) ) config.substitutions.append( ('%env ', "env ") ) + config.compile_wrapper = "" elif config.ios: + config.available_features.add('ios') + device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER" if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env] ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands") @@ -105,9 +108,12 @@ elif config.ios: config.substitutions.append(('%run', run_wrapper)) env_wrapper = os.path.join(ios_commands_dir, "iossim_env.py" if config.iossim else "ios_env.py") config.substitutions.append(('%env ', env_wrapper + " ")) + compile_wrapper = os.path.join(ios_commands_dir, "iossim_compile.py" if config.iossim else "ios_compile.py") + config.compile_wrapper = compile_wrapper else: config.substitutions.append( ('%run', "") ) config.substitutions.append( ('%env ', "env ") ) + config.compile_wrapper = "" # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) diff --git a/test/sanitizer_common/ios_commands/iossim_compile.py b/test/sanitizer_common/ios_commands/iossim_compile.py new file mode 100755 index 000000000..8fa480ed5 --- /dev/null +++ b/test/sanitizer_common/ios_commands/iossim_compile.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +import os, sys, subprocess + +output = None +output_type = 'executable' + +args = sys.argv[1:] +while args: + arg = args.pop(0) + if arg == '-shared': + output_type = 'shared' + elif arg == '-dynamiclib': + output_type = 'dylib' + elif arg == '-c': + output_type = 'object' + elif arg == '-S': + output_type = 'assembly' + elif arg == '-o': + output = args.pop(0) + +if output == None: + print "No output file name!" + sys.exit(1) + +ret = subprocess.call(sys.argv[1:]) +if ret != 0: + sys.exit(ret) + +# If we produce a dylib, ad-hoc sign it. +if output_type in ['shared', 'dylib']: + ret = subprocess.call(["codesign", "-s", "-", output]) -- cgit v1.2.1 From ce5dde422ec2872cec09f60ad1a34b6ff3ecf8ee Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 28 Apr 2017 05:48:27 +0000 Subject: Fix the reexec-insert-libraries-env.cc testcase to use %env to make it work on iOS simulator. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301621 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc index aa4d92b00..cd277a05b 100644 --- a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc +++ b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc @@ -7,7 +7,7 @@ // RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib // FIXME: the following command line may hang in the case of a regression. -// RUN: env DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ +// RUN: %env DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ // RUN: %run %t 2>&1 | FileCheck %s || exit 1 #if !defined(SHARED_LIB) -- cgit v1.2.1 From fce320da7a80b1b0f2d1228b9be6a83280315d40 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 28 Apr 2017 05:50:46 +0000 Subject: Fix unset-insert-libraries-on-exec.cc to use "%env" to make it work in iOS simulator. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301622 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc index f8a330ad5..62cf853a5 100644 --- a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc +++ b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc @@ -10,7 +10,7 @@ // execl(). // RUN: %run %t %T/echo-env >/dev/null 2>&1 -// RUN: env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \ +// RUN: %env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \ // RUN: %run %t %T/echo-env 2>&1 | FileCheck %s || exit 1 #if !defined(SHARED_LIB) -- cgit v1.2.1 From aa1c977562f63984d19f8c1fc97adb94b9e493eb Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 30 Apr 2017 20:35:18 +0000 Subject: [tsan] Track external tags in thread traces To make the TSan external API work with Swift and other use cases, we need to track "tags" for individual memory accesses. Since there is no space to store this information in shadow cells, let's use the thread traces for that. This patch stores the tag as an extra frame in the stack traces (by calling FuncEntry and FuncExit with the address of a registered tag), this extra frame is then stripped before printing the backtrace to stderr. Differential Revision: https://reviews.llvm.org/D32382 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301777 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/go/buildgo.sh | 1 + lib/tsan/rtl/tsan_external.cc | 29 +++++++++++++++++++++-------- lib/tsan/rtl/tsan_report.cc | 2 +- lib/tsan/rtl/tsan_rtl.h | 34 +++++++++++++++++++++++++++++----- lib/tsan/rtl/tsan_rtl_report.cc | 16 ++++++++++------ 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 42d479064..59176809e 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -5,6 +5,7 @@ set -e SRCS=" tsan_go.cc ../rtl/tsan_clock.cc + ../rtl/tsan_external.cc ../rtl/tsan_flags.cc ../rtl/tsan_interface_atomic.cc ../rtl/tsan_md5.cc diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc index 88468e406..2d32b6dac 100644 --- a/lib/tsan/rtl/tsan_external.cc +++ b/lib/tsan/rtl/tsan_external.cc @@ -17,11 +17,8 @@ namespace __tsan { #define CALLERPC ((uptr)__builtin_return_address(0)) -const uptr kMaxTag = 128; // Limited to 65,536, since MBlock only stores tags - // as 16-bit values, see tsan_defs.h. - -const char *registered_tags[kMaxTag]; -static atomic_uint32_t used_tags{1}; // Tag 0 means "no tag". NOLINT +const char *registered_tags[kExternalTagMax]; +static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT. const char *GetObjectTypeFromTag(uptr tag) { if (tag == 0) return nullptr; @@ -30,25 +27,39 @@ const char *GetObjectTypeFromTag(uptr tag) { return registered_tags[tag]; } +void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) { + FuncEntry(thr, (uptr)®istered_tags[tag]); +} + +uptr TagFromShadowStackFrame(uptr pc) { + uptr tag_count = atomic_load(&used_tags, memory_order_relaxed); + void *pc_ptr = (void *)pc; + if (pc_ptr < ®istered_tags[0] || pc_ptr >= ®istered_tags[tag_count]) + return 0; + return (const char **)pc_ptr - ®istered_tags[0]; +} + +#if !SANITIZER_GO + typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int); void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) { CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); ThreadState *thr = cur_thread(); - thr->external_tag = (uptr)tag; if (caller_pc) FuncEntry(thr, (uptr)caller_pc); + InsertShadowStackFrameForTag(thr, (uptr)tag); bool in_ignored_lib; if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { access(thr, CALLERPC, (uptr)addr, kSizeLog1); } + FuncExit(thr); if (caller_pc) FuncExit(thr); - thr->external_tag = 0; } extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void *__tsan_external_register_tag(const char *object_type) { uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed); - CHECK_LT(new_tag, kMaxTag); + CHECK_LT(new_tag, kExternalTagMax); registered_tags[new_tag] = internal_strdup(object_type); return (void *)new_tag; } @@ -78,4 +89,6 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag) { } } // extern "C" +#endif // !SANITIZER_GO + } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index af5fe6176..b188af2a0 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -164,7 +164,7 @@ static void PrintMop(const ReportMop *mop, bool first) { char thrbuf[kThreadBufSize]; Printf("%s", d.Access()); const char *object_type = GetObjectTypeFromTag(mop->external_tag); - if (!object_type) { + if (mop->external_tag == kExternalTagNone || !object_type) { Printf(" %s of size %d at %p by %s", MopDesc(first, mop->write, mop->atomic), mop->size, (void *)mop->addr, thread_name(thrbuf, mop->tid)); diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 09c97a3a4..cc60eb6db 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -411,7 +411,6 @@ struct ThreadState { bool is_dead; bool is_freeing; bool is_vptr_access; - uptr external_tag; const uptr stk_addr; const uptr stk_size; const uptr tls_addr; @@ -565,6 +564,16 @@ struct ScopedIgnoreInterceptors { } }; +enum ExternalTag : uptr { + kExternalTagNone = 0, + kExternalTagFirstUserAvailable = 1, + kExternalTagMax = 1024, + // Don't set kExternalTagMax over 65,536, since MBlock only stores tags + // as 16-bit values, see tsan_defs.h. +}; +const char *GetObjectTypeFromTag(uptr tag); +uptr TagFromShadowStackFrame(uptr pc); + class ScopedReport { public: explicit ScopedReport(ReportType typ); @@ -598,10 +607,26 @@ class ScopedReport { ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack); void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, - MutexSet *mset); + MutexSet *mset, uptr *tag = nullptr); + +// The stack could look like: +// |
| | tag | +// This will extract the tag and keep: +// |
| | +template +void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) { + if (stack->size < 2) return; + uptr possible_tag_pc = stack->trace[stack->size - 2]; + uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc); + if (possible_tag == kExternalTagNone) return; + stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1]; + stack->size -= 1; + if (tag) *tag = possible_tag; +} template -void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) { +void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack, + uptr *tag = nullptr) { uptr size = thr->shadow_stack_pos - thr->shadow_stack; uptr start = 0; if (size + !!toppc > kStackTraceMax) { @@ -609,6 +634,7 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) { size = kStackTraceMax - !!toppc; } stack->Init(&thr->shadow_stack[start], size, toppc); + ExtractTagFromStack(stack, tag); } @@ -646,8 +672,6 @@ bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace); bool IsExpectedReport(uptr addr, uptr size); void PrintMatchedBenignRaces(); -const char *GetObjectTypeFromTag(uptr tag); - #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1 # define DPrintf Printf #else diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index 5cd93a184..055029b91 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -377,7 +377,7 @@ const ReportDesc *ScopedReport::GetReport() const { } void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, - MutexSet *mset) { + MutexSet *mset, uptr *tag) { // This function restores stack trace and mutex set for the thread/epoch. // It does so by getting stack trace and mutex set at the beginning of // trace part, and then replaying the trace till the given epoch. @@ -436,6 +436,7 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, return; pos++; stk->Init(&stack[0], pos); + ExtractTagFromStack(stk, tag); } static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], @@ -625,16 +626,15 @@ void ReportRace(ThreadState *thr) { typ = ReportTypeVptrRace; else if (freed) typ = ReportTypeUseAfterFree; - else if (thr->external_tag > 0) - typ = ReportTypeExternalRace; if (IsFiredSuppression(ctx, typ, addr)) return; const uptr kMop = 2; VarSizeStackTrace traces[kMop]; + uptr tags[kMop] = {kExternalTagNone}; const uptr toppc = TraceTopPC(thr); - ObtainCurrentStack(thr, toppc, &traces[0]); + ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]); if (IsFiredSuppression(ctx, typ, traces[0])) return; @@ -644,18 +644,22 @@ void ReportRace(ThreadState *thr) { MutexSet *mset2 = new(&mset_buffer[0]) MutexSet(); Shadow s2(thr->racy_state[1]); - RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2); + RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2, &tags[1]); if (IsFiredSuppression(ctx, typ, traces[1])) return; if (HandleRacyStacks(thr, traces, addr_min, addr_max)) return; + // If any of the two accesses has a tag, treat this as an "external" race. + if (tags[0] != kExternalTagNone || tags[1] != kExternalTagNone) + typ = ReportTypeExternalRace; + ThreadRegistryLock l0(ctx->thread_registry); ScopedReport rep(typ); for (uptr i = 0; i < kMop; i++) { Shadow s(thr->racy_state[i]); - rep.AddMemoryAccess(addr, thr->external_tag, s, traces[i], + rep.AddMemoryAccess(addr, tags[i], s, traces[i], i == 0 ? &thr->mset : mset2); } -- cgit v1.2.1 From d816020bbf906c6452e8911151abb688176c2ef5 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 1 May 2017 00:52:57 +0000 Subject: [XRay][compiler-rt] Document and update the XRay Logging API Summary: In this patch we document the requirements for implementations that want to install handlers for the dynamically-controlled XRay "framework". This clarifies what the expectations are for implementations that want to install their handlers using this API (similar to how the FDR logging implementation does so). It also gives users some guarantees on semantics for the APIs. If all goes well, users can decide to use the XRay APIs to control the tracing/logging at the application level, without having to depend on implementation details of the installed logging implementation. This lets users choose the implementation that comes with compiler-rt, or potentially multiple other implementations that use the same APIs. We also add one convenience function (__xray_remove_log_impl()) for explicitly removing the currently installed log implementation. Reviewers: kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32579 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301784 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_log_interface.h | 171 ++++++++++++++++++++++++++++++++++++++ lib/xray/xray_log_interface.cc | 10 +++ 2 files changed, 181 insertions(+) diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h index a8709c3a7..cdb20094d 100644 --- a/include/xray/xray_log_interface.h +++ b/include/xray/xray_log_interface.h @@ -10,7 +10,73 @@ // This file is a part of XRay, a function call tracing system. // // APIs for installing a new logging implementation. +// //===----------------------------------------------------------------------===// +/// +/// XRay allows users to implement their own logging handlers and install them +/// to replace the default runtime-controllable implementation that comes with +/// compiler-rt/xray. The "flight data recorder" (FDR) mode implementation uses +/// this API to install itself in an XRay-enabled binary. See +/// compiler-rt/lib/xray_fdr_logging.{h,cc} for details of that implementation. +/// +/// The high-level usage pattern for these APIs look like the following: +/// +/// // Before we try initializing the log implementation, we must set it as +/// // the log implementation. We provide the function pointers that define +/// // the various initialization, finalization, and other pluggable hooks +/// // that we need. +/// __xray_set_log_impl({...}); +/// +/// // Once that's done, we can now initialize the implementation. Each +/// // implementation has a chance to let users customize the implementation +/// // with a struct that their implementation supports. Roughly this might +/// // look like: +/// MyImplementationOptions opts; +/// opts.enable_feature = true; +/// ... +/// auto init_status = __xray_log_init( +/// BufferSize, MaxBuffers, &opts, sizeof opts); +/// if (init_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { +/// // deal with the error here, if there is one. +/// } +/// +/// // When the log implementation has had the chance to initialize, we can +/// // now patch the sleds. +/// auto patch_status = __xray_patch(); +/// if (patch_status != XRayPatchingStatus::SUCCESS) { +/// // deal with the error here, if it is an error. +/// } +/// +/// // If we want to stop the implementation, we can then finalize it (before +/// // optionally flushing the log). +/// auto fin_status = __xray_log_finalize(); +/// if (fin_status != XRayLogInitStatus::XRAY_LOG_FINALIZED) { +/// // deal with the error here, if it is an error. +/// } +/// +/// // We can optionally wait before flushing the log to give other threads a +/// // chance to see that the implementation is already finalized. Also, at +/// // this point we can optionally unpatch the sleds to reduce overheads at +/// // runtime. +/// auto unpatch_status = __xray_unpatch(); +/// if (unpatch_status != XRayPatchingStatus::SUCCESS) { +// // deal with the error here, if it is an error. +// } +/// +/// // If there are logs or data to be flushed somewhere, we can do so only +/// // after we've finalized the log. Some implementations may not actually +/// // have anything to log (it might keep the data in memory, or periodically +/// // be logging the data anyway). +/// auto flush_status = __xray_log_flushLog(); +/// if (flush_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) { +/// // deal with the error here, if it is an error. +/// } +/// +/// +/// NOTE: Before calling __xray_patch() again, consider re-initializing the +/// implementation first. Some implementations might stay in an "off" state when +/// they are finalized, while some might be in an invalid/unknown state. +/// #ifndef XRAY_XRAY_LOG_INTERFACE_H #define XRAY_XRAY_LOG_INTERFACE_H @@ -19,36 +85,141 @@ extern "C" { +/// This enum defines the valid states in which the logging implementation can +/// be at. enum XRayLogInitStatus { + /// The default state is uninitialized, and in case there were errors in the + /// initialization, the implementation MUST return XRAY_LOG_UNINITIALIZED. XRAY_LOG_UNINITIALIZED = 0, + + /// Some implementations support multi-stage init (or asynchronous init), and + /// may return XRAY_LOG_INITIALIZING to signal callers of the API that + /// there's an ongoing initialization routine running. This allows + /// implementations to support concurrent threads attempting to initialize, + /// while only signalling success in one. XRAY_LOG_INITIALIZING = 1, + + /// When an implementation is done initializing, it MUST return + /// XRAY_LOG_INITIALIZED. When users call `__xray_patch()`, they are + /// guaranteed that the implementation installed with + /// `__xray_set_log_impl(...)` has been initialized. XRAY_LOG_INITIALIZED = 2, + + /// Some implementations might support multi-stage finalization (or + /// asynchronous finalization), and may return XRAY_LOG_FINALIZING to signal + /// callers of the API that there's an ongoing finalization routine running. + /// This allows implementations to support concurrent threads attempting to + /// finalize, while only signalling success/completion in one. XRAY_LOG_FINALIZING = 3, + + /// When an implementation is done finalizing, it MUST return + /// XRAY_LOG_FINALIZED. It is up to the implementation to determine what the + /// semantics of a finalized implementation is. Some implementations might + /// allow re-initialization once the log is finalized, while some might always + /// be on (and that finalization is a no-op). XRAY_LOG_FINALIZED = 4, }; +/// This enum allows an implementation to signal log flushing operations via +/// `__xray_log_flushLog()`, and the state of flushing the log. enum XRayLogFlushStatus { XRAY_LOG_NOT_FLUSHING = 0, XRAY_LOG_FLUSHING = 1, XRAY_LOG_FLUSHED = 2, }; +/// A valid XRay logging implementation MUST provide all of the function +/// pointers in XRayLogImpl when being installed through `__xray_set_log_impl`. +/// To be precise, ALL the functions pointers MUST NOT be nullptr. struct XRayLogImpl { + /// The log initialization routine provided by the implementation, always + /// provided with the following parameters: + /// + /// - buffer size + /// - maximum number of buffers + /// - a pointer to an argument struct that the implementation MUST handle + /// - the size of the argument struct + /// + /// See XRayLogInitStatus for details on what the implementation MUST return + /// when called. + /// + /// If the implementation needs to install handlers aside from the 0-argument + /// function call handler, it MUST do so in this initialization handler. + /// + /// See xray_interface.h for available handler installation routines. XRayLogInitStatus (*log_init)(size_t, size_t, void *, size_t); + + /// The log finalization routine provided by the implementation. + /// + /// See XRayLogInitStatus for details on what the implementation MUST return + /// when called. XRayLogInitStatus (*log_finalize)(); + + /// The 0-argument function call handler. XRay logging implementations MUST + /// always have a handler for function entry and exit events. In case the + /// implementation wants to support arg1 (or other future extensions to XRay + /// logging) those MUST be installed by the installed 'log_init' handler. void (*handle_arg0)(int32_t, XRayEntryType); + + /// The log implementation provided routine for when __xray_log_flushLog() is + /// called. + /// + /// See XRayLogFlushStatus for details on what the implementation MUST return + /// when called. XRayLogFlushStatus (*flush_log)(); }; +/// This function installs a new logging implementation that XRay will use. In +/// case there are any nullptr members in Impl, XRay will *uninstall any +/// existing implementations*. It does NOT patch the instrumentation sleds. +/// +/// NOTE: This function does NOT attempt to finalize the currently installed +/// implementation. Use with caution. +/// +/// It is guaranteed safe to call this function in the following states: +/// +/// - When the implementation is UNINITIALIZED. +/// - When the implementation is FINALIZED. +/// - When there is no current implementation installed. +/// +/// It is logging implementation defined what happens when this function is +/// called while in any other states. void __xray_set_log_impl(XRayLogImpl Impl); + +/// This function removes the currently installed implementation. It will also +/// uninstall any handlers that have been previously installed. It does NOT +/// unpatch the instrumentation sleds. +/// +/// NOTE: This function does NOT attempt to finalize the currently installed +/// implementation. Use with caution. +/// +/// It is guaranteed safe to call this function in the following states: +/// +/// - When the implementation is UNINITIALIZED. +/// - When the implementation is FINALIZED. +/// - When there is no current implementation installed. +/// +/// It is logging implementation defined what happens when this function is +/// called while in any other states. +void __xray_remove_log_impl(); + +/// Invokes the installed implementation initialization routine. See +/// XRayLogInitStatus for what the return values mean. XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, void *Args, size_t ArgsSize); + +/// Invokes the installed implementation finalization routine. See +/// XRayLogInitStatus for what the return values mean. XRayLogInitStatus __xray_log_finalize(); + +/// Invokes the install implementation log flushing routine. See +/// XRayLogFlushStatus for what the return values mean. XRayLogFlushStatus __xray_log_flushLog(); } // extern "C" namespace __xray { + // Options used by the LLVM XRay FDR implementation. struct FDRLoggingOptions { bool ReportErrors = false; diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc index ffed601c0..ee14ae4b1 100644 --- a/lib/xray/xray_log_interface.cc +++ b/lib/xray/xray_log_interface.cc @@ -27,12 +27,22 @@ void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT { Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); GlobalXRayImpl.reset(); + __xray_remove_handler(); + __xray_remove_handler_arg1(); return; } __sanitizer::SpinMutexLock Guard(&XRayImplMutex); GlobalXRayImpl.reset(new XRayLogImpl); *GlobalXRayImpl = Impl; + __xray_set_handler(Impl.handle_arg0); +} + +void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); + GlobalXRayImpl.reset(); + __xray_remove_handler(); + __xray_remove_handler_arg1(); } XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, -- cgit v1.2.1 From 1531d487bd209ea8b183db067a0a2161a5db9b4b Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 1 May 2017 10:01:13 +0000 Subject: tsan: support linker init flag in __tsan_mutex_destroy For a linker init mutex with lazy flag setup (no __tsan_mutex_create call), it is possible that no lock/unlock happened before the destroy call. Then when destroy runs we still don't know that it is a linker init mutex and will emulate a memory write. This in turn can lead to false positives as the mutex is in fact linker initialized. Support linker init flag in destroy annotation to resolve this. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301795 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/tsan_interface.h | 3 ++- lib/tsan/rtl/tsan_interface_ann.cc | 2 +- lib/tsan/rtl/tsan_rtl.h | 2 +- lib/tsan/rtl/tsan_rtl_mutex.cc | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h index 45e54f758..a0c702638 100644 --- a/include/sanitizer/tsan_interface.h +++ b/include/sanitizer/tsan_interface.h @@ -68,7 +68,8 @@ const unsigned __tsan_mutex_recursive_unlock = 1 << 7; void __tsan_mutex_create(void *addr, unsigned flags); // Annotate destruction of a mutex. -// Supported flags: none. +// Supported flags: +// - __tsan_mutex_linker_init void __tsan_mutex_destroy(void *addr, unsigned flags); // Annotate start of lock operation. diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc index 810c84025..45ec45bbd 100644 --- a/lib/tsan/rtl/tsan_interface_ann.cc +++ b/lib/tsan/rtl/tsan_interface_ann.cc @@ -471,7 +471,7 @@ void __tsan_mutex_create(void *m, unsigned flagz) { INTERFACE_ATTRIBUTE void __tsan_mutex_destroy(void *m, unsigned flagz) { SCOPED_ANNOTATION(__tsan_mutex_destroy); - MutexDestroy(thr, pc, (uptr)m); + MutexDestroy(thr, pc, (uptr)m, flagz); } INTERFACE_ATTRIBUTE diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index cc60eb6db..8bf1c191a 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -763,7 +763,7 @@ void ProcUnwire(Processor *proc, ThreadState *thr); // Note: the parameter is called flagz, because flags is already taken // by the global function that returns flags. void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); -void MutexDestroy(ThreadState *thr, uptr pc, uptr addr); +void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0, int rec = 1); diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index 086b28927..54938f37e 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -78,13 +78,13 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { s->mtx.Unlock(); } -void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { +void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); StatInc(thr, StatMutexDestroy); SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); if (s == 0) return; - if (s->IsFlagSet(MutexFlagLinkerInit)) { + if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit)) { // Destroy is no-op for linker-initialized mutexes. s->mtx.Unlock(); return; -- cgit v1.2.1 From 33fde816a85288ef7140c43d42a9881abb1e3b05 Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Mon, 1 May 2017 13:56:04 +0000 Subject: [powerpc] deactivate flakey tests on powerpc64le These test cases occassionally fail when run on powerpc64le: ignore_lib1.cc ignore_lib5.cc TestCases/Posix/current_allocated_bytes.cc rtl/TsanRtlTest/Posix.ThreadLocalAccesses TestCases/Posix/coverage-fork-direct.cc The failures cause false problem reports to be sent to developers whose code had nothing to do with the failures. Reactivate them when the real problems are fixed. This could also be related to the same problems as with the tests ThreadedOneSizeMallocStressTest, ThreadedMallocStressTest, ManyThreadsTest, and several others that do not run reliably on powerpc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301798 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/tests/rtl/tsan_posix.cc | 5 +++-- test/asan/TestCases/Posix/coverage-fork-direct.cc | 3 +++ test/asan/TestCases/Posix/current_allocated_bytes.cc | 3 +++ test/tsan/ignore_lib1.cc | 3 +++ test/tsan/ignore_lib5.cc | 3 +++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/tsan/tests/rtl/tsan_posix.cc b/lib/tsan/tests/rtl/tsan_posix.cc index 9c0e013e5..e66dab609 100644 --- a/lib/tsan/tests/rtl/tsan_posix.cc +++ b/lib/tsan/tests/rtl/tsan_posix.cc @@ -94,8 +94,9 @@ TEST(Posix, ThreadLocalAccesses) { // The test is failing with high thread count for aarch64. // FIXME: track down the issue and re-enable the test. // On Darwin, we're running unit tests without interceptors and __thread is -// using malloc and free, which causes false data race reports. -#if !defined(__aarch64__) && !defined(__APPLE__) +// using malloc and free, which causes false data race reports. On rare +// occasions on powerpc64le this test also fails. +#if !defined(__aarch64__) && !defined(__APPLE__) && !defined(powerpc64le) local_thread((void*)2); #endif } diff --git a/test/asan/TestCases/Posix/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc index dba0cb022..4f14d081c 100644 --- a/test/asan/TestCases/Posix/coverage-fork-direct.cc +++ b/test/asan/TestCases/Posix/coverage-fork-direct.cc @@ -7,6 +7,9 @@ // RUN: FileCheck %s < %t.log // // XFAIL: android +// 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 #include diff --git a/test/asan/TestCases/Posix/current_allocated_bytes.cc b/test/asan/TestCases/Posix/current_allocated_bytes.cc index c49e433b1..51630cfd8 100644 --- a/test/asan/TestCases/Posix/current_allocated_bytes.cc +++ b/test/asan/TestCases/Posix/current_allocated_bytes.cc @@ -1,6 +1,9 @@ // 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 #include diff --git a/test/tsan/ignore_lib1.cc b/test/tsan/ignore_lib1.cc index e6a13a394..5949d811e 100644 --- a/test/tsan/ignore_lib1.cc +++ b/test/tsan/ignore_lib1.cc @@ -9,6 +9,9 @@ // in called_from_lib suppression are ignored. // REQUIRES: stable-runtime +// UNSUPPORTED: powerpc64le +// FIXME: This test regularly fails on powerpc64 LE possibly starting with +// r279664. Re-enable the test once the problem(s) have been fixed. #ifndef LIB diff --git a/test/tsan/ignore_lib5.cc b/test/tsan/ignore_lib5.cc index d7cd28500..54630d534 100644 --- a/test/tsan/ignore_lib5.cc +++ b/test/tsan/ignore_lib5.cc @@ -6,6 +6,9 @@ // RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP // 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. // Previously the test episodically failed with: // ThreadSanitizer: called_from_lib suppression '/libignore_lib1.so$' is -- cgit v1.2.1 From f62c0be792360faf6d80f940dea1fbd2b66db3b4 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 1 May 2017 17:43:29 +0000 Subject: Add a blank line as a test-commit. Per http://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301818 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 29d9f8844..ae2f49318 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -166,4 +166,5 @@ #define END_COMPILERRT_FUNCTION(name) #endif + #endif /* COMPILERRT_ASSEMBLY_H */ -- cgit v1.2.1 From 62e0c63b809f55ad0b087366fd0d6ed9b1c46c2a Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 1 May 2017 18:04:06 +0000 Subject: Cleanup previous test commit. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301820 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index ae2f49318..29d9f8844 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -166,5 +166,4 @@ #define END_COMPILERRT_FUNCTION(name) #endif - #endif /* COMPILERRT_ASSEMBLY_H */ -- cgit v1.2.1 From 120e487c471b4dcedc829166cb67b513aab62edc Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 1 May 2017 20:01:50 +0000 Subject: [sanitizer-coverage] disable coverage_direct=1, will remove the code in a few weeks git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301826 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 2 + .../TestCases/Posix/coverage-direct-activation.cc | 59 --------------- test/asan/TestCases/Posix/coverage-direct-large.cc | 65 ----------------- test/asan/TestCases/Posix/coverage-direct.cc | 83 ---------------------- test/asan/TestCases/Posix/coverage-fork-direct.cc | 45 ------------ test/asan/TestCases/coverage-disabled.cc | 5 -- 6 files changed, 2 insertions(+), 257 deletions(-) delete mode 100644 test/asan/TestCases/Posix/coverage-direct-activation.cc delete mode 100644 test/asan/TestCases/Posix/coverage-direct-large.cc delete mode 100644 test/asan/TestCases/Posix/coverage-direct.cc delete mode 100644 test/asan/TestCases/Posix/coverage-fork-direct.cc diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index bb59c344e..1794e4754 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -165,6 +165,8 @@ void CoverageData::Enable() { MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); atomic_store(&pc_array_index, 0, memory_order_relaxed); if (common_flags()->coverage_direct) { + Report("coverage_direct=1 is deprecated, don't use it.\n"); + Die(); atomic_store(&pc_array_size, 0, memory_order_relaxed); } else { atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); diff --git a/test/asan/TestCases/Posix/coverage-direct-activation.cc b/test/asan/TestCases/Posix/coverage-direct-activation.cc deleted file mode 100644 index 0af3296f2..000000000 --- a/test/asan/TestCases/Posix/coverage-direct-activation.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Test for direct coverage writing enabled at activation time. - -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib -fPIC -// RUN: %clangxx -c -DSO_DIR=\"%T\" %s -o %t.o -// RUN: %clangxx_asan -fsanitize-coverage=func %t.o %libdl -o %t - -// RUN: rm -rf %T/coverage-direct-activation - -// RUN: mkdir -p %T/coverage-direct-activation/normal -// RUN: %env_asan_opts=coverage=1,coverage_direct=0,coverage_dir=%T/coverage-direct-activation/normal:verbosity=1 %run %t %dynamiclib -// RUN: %sancov print %T/coverage-direct-activation/normal/*.sancov >%T/coverage-direct-activation/normal/out.txt - -// RUN: mkdir -p %T/coverage-direct-activation/direct -// RUN: %env_asan_opts=start_deactivated=1,coverage_direct=1,verbosity=1 \ -// RUN: ASAN_ACTIVATION_OPTIONS=coverage=1,coverage_dir=%T/coverage-direct-activation/direct %run %t %dynamiclib -// RUN: cd %T/coverage-direct-activation/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// Test start_deactivated=1,coverage=1 in ASAN_OPTIONS. - -// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct/out.txt - -// RUN: mkdir -p %T/coverage-direct-activation/direct2 -// RUN: %env_asan_opts=start_deactivated=1,coverage=1,coverage_direct=1,verbosity=1 \ -// RUN: ASAN_ACTIVATION_OPTIONS=coverage_dir=%T/coverage-direct-activation/direct2 %run %t %dynamiclib -// RUN: cd %T/coverage-direct-activation/direct2 -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct2/out.txt - -// XFAIL: android - -#include -#include -#include -#include - -#ifdef SHARED -extern "C" { -void bar() { printf("bar\n"); } -} -#else - -int main(int argc, char **argv) { - fprintf(stderr, "PID: %d\n", getpid()); - assert(argc > 1); - void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib - assert(handle1); - void (*bar1)() = (void (*)())dlsym(handle1, "bar"); - assert(bar1); - bar1(); - - return 0; -} -#endif diff --git a/test/asan/TestCases/Posix/coverage-direct-large.cc b/test/asan/TestCases/Posix/coverage-direct-large.cc deleted file mode 100644 index 367a5667a..000000000 --- a/test/asan/TestCases/Posix/coverage-direct-large.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Test for direct coverage writing with lots of data. -// Current implementation maps output file in chunks of 64K. This test overflows -// 1 chunk. - -// RUN: %clangxx_asan -fsanitize-coverage=func -O0 -DSHARED %s -shared -o %dynamiclib -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -O0 %s %libdl -o %t - -// RUN: rm -rf %T/coverage-direct-large - -// RUN: mkdir -p %T/coverage-direct-large/normal && cd %T/coverage-direct-large/normal -// RUN: %env_asan_opts=coverage=1:coverage_direct=0:verbosity=1 %run %t %dynamiclib -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: mkdir -p %T/coverage-direct-large/direct && cd %T/coverage-direct-large/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t %dynamiclib -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: diff -u coverage-direct-large/normal/out.txt coverage-direct-large/direct/out.txt -// -// XFAIL: android - -#define F0(Q, x) Q(x) -#define F1(Q, x) \ - F0(Q, x##0) F0(Q, x##1) F0(Q, x##2) F0(Q, x##3) F0(Q, x##4) F0(Q, x##5) \ - F0(Q, x##6) F0(Q, x##7) F0(Q, x##8) F0(Q, x##9) -#define F2(Q, x) \ - F1(Q, x##0) F1(Q, x##1) F1(Q, x##2) F1(Q, x##3) F1(Q, x##4) F1(Q, x##5) \ - F1(Q, x##6) F1(Q, x##7) F1(Q, x##8) F1(Q, x##9) -#define F3(Q, x) \ - F2(Q, x##0) F2(Q, x##1) F2(Q, x##2) F2(Q, x##3) F2(Q, x##4) F2(Q, x##5) \ - F2(Q, x##6) F2(Q, x##7) F2(Q, x##8) F2(Q, x##9) -#define F4(Q, x) \ - F3(Q, x##0) F3(Q, x##1) F3(Q, x##2) F3(Q, x##3) F3(Q, x##4) F3(Q, x##5) \ - F3(Q, x##6) F3(Q, x##7) F3(Q, x##8) F3(Q, x##9) - -#define DECL(x) __attribute__((noinline)) static void x() {} -#define CALL(x) x(); - -F4(DECL, f) - -#ifdef SHARED -extern "C" void so_entry() { - F4(CALL, f) -} -#else - -#include -#include -#include -int main(int argc, char **argv) { - F4(CALL, f) - assert(argc > 1); - void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib - assert(handle1); - void (*so_entry)() = (void (*)())dlsym(handle1, "so_entry"); - assert(so_entry); - so_entry(); - - return 0; -} - -#endif // SHARED diff --git a/test/asan/TestCases/Posix/coverage-direct.cc b/test/asan/TestCases/Posix/coverage-direct.cc deleted file mode 100644 index 8caa9c553..000000000 --- a/test/asan/TestCases/Posix/coverage-direct.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Test for direct coverage writing with dlopen at coverage level 1 to 3. - -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func %s %libdl -o %t - -// RUN: rm -rf %T/coverage-direct - -// RUN: mkdir -p %T/coverage-direct/normal -// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib -// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt - -// RUN: mkdir -p %T/coverage-direct/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib -// RUN: cd %T/coverage-direct/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt - - -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED %s -shared -o %dynamiclib -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%T\" %s %libdl -o %t - -// RUN: rm -rf %T/coverage-direct - -// RUN: mkdir -p %T/coverage-direct/normal -// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib -// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt - -// RUN: mkdir -p %T/coverage-direct/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib -// RUN: cd %T/coverage-direct/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt - - -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED %s -shared -o %dynamiclib -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%T\" %s %libdl -o %t - -// RUN: rm -rf %T/coverage-direct - -// RUN: mkdir -p %T/coverage-direct/normal -// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib -// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt - -// RUN: mkdir -p %T/coverage-direct/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib -// RUN: cd %T/coverage-direct/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >out.txt -// RUN: cd ../.. - -// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt - -// XFAIL: android - -#include -#include -#include -#include - -#ifdef SHARED -extern "C" { -void bar() { printf("bar\n"); } -} -#else - -int main(int argc, char **argv) { - fprintf(stderr, "PID: %d\n", getpid()); - assert(argc > 1); - void *handle1 = dlopen(argv[1], RTLD_LAZY); - assert(handle1); - void (*bar1)() = (void (*)())dlsym(handle1, "bar"); - assert(bar1); - bar1(); - - return 0; -} -#endif diff --git a/test/asan/TestCases/Posix/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc deleted file mode 100644 index 4f14d081c..000000000 --- a/test/asan/TestCases/Posix/coverage-fork-direct.cc +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -// RUN: rm -rf %T/coverage-fork-direct -// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t > %t.log 2>&1 -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov >> %t.log 2>&1 -// RUN: FileCheck %s < %t.log -// -// XFAIL: android -// 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 -#include -#include - -__attribute__((noinline)) -void foo() { printf("foo\n"); } - -__attribute__((noinline)) -void bar() { printf("bar\n"); } - -__attribute__((noinline)) -void baz() { printf("baz\n"); } - -int main(int argc, char **argv) { - pid_t child_pid = fork(); - if (child_pid == 0) { - fprintf(stderr, "Child PID: %d\n", getpid()); - baz(); - } else { - fprintf(stderr, "Parent PID: %d\n", getpid()); - foo(); - bar(); - } - return 0; -} - -// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] -// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] -// CHECK-DAG: read 3 {{64|32}}-bit PCs from {{.*}}.[[ParentPID]].sancov - -// FIXME: this is missing -// XCHECK-DAG: read 1 {{64|32}}-bit PCs from {{.*}}.[[ChildPID]].sancov diff --git a/test/asan/TestCases/coverage-disabled.cc b/test/asan/TestCases/coverage-disabled.cc index 490f2b272..b225035ee 100644 --- a/test/asan/TestCases/coverage-disabled.cc +++ b/test/asan/TestCases/coverage-disabled.cc @@ -8,11 +8,6 @@ // RUN: %env_asan_opts=coverage_direct=0:coverage_dir='"%T/coverage-disabled/normal"':verbosity=1 %run %t // RUN: not %sancov print %T/coverage-disabled/normal/*.sancov 2>&1 // -// RUN: mkdir -p %T/coverage-disabled/direct -// RUN: %env_asan_opts=coverage_direct=1:coverage_dir='"%T/coverage-disabled/direct"':verbosity=1 %run %t -// RUN: cd %T/coverage-disabled/direct -// RUN: not %sancov rawunpack *.sancov -// // UNSUPPORTED: android int main(int argc, char **argv) { -- cgit v1.2.1 From 612bed15f9652384a92a7967c0b62f068bd00088 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 1 May 2017 20:35:02 +0000 Subject: Add powerpc64 and powerpc64le to build infrastructure. From Phab D32031. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301831 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 6 ++++++ cmake/base-config-ix.cmake | 5 +++++ cmake/builtin-config-ix.cmake | 2 +- lib/builtins/CMakeLists.txt | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 3b3a0c153..a04352440 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -167,6 +167,8 @@ macro(detect_target_arch) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) + check_symbol_exists(__powerpc64__ "" __PPC64) + check_symbol_exists(__powerpc64le__ "" __PPC64LE) check_symbol_exists(__s390x__ "" __S390X) check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32) check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64) @@ -184,6 +186,10 @@ macro(detect_target_arch) add_default_target_arch(mips64) elseif(__MIPS) add_default_target_arch(mips) + elseif(__PPC64) + add_default_target_arch(powerpc64) + elseif(__PPC64LE) + add_default_target_arch(powerpc64le) elseif(__S390X) add_default_target_arch(s390x) elseif(__WEBASSEMBLY32) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 6f9f15139..a46405a55 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -4,6 +4,7 @@ # runtime libraries. include(CheckIncludeFile) +include(TestBigEndian) check_include_file(unwind.h HAVE_UNWIND_H) # Top level target used to build all compiler-rt libraries. @@ -178,6 +179,10 @@ macro(test_targets) test_target_arch(aarch32 "" "-march=armv8-a") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64") test_target_arch(aarch64 "" "-march=armv8-a") + elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc64") + test_target_arch(powerpc64 "" "--target=powerpc64-unknown-unknown") + elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc64le") + test_target_arch(powerpc64le "" "--target=powerpc64le-unknown-unknown") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32") test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64") diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index dc2ec1694..74b4d583d 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -40,7 +40,7 @@ if(APPLE) endif() set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} - ${MIPS32} ${MIPS64} ${WASM32} ${WASM64}) + ${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64}) include(CompilerRTUtils) include(CompilerRTDarwinUtils) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index c30d9b363..3ee32038b 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -440,6 +440,20 @@ set(mipsel_SOURCES ${mips_SOURCES}) set(mips64_SOURCES ${mips_SOURCES}) set(mips64el_SOURCES ${mips_SOURCES}) +set(powerpc64_SOURCES + ppc/divtc3.c + ppc/fixtfdi.c + ppc/fixunstfdi.c + ppc/floatditf.c + ppc/floatunditf.c + ppc/gcc_qadd.c + ppc/gcc_qdiv.c + ppc/gcc_qmul.c + ppc/gcc_qsub.c + ppc/multc3.c + ${GENERIC_SOURCES}) +set(powerpc64le_SOURCES ${powerpc64_SOURCES}) + set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) -- cgit v1.2.1 From aea5fa3b2a35d462c4ddc7c8f0d2e6490c6174e6 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 1 May 2017 21:05:29 +0000 Subject: [asan] speed up small memcpy (> 32 but <= 64 bytes) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301837 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 7 +++++++ test/asan/TestCases/small_memcpy_test.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/asan/TestCases/small_memcpy_test.cc diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 6ee326606..905dd2e23 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -37,12 +37,19 @@ namespace __asan { // Return true if we can quickly decide that the region is unpoisoned. +// We assume that a redzone is at least 16 bytes. static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { if (size == 0) return true; if (size <= 32) return !AddressIsPoisoned(beg) && !AddressIsPoisoned(beg + size - 1) && !AddressIsPoisoned(beg + size / 2); + if (size <= 64) + return !AddressIsPoisoned(beg) && + !AddressIsPoisoned(beg + size / 4) && + !AddressIsPoisoned(beg + size - 1) && + !AddressIsPoisoned(beg + 3 * size / 4) && + !AddressIsPoisoned(beg + size / 2); return false; } diff --git a/test/asan/TestCases/small_memcpy_test.cc b/test/asan/TestCases/small_memcpy_test.cc new file mode 100644 index 000000000..2d6dea60c --- /dev/null +++ b/test/asan/TestCases/small_memcpy_test.cc @@ -0,0 +1,28 @@ +// Test that small memcpy works correctly. + +// RUN: %clangxx_asan %s -o %t +// RUN: not %run %t 8 24 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 16 32 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 24 40 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 32 48 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 40 56 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 48 64 2>&1 | FileCheck %s --check-prefix=CHECK +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) { + assert(argc == 3); + size_t poison_from = atoi(argv[1]); + size_t poison_to = atoi(argv[2]); + assert(poison_from <= poison_to); + char A1[64], A2[64]; + fprintf(stderr, "%zd %zd\n", poison_from, poison_to - poison_from); + __asan_poison_memory_region(&A1[0] + poison_from, poison_to - poison_from); + memcpy(A1, A2, sizeof(A1)); +// CHECK: AddressSanitizer: use-after-poison + return 0; +} -- cgit v1.2.1 From a88ac2959bf2987b64e38382a607e991c617dd9d Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 1 May 2017 21:41:01 +0000 Subject: [ubsan] Fall back to the fast unwinder when print_stacktrace=1 This makes it possible to get stacktrace info when print_stacktrace=1 on Darwin (where the slow unwinder is not currently supported [1]). This should not regress any other platforms. [1] The thread about r300295 has a relatively recent discusion about this. We should be able to enable the existing slow unwind functionality for Darwin, but this needs more testing. Differential Revision: https://reviews.llvm.org/D32517 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301839 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_diag.cc | 17 +++++++++-------- test/ubsan/TestCases/Misc/missing_return.cpp | 7 ++----- test/ubsan/TestCases/TypeCheck/misaligned.cpp | 8 ++------ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index bbe1e0739..742802b8f 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -31,15 +31,16 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) { // will definitely be called when we print the first diagnostics message. if (!flags()->print_stacktrace) return; - // We can only use slow unwind, as we don't have any information about stack - // top/bottom. - // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and - // fetch stack top/bottom information if we have it (e.g. if we're running - // under ASan). - if (StackTrace::WillUseFastUnwind(false)) - return; + + uptr top = 0; + uptr bottom = 0; + bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; + if (request_fast_unwind) + __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); + BufferedStackTrace stack; - stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false); + stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, + request_fast_unwind); stack.Print(); } diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp index 68082272d..7b56b9704 100644 --- a/test/ubsan/TestCases/Misc/missing_return.cpp +++ b/test/ubsan/TestCases/Misc/missing_return.cpp @@ -1,13 +1,10 @@ // RUN: %clangxx -fsanitize=return -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s -// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%os-STACKTRACE +// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-STACKTRACE // CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value int f() { -// Slow stack unwinding is not available on Darwin for now, see -// https://code.google.com/p/address-sanitizer/issues/detail?id=137 -// CHECK-Linux-STACKTRACE: #0 {{.*}}f(){{.*}}missing_return.cpp:[[@LINE-3]] -// CHECK-FreeBSD-STACKTRACE: #0 {{.*}}f(void){{.*}}missing_return.cpp:[[@LINE-4]] +// CHECK-STACKTRACE: #0 {{.*}}f{{.*}}missing_return.cpp:[[@LINE-1]] } int main(int, char **argv) { diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 35b1ec3fe..b3ff3588b 100644 --- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -11,7 +11,7 @@ // RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN // RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW // RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST -// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD +// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-STACK-LOAD // RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover=alignment %s -O3 -o %t // RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD @@ -47,11 +47,7 @@ int main(int, char **argv) { // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}} // CHECK-LOAD-NEXT: {{^ \^}} return *p && 0; - // Slow stack unwinding is disabled on Darwin for now, see - // https://code.google.com/p/address-sanitizer/issues/detail?id=137 - // CHECK-Linux-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp - // Check for the already checked line to avoid lit error reports. - // CHECK-Darwin-STACK-LOAD: {{ }} + // CHECK-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp case 's': // CHECK-STORE: misaligned.cpp:[[@LINE+4]]{{(:5)?}}: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment -- cgit v1.2.1 From fed66060a60ff04177b5dbdd6aab1d0518004e96 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 1 May 2017 22:07:12 +0000 Subject: [sanitizer-coverage] remove more stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301845 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 31 ---------------------- lib/sanitizer_common/sanitizer_flags.inc | 6 ----- test/asan/TestCases/coverage-levels.cc | 31 ---------------------- 3 files changed, 68 deletions(-) delete mode 100644 test/asan/TestCases/coverage-levels.cc diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 1794e4754..11d952c43 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -84,7 +84,6 @@ class CoverageData { void AfterFork(int child_pid); void Extend(uptr npcs); void Add(uptr pc, u32 *guard); - void DumpAsBitSet(); void DumpOffsets(); void DumpAll(); @@ -421,35 +420,6 @@ static fd_t CovOpenFile(InternalScopedString *path, bool packed, return fd; } -void CoverageData::DumpAsBitSet() { - if (!common_flags()->coverage_bitset) return; - if (!size()) return; - InternalScopedBuffer out(size()); - InternalScopedString path(kMaxPathLength); - for (uptr m = 0; m < module_name_vec.size(); m++) { - uptr n_set_bits = 0; - auto r = module_name_vec[m]; - CHECK(r.copied_module_name); - CHECK_LE(r.beg, r.end); - CHECK_LE(r.end, size()); - for (uptr i = r.beg; i < r.end; i++) { - uptr pc = UnbundlePc(pc_array[i]); - out[i] = pc ? '1' : '0'; - if (pc) - n_set_bits++; - } - const char *base_name = StripModuleName(r.copied_module_name); - fd_t fd = CovOpenFile(&path, /* packed */false, base_name, "bitset-sancov"); - if (fd == kInvalidFd) return; - WriteToFile(fd, out.data() + r.beg, r.end - r.beg); - CloseFile(fd); - VReport(1, - " CovDump: bitset of %zd bits written for '%s', %zd bits are set\n", - r.end - r.beg, base_name, n_set_bits); - } -} - - void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym, InternalMmapVector* offsets) const { offsets->clear(); @@ -567,7 +537,6 @@ void CoverageData::DumpAll() { if (!coverage_enabled || common_flags()->coverage_direct) return; if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) return; - DumpAsBitSet(); DumpOffsets(); } diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 40f8b6204..7a5fffcf6 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -142,12 +142,6 @@ COMMON_FLAG(bool, coverage_pcs, true, COMMON_FLAG(bool, coverage_order_pcs, false, "If true, the PCs will be dumped in the order they've" " appeared during the execution.") -COMMON_FLAG(bool, coverage_bitset, false, - "If set (and if 'coverage' is set too), the coverage information " - "will also be dumped as a bitset to a separate file.") -COMMON_FLAG(bool, coverage_counters, false, - "If set (and if 'coverage' is set too), the bitmap that corresponds" - " to coverage counters will be dumped.") COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, "If set, coverage information will be dumped directly to a memory " "mapped file. This way data is not lost even if the process is " diff --git a/test/asan/TestCases/coverage-levels.cc b/test/asan/TestCases/coverage-levels.cc deleted file mode 100644 index ae9ac4841..000000000 --- a/test/asan/TestCases/coverage-levels.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Test various levels of coverage -// -// RUN: %clangxx_asan -O1 -fsanitize-coverage=func %s -o %t -// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %clangxx_asan -O1 -fsanitize-coverage=bb %s -o %t -// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %clangxx_asan -O1 -fsanitize-coverage=edge %s -o %t -// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 -// RUN: %clangxx_asan -O1 -fsanitize-coverage=edge -mllvm -sanitizer-coverage-block-threshold=0 %s -o %t -// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 - -// RUN: %env_asan_opts=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET -// RUN: %env_asan_opts=coverage=1:coverage_pcs=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOPCS -// -// REQUIRES: asan-64-bits -// UNSUPPORTED: android -volatile int sink; -int main(int argc, char **argv) { - if (argc == 0) - sink = 0; -} - -// CHECK1: CovDump: bitset of 1 bits written for '{{.*}}', 1 bits are set -// CHECK1: 1 PCs written -// CHECK2: CovDump: bitset of 2 bits written for '{{.*}}', 1 bits are set -// CHECK2: 1 PCs written -// CHECK3: CovDump: bitset of 3 bits written for '{{.*}}', 2 bits are set -// CHECK3: 2 PCs written -// CHECK3_NOBITSET-NOT: bitset of -// CHECK3_NOPCS-NOT: PCs written -- cgit v1.2.1 From fb29bf0414b2ea0197255e1212649141b72f69a6 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 2 May 2017 00:44:24 +0000 Subject: [sanitizer-coverage] add a deprecation note for the old sanitizer-coverage; remove a TODO printf git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301889 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 7 +++++++ lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 4 ---- test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc | 6 ------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 11d952c43..754ece984 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -155,6 +155,13 @@ void CoverageData::DirectOpen() { void CoverageData::Init() { pc_fd = kInvalidFd; + + if (!common_flags()->coverage) return; + Printf("**\n***\n***\n"); + Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n"); + Printf("**WARNING: and will be removed in future versions\n"); + Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n"); + Printf("**\n***\n***\n"); } void CoverageData::Enable() { diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 73c36082b..6d8e3e041 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -98,10 +98,6 @@ static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { InternalFree(file_path); InternalFree(module_name); InternalFree(pcs); - - if (sancov_flags()->symbolize) { - Printf("TODO(aizatsky): call sancov to symbolize\n"); - } } // Collects trace-pc guard coverage. diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc index 48f32a705..266dc3f0e 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc @@ -9,7 +9,6 @@ // RUN: cd $DIR // RUN: %clangxx -O0 -fsanitize-coverage=trace-pc-guard %s -ldl -o %t // RUN: %env_tool_opts=coverage=1 %t 2>&1 | FileCheck %s -// RUN: %env_tool_opts=coverage=1 SANCOV_OPTIONS=symbolize=0 %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSYM // RUN: rm -rf $DIR #include @@ -27,8 +26,3 @@ int main() { // CHECK: main // CHECK: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov 2 PCs written -// CHECK: call sancov - -// CHECK-NOSYM: main -// CHECK-NOSYM: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov 2 PCs written -// CHECK-NOSYM-NOT: call sancov -- cgit v1.2.1 From 25469d9bd4174709ad3c4b85dadfa7892ebf3171 Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Tue, 2 May 2017 09:01:02 +0000 Subject: [asan] Add strndup/__strndup interceptors if targeting linux. Differential Revision: https://reviews.llvm.org/D31457 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301904 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 ++ lib/asan/tests/asan_str_test.cc | 21 +++++++++++ lib/msan/msan_interceptors.cc | 36 ++++-------------- lib/msan/tests/msan_test.cc | 6 ++- .../sanitizer_common_interceptors.inc | 43 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_flags.inc | 3 ++ .../sanitizer_platform_interceptors.h | 14 +++++++ lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 +++ test/asan/TestCases/Posix/strndup_oob_test.cc | 26 +++++++++++++ test/msan/strndup.cc | 28 ++++++++++++++ 10 files changed, 156 insertions(+), 31 deletions(-) create mode 100644 test/asan/TestCases/Posix/strndup_oob_test.cc create mode 100644 test/msan/strndup.cc diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index c8ae3faed..6be0d6e94 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,6 +194,10 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } + if (!f->replace_str && common_flags()->intercept_strndup) { + Report("WARNING: strndup* interceptors are enabled even though " + "replace_str=0. Use intercept_strndup=0 to disable them."); + } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index c790088f8..8f4911fd9 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,6 +154,27 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } +#if SANITIZER_TEST_HAS_STRNDUP +TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { + size_t size = Ident(42); + char *str = MallocAndMemsetString(size); + char *new_str; + // Normal strndup calls. + str[size - 1] = '\0'; + new_str = strndup(str, size - 13); + free(new_str); + new_str = strndup(str + size - 1, 13); + free(new_str); + // Argument points to not allocated memory. + EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); + // Overwrite the terminating '\0' and hit unallocated memory. + str[size - 1] = 'z'; + EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); + free(str); +} +#endif // SANITIZER_TEST_HAS_STRNDUP + TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 15543bd91..0f5069344 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,33 +341,6 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif -INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - // On FreeBSD strndup() leverages strnlen(). - InterceptorScope interceptor_scope; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} - -#if !SANITIZER_FREEBSD -INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(__strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} -#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) -#else -#define MSAN_MAYBE_INTERCEPT___STRNDUP -#endif - INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1371,6 +1344,13 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1538,8 +1518,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; - INTERCEPT_FUNCTION(strndup); - MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index dd81c4d79..432d92c2e 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,7 +1581,8 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 3); + char *x; + EXPECT_UMR(x = strndup(buf, 3)); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); @@ -1593,7 +1594,8 @@ TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 2); + char *x; + EXPECT_UMR(x = strndup(buf, 2)); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 4fe1ac8f9..04a38b9b2 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,8 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_COPY_STRING +// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -217,6 +219,25 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif +#ifndef COMMON_INTERCEPTOR_COPY_STRING +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr from_length = REAL(strnlen)(s, size); \ + uptr copy_length = Min(size, from_length); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, copy_length + 1); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ + return new_mem; +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -300,6 +321,26 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif +#if SANITIZER_INTERCEPT_STRNDUP +INTERCEPTOR(char*, strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) +#else +#define INIT_STRNDUP +#endif // SANITIZER_INTERCEPT_STRNDUP + +#if SANITIZER_INTERCEPT___STRNDUP +INTERCEPTOR(char*, __strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) +#else +#define INIT___STRNDUP +#endif // SANITIZER_INTERCEPT___STRNDUP + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6149,6 +6190,8 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; + INIT_STRNDUP; + INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 7a5fffcf6..67a0a5810 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -195,6 +195,9 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a583e989c..5083ffc1e 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,6 +25,12 @@ # define SI_NOT_WINDOWS 0 #endif +#if SANITIZER_POSIX +# define SI_POSIX 1 +#else +# define SI_POSIX 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -69,6 +75,12 @@ # define SI_UNIX_NOT_MAC 0 #endif +#if SANITIZER_LINUX && !SANITIZER_FREEBSD +# define SI_LINUX_NOT_FREEBSD 1 +# else +# define SI_LINUX_NOT_FREEBSD 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -86,6 +98,8 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX +#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index 9c162a66f..b7728d9ea 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,4 +124,10 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif +#if !defined(_MSC_VER) +# define SANITIZER_TEST_HAS_STRNDUP 1 +#else +# define SANITIZER_TEST_HAS_STRNDUP 0 +#endif + #endif // SANITIZER_TEST_UTILS_H diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc new file mode 100644 index 000000000..4367e2474 --- /dev/null +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s + +// UNSUPPORTED: win32 + +#include + +char kString[] = "foo"; + +int main(int argc, char **argv) { + char *copy = strndup(kString, 2); + int x = copy[2 + argc]; // BOOM + // CHECK: AddressSanitizer: heap-buffer-overflow + // CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]] + // CHECK-LABEL: allocated by thread T{{.*}} here: + // CHECK: #{{[01]}} {{.*}}strndup + // CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]] + // CHECK-LABEL: SUMMARY + // CHECK: strndup_oob_test.cc:[[@LINE-7]] + return x; +} diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc new file mode 100644 index 000000000..d4b9af1a9 --- /dev/null +++ b/test/msan/strndup.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s +// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s + +// UNSUPPORTED: win32 + +#include +#include +#include +#include + +int main(int argc, char **argv) { + char kString[4] = "abc"; + __msan_poison(kString + 2, 1); + char *copy = strndup(kString, 4); // BOOM + assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved. + free(copy); + return 0; + // ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4) + // ON: MemorySanitizer: use-of-uninitialized-value + // ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]] + // ON-LABEL: SUMMARY + // ON: {{.*}}strndup.cc:[[@LINE-8]] + // OFF-NOT: MemorySanitizer +} + -- cgit v1.2.1 From a09710f1e54c089241210527d2814f588d73b0be Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Tue, 2 May 2017 10:22:05 +0000 Subject: Revert r301904 causing tsan test failure in x86_64-linux-autoconf git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301909 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 -- lib/asan/tests/asan_str_test.cc | 21 ----------- lib/msan/msan_interceptors.cc | 36 ++++++++++++++---- lib/msan/tests/msan_test.cc | 6 +-- .../sanitizer_common_interceptors.inc | 43 ---------------------- lib/sanitizer_common/sanitizer_flags.inc | 3 -- .../sanitizer_platform_interceptors.h | 14 ------- lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 --- test/asan/TestCases/Posix/strndup_oob_test.cc | 26 ------------- test/msan/strndup.cc | 28 -------------- 10 files changed, 31 insertions(+), 156 deletions(-) delete mode 100644 test/asan/TestCases/Posix/strndup_oob_test.cc delete mode 100644 test/msan/strndup.cc diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 6be0d6e94..c8ae3faed 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,10 +194,6 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } - if (!f->replace_str && common_flags()->intercept_strndup) { - Report("WARNING: strndup* interceptors are enabled even though " - "replace_str=0. Use intercept_strndup=0 to disable them."); - } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index 8f4911fd9..c790088f8 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,27 +154,6 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } -#if SANITIZER_TEST_HAS_STRNDUP -TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { - size_t size = Ident(42); - char *str = MallocAndMemsetString(size); - char *new_str; - // Normal strndup calls. - str[size - 1] = '\0'; - new_str = strndup(str, size - 13); - free(new_str); - new_str = strndup(str + size - 1, 13); - free(new_str); - // Argument points to not allocated memory. - EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); - EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); - // Overwrite the terminating '\0' and hit unallocated memory. - str[size - 1] = 'z'; - EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); - free(str); -} -#endif // SANITIZER_TEST_HAS_STRNDUP - TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 0f5069344..15543bd91 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,6 +341,33 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif +INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + // On FreeBSD strndup() leverages strnlen(). + InterceptorScope interceptor_scope; + SIZE_T copy_size = REAL(strnlen)(src, n); + char *res = REAL(strndup)(src, n); + CopyShadowAndOrigin(res, src, copy_size, &stack); + __msan_unpoison(res + copy_size, 1); // \0 + return res; +} + +#if !SANITIZER_FREEBSD +INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = REAL(strnlen)(src, n); + char *res = REAL(__strndup)(src, n); + CopyShadowAndOrigin(res, src, copy_size, &stack); + __msan_unpoison(res + copy_size, 1); // \0 + return res; +} +#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) +#else +#define MSAN_MAYBE_INTERCEPT___STRNDUP +#endif + INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1344,13 +1371,6 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } -#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ - do { \ - GET_STORE_STACK_TRACE; \ - CopyShadowAndOrigin(to, from, size, &stack); \ - __msan_unpoison(to + size, 1); \ - } while (false) - #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1518,6 +1538,8 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; + INTERCEPT_FUNCTION(strndup); + MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 432d92c2e..dd81c4d79 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,8 +1581,7 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x; - EXPECT_UMR(x = strndup(buf, 3)); + char *x = strndup(buf, 3); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); @@ -1594,8 +1593,7 @@ TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x; - EXPECT_UMR(x = strndup(buf, 2)); + char *x = strndup(buf, 2); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 04a38b9b2..4fe1ac8f9 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,8 +34,6 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL -// COMMON_INTERCEPTOR_COPY_STRING -// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -219,25 +217,6 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif -#ifndef COMMON_INTERCEPTOR_COPY_STRING -#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} -#endif - -#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL -#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ - COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ - uptr from_length = REAL(strnlen)(s, size); \ - uptr copy_length = Min(size, from_length); \ - char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ - if (common_flags()->intercept_strndup) { \ - COMMON_INTERCEPTOR_READ_RANGE(ctx, s, copy_length + 1); \ - } \ - COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ - internal_memcpy(new_mem, s, copy_length); \ - new_mem[copy_length] = '\0'; \ - return new_mem; -#endif - struct FileMetadata { // For open_memstream(). char **addr; @@ -321,26 +300,6 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif -#if SANITIZER_INTERCEPT_STRNDUP -INTERCEPTOR(char*, strndup, const char *s, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); -} -#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) -#else -#define INIT_STRNDUP -#endif // SANITIZER_INTERCEPT_STRNDUP - -#if SANITIZER_INTERCEPT___STRNDUP -INTERCEPTOR(char*, __strndup, const char *s, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); -} -#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) -#else -#define INIT___STRNDUP -#endif // SANITIZER_INTERCEPT___STRNDUP - #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6190,8 +6149,6 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; - INIT_STRNDUP; - INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 67a0a5810..7a5fffcf6 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -195,9 +195,6 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") -COMMON_FLAG(bool, intercept_strndup, true, - "If set, uses custom wrappers for strndup functions " - "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 5083ffc1e..a583e989c 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,12 +25,6 @@ # define SI_NOT_WINDOWS 0 #endif -#if SANITIZER_POSIX -# define SI_POSIX 1 -#else -# define SI_POSIX 0 -#endif - #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -75,12 +69,6 @@ # define SI_UNIX_NOT_MAC 0 #endif -#if SANITIZER_LINUX && !SANITIZER_FREEBSD -# define SI_LINUX_NOT_FREEBSD 1 -# else -# define SI_LINUX_NOT_FREEBSD 0 -#endif - #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -98,8 +86,6 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 -#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index b7728d9ea..9c162a66f 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,10 +124,4 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif -#if !defined(_MSC_VER) -# define SANITIZER_TEST_HAS_STRNDUP 1 -#else -# define SANITIZER_TEST_HAS_STRNDUP 0 -#endif - #endif // SANITIZER_TEST_UTILS_H diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc deleted file mode 100644 index 4367e2474..000000000 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ /dev/null @@ -1,26 +0,0 @@ -// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s - -// When built as C on Linux, strndup is transformed to __strndup. -// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s - -// UNSUPPORTED: win32 - -#include - -char kString[] = "foo"; - -int main(int argc, char **argv) { - char *copy = strndup(kString, 2); - int x = copy[2 + argc]; // BOOM - // CHECK: AddressSanitizer: heap-buffer-overflow - // CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]] - // CHECK-LABEL: allocated by thread T{{.*}} here: - // CHECK: #{{[01]}} {{.*}}strndup - // CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]] - // CHECK-LABEL: SUMMARY - // CHECK: strndup_oob_test.cc:[[@LINE-7]] - return x; -} diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc deleted file mode 100644 index d4b9af1a9..000000000 --- a/test/msan/strndup.cc +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s -// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s - -// When built as C on Linux, strndup is transformed to __strndup. -// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s - -// UNSUPPORTED: win32 - -#include -#include -#include -#include - -int main(int argc, char **argv) { - char kString[4] = "abc"; - __msan_poison(kString + 2, 1); - char *copy = strndup(kString, 4); // BOOM - assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved. - free(copy); - return 0; - // ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4) - // ON: MemorySanitizer: use-of-uninitialized-value - // ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]] - // ON-LABEL: SUMMARY - // ON: {{.*}}strndup.cc:[[@LINE-8]] - // OFF-NOT: MemorySanitizer -} - -- cgit v1.2.1 From 89fac7a414ac95fe9c389e96ce5c0cd21c168e02 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 2 May 2017 15:13:36 +0000 Subject: [compiler-rt] move tsan's Android __get_tls() to sanitizer_common Summary: TSan's Android `__get_tls()` and `TLS_SLOT_TSAN` can be used by other sanitizers as well (see D32649), this change moves them to sanitizer_common. I picked sanitizer_linux.h as their new home. In the process, add the 32-bit versions for ARM, i386 & MIPS. Can the address of `__get_tls()[TLS_SLOT_TSAN]` change in between the calls? I am not sure if there is a need to repeat the construct as opposed to using a variable. So I left things as they were. Testing on my side was restricted to a successful cross-compilation. Reviewers: dvyukov, kubamracek Reviewed By: dvyukov Subscribers: aemerson, rengolin, srhines, dberris, arichardson, llvm-commits Differential Revision: https://reviews.llvm.org/D32705 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301926 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.h | 40 ++++++++++++++++++++++++++++++++++ lib/tsan/rtl/tsan_platform_linux.cc | 24 +++++--------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 14047b480..ee336f7dd 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -88,6 +88,46 @@ bool LibraryNameIs(const char *full_name, const char *base_name); // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); + +#if SANITIZER_ANDROID + +#if defined(__aarch64__) +# define __get_tls() \ + ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; }) +#elif defined(__arm__) +# define __get_tls() \ + ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; }) +#elif defined(__mips__) +// On mips32r1, this goes via a kernel illegal instruction trap that's +// optimized for v1. +# define __get_tls() \ + ({ register void** __v asm("v1"); \ + __asm__(".set push\n" \ + ".set mips32r2\n" \ + "rdhwr %0,$29\n" \ + ".set pop\n" : "=r"(__v)); \ + __v; }) +#elif defined(__i386__) +# define __get_tls() \ + ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; }) +#elif defined(__x86_64__) +# define __get_tls() \ + ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; }) +#else +#error "Unsupported architecture." +#endif + +// The Android Bionic team has allocated a TLS slot for TSan starting with N, +// given that Android currently doesn't support ELF TLS. It is used to store +// Sanitizers thread specific data. +static const int TLS_SLOT_TSAN = 8; + +ALWAYS_INLINE uptr *get_android_tls_ptr() { + return reinterpret_cast(&__get_tls()[TLS_SLOT_TSAN]); +} + +#endif // SANITIZER_ANDROID + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 3313288a7..2d488cadd 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -341,36 +341,22 @@ void ReplaceSystemMalloc() { } #if !SANITIZER_GO #if SANITIZER_ANDROID - -#if defined(__aarch64__) -# define __get_tls() \ - ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; }) -#elif defined(__x86_64__) -# define __get_tls() \ - ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; }) -#else -#error unsupported architecture -#endif - -// On Android, __thread is not supported. So we store the pointer to ThreadState -// in TLS_SLOT_TSAN, which is the tls slot allocated by Android bionic for tsan. -static const int TLS_SLOT_TSAN = 8; // On Android, one thread can call intercepted functions after // DestroyThreadState(), so add a fake thread state for "dead" threads. static ThreadState *dead_thread_state = nullptr; ThreadState *cur_thread() { - ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN]; + ThreadState* thr = reinterpret_cast(*get_android_tls_ptr()); if (thr == nullptr) { __sanitizer_sigset_t emptyset; internal_sigfillset(&emptyset); __sanitizer_sigset_t oldset; CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset)); - thr = reinterpret_cast(__get_tls()[TLS_SLOT_TSAN]); + thr = reinterpret_cast(*get_android_tls_ptr()); if (thr == nullptr) { thr = reinterpret_cast(MmapOrDie(sizeof(ThreadState), "ThreadState")); - __get_tls()[TLS_SLOT_TSAN] = thr; + *get_android_tls_ptr() = reinterpret_cast(thr); if (dead_thread_state == nullptr) { dead_thread_state = reinterpret_cast( MmapOrDie(sizeof(ThreadState), "ThreadState")); @@ -392,9 +378,9 @@ void cur_thread_finalize() { internal_sigfillset(&emptyset); __sanitizer_sigset_t oldset; CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset)); - ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN]; + ThreadState* thr = reinterpret_cast(*get_android_tls_ptr()); if (thr != dead_thread_state) { - __get_tls()[TLS_SLOT_TSAN] = dead_thread_state; + *get_android_tls_ptr() = reinterpret_cast(dead_thread_state); UnmapOrDie(thr, sizeof(ThreadState)); } CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); -- cgit v1.2.1 From dc6e2b60c572c4f67238e319b49259c13daca56d Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 2 May 2017 15:15:45 +0000 Subject: tsan: allow fast large MemoryRangeSet on non-Windows Go The fast reset for large memory regions is not working only on windows. So enable it for Go/linux/darwin/freebsd. See https://github.com/golang/go/issues/20139 for background and motivation. Based on idea by Josh Bleecher Snyder. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301927 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_rtl.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index 70393037e..fa60f3247 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -866,9 +866,8 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, // Don't want to touch lots of shadow memory. // If a program maps 10MB stack, there is no need reset the whole range. size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1); - // UnmapOrDie/MmapFixedNoReserve does not work on Windows, - // so we do it only for C/C++. - if (SANITIZER_GO || size < common_flags()->clear_shadow_mmap_threshold) { + // UnmapOrDie/MmapFixedNoReserve does not work on Windows. + if (SANITIZER_WINDOWS || size < common_flags()->clear_shadow_mmap_threshold) { u64 *p = (u64*)MemToShadow(addr); CHECK(IsShadowMem((uptr)p)); CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1))); -- cgit v1.2.1 From f5a63956c00b95c29723f6c9f2b1649ad435c3ef Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Tue, 2 May 2017 16:43:39 +0000 Subject: Roll back r301831 to fix broken powerpc64le tests. http://lab.llvm.org:8011/builders/clang-ppc64le-linux/builds/5941 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301935 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 6 ------ cmake/base-config-ix.cmake | 5 ----- cmake/builtin-config-ix.cmake | 2 +- lib/builtins/CMakeLists.txt | 14 -------------- 4 files changed, 1 insertion(+), 26 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index a04352440..3b3a0c153 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -167,8 +167,6 @@ macro(detect_target_arch) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) - check_symbol_exists(__powerpc64__ "" __PPC64) - check_symbol_exists(__powerpc64le__ "" __PPC64LE) check_symbol_exists(__s390x__ "" __S390X) check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32) check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64) @@ -186,10 +184,6 @@ macro(detect_target_arch) add_default_target_arch(mips64) elseif(__MIPS) add_default_target_arch(mips) - elseif(__PPC64) - add_default_target_arch(powerpc64) - elseif(__PPC64LE) - add_default_target_arch(powerpc64le) elseif(__S390X) add_default_target_arch(s390x) elseif(__WEBASSEMBLY32) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index a46405a55..6f9f15139 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -4,7 +4,6 @@ # runtime libraries. include(CheckIncludeFile) -include(TestBigEndian) check_include_file(unwind.h HAVE_UNWIND_H) # Top level target used to build all compiler-rt libraries. @@ -179,10 +178,6 @@ macro(test_targets) test_target_arch(aarch32 "" "-march=armv8-a") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64") test_target_arch(aarch64 "" "-march=armv8-a") - elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc64") - test_target_arch(powerpc64 "" "--target=powerpc64-unknown-unknown") - elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc64le") - test_target_arch(powerpc64le "" "--target=powerpc64le-unknown-unknown") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32") test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64") diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 74b4d583d..dc2ec1694 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -40,7 +40,7 @@ if(APPLE) endif() set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} - ${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64}) + ${MIPS32} ${MIPS64} ${WASM32} ${WASM64}) include(CompilerRTUtils) include(CompilerRTDarwinUtils) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 3ee32038b..c30d9b363 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -440,20 +440,6 @@ set(mipsel_SOURCES ${mips_SOURCES}) set(mips64_SOURCES ${mips_SOURCES}) set(mips64el_SOURCES ${mips_SOURCES}) -set(powerpc64_SOURCES - ppc/divtc3.c - ppc/fixtfdi.c - ppc/fixunstfdi.c - ppc/floatditf.c - ppc/floatunditf.c - ppc/gcc_qadd.c - ppc/gcc_qdiv.c - ppc/gcc_qmul.c - ppc/gcc_qsub.c - ppc/multc3.c - ${GENERIC_SOURCES}) -set(powerpc64le_SOURCES ${powerpc64_SOURCES}) - set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) -- cgit v1.2.1 From 14c50978c3e80fc37134d823e44eabdb6b86acb5 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 2 May 2017 19:35:29 +0000 Subject: [asan] Disable some Darwin tests that don't work on iOS simulator Differential Revision: https://reviews.llvm.org/D32633 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301965 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/address-range-limit.mm | 3 +++ test/asan/TestCases/Darwin/atos-symbolizer.cc | 3 +++ test/asan/TestCases/Darwin/dladdr-demangling.cc | 3 +++ test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc | 2 ++ test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc | 2 ++ test/asan/TestCases/Darwin/haswell-symbolication.cc | 1 + test/asan/TestCases/Darwin/interface_symbols_darwin.c | 2 ++ test/asan/TestCases/Darwin/sandbox-symbolizer.cc | 3 +++ test/asan/TestCases/Darwin/suppressions-sandbox.cc | 3 +++ test/asan/TestCases/Darwin/uuid.cc | 3 +++ 10 files changed, 25 insertions(+) diff --git a/test/asan/TestCases/Darwin/address-range-limit.mm b/test/asan/TestCases/Darwin/address-range-limit.mm index ba9175a2c..5f0fd89f8 100644 --- a/test/asan/TestCases/Darwin/address-range-limit.mm +++ b/test/asan/TestCases/Darwin/address-range-limit.mm @@ -3,6 +3,9 @@ // RUN: %clangxx_asan %s -Wno-deprecated-declarations -flat_namespace -bundle -undefined suppress -o %t.bundle // RUN: %clangxx_asan %s -Wno-deprecated-declarations -o %t -framework Foundation && not %run %t 2>&1 | FileCheck %s +// NSCreateObjectFileImageFromFile/NSLinkModule isn't available on iOS +// UNSUPPORTED: ios + #import #import diff --git a/test/asan/TestCases/Darwin/atos-symbolizer.cc b/test/asan/TestCases/Darwin/atos-symbolizer.cc index b4a868e24..7b091c4d6 100644 --- a/test/asan/TestCases/Darwin/atos-symbolizer.cc +++ b/test/asan/TestCases/Darwin/atos-symbolizer.cc @@ -3,6 +3,9 @@ // RUN: %clangxx_asan -O0 %s -o %t // RUN: %env_asan_opts=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) not %run %t 2>&1 | FileCheck %s +// Path returned by `which atos` is invalid on iOS. +// UNSUPPORTED: ios + #include #include int main(int argc, char **argv) { diff --git a/test/asan/TestCases/Darwin/dladdr-demangling.cc b/test/asan/TestCases/Darwin/dladdr-demangling.cc index 6f52b93da..fb6f6d79b 100644 --- a/test/asan/TestCases/Darwin/dladdr-demangling.cc +++ b/test/asan/TestCases/Darwin/dladdr-demangling.cc @@ -5,6 +5,9 @@ // RUN: not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=verbosity=2 not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DLADDR +// sandbox-exec isn't available on iOS +// UNSUPPORTED: ios + #include class MyClass { diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc index b22036a7e..5c975b8da 100644 --- a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc @@ -1,6 +1,8 @@ // When DYLD-inserting the ASan dylib from a different location than the // original, make sure we don't try to reexec. +// UNSUPPORTED: ios + // RUN: mkdir -p %T/dyld_insert_libraries_reexec // RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \ // RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc index a3af8c156..69d849793 100644 --- a/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc @@ -2,6 +2,8 @@ // the ASan dylib from the environment variable (both when using an absolute // or relative path) and also that the other dylibs are left untouched. +// UNSUPPORTED: ios + // RUN: mkdir -p %T/dyld_insert_libraries_remove // RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \ // RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ diff --git a/test/asan/TestCases/Darwin/haswell-symbolication.cc b/test/asan/TestCases/Darwin/haswell-symbolication.cc index 59c938ca5..7856c4d61 100644 --- a/test/asan/TestCases/Darwin/haswell-symbolication.cc +++ b/test/asan/TestCases/Darwin/haswell-symbolication.cc @@ -48,6 +48,7 @@ // REQUIRES: x86-target-arch // REQUIRES: x86_64h +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c index 9450575b4..09af1ece5 100644 --- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c +++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c @@ -31,4 +31,6 @@ // RUN: echo "=== NOTE === If you see a mismatch below, please update sanitizer_interface.inc files." // RUN: diff %t.imports-sorted %t.exports-sorted +// UNSUPPORTED: ios + int main() { return 0; } diff --git a/test/asan/TestCases/Darwin/sandbox-symbolizer.cc b/test/asan/TestCases/Darwin/sandbox-symbolizer.cc index 4310f9c59..b36c4faed 100644 --- a/test/asan/TestCases/Darwin/sandbox-symbolizer.cc +++ b/test/asan/TestCases/Darwin/sandbox-symbolizer.cc @@ -12,6 +12,9 @@ // RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s // RUN: env ASAN_SYMBOLIZER_PATH="" not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s +// sandbox-exec isn't available on iOS +// UNSUPPORTED: ios + #include int main() { char *x = (char*)malloc(10 * sizeof(char)); diff --git a/test/asan/TestCases/Darwin/suppressions-sandbox.cc b/test/asan/TestCases/Darwin/suppressions-sandbox.cc index c0b84adda..966f21346 100644 --- a/test/asan/TestCases/Darwin/suppressions-sandbox.cc +++ b/test/asan/TestCases/Darwin/suppressions-sandbox.cc @@ -8,6 +8,9 @@ // RUN: sandbox-exec -p '(version 1)(allow default)(deny process-fork)' \ // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// sandbox-exec isn't available on iOS +// UNSUPPORTED: ios + #include int main() { diff --git a/test/asan/TestCases/Darwin/uuid.cc b/test/asan/TestCases/Darwin/uuid.cc index 3f50272e9..33638587e 100644 --- a/test/asan/TestCases/Darwin/uuid.cc +++ b/test/asan/TestCases/Darwin/uuid.cc @@ -4,6 +4,9 @@ // RUN: %clangxx_asan %s -o %t -fsanitize-recover=address // RUN: %env_asan_opts=print_module_map=2:halt_on_error=0 %run %t 2>&1 | FileCheck %s +// We can't run system("otool") in the simulator. +// UNSUPPORTED: ios + #include #include #include -- cgit v1.2.1 From cfa8c9c868b8643a786ad5cc6d1a1eedd422e353 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 2 May 2017 19:37:28 +0000 Subject: [asan] Mark a bunch of tests as unsupported on iOS This patch marks a few ASan tests as unsupported on iOS. These are mostly tests that use files or paths that are invalid/inaccessible on iOS or the simulator. We currently don't have a good way of propagating/copying secondary files that individual tests need. The same problem exists on Android, so I'm just marking the tests as UNSUPPORTED now. Differential Revision: https://reviews.llvm.org/D32632 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301966 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/closed-fds.cc | 1 + test/asan/TestCases/Posix/coverage-maybe-open-file.cc | 1 + test/asan/TestCases/Posix/coverage-sandboxing.cc | 1 + test/asan/TestCases/Posix/coverage.cc | 1 + test/asan/TestCases/Posix/start-deactivated.cc | 1 + test/asan/TestCases/default_blacklist.cc | 1 + test/asan/TestCases/suppressions-function.cc | 1 + 7 files changed, 7 insertions(+) diff --git a/test/asan/TestCases/Posix/closed-fds.cc b/test/asan/TestCases/Posix/closed-fds.cc index 75e3216aa..b2604bba5 100644 --- a/test/asan/TestCases/Posix/closed-fds.cc +++ b/test/asan/TestCases/Posix/closed-fds.cc @@ -8,6 +8,7 @@ // FIXME: copy %t.log back from the device and re-enable on Android. // UNSUPPORTED: android +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc index 95f2b5449..ee2977af1 100644 --- a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc +++ b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc @@ -1,5 +1,6 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android +// UNSUPPORTED: ios // // RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t // RUN: rm -rf %T/coverage-maybe-open-file diff --git a/test/asan/TestCases/Posix/coverage-sandboxing.cc b/test/asan/TestCases/Posix/coverage-sandboxing.cc index 431dce149..354070708 100644 --- a/test/asan/TestCases/Posix/coverage-sandboxing.cc +++ b/test/asan/TestCases/Posix/coverage-sandboxing.cc @@ -21,6 +21,7 @@ // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/Posix/coverage.cc b/test/asan/TestCases/Posix/coverage.cc index 3d1dccfbd..bff060968 100644 --- a/test/asan/TestCases/Posix/coverage.cc +++ b/test/asan/TestCases/Posix/coverage.cc @@ -18,6 +18,7 @@ // // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc index 2a2aa674c..2870ffb2f 100644 --- a/test/asan/TestCases/Posix/start-deactivated.cc +++ b/test/asan/TestCases/Posix/start-deactivated.cc @@ -19,6 +19,7 @@ // RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED // XFAIL: arm-linux-gnueabi +// UNSUPPORTED: ios // END. diff --git a/test/asan/TestCases/default_blacklist.cc b/test/asan/TestCases/default_blacklist.cc index 9358cc47c..84c0438f3 100644 --- a/test/asan/TestCases/default_blacklist.cc +++ b/test/asan/TestCases/default_blacklist.cc @@ -1,5 +1,6 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android +// UNSUPPORTED: ios // // Test that ASan uses the default blacklist from resource directory. // RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/suppressions-function.cc b/test/asan/TestCases/suppressions-function.cc index d5ac9f779..c7f1ebe66 100644 --- a/test/asan/TestCases/suppressions-function.cc +++ b/test/asan/TestCases/suppressions-function.cc @@ -8,6 +8,7 @@ // FIXME: Windows symbolizer needs work to make this pass. // XFAIL: android,win32 +// UNSUPPORTED: ios #include #include -- cgit v1.2.1 From a14170f79bdca5e6e4333d16ee8d8fa13c35716e Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 2 May 2017 20:09:33 +0000 Subject: [asan] Mark atos-symbolizer-dyld-root-path.cc testcase as unsupported on iOS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301967 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc b/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc index d2facd6d0..fc3d0dd0b 100644 --- a/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc +++ b/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cc @@ -6,6 +6,9 @@ // Due to a bug in atos, this only works on x86_64. // REQUIRES: asan-64-bits +// Path returned by `which atos` is invalid on iOS. +// UNSUPPORTED: ios + #include #include int main(int argc, char **argv) { -- cgit v1.2.1 From ecf7ab5097c84b00228c87e967fd7b48b57af4f8 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 2 May 2017 21:22:29 +0000 Subject: [asan] Mark some more testcases as unsupported on iOS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301976 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-module-unloaded.cc | 1 + test/asan/TestCases/Posix/glob.cc | 1 + test/asan/TestCases/log-path_test.cc | 1 + test/asan/TestCases/suppressions-exec-relative-location.cc | 1 + test/asan/TestCases/verbose-log-path_test.cc | 1 + 5 files changed, 5 insertions(+) diff --git a/test/asan/TestCases/Posix/coverage-module-unloaded.cc b/test/asan/TestCases/Posix/coverage-module-unloaded.cc index d492af666..db27283a6 100644 --- a/test/asan/TestCases/Posix/coverage-module-unloaded.cc +++ b/test/asan/TestCases/Posix/coverage-module-unloaded.cc @@ -10,6 +10,7 @@ // // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/Posix/glob.cc b/test/asan/TestCases/Posix/glob.cc index e0eeb33cc..46d4a0d8d 100644 --- a/test/asan/TestCases/Posix/glob.cc +++ b/test/asan/TestCases/Posix/glob.cc @@ -1,5 +1,6 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android +// UNSUPPORTED: ios // // RUN: %clangxx_asan -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/log-path_test.cc b/test/asan/TestCases/log-path_test.cc index b4218ad85..710d22017 100644 --- a/test/asan/TestCases/log-path_test.cc +++ b/test/asan/TestCases/log-path_test.cc @@ -1,5 +1,6 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android +// UNSUPPORTED: ios // // The for loop in the backticks below requires bash. // REQUIRES: shell diff --git a/test/asan/TestCases/suppressions-exec-relative-location.cc b/test/asan/TestCases/suppressions-exec-relative-location.cc index 740cecee1..d4e214d35 100644 --- a/test/asan/TestCases/suppressions-exec-relative-location.cc +++ b/test/asan/TestCases/suppressions-exec-relative-location.cc @@ -25,6 +25,7 @@ // XFAIL: android // XFAIL: win32 +// UNSUPPORTED: ios #include #include diff --git a/test/asan/TestCases/verbose-log-path_test.cc b/test/asan/TestCases/verbose-log-path_test.cc index 47a5c226a..a63c58475 100644 --- a/test/asan/TestCases/verbose-log-path_test.cc +++ b/test/asan/TestCases/verbose-log-path_test.cc @@ -10,6 +10,7 @@ // FIXME: only FreeBSD and Linux have verbose log paths now. // XFAIL: win32,android +// UNSUPPORTED: ios #include #include -- cgit v1.2.1 From b8d03f43d6780a3de2c27724d265beb3735fd8c0 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Wed, 3 May 2017 07:09:10 +0000 Subject: [sanitizer] Intercept mcheck and mprobe on Linux This patch addresses https://github.com/google/sanitizers/issues/804. Users can use mcheck and mprobe functions to verify heap state so we should intercept them to avoid breakage of valid code. Differential Revision: https://reviews.llvm.org/D32589 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302001 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_interceptors.cc | 14 ++++++++ .../sanitizer_common_interceptors.inc | 14 ++++++++ .../sanitizer_platform_interceptors.h | 1 + test/sanitizer_common/TestCases/Linux/mprobe.cc | 42 ++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 test/sanitizer_common/TestCases/Linux/mprobe.cc diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index fe1f49bcd..9e39a7d19 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -185,6 +185,20 @@ INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free)); #define LSAN_MAYBE_INTERCEPT_CFREE #endif // SANITIZER_INTERCEPT_CFREE +#if SANITIZER_INTERCEPT_MCHECK_MPROBE +INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mprobe, void *ptr) { + return 0; +} +#endif // SANITIZER_INTERCEPT_MCHECK_MPROBE + #define OPERATOR_NEW_BODY \ ENSURE_LSAN_INITED; \ GET_STACK_TRACE_MALLOC; \ diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 4fe1ac8f9..53204b48e 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6142,6 +6142,20 @@ INTERCEPTOR(int, getloadavg, double *loadavg, int nelem) { #define INIT_GETLOADAVG #endif +#if SANITIZER_INTERCEPT_MCHECK_MPROBE +INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mprobe, void *ptr) { + return 0; +} +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a583e989c..e5644ef25 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -339,5 +339,6 @@ #define SANITIZER_INTERCEPT_CFREE (!SI_FREEBSD && !SI_MAC) #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) +#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/test/sanitizer_common/TestCases/Linux/mprobe.cc b/test/sanitizer_common/TestCases/Linux/mprobe.cc new file mode 100644 index 000000000..57e5ba5a6 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/mprobe.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx %s -o %t && %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: android + +#include +#include +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 2) +#include +#else +#define MCHECK_OK 0 +extern "C" int mcheck(void (*abortfunc)(int mstatus)); +extern "C" int mcheck_pedantic(void (*abortfunc)(int mstatus)); +extern "C" int mprobe(void *ptr); +#endif + +void check_heap() { + void *p = malloc(1000); + int res = mprobe(p); + if (res == MCHECK_OK) + printf("Success!\n"); + free(p); +} + +int main(int argc, char *argv[]) { + void *p; + if (mcheck(NULL) != 0) { + fprintf(stderr, "mcheck() failed\n"); + exit(EXIT_FAILURE); + } + + check_heap(); + // CHECK: Success! + + if (mcheck_pedantic(NULL) != 0) { + fprintf(stderr, "mcheck_pedantic() failed\n"); + exit(EXIT_FAILURE); + } + + check_heap(); + // CHECK: Success! + + return 0; +} -- cgit v1.2.1 From da99eb266cb67d7ef7c33bc9a103b108285171ef Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 3 May 2017 15:59:07 +0000 Subject: Speculative fix for WinASan after r301994 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302043 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/coverage-basic.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Windows/coverage-basic.cc b/test/asan/TestCases/Windows/coverage-basic.cc index 918872f18..93a382954 100644 --- a/test/asan/TestCases/Windows/coverage-basic.cc +++ b/test/asan/TestCases/Windows/coverage-basic.cc @@ -1,6 +1,6 @@ // RUN: rm -rf %T/coverage-basic // RUN: mkdir %T/coverage-basic && cd %T/coverage-basic -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o test.exe +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc %s -o test.exe // RUN: %env_asan_opts=coverage=1 %run ./test.exe // // RUN: %sancov print *.sancov | FileCheck %s -- cgit v1.2.1 From f5be24d91f5c9975ce71c5343b7c5731ce560d42 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 3 May 2017 16:11:01 +0000 Subject: Revert my bad winasan coverage test fix and apply one that actually works trace-pc doesn't work, but trace-pc-guard does. *shrug* git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302045 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/coverage-basic.cc | 2 +- test/asan/TestCases/Windows/coverage-dll-stdio.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Windows/coverage-basic.cc b/test/asan/TestCases/Windows/coverage-basic.cc index 93a382954..918872f18 100644 --- a/test/asan/TestCases/Windows/coverage-basic.cc +++ b/test/asan/TestCases/Windows/coverage-basic.cc @@ -1,6 +1,6 @@ // RUN: rm -rf %T/coverage-basic // RUN: mkdir %T/coverage-basic && cd %T/coverage-basic -// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc %s -o test.exe +// RUN: %clangxx_asan -fsanitize-coverage=func %s -o test.exe // RUN: %env_asan_opts=coverage=1 %run ./test.exe // // RUN: %sancov print *.sancov | FileCheck %s diff --git a/test/asan/TestCases/Windows/coverage-dll-stdio.cc b/test/asan/TestCases/Windows/coverage-dll-stdio.cc index 5e12e3855..92cd0a7bc 100644 --- a/test/asan/TestCases/Windows/coverage-dll-stdio.cc +++ b/test/asan/TestCases/Windows/coverage-dll-stdio.cc @@ -2,8 +2,8 @@ // __local_stdio_printf_options function isn't instrumented for coverage. // RUN: rm -rf %t && mkdir %t && cd %t -// RUN: %clang_cl_asan -fsanitize-coverage=func -O0 %p/dll_host.cc -Fet.exe -// RUN: %clang_cl_asan -fsanitize-coverage=func -LD -O0 %s -Fet.dll +// RUN: %clang_cl_asan -fsanitize-coverage=func,trace-pc-guard -O0 %p/dll_host.cc -Fet.exe +// RUN: %clang_cl_asan -fsanitize-coverage=func,trace-pc-guard -LD -O0 %s -Fet.dll // RUN: %run ./t.exe t.dll 2>&1 | FileCheck %s #include -- cgit v1.2.1 From 4e8f70074eb0b1b8612f770d269791afaac38f74 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 3 May 2017 16:51:01 +0000 Subject: [tsan] Detect races on modifying accesses in Swift code This patch allows the Swift compiler to emit calls to `__tsan_external_write` before starting any modifying access, which will cause TSan to detect races on arrays, dictionaries and other classes defined in non-instrumented modules. Races on collections from the Swift standard library and user-defined structs and a frequent cause of subtle bugs and it's important that TSan detects those on top of existing LLVM IR instrumentation, which already detects races in direct memory accesses. Differential Revision: https://reviews.llvm.org/D31630 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302050 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/tsan_interface.h | 1 + lib/tsan/rtl/tsan_defs.h | 9 ++++ lib/tsan/rtl/tsan_external.cc | 47 +++++++++++++++---- lib/tsan/rtl/tsan_interface.h | 2 + lib/tsan/rtl/tsan_report.cc | 21 +++++---- lib/tsan/rtl/tsan_report.h | 1 + lib/tsan/rtl/tsan_rtl.h | 10 +---- lib/tsan/rtl/tsan_rtl_report.cc | 17 ++++--- test/tsan/Darwin/external-dups.cc | 4 +- test/tsan/Darwin/external-swift.cc | 92 ++++++++++++++++++++++++++++++++++++++ test/tsan/Darwin/external.cc | 14 +++--- 11 files changed, 180 insertions(+), 38 deletions(-) create mode 100644 test/tsan/Darwin/external-swift.cc diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h index a0c702638..5ea09ab5c 100644 --- a/include/sanitizer/tsan_interface.h +++ b/include/sanitizer/tsan_interface.h @@ -126,6 +126,7 @@ void __tsan_mutex_post_divert(void *addr, unsigned flags); // which is later used in read/write annotations to denote the object type // - __tsan_external_assign_tag can optionally mark a heap object with a tag void *__tsan_external_register_tag(const char *object_type); +void __tsan_external_register_header(void *tag, const char *header); void __tsan_external_assign_tag(void *addr, void *tag); void __tsan_external_read(void *addr, void *caller_pc, void *tag); void __tsan_external_write(void *addr, void *caller_pc, void *tag); diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h index 8a0381e61..8977fea7c 100644 --- a/lib/tsan/rtl/tsan_defs.h +++ b/lib/tsan/rtl/tsan_defs.h @@ -157,6 +157,15 @@ struct MBlock { COMPILER_CHECK(sizeof(MBlock) == 16); +enum ExternalTag : uptr { + kExternalTagNone = 0, + kExternalTagSwiftModifyingAccess = 1, + kExternalTagFirstUserAvailable = 2, + kExternalTagMax = 1024, + // Don't set kExternalTagMax over 65,536, since MBlock only stores tags + // as 16-bit values, see tsan_defs.h. +}; + } // namespace __tsan #endif // TSAN_DEFS_H diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc index 2d32b6dac..6c0e9477e 100644 --- a/lib/tsan/rtl/tsan_external.cc +++ b/lib/tsan/rtl/tsan_external.cc @@ -17,14 +17,30 @@ namespace __tsan { #define CALLERPC ((uptr)__builtin_return_address(0)) -const char *registered_tags[kExternalTagMax]; -static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT. +struct TagData { + const char *object_type; + const char *header; +}; -const char *GetObjectTypeFromTag(uptr tag) { - if (tag == 0) return nullptr; +static TagData registered_tags[kExternalTagMax] = { + {}, + {"Swift variable", "Swift access race"}, +}; +static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT. +static TagData *GetTagData(uptr tag) { // Invalid/corrupted tag? Better return NULL and let the caller deal with it. if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr; - return registered_tags[tag]; + return ®istered_tags[tag]; +} + +const char *GetObjectTypeFromTag(uptr tag) { + TagData *tag_data = GetTagData(tag); + return tag_data ? tag_data->object_type : nullptr; +} + +const char *GetReportHeaderFromTag(uptr tag) { + TagData *tag_data = GetTagData(tag); + return tag_data ? tag_data->header : nullptr; } void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) { @@ -34,9 +50,9 @@ void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) { uptr TagFromShadowStackFrame(uptr pc) { uptr tag_count = atomic_load(&used_tags, memory_order_relaxed); void *pc_ptr = (void *)pc; - if (pc_ptr < ®istered_tags[0] || pc_ptr >= ®istered_tags[tag_count]) + if (pc_ptr < GetTagData(0) || pc_ptr > GetTagData(tag_count - 1)) return 0; - return (const char **)pc_ptr - ®istered_tags[0]; + return (TagData *)pc_ptr - GetTagData(0); } #if !SANITIZER_GO @@ -60,10 +76,25 @@ SANITIZER_INTERFACE_ATTRIBUTE void *__tsan_external_register_tag(const char *object_type) { uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed); CHECK_LT(new_tag, kExternalTagMax); - registered_tags[new_tag] = internal_strdup(object_type); + GetTagData(new_tag)->object_type = internal_strdup(object_type); + char header[127] = {0}; + internal_snprintf(header, sizeof(header), "race on %s", object_type); + GetTagData(new_tag)->header = internal_strdup(header); return (void *)new_tag; } +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_external_register_header(void *tag, const char *header) { + CHECK_GE((uptr)tag, kExternalTagFirstUserAvailable); + CHECK_LT((uptr)tag, kExternalTagMax); + atomic_uintptr_t *header_ptr = + (atomic_uintptr_t *)&GetTagData((uptr)tag)->header; + header = internal_strdup(header); + char *old_header = + (char *)atomic_exchange(header_ptr, (uptr)header, memory_order_seq_cst); + if (old_header) internal_free(old_header); +} + SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_assign_tag(void *addr, void *tag) { CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h index 71986283e..a80a48991 100644 --- a/lib/tsan/rtl/tsan_interface.h +++ b/lib/tsan/rtl/tsan_interface.h @@ -82,6 +82,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_end(); SANITIZER_INTERFACE_ATTRIBUTE void *__tsan_external_register_tag(const char *object_type); SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_external_register_header(void *tag, const char *header); +SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_assign_tag(void *addr, void *tag); SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_read(void *addr, void *caller_pc, void *tag); diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index b188af2a0..2de7ffc74 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -53,7 +53,8 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { }; ReportDesc::ReportDesc() - : stacks(MBlockReportStack) + : tag(kExternalTagNone) + , stacks(MBlockReportStack) , mops(MBlockReportMop) , locs(MBlockReportLoc) , mutexes(MBlockReportMutex) @@ -81,7 +82,7 @@ const char *thread_name(char *buf, int tid) { return buf; } -static const char *ReportTypeString(ReportType typ) { +static const char *ReportTypeString(ReportType typ, uptr tag) { if (typ == ReportTypeRace) return "data race"; if (typ == ReportTypeVptrRace) @@ -90,8 +91,9 @@ static const char *ReportTypeString(ReportType typ) { return "heap-use-after-free"; if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free (virtual call vs free)"; - if (typ == ReportTypeExternalRace) - return "race on a library object"; + if (typ == ReportTypeExternalRace) { + return GetReportHeaderFromTag(tag) ?: "race on external object"; + } if (typ == ReportTypeThreadLeak) return "thread leak"; if (typ == ReportTypeMutexDestroyLocked) @@ -155,20 +157,21 @@ static const char *MopDesc(bool first, bool write, bool atomic) { } static const char *ExternalMopDesc(bool first, bool write) { - return first ? (write ? "Mutating" : "Read-only") - : (write ? "Previous mutating" : "Previous read-only"); + return first ? (write ? "Modifying" : "Read-only") + : (write ? "Previous modifying" : "Previous read-only"); } static void PrintMop(const ReportMop *mop, bool first) { Decorator d; char thrbuf[kThreadBufSize]; Printf("%s", d.Access()); - const char *object_type = GetObjectTypeFromTag(mop->external_tag); - if (mop->external_tag == kExternalTagNone || !object_type) { + if (mop->external_tag == kExternalTagNone) { Printf(" %s of size %d at %p by %s", MopDesc(first, mop->write, mop->atomic), mop->size, (void *)mop->addr, thread_name(thrbuf, mop->tid)); } else { + const char *object_type = + GetObjectTypeFromTag(mop->external_tag) ?: "external object"; Printf(" %s access of %s at %p by %s", ExternalMopDesc(first, mop->write), object_type, (void *)mop->addr, thread_name(thrbuf, mop->tid)); @@ -315,7 +318,7 @@ static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) { void PrintReport(const ReportDesc *rep) { Decorator d; Printf("==================\n"); - const char *rep_typ_str = ReportTypeString(rep->typ); + const char *rep_typ_str = ReportTypeString(rep->typ, rep->tag); Printf("%s", d.Warning()); Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, (int)internal_getpid()); diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h index a0473e8db..bc1582f90 100644 --- a/lib/tsan/rtl/tsan_report.h +++ b/lib/tsan/rtl/tsan_report.h @@ -108,6 +108,7 @@ struct ReportMutex { class ReportDesc { public: ReportType typ; + uptr tag; Vector stacks; Vector mops; Vector locs; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 8bf1c191a..e92a0f357 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -564,19 +564,13 @@ struct ScopedIgnoreInterceptors { } }; -enum ExternalTag : uptr { - kExternalTagNone = 0, - kExternalTagFirstUserAvailable = 1, - kExternalTagMax = 1024, - // Don't set kExternalTagMax over 65,536, since MBlock only stores tags - // as 16-bit values, see tsan_defs.h. -}; const char *GetObjectTypeFromTag(uptr tag); +const char *GetReportHeaderFromTag(uptr tag); uptr TagFromShadowStackFrame(uptr pc); class ScopedReport { public: - explicit ScopedReport(ReportType typ); + explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone); ~ScopedReport(); void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack, diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index 055029b91..68b9f5030 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -143,11 +143,12 @@ static ReportStack *SymbolizeStack(StackTrace trace) { return stack; } -ScopedReport::ScopedReport(ReportType typ) { +ScopedReport::ScopedReport(ReportType typ, uptr tag) { ctx->thread_registry->CheckLocked(); void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); rep_ = new(mem) ReportDesc; rep_->typ = typ; + rep_->tag = tag; ctx->report_mtx.Lock(); CommonSanitizerReportMutex.Lock(); } @@ -651,12 +652,18 @@ void ReportRace(ThreadState *thr) { if (HandleRacyStacks(thr, traces, addr_min, addr_max)) return; - // If any of the two accesses has a tag, treat this as an "external" race. - if (tags[0] != kExternalTagNone || tags[1] != kExternalTagNone) - typ = ReportTypeExternalRace; + // If any of the accesses has a tag, treat this as an "external" race. + uptr tag = kExternalTagNone; + for (uptr i = 0; i < kMop; i++) { + if (tags[i] != kExternalTagNone) { + typ = ReportTypeExternalRace; + tag = tags[i]; + break; + } + } ThreadRegistryLock l0(ctx->thread_registry); - ScopedReport rep(typ); + ScopedReport rep(typ, tag); for (uptr i = 0; i < kMop; i++) { Shadow s(thr->racy_state[i]); rep.AddMemoryAccess(addr, tags[i], s, traces[i], diff --git a/test/tsan/Darwin/external-dups.cc b/test/tsan/Darwin/external-dups.cc index 79432bac4..ca1eb3e7c 100644 --- a/test/tsan/Darwin/external-dups.cc +++ b/test/tsan/Darwin/external-dups.cc @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) { barrier_wait(&barrier); ExternalWrite(opaque_object); }); - // CHECK: WARNING: ThreadSanitizer: race on a library object + // CHECK: WARNING: ThreadSanitizer: race on HelloWorld t1.join(); t2.join(); } @@ -46,7 +46,7 @@ int main(int argc, char *argv[]) { barrier_wait(&barrier); ExternalWrite(opaque_object); }); - // CHECK: WARNING: ThreadSanitizer: race on a library object + // CHECK: WARNING: ThreadSanitizer: race on HelloWorld t1.join(); t2.join(); } diff --git a/test/tsan/Darwin/external-swift.cc b/test/tsan/Darwin/external-swift.cc new file mode 100644 index 000000000..f6f9e7f4e --- /dev/null +++ b/test/tsan/Darwin/external-swift.cc @@ -0,0 +1,92 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#include + +#import "../test.h" + +extern "C" { +void __tsan_write8(void *addr); +} + +static void *tag = (void *)0x1; + +__attribute__((no_sanitize("thread"))) +void ExternalWrite(void *addr) { + __tsan_external_write(addr, nullptr, tag); +} + +__attribute__((no_sanitize("thread"))) +void RegularWrite(void *addr) { + __tsan_write8(addr); +} + +int main(int argc, char *argv[]) { + barrier_init(&barrier, 2); + fprintf(stderr, "Start.\n"); + // CHECK: Start. + + { + void *opaque_object = malloc(16); + std::thread t1([opaque_object] { + ExternalWrite(opaque_object); + barrier_wait(&barrier); + }); + std::thread t2([opaque_object] { + barrier_wait(&barrier); + ExternalWrite(opaque_object); + }); + // CHECK: WARNING: ThreadSanitizer: Swift access race + // CHECK: Modifying access of Swift variable at {{.*}} by thread {{.*}} + // CHECK: Previous modifying access of Swift variable at {{.*}} by thread {{.*}} + // CHECK: SUMMARY: ThreadSanitizer: Swift access race + t1.join(); + t2.join(); + } + + fprintf(stderr, "external+external test done.\n"); + // CHECK: external+external test done. + + { + void *opaque_object = malloc(16); + std::thread t1([opaque_object] { + ExternalWrite(opaque_object); + barrier_wait(&barrier); + }); + std::thread t2([opaque_object] { + barrier_wait(&barrier); + RegularWrite(opaque_object); + }); + // CHECK: WARNING: ThreadSanitizer: Swift access race + // CHECK: Write of size 8 at {{.*}} by thread {{.*}} + // CHECK: Previous modifying access of Swift variable at {{.*}} by thread {{.*}} + // CHECK: SUMMARY: ThreadSanitizer: Swift access race + t1.join(); + t2.join(); + } + + fprintf(stderr, "external+regular test done.\n"); + // CHECK: external+regular test done. + + { + void *opaque_object = malloc(16); + std::thread t1([opaque_object] { + RegularWrite(opaque_object); + barrier_wait(&barrier); + }); + std::thread t2([opaque_object] { + barrier_wait(&barrier); + ExternalWrite(opaque_object); + }); + // CHECK: WARNING: ThreadSanitizer: Swift access race + // CHECK: Modifying access of Swift variable at {{.*}} by thread {{.*}} + // CHECK: Previous write of size 8 at {{.*}} by thread {{.*}} + // CHECK: SUMMARY: ThreadSanitizer: Swift access race + t1.join(); + t2.join(); + } + + fprintf(stderr, "regular+external test done.\n"); + // CHECK: regular+external test done. +} + diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc index 211694ab7..e72281afa 100644 --- a/test/tsan/Darwin/external.cc +++ b/test/tsan/Darwin/external.cc @@ -67,13 +67,14 @@ int main(int argc, char *argv[]) { // TEST2-NOT: WARNING: ThreadSanitizer - // TEST3: WARNING: ThreadSanitizer: race on a library object - // TEST3: {{Mutating|read-only}} access of MyLibrary::MyObject at + // TEST3: WARNING: ThreadSanitizer: race on MyLibrary::MyObject + // TEST3: {{Modifying|read-only}} access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectRead}} - // TEST3: Previous {{mutating|read-only}} access of MyLibrary::MyObject at + // TEST3: Previous {{modifying|read-only}} access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectRead}} // TEST3: Location is MyLibrary::MyObject of size 16 at // TEST3: {{ObjectCreate}} + // TEST3: SUMMARY: ThreadSanitizer: race on MyLibrary::MyObject {{.*}} in {{ObjectWrite|ObjectRead}} fprintf(stderr, "RW test done\n"); // CHECK: RW test done @@ -90,13 +91,14 @@ int main(int argc, char *argv[]) { // TEST2-NOT: WARNING: ThreadSanitizer - // TEST3: WARNING: ThreadSanitizer: race on a library object - // TEST3: Mutating access of MyLibrary::MyObject at + // TEST3: WARNING: ThreadSanitizer: race on MyLibrary::MyObject + // TEST3: Modifying access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectWriteAnother}} - // TEST3: Previous mutating access of MyLibrary::MyObject at + // TEST3: Previous modifying access of MyLibrary::MyObject at // TEST3: {{ObjectWrite|ObjectWriteAnother}} // TEST3: Location is MyLibrary::MyObject of size 16 at // TEST3: {{ObjectCreate}} + // TEST3: SUMMARY: ThreadSanitizer: race on MyLibrary::MyObject {{.*}} in {{ObjectWrite|ObjectWriteAnother}} fprintf(stderr, "WW test done\n"); // CHECK: WW test done -- cgit v1.2.1 From 72830dd7ffe3932beb5f5fbe29d84105b7df3f8a Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 3 May 2017 18:38:34 +0000 Subject: [asan] print the 'unexpected format specifier in printf interceptor' warning just once (came up in https://github.com/google/oss-fuzz/pull/562). Not touching a similar scanf warning -- for some reason it does not fire for me. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302064 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors_format.inc | 12 ++++++++---- .../TestCases/Linux/unexpected_format_specifier_test.cc | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc index 12563499c..5ebe5a6ba 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -325,8 +325,8 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, continue; int size = scanf_get_value_size(&dir); if (size == FSS_INVALID) { - Report("WARNING: unexpected format specifier in scanf interceptor: " - "%.*s\n", dir.end - dir.begin, dir.begin); + Report("%s: WARNING: unexpected format specifier in scanf interceptor: ", + SanitizerToolName, "%.*s\n", dir.end - dir.begin, dir.begin); break; } void *argp = va_arg(aq, void *); @@ -520,8 +520,12 @@ static void printf_common(void *ctx, const char *format, va_list aq) { continue; int size = printf_get_value_size(&dir); if (size == FSS_INVALID) { - Report("WARNING: unexpected format specifier in printf " - "interceptor: %.*s\n", dir.end - dir.begin, dir.begin); + static int ReportedOnce; + if (!ReportedOnce++) + Report( + "%s: WARNING: unexpected format specifier in printf " + "interceptor: %.*s (reported once per process)\n", + SanitizerToolName, dir.end - dir.begin, dir.begin); break; } if (dir.convSpecifier == 'n') { diff --git a/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc b/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc new file mode 100644 index 000000000..f48cce8ea --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc @@ -0,0 +1,12 @@ +// RUN: %clang -w -O0 %s -o %t && %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: lsan +// UNSUPPORTED: msan +#include +int main() { + int a; + printf("%Q\n", 1); + printf("%Q\n", 1); + printf("%Q\n", 1); +} +// CHECK: unexpected format specifier in printf interceptor: %Q (reported once per process) +// CHECK-NOT: unexpected format specifier in printf interceptor -- cgit v1.2.1 From be190670452d24c95b99fc32a42357e5cfced738 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 4 May 2017 04:59:20 +0000 Subject: [XRay][compiler-rt] Support patching/unpatching specific functions Summary: This change allows us to patch/unpatch specific functions using the function ID. This is useful in cases where implementations might want to do coverage-style, or more fine-grained control of which functions to patch or un-patch at runtime. Depends on D32693. Reviewers: dblaikie, echristo, kpw Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32695 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302112 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 8 ++ lib/xray/xray_init.cc | 4 + lib/xray/xray_interface.cc | 129 ++++++++++++++++++++------- lib/xray/xray_interface_internal.h | 7 ++ test/xray/TestCases/Linux/coverage-sample.cc | 88 ++++++++++++++++++ 5 files changed, 203 insertions(+), 33 deletions(-) create mode 100644 test/xray/TestCases/Linux/coverage-sample.cc diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index 52a7e1d9e..e2d0a89d6 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -67,6 +67,14 @@ extern XRayPatchingStatus __xray_patch(); // result values. extern XRayPatchingStatus __xray_unpatch(); +// This patches a specific function id. See XRayPatchingStatus for possible +// result values. +extern XRayPatchingStatus __xray_patch_function(int32_t FuncId); + +// This unpatches a specific function id. See XRayPatchingStatus for possible +// result values. +extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId); + // Use XRay to log the first argument of each (instrumented) function call. // When this function exits, all threads will have observed the effect and // start logging their subsequent affected function calls (if patched). diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index 6f558d656..aa660baa9 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -25,6 +25,8 @@ extern "C" { void __xray_init(); extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak)); extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak)); +extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak)); +extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak)); } using namespace __xray; @@ -55,6 +57,8 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); XRayInstrMap.Sleds = __start_xray_instr_map; XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map; + XRayInstrMap.SledsIndex = __start_xray_fn_idx; + XRayInstrMap.Functions = __stop_xray_fn_idx - __start_xray_fn_idx; } __sanitizer::atomic_store(&XRayInitialized, true, __sanitizer::memory_order_release); diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 26ec161fe..73cca80bc 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -132,12 +132,48 @@ CleanupInvoker scopeCleanup(Function Fn) XRAY_NEVER_INSTRUMENT { return CleanupInvoker{Fn}; } +inline bool patchSled(const XRaySledEntry &Sled, bool Enable, + int32_t FuncId) XRAY_NEVER_INSTRUMENT { + // While we're here, we should patch the nop sled. To do that we mprotect + // the page containing the function to be writeable. + const uint64_t PageSize = GetPageSizeCached(); + void *PageAlignedAddr = + reinterpret_cast(Sled.Address & ~(PageSize - 1)); + std::size_t MProtectLen = (Sled.Address + cSledLength) - + reinterpret_cast(PageAlignedAddr); + MProtectHelper Protector(PageAlignedAddr, MProtectLen); + if (Protector.MakeWriteable() == -1) { + printf("Failed mprotect: %d\n", errno); + return XRayPatchingStatus::FAILED; + } + + bool Success = false; + switch (Sled.Kind) { + case XRayEntryType::ENTRY: + Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); + break; + case XRayEntryType::EXIT: + Success = patchFunctionExit(Enable, FuncId, Sled); + break; + case XRayEntryType::TAIL: + Success = patchFunctionTailExit(Enable, FuncId, Sled); + break; + case XRayEntryType::LOG_ARGS_ENTRY: + Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); + break; + default: + Report("Unsupported sled kind '%d' @%04x\n", Sled.Address, int(Sled.Kind)); + return false; + } + return Success; +} + // controlPatching implements the common internals of the patching/unpatching // implementation. |Enable| defines whether we're enabling or disabling the // runtime XRay instrumentation. XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { if (!__sanitizer::atomic_load(&XRayInitialized, - __sanitizer::memory_order_acquire)) + __sanitizer::memory_order_acquire)) return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. uint8_t NotPatching = false; @@ -179,38 +215,7 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { ++FuncId; CurFun = F; } - - // While we're here, we should patch the nop sled. To do that we mprotect - // the page containing the function to be writeable. - void *PageAlignedAddr = - reinterpret_cast(Sled.Address & ~(PageSize - 1)); - std::size_t MProtectLen = (Sled.Address + cSledLength) - - reinterpret_cast(PageAlignedAddr); - MProtectHelper Protector(PageAlignedAddr, MProtectLen); - if (Protector.MakeWriteable() == -1) { - printf("Failed mprotect: %d\n", errno); - return XRayPatchingStatus::FAILED; - } - - bool Success = false; - switch (Sled.Kind) { - case XRayEntryType::ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); - break; - case XRayEntryType::EXIT: - Success = patchFunctionExit(Enable, FuncId, Sled); - break; - case XRayEntryType::TAIL: - Success = patchFunctionTailExit(Enable, FuncId, Sled); - break; - case XRayEntryType::LOG_ARGS_ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); - break; - default: - Report("Unsupported sled kind: %d\n", int(Sled.Kind)); - continue; - } - (void)Success; + patchSled(Sled, Enable, FuncId); } __sanitizer::atomic_store(&XRayPatching, false, __sanitizer::memory_order_release); @@ -226,6 +231,64 @@ XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT { return controlPatching(false); } +XRayPatchingStatus patchFunction(int32_t FuncId, + bool Enable) XRAY_NEVER_INSTRUMENT { + if (!__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) + return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. + + uint8_t NotPatching = false; + if (!__sanitizer::atomic_compare_exchange_strong( + &XRayPatching, &NotPatching, true, __sanitizer::memory_order_acq_rel)) + return XRayPatchingStatus::ONGOING; // Already patching. + + // Next, we look for the function index. + XRaySledMap InstrMap; + { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + InstrMap = XRayInstrMap; + } + + // If we don't have an index, we can't patch individual functions. + if (InstrMap.Functions == 0) + return XRayPatchingStatus::NOT_INITIALIZED; + + // FuncId must be a positive number, less than the number of functions + // instrumented. + if (FuncId <= 0 || static_cast(FuncId) >= InstrMap.Functions) { + Report("Invalid function id provided: %d\n", FuncId); + return XRayPatchingStatus::FAILED; + } + + // Now we patch ths sleds for this specific function. + auto SledRange = InstrMap.SledsIndex[FuncId - 1]; + auto *f = SledRange.Begin; + auto *e = SledRange.End; + + bool SucceedOnce = false; + while (f != e) + SucceedOnce |= patchSled(*f++, Enable, FuncId); + + __sanitizer::atomic_store(&XRayPatching, false, + __sanitizer::memory_order_release); + + if (!SucceedOnce) { + Report("Failed patching any sled for function '%d'.", FuncId); + return XRayPatchingStatus::FAILED; + } + + return XRayPatchingStatus::SUCCESS; +} + +XRayPatchingStatus __xray_patch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + return patchFunction(FuncId, true); +} + +XRayPatchingStatus +__xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + return patchFunction(FuncId, false); +} + int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { if (!__sanitizer::atomic_load(&XRayInitialized, __sanitizer::memory_order_acquire)) diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index 0e3a251f3..ef0c6b158 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -39,6 +39,11 @@ struct XRaySledEntry { #error "Unsupported word size." #endif }; + +struct XRayFunctionSledIndex { + const XRaySledEntry* Begin; + const XRaySledEntry* End; +}; } namespace __xray { @@ -46,6 +51,8 @@ namespace __xray { struct XRaySledMap { const XRaySledEntry *Sleds; size_t Entries; + const XRayFunctionSledIndex *SledsIndex; + size_t Functions; }; bool patchFunctionEntry(bool Enable, uint32_t FuncId, diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Linux/coverage-sample.cc new file mode 100644 index 000000000..623b4e345 --- /dev/null +++ b/test/xray/TestCases/Linux/coverage-sample.cc @@ -0,0 +1,88 @@ +// Check that we can patch and unpatch specific function ids. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s + +#include "xray/xray_interface.h" + +#include +#include + +std::set function_ids; + +[[clang::xray_never_instrument]] void coverage_handler(int32_t fid, + XRayEntryType) { + thread_local bool patching = false; + if (patching) return; + patching = true; + function_ids.insert(fid); + __xray_unpatch_function(fid); + patching = false; +} + +[[clang::xray_always_instrument]] void baz() { + // do nothing! +} + +[[clang::xray_always_instrument]] void bar() { + baz(); +} + +[[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + __xray_set_handler(coverage_handler); + __xray_patch(); + foo(); + __xray_unpatch(); + + // print out the function_ids. + printf("first pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + + // CHECK-LABEL: first pass. + // CHECK-DAG: patched: [[F1:.*]] + // CHECK-DAG: patched: [[F2:.*]] + // CHECK-DAG: patched: [[F3:.*]] + + // make a copy of the function_ids, then patch them later. + auto called_fns = function_ids; + + // clear the function_ids. + function_ids.clear(); + + // patch the functions we've called before. + for (const auto id : called_fns) + __xray_patch_function(id); + + // then call them again. + foo(); + __xray_unpatch(); + + // confirm that we've seen the same functions again. + printf("second pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: second pass. + // CHECK-DAG: patched: [[F1]] + // CHECK-DAG: patched: [[F2]] + // CHECK-DAG: patched: [[F3]] + + // Now we want to make sure that if we unpatch one, that we're only going to + // see two calls of the coverage_handler. + function_ids.clear(); + __xray_patch(); + __xray_unpatch_function(1); + foo(); + __xray_unpatch(); + + // confirm that we don't see function id one called anymore. + printf("missing 1.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: missing 1. + // CHECK-NOT: patched: 1 +} -- cgit v1.2.1 From c5b0187af67133194c16bd3018e5a7938ea12f48 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 4 May 2017 06:27:51 +0000 Subject: [XRay][compiler-rt][NFC] Update comments to doxygen format; group functions better. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302121 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 82 ++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index e2d0a89d6..469bfffe5 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -18,7 +18,7 @@ extern "C" { -// Synchronize this with AsmPrinter::SledKind in LLVM. +/// Synchronize this with AsmPrinter::SledKind in LLVM. enum XRayEntryType { ENTRY = 0, EXIT = 1, @@ -26,32 +26,43 @@ enum XRayEntryType { LOG_ARGS_ENTRY = 3, }; -// Provide a function to invoke for when instrumentation points are hit. This is -// a user-visible control surface that overrides the default implementation. The -// function provided should take the following arguments: -// -// - function id: an identifier that indicates the id of a function; this id -// is generated by xray; the mapping between the function id -// and the actual function pointer is available through -// __xray_table. -// - entry type: identifies what kind of instrumentation point was encountered -// (function entry, function exit, etc.). See the enum -// XRayEntryType for more details. -// -// The user handler must handle correctly spurious calls after this handler is -// removed or replaced with another handler, because it would be too costly for -// XRay runtime to avoid spurious calls. -// To prevent circular calling, the handler function itself and all its -// direct&indirect callees must not be instrumented with XRay, which can be -// achieved by marking them all with: __attribute__((xray_never_instrument)) -// -// Returns 1 on success, 0 on error. +/// Provide a function to invoke for when instrumentation points are hit. This +/// is a user-visible control surface that overrides the default implementation. +/// The function provided should take the following arguments: +/// +/// - function id: an identifier that indicates the id of a function; this id +/// is generated by xray; the mapping between the function id +/// and the actual function pointer is available through +/// __xray_table. +/// - entry type: identifies what kind of instrumentation point was +/// encountered (function entry, function exit, etc.). See the +/// enum XRayEntryType for more details. +/// +/// The user handler must handle correctly spurious calls after this handler is +/// removed or replaced with another handler, because it would be too costly for +/// XRay runtime to avoid spurious calls. +/// To prevent circular calling, the handler function itself and all its +/// direct&indirect callees must not be instrumented with XRay, which can be +/// achieved by marking them all with: __attribute__((xray_never_instrument)) +/// +/// Returns 1 on success, 0 on error. extern int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)); -// This removes whatever the currently provided handler is. Returns 1 on -// success, 0 on error. +/// This removes whatever the currently provided handler is. Returns 1 on +/// success, 0 on error. extern int __xray_remove_handler(); +/// Use XRay to log the first argument of each (instrumented) function call. +/// When this function exits, all threads will have observed the effect and +/// start logging their subsequent affected function calls (if patched). +/// +/// Returns 1 on success, 0 on error. +extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); + +/// Disables the XRay handler used to log first arguments of function calls. +/// Returns 1 on success, 0 on error. +extern int __xray_remove_handler_arg1(); + enum XRayPatchingStatus { NOT_INITIALIZED = 0, SUCCESS = 1, @@ -59,32 +70,23 @@ enum XRayPatchingStatus { FAILED = 3, }; -// This tells XRay to patch the instrumentation points. See XRayPatchingStatus -// for possible result values. +/// This tells XRay to patch the instrumentation points. See XRayPatchingStatus +/// for possible result values. extern XRayPatchingStatus __xray_patch(); -// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible -// result values. +/// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible +/// result values. extern XRayPatchingStatus __xray_unpatch(); -// This patches a specific function id. See XRayPatchingStatus for possible -// result values. +/// This patches a specific function id. See XRayPatchingStatus for possible +/// result values. extern XRayPatchingStatus __xray_patch_function(int32_t FuncId); -// This unpatches a specific function id. See XRayPatchingStatus for possible -// result values. +/// This unpatches a specific function id. See XRayPatchingStatus for possible +/// result values. extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId); -// Use XRay to log the first argument of each (instrumented) function call. -// When this function exits, all threads will have observed the effect and -// start logging their subsequent affected function calls (if patched). -// -// Returns 1 on success, 0 on error. -extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); -// Disables the XRay handler used to log first arguments of function calls. -// Returns 1 on success, 0 on error. -extern int __xray_remove_handler_arg1(); } #endif -- cgit v1.2.1 From 6bae4bb552040cae850681707c0c2f8d65a0b023 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Thu, 4 May 2017 13:34:17 +0000 Subject: [compiler-rt][mips] Add support for quad precision builtins for mips64 Match the builtins that GCC provides for IEEE754 quad precision on MIPS64. Also, enable building them with clang as PR20098 is resolved. Disable tests for xf and xc modes as MIPS doesn't support that mode in hardware or software. Reviewers: slthakur Differential Revision: https://reviews.llvm.org/D32794 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302147 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 45 +++++++++++++++++++---------------- lib/builtins/int_types.h | 4 +--- test/builtins/Unit/divxc3_test.c | 1 + test/builtins/Unit/fixunstfti_test.c | 2 ++ test/builtins/Unit/fixunsxfti_test.c | 2 ++ test/builtins/Unit/fixxfti_test.c | 2 ++ test/builtins/Unit/floattixf_test.c | 2 ++ test/builtins/Unit/floatuntixf_test.c | 2 ++ test/builtins/Unit/mulxc3_test.c | 1 + 9 files changed, 38 insertions(+), 23 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index c30d9b363..74a6531b0 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -167,6 +167,26 @@ set(GENERIC_SOURCES umodti3.c emutls.c) +set(GENERIC_TF_SOURCES + comparetf2.c + extenddftf2.c + extendsftf2.c + fixtfdi.c + fixtfsi.c + fixtfti.c + fixunstfdi.c + fixunstfsi.c + fixunstfti.c + floatditf.c + floatsitf.c + floattitf.c + floatunditf.c + floatunsitf.c + floatuntitf.c + multc3.c + trunctfdf2.c + trunctfsf2.c) + option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" Off) @@ -404,24 +424,7 @@ elseif(NOT WIN32) endif() set(aarch64_SOURCES - comparetf2.c - extenddftf2.c - extendsftf2.c - fixtfdi.c - fixtfsi.c - fixtfti.c - fixunstfdi.c - fixunstfsi.c - fixunstfti.c - floatditf.c - floatsitf.c - floattitf.c - floatunditf.c - floatunsitf.c - floatuntitf.c - multc3.c - trunctfdf2.c - trunctfsf2.c + ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES}) set(armhf_SOURCES ${arm_SOURCES}) @@ -437,8 +440,10 @@ set(armv7em_SOURCES ${arm_SOURCES}) set(mips_SOURCES ${GENERIC_SOURCES}) set(mipsel_SOURCES ${mips_SOURCES}) -set(mips64_SOURCES ${mips_SOURCES}) -set(mips64el_SOURCES ${mips_SOURCES}) +set(mips64_SOURCES ${GENERIC_TF_SOURCES} + ${mips_SOURCES}) +set(mips64el_SOURCES ${GENERIC_TF_SOURCES} + ${mips_SOURCES}) set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h index 660385ecd..a92238c5b 100644 --- a/lib/builtins/int_types.h +++ b/lib/builtins/int_types.h @@ -60,9 +60,7 @@ typedef union }s; } udwords; -/* MIPS64 issue: PR 20098 */ -#if (defined(__LP64__) || defined(__wasm__)) && \ - !(defined(__mips__) && defined(__clang__)) +#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) #define CRT_HAS_128BIT #endif diff --git a/test/builtins/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c index d0cdb0169..6517ef124 100644 --- a/test/builtins/Unit/divxc3_test.c +++ b/test/builtins/Unit/divxc3_test.c @@ -19,6 +19,7 @@ #include #include +// UNSUPPORTED: mips // REQUIRES: c99-complex // Returns: the quotient of (a + ib) / (c + id) diff --git a/test/builtins/Unit/fixunstfti_test.c b/test/builtins/Unit/fixunstfti_test.c index 019b72049..eaf4b8fb5 100644 --- a/test/builtins/Unit/fixunstfti_test.c +++ b/test/builtins/Unit/fixunstfti_test.c @@ -14,6 +14,8 @@ #include +// UNSUPPORTED: mips + #if __LDBL_MANT_DIG__ == 113 #include "fp_test.h" diff --git a/test/builtins/Unit/fixunsxfti_test.c b/test/builtins/Unit/fixunsxfti_test.c index 28a7e9783..0a48a7332 100644 --- a/test/builtins/Unit/fixunsxfti_test.c +++ b/test/builtins/Unit/fixunsxfti_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- fixunsxfti_test.c - Test __fixunsxfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixxfti_test.c b/test/builtins/Unit/fixxfti_test.c index c6d42c6e1..e5e15ab78 100644 --- a/test/builtins/Unit/fixxfti_test.c +++ b/test/builtins/Unit/fixxfti_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- fixxfti_test.c - Test __fixxfti -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattixf_test.c b/test/builtins/Unit/floattixf_test.c index 00644fae1..3de472934 100644 --- a/test/builtins/Unit/floattixf_test.c +++ b/test/builtins/Unit/floattixf_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- floattixf.c - Test __floattixf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntixf_test.c b/test/builtins/Unit/floatuntixf_test.c index 70ad5f36f..2d71f0f88 100644 --- a/test/builtins/Unit/floatuntixf_test.c +++ b/test/builtins/Unit/floatuntixf_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- floatuntixf.c - Test __floatuntixf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c index 3260b7521..c48b0da50 100644 --- a/test/builtins/Unit/mulxc3_test.c +++ b/test/builtins/Unit/mulxc3_test.c @@ -19,6 +19,7 @@ #include #include +// UNSUPPORTED: mips // REQUIRES: c99-complex // Returns: the product of a + ib and c + id -- cgit v1.2.1 From daf4d1dbabac3085ea44745f44decc99449e5771 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 4 May 2017 14:03:57 +0000 Subject: [ASAN] Add interceptor for __longjmp_chk Summary: glibc on Linux calls __longjmp_chk instead of longjmp (or _longjmp) when _FORTIFY_SOURCE is defined. Ensure that an ASAN-instrumented program intercepts this function when a system library calls it, otherwise the stack might remain poisoned and result in CHECK failures and false positives. Fixes https://github.com/google/sanitizers/issues/721 Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D32408 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302152 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 10 +++++++ lib/asan/asan_interceptors.h | 6 ++++ test/asan/TestCases/Linux/longjmp_chk.c | 51 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 test/asan/TestCases/Linux/longjmp_chk.c diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 905dd2e23..c6969c979 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -443,6 +443,13 @@ INTERCEPTOR(void, _longjmp, void *env, int val) { } #endif +#if ASAN_INTERCEPT___LONGJMP_CHK +INTERCEPTOR(void, __longjmp_chk, void *env, int val) { + __asan_handle_no_return(); + REAL(__longjmp_chk)(env, val); +} +#endif + #if ASAN_INTERCEPT_SIGLONGJMP INTERCEPTOR(void, siglongjmp, void *env, int val) { __asan_handle_no_return(); @@ -758,6 +765,9 @@ void InitializeAsanInterceptors() { #if ASAN_INTERCEPT__LONGJMP ASAN_INTERCEPT_FUNC(_longjmp); #endif +#if ASAN_INTERCEPT___LONGJMP_CHK + ASAN_INTERCEPT_FUNC(__longjmp_chk); +#endif #if ASAN_INTERCEPT_SIGLONGJMP ASAN_INTERCEPT_FUNC(siglongjmp); #endif diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index d747c31a5..93fca4f67 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -58,6 +58,12 @@ # define ASAN_INTERCEPT_SIGLONGJMP 0 #endif +#if SANITIZER_LINUX && !SANITIZER_ANDROID +# define ASAN_INTERCEPT___LONGJMP_CHK 1 +#else +# define ASAN_INTERCEPT___LONGJMP_CHK 0 +#endif + // Android bug: https://code.google.com/p/android/issues/detail?id=61799 #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \ !(SANITIZER_ANDROID && defined(__i386)) diff --git a/test/asan/TestCases/Linux/longjmp_chk.c b/test/asan/TestCases/Linux/longjmp_chk.c new file mode 100644 index 000000000..99a4a1630 --- /dev/null +++ b/test/asan/TestCases/Linux/longjmp_chk.c @@ -0,0 +1,51 @@ +// Verify that use of longjmp() in a _FORTIFY_SOURCE'd library (without ASAN) +// is correctly intercepted such that the stack is unpoisoned. +// Note: it is essential that the external library is not built with ASAN, +// otherwise it would be able to unpoison the stack before use. +// +// RUN: %clang -DIS_LIBRARY -D_FORTIFY_SOURCE=2 -O2 %s -c -o %t.o +// RUN: %clang_asan -O2 %s %t.o -o %t +// RUN: %run %t + +#ifdef IS_LIBRARY +/* the library */ +#include +#include +#include + +static jmp_buf jenv; + +void external_callme(void (*callback)(void)) { + if (setjmp(jenv) == 0) { + callback(); + } +} + +void external_longjmp(char *msg) { + longjmp(jenv, 1); +} + +void external_check_stack(void) { + char buf[256] = ""; + for (int i = 0; i < 256; i++) { + assert(!__asan_address_is_poisoned(buf + i)); + } +} +#else +/* main program */ +extern void external_callme(void (*callback)(void)); +extern void external_longjmp(char *msg); +extern void external_check_stack(void); + +static void callback(void) { + char msg[16]; /* Note: this triggers addition of a redzone. */ + /* Note: msg is passed to prevent compiler optimization from removing it. */ + external_longjmp(msg); +} + +int main() { + external_callme(callback); + external_check_stack(); + return 0; +} +#endif -- cgit v1.2.1 From b6657afbf2e4f85db5e0f27b359543c3577a8e23 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 5 May 2017 01:27:11 +0000 Subject: [XRay][compiler-rt] Add function id utilities for XRay Summary: This change allows us to provide users and implementers of XRay handlers a means of converting XRay function id's to addresses. This, in combination with the facilities provided in D32695, allows users to find out: - How many function id's there are defined in the current binary. - Get the address of the function associated with this function id. - Patch only specific functions according to their requirements. While we don't directly provide symbolization support in XRay, having the function's address lets users determine this information easily either during runtime, or offline with tools like 'addr2line'. Reviewers: dblaikie, echristo, pelikan Subscribers: kpw, llvm-commits Differential Revision: https://reviews.llvm.org/D32846 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302210 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 9 ++++++ lib/xray/xray_interface.cc | 14 ++++++++- test/xray/TestCases/Linux/func-id-utils.cc | 46 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/xray/TestCases/Linux/func-id-utils.cc diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index 469bfffe5..c90025e38 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -15,6 +15,7 @@ #define XRAY_XRAY_INTERFACE_H #include +#include extern "C" { @@ -86,6 +87,14 @@ extern XRayPatchingStatus __xray_patch_function(int32_t FuncId); /// result values. extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId); +/// This function returns the address of the function provided a valid function +/// id. We return 0 if we encounter any error, even if 0 may be a valid function +/// address. +extern uintptr_t __xray_function_address(int32_t FuncId); + +/// This function returns the maximum valid function id. Returns 0 if we +/// encounter errors (when there are no instrumented functions, etc.). +extern size_t __xray_max_function_id(); } diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 73cca80bc..26f0ab122 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -255,7 +255,7 @@ XRayPatchingStatus patchFunction(int32_t FuncId, // FuncId must be a positive number, less than the number of functions // instrumented. - if (FuncId <= 0 || static_cast(FuncId) >= InstrMap.Functions) { + if (FuncId <= 0 || static_cast(FuncId) > InstrMap.Functions) { Report("Invalid function id provided: %d\n", FuncId); return XRayPatchingStatus::FAILED; } @@ -302,3 +302,15 @@ int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { return 1; } int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } + +uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + if (FuncId <= 0 || static_cast(FuncId) > XRayInstrMap.Functions) + return 0; + return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Address; +} + +size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + return XRayInstrMap.Functions; +} diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc new file mode 100644 index 000000000..834e7b499 --- /dev/null +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -0,0 +1,46 @@ +// Check that we can turn a function id to a function address, and also get the +// maximum function id for the current binary. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s + +#include "xray/xray_interface.h" +#include +#include +#include +#include + +[[clang::xray_always_instrument]] void bar(){ + // do nothing! +} + + [[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + printf("max function id: %zu\n", __xray_max_function_id()); + // CHECK: max function id: [[MAX:.*]] + + std::set must_be_instrumented; + must_be_instrumented.insert(reinterpret_cast(&foo)); + must_be_instrumented.insert(reinterpret_cast(&bar)); + printf("addresses:\n"); + std::set all_instrumented; + for (auto i = __xray_max_function_id(); i != 0; --i) { + auto addr = __xray_function_address(i); + printf("#%lu -> @%04lx\n", i, addr); + all_instrumented.insert(reinterpret_cast(addr)); + } + + // CHECK-LABEL: addresses: + // CHECK: #[[MAX]] -> @[[ADDR:.*]] + // CHECK-NOT: #0 -> @{{.*}} + std::set common; + + std::set_intersection(all_instrumented.begin(), all_instrumented.end(), + must_be_instrumented.begin(), + must_be_instrumented.end(), + std::inserter(common, common.begin())); + return common == must_be_instrumented ? 0 : 1; +} -- cgit v1.2.1 From e498e2e10756db887cf408e2561a5fb5ec2f4cbe Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 5 May 2017 01:35:42 +0000 Subject: [ubsan] Fix error summary message for ObjC BOOL invalid loads git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302211 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 3 ++- test/ubsan/TestCases/Misc/bool.m | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/ubsan/TestCases/Misc/bool.m diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index de13ab893..d6a8f52a2 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -410,7 +410,8 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, SourceLocation Loc = Data->Loc.acquire(); // This check could be more precise if we used different handlers for // -fsanitize=bool and -fsanitize=enum. - bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")); + bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) || + (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6)); ErrorType ET = IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad; diff --git a/test/ubsan/TestCases/Misc/bool.m b/test/ubsan/TestCases/Misc/bool.m new file mode 100644 index 000000000..0430b452b --- /dev/null +++ b/test/ubsan/TestCases/Misc/bool.m @@ -0,0 +1,14 @@ +// RUN: %clang -fsanitize=bool %s -O3 -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 not %run %t 2>&1 | FileCheck %s --check-prefix=SUMMARY + +typedef char BOOL; +unsigned char NotABool = 123; + +int main(int argc, char **argv) { + BOOL *p = (BOOL*)&NotABool; + + // CHECK: bool.m:[[@LINE+1]]:10: runtime error: load of value 123, which is not a valid value for type 'BOOL' + return *p; + // SUMMARY: SUMMARY: {{.*}}Sanitizer: invalid-bool-load {{.*}}bool.m:[[@LINE-1]] +} -- cgit v1.2.1 From f8e7a418d567bfbabafbff41c9e52a8386dd1160 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 5 May 2017 01:55:13 +0000 Subject: [XRay][compiler-rt] Remove dependency on FileCheck from function id utilities tests Follow-up on D32846 to simplify testing and not rely on FileCheck to test boundary conditions, and instead do all the testing in code instead. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302212 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/func-id-utils.cc | 32 +++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc index 834e7b499..1183d01c7 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -2,45 +2,41 @@ // maximum function id for the current binary. // // RUN: %clangxx_xray -std=c++11 %s -o %t -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t #include "xray/xray_interface.h" #include +#include #include -#include #include +#include -[[clang::xray_always_instrument]] void bar(){ - // do nothing! -} +[[clang::xray_always_instrument]] void bar(){} - [[clang::xray_always_instrument]] void foo() { +[[clang::xray_always_instrument]] void foo() { bar(); } [[clang::xray_always_instrument]] int main(int argc, char *argv[]) { - printf("max function id: %zu\n", __xray_max_function_id()); - // CHECK: max function id: [[MAX:.*]] - - std::set must_be_instrumented; - must_be_instrumented.insert(reinterpret_cast(&foo)); - must_be_instrumented.insert(reinterpret_cast(&bar)); - printf("addresses:\n"); + assert(__xray_max_function_id() != 0 && "we need xray instrumentation!"); + std::set must_be_instrumented = {reinterpret_cast(&foo), + reinterpret_cast(&bar), + reinterpret_cast(&main)}; std::set all_instrumented; for (auto i = __xray_max_function_id(); i != 0; --i) { auto addr = __xray_function_address(i); - printf("#%lu -> @%04lx\n", i, addr); all_instrumented.insert(reinterpret_cast(addr)); } + assert(all_instrumented.size() == __xray_max_function_id() && + "each function id must be assigned to a unique function"); - // CHECK-LABEL: addresses: - // CHECK: #[[MAX]] -> @[[ADDR:.*]] - // CHECK-NOT: #0 -> @{{.*}} std::set common; - std::set_intersection(all_instrumented.begin(), all_instrumented.end(), must_be_instrumented.begin(), must_be_instrumented.end(), std::inserter(common, common.begin())); + assert( + common == must_be_instrumented && + "we should see all explicitly instrumented functions with function ids"); return common == must_be_instrumented ? 0 : 1; } -- cgit v1.2.1 From 4ff00356cf47a180215cf673c33228b79c5a777a Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 5 May 2017 09:02:28 +0000 Subject: [ubsan] Implement __sanitizer_print_stack_trace for standalone UBSan runtime. Patch by Max Moroz, reviewed at https://reviews.llvm.org/D32542 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302218 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 1 + lib/ubsan/ubsan_diag_standalone.cc | 37 ++++++++++++++++++++++ .../TestCases/Misc/Linux/print_stack_trace.cc | 20 ++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 lib/ubsan/ubsan_diag_standalone.cc create mode 100644 test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index f35b40f3b..7e10456e3 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -9,6 +9,7 @@ set(UBSAN_SOURCES ) set(UBSAN_STANDALONE_SOURCES + ubsan_diag_standalone.cc ubsan_init_standalone.cc ) diff --git a/lib/ubsan/ubsan_diag_standalone.cc b/lib/ubsan/ubsan_diag_standalone.cc new file mode 100644 index 000000000..df8ed5fcd --- /dev/null +++ b/lib/ubsan/ubsan_diag_standalone.cc @@ -0,0 +1,37 @@ +//===-- ubsan_diag_standalone.cc ------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Diagnostic reporting for the standalone UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB +#include "ubsan_diag.h" + +using namespace __ubsan; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_stack_trace() { + uptr top = 0; + uptr bottom = 0; + bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; + if (request_fast_unwind) + __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); + + GET_REPORT_OPTIONS(false); + BufferedStackTrace stack; + stack.Unwind(kStackTraceMax, Opts.pc, Opts.bp, nullptr, top, bottom, + request_fast_unwind); + stack.Print(); +} +} // extern "C" + +#endif // CAN_SANITIZE_UB diff --git a/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc new file mode 100644 index 000000000..f41ffbc3b --- /dev/null +++ b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s + +// The test doesn't pass on Darwin in UBSan-TSan configuration, because TSan is +// using the slow unwinder which is not supported on Darwin. The test should +// be universal after landing of https://reviews.llvm.org/D32806. + +#include + +static inline void FooBarBaz() { + __sanitizer_print_stack_trace(); +} + +int main() { + FooBarBaz(); + return 0; +} + +// CHECK: {{.*}} in FooBarBaz{{.*}}print_stack_trace.cc{{.*}} +// CHECK: {{.*}} in main{{.*}}print_stack_trace.cc{{.*}} -- cgit v1.2.1 From b5fcaaae01d4d4cc45cc203d801beb4edd74fbac Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Fri, 5 May 2017 14:20:11 +0000 Subject: [powerpc] Mark coverage-sample.cc as XFAIL on powerpc64le When run this test case causes a segementation fault on powerpc64le. The xfail should be removed when the problem is fixed. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302237 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/coverage-sample.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Linux/coverage-sample.cc index 623b4e345..df23d9f73 100644 --- a/test/xray/TestCases/Linux/coverage-sample.cc +++ b/test/xray/TestCases/Linux/coverage-sample.cc @@ -2,6 +2,9 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s +// FIXME: When run this test case causes a segementation fault on powerpc64le. +// Remove the xfail when the problem is fixed. +// XFAIL: powerpc64le #include "xray/xray_interface.h" -- cgit v1.2.1 From 5c7827db19f1b91ee4b5b12935c97c5b387af127 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 5 May 2017 14:51:16 +0000 Subject: [ubsan]: temporarily disable print_stack_trace.cc test Some problems with ARM stack unwinding led to inaccurate stack traces being printed, which caused this test to fail on http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302239 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc index f41ffbc3b..341fd7a82 100644 --- a/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc +++ b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc @@ -1,6 +1,9 @@ // RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s // RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s +// This test is temporarily disabled due to broken unwinding on ARM. +// UNSUPPORTED: -linux- + // The test doesn't pass on Darwin in UBSan-TSan configuration, because TSan is // using the slow unwinder which is not supported on Darwin. The test should // be universal after landing of https://reviews.llvm.org/D32806. -- cgit v1.2.1 From 9c750028710b8a125dd4c4f7d011af98f7830cb3 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 5 May 2017 18:46:14 +0000 Subject: CFI: Add a blacklist entry for std::_Sp_counted_ptr_inplace::_Sp_counted_ptr_inplace(). This ctor is used by std::make_shared and needs to cast to uninitialized T* in order to call std::allocator_traits::construct. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302272 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi_blacklist.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index 1f0eeb355..cc111be81 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -24,3 +24,8 @@ fun:_ZNSt3__19addressof* # Windows C++ stdlib headers that contain bad unrelated casts. src:*xmemory0 src:*xstddef + +# std::_Sp_counted_ptr_inplace::_Sp_counted_ptr_inplace() (libstdc++). +# This ctor is used by std::make_shared and needs to cast to uninitialized T* +# in order to call std::allocator_traits::construct. +fun:_ZNSt23_Sp_counted_ptr_inplace* -- cgit v1.2.1 From acd49d83b411ab2fffef9b41d313e599bfa85885 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 5 May 2017 21:38:22 +0000 Subject: [scudo] Add Android support Summary: This change adds Android support to the allocator (but doesn't yet enable it in the cmake config), and should be the last fragment of the rewritten change D31947. Android has more memory constraints than other platforms, so the idea of a unique context per thread would not have worked. The alternative chosen is to allocate a set of contexts based on the number of cores on the machine, and share those contexts within the threads. Contexts can be dynamically reassigned to threads to prevent contention, based on a scheme suggested by @dvyuokv in the initial review. Additionally, given that Android doesn't support ELF TLS (only emutls for now), we use the TSan TLS slot to make things faster: Scudo is mutually exclusive with other sanitizers so this shouldn't cause any problem. An additional change made here, is replacing `thread_local` by `THREADLOCAL` and using the initial-exec thread model in the non-Android version to prevent extraneous weak definition and checks on the relevant variables. Reviewers: kcc, dvyukov, alekseyshl Reviewed By: alekseyshl Subscribers: srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D32649 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302300 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/CMakeLists.txt | 1 + lib/scudo/scudo_allocator.cpp | 9 ++-- lib/scudo/scudo_allocator.h | 8 ++- lib/scudo/scudo_tls.h | 15 ++++-- lib/scudo/scudo_tls_android.cpp | 95 +++++++++++++++++++++++++++++++++ lib/scudo/scudo_tls_android.inc | 44 +++++++++++++++ lib/scudo/scudo_tls_context_android.inc | 54 +++++++++++++++++++ lib/scudo/scudo_tls_context_linux.inc | 29 ++++++++++ lib/scudo/scudo_tls_linux.cpp | 10 ++-- lib/scudo/scudo_tls_linux.h | 48 ----------------- lib/scudo/scudo_tls_linux.inc | 48 +++++++++++++++++ 11 files changed, 301 insertions(+), 60 deletions(-) create mode 100644 lib/scudo/scudo_tls_android.cpp create mode 100644 lib/scudo/scudo_tls_android.inc create mode 100644 lib/scudo/scudo_tls_context_android.inc create mode 100644 lib/scudo/scudo_tls_context_linux.inc delete mode 100644 lib/scudo/scudo_tls_linux.h create mode 100644 lib/scudo/scudo_tls_linux.inc diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 3a8f4ae4f..14c199fa8 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -14,6 +14,7 @@ set(SCUDO_SOURCES scudo_interceptors.cpp scudo_new_delete.cpp scudo_termination.cpp + scudo_tls_android.cpp scudo_tls_linux.cpp scudo_utils.cpp) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 2ccdcd903..5420fc964 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -368,11 +368,12 @@ struct ScudoAllocator { void *Ptr; uptr Salt; uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { Salt = getPrng(ThreadContext)->getNext(); Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), NeededSize, AllocationAlignment); + ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); Salt = FallbackPrng.getNext(); @@ -434,9 +435,10 @@ struct ScudoAllocator { if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr); + ThreadContext->unlock(); } else { SpinMutexLock Lock(&FallbackMutex); getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr); @@ -445,12 +447,13 @@ struct ScudoAllocator { UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { AllocatorQuarantine.Put(getQuarantineCache(ThreadContext), QuarantineCallback( getAllocatorCache(ThreadContext)), Chunk, Size); + ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 2cac2de71..f159deffb 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -72,7 +72,13 @@ const uptr AlignedChunkHeaderSize = #if SANITIZER_CAN_USE_ALLOCATOR64 const uptr AllocatorSpace = ~0ULL; -const uptr AllocatorSize = 0x40000000000ULL; // 4TB. +# if defined(__aarch64__) && SANITIZER_ANDROID +const uptr AllocatorSize = 0x4000000000ULL; // 256G. +# elif defined(__aarch64__) +const uptr AllocatorSize = 0x10000000000ULL; // 1T. +# else +const uptr AllocatorSize = 0x40000000000ULL; // 4T. +# endif typedef DefaultSizeClassMap SizeClassMap; struct AP { static const uptr kSpaceBeg = AllocatorSpace; diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index 0d7d1bffd..f6039bebe 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -19,10 +19,16 @@ #include "scudo_allocator.h" #include "scudo_utils.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform.h" + namespace __scudo { -struct ALIGNED(64) ScudoThreadContext { - public: +// Platform specific base thread context definitions. +#include "scudo_tls_context_android.inc" +#include "scudo_tls_context_linux.inc" + +struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { AllocatorCache Cache; Xorshift128Plus Prng; uptr QuarantineCachePlaceHolder[4]; @@ -32,8 +38,9 @@ struct ALIGNED(64) ScudoThreadContext { void initThread(); -// Fastpath functions are defined in the following platform specific headers. -#include "scudo_tls_linux.h" +// Platform specific dastpath functions definitions. +#include "scudo_tls_android.inc" +#include "scudo_tls_linux.inc" } // namespace __scudo diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp new file mode 100644 index 000000000..0e3602b2f --- /dev/null +++ b/lib/scudo/scudo_tls_android.cpp @@ -0,0 +1,95 @@ +//===-- scudo_tls_android.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure implementation for Android. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +#include "scudo_tls.h" + +#include + +namespace __scudo { + +static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; +static pthread_key_t PThreadKey; + +static atomic_uint32_t ThreadContextCurrentIndex; +static ScudoThreadContext *ThreadContexts; +static uptr NumberOfContexts; + +// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. +static uptr getNumberOfCPUs() { + cpu_set_t CPUs; + CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); + return CPU_COUNT(&CPUs); +} + +static void initOnce() { + // Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for + // testing, we create an unused key. Since the key_data array follows the tls + // array, it basically gives us the extra entry we need. + // TODO(kostyak): remove and restrict to N and above. + CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); + initScudo(); + NumberOfContexts = getNumberOfCPUs(); + ThreadContexts = reinterpret_cast( + MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__)); + for (int i = 0; i < NumberOfContexts; i++) + ThreadContexts[i].init(); +} + +void initThread() { + pthread_once(&GlobalInitialized, initOnce); + // Initial context assignment is done in a plain round-robin fashion. + u32 Index = atomic_fetch_add(&ThreadContextCurrentIndex, 1, + memory_order_relaxed); + ScudoThreadContext *ThreadContext = + &ThreadContexts[Index % NumberOfContexts]; + *get_android_tls_ptr() = reinterpret_cast(ThreadContext); +} + +ScudoThreadContext *getThreadContextAndLockSlow() { + ScudoThreadContext *ThreadContext; + // Go through all the contexts and find the first unlocked one. + for (u32 i = 0; i < NumberOfContexts; i++) { + ThreadContext = &ThreadContexts[i]; + if (ThreadContext->tryLock()) { + *get_android_tls_ptr() = reinterpret_cast(ThreadContext); + return ThreadContext; + } + } + // No luck, find the one with the lowest precedence, and slow lock it. + u64 Precedence = UINT64_MAX; + for (u32 i = 0; i < NumberOfContexts; i++) { + u64 SlowLockPrecedence = ThreadContexts[i].getSlowLockPrecedence(); + if (SlowLockPrecedence && SlowLockPrecedence < Precedence) { + ThreadContext = &ThreadContexts[i]; + Precedence = SlowLockPrecedence; + } + } + if (LIKELY(Precedence != UINT64_MAX)) { + ThreadContext->lock(); + *get_android_tls_ptr() = reinterpret_cast(ThreadContext); + return ThreadContext; + } + // Last resort (can this happen?), stick with the current one. + ThreadContext = + reinterpret_cast(*get_android_tls_ptr()); + ThreadContext->lock(); + return ThreadContext; +} + +} // namespace __scudo + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc new file mode 100644 index 000000000..8ecad7a30 --- /dev/null +++ b/lib/scudo/scudo_tls_android.inc @@ -0,0 +1,44 @@ +//===-- scudo_tls_android.inc -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure fastpath functions implementation for Android. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_ANDROID_H_ +#define SCUDO_TLS_ANDROID_H_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +ALWAYS_INLINE void initThreadMaybe() { + if (LIKELY(*get_android_tls_ptr())) + return; + initThread(); +} + +ScudoThreadContext *getThreadContextAndLockSlow(); + +ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { + ScudoThreadContext *ThreadContext = + reinterpret_cast(*get_android_tls_ptr()); + CHECK(ThreadContext); + // Try to lock the currently associated context. + if (ThreadContext->tryLock()) + return ThreadContext; + // If it failed, go the slow path. + return getThreadContextAndLockSlow(); +} + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID + +#endif // SCUDO_TLS_ANDROID_H_ diff --git a/lib/scudo/scudo_tls_context_android.inc b/lib/scudo/scudo_tls_context_android.inc new file mode 100644 index 000000000..f1951319d --- /dev/null +++ b/lib/scudo/scudo_tls_context_android.inc @@ -0,0 +1,54 @@ +//===-- scudo_tls_context_android.inc ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Android specific base thread context definition. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_CONTEXT_ANDROID_INC_ +#define SCUDO_TLS_CONTEXT_ANDROID_INC_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +struct ScudoThreadContextPlatform { + INLINE bool tryLock() { + if (Mutex.TryLock()) { + atomic_store_relaxed(&SlowLockPrecedence, 0); + return true; + } + if (atomic_load_relaxed(&SlowLockPrecedence) == 0) + atomic_store_relaxed(&SlowLockPrecedence, NanoTime()); + return false; + } + + INLINE void lock() { + Mutex.Lock(); + atomic_store_relaxed(&SlowLockPrecedence, 0); + } + + INLINE void unlock() { + Mutex.Unlock(); + } + + INLINE u64 getSlowLockPrecedence() { + return atomic_load_relaxed(&SlowLockPrecedence); + } + + private: + StaticSpinMutex Mutex; + atomic_uint64_t SlowLockPrecedence; +}; + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID + +#endif // SCUDO_TLS_CONTEXT_ANDROID_INC_ diff --git a/lib/scudo/scudo_tls_context_linux.inc b/lib/scudo/scudo_tls_context_linux.inc new file mode 100644 index 000000000..8d292bdbc --- /dev/null +++ b/lib/scudo/scudo_tls_context_linux.inc @@ -0,0 +1,29 @@ +//===-- scudo_tls_context_linux.inc -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Linux specific base thread context definition. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_CONTEXT_LINUX_INC_ +#define SCUDO_TLS_CONTEXT_LINUX_INC_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + +struct ScudoThreadContextPlatform { + ALWAYS_INLINE void unlock() {} +}; + +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#endif // SCUDO_TLS_CONTEXT_LINUX_INC_ diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index 3453367f8..5a9cc998b 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID #include "scudo_tls.h" @@ -26,8 +26,10 @@ namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; static pthread_key_t PThreadKey; -thread_local ThreadState ScudoThreadState = ThreadNotInitialized; -thread_local ScudoThreadContext ThreadLocalContext; +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ScudoThreadContext ThreadLocalContext; static void teardownThread(void *Ptr) { uptr Iteration = reinterpret_cast(Ptr); @@ -59,4 +61,4 @@ void initThread() { } // namespace __scudo -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_linux.h b/lib/scudo/scudo_tls_linux.h deleted file mode 100644 index 0994f2d7b..000000000 --- a/lib/scudo/scudo_tls_linux.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- scudo_tls_linux.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure fastpath functions implementation for platforms -/// supporting thread_local. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_LINUX_H_ -#define SCUDO_TLS_LINUX_H_ - -#ifndef SCUDO_TLS_H_ -# error "This file must be included inside scudo_tls.h." -#endif // SCUDO_TLS_H_ - -#include "sanitizer_common/sanitizer_platform.h" - -#if SANITIZER_LINUX - -enum ThreadState : u8 { - ThreadNotInitialized = 0, - ThreadInitialized, - ThreadTornDown, -}; -extern thread_local ThreadState ScudoThreadState; -extern thread_local ScudoThreadContext ThreadLocalContext; - -ALWAYS_INLINE void initThreadMaybe() { - if (LIKELY(ScudoThreadState != ThreadNotInitialized)) - return; - initThread(); -} - -ALWAYS_INLINE ScudoThreadContext *getThreadContext() { - if (UNLIKELY(ScudoThreadState == ThreadTornDown)) - return nullptr; - return &ThreadLocalContext; -} - -#endif // SANITIZER_LINUX - -#endif // SCUDO_TLS_LINUX_H_ diff --git a/lib/scudo/scudo_tls_linux.inc b/lib/scudo/scudo_tls_linux.inc new file mode 100644 index 000000000..242ee3329 --- /dev/null +++ b/lib/scudo/scudo_tls_linux.inc @@ -0,0 +1,48 @@ +//===-- scudo_tls_linux.inc -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure fastpath functions implementation for platforms +/// supporting thread_local. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_LINUX_H_ +#define SCUDO_TLS_LINUX_H_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + +enum ThreadState : u8 { + ThreadNotInitialized = 0, + ThreadInitialized, + ThreadTornDown, +}; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ThreadState ScudoThreadState; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ScudoThreadContext ThreadLocalContext; + +ALWAYS_INLINE void initThreadMaybe() { + if (LIKELY(ScudoThreadState != ThreadNotInitialized)) + return; + initThread(); +} + +ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { + if (UNLIKELY(ScudoThreadState == ThreadTornDown)) + return nullptr; + return &ThreadLocalContext; +} + +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#endif // SCUDO_TLS_LINUX_H_ -- cgit v1.2.1 From 9ae2a099f0568cc3e185aa74dbaa8db8997093a9 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 5 May 2017 23:28:47 +0000 Subject: [sanitizer-coverage] implement -fsanitize-coverage=no-prune,... instead of a hidden -mllvm flag. compiler-rt part (test only). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302321 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/sanitizer_coverage_no_prune.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc new file mode 100644 index 000000000..843053982 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -0,0 +1,15 @@ +// Tests -fsanitize-coverage=no-prune +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin +// XFAIL: tsan,powerpc64,s390x,mips +// +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 4 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 + +void foo(int *a) { + if (a) + *a = 1; +} -- cgit v1.2.1 From b9bbfab7172f6f4f76532f626b0ab489f62a8255 Mon Sep 17 00:00:00 2001 From: Martell Malone Date: Sat, 6 May 2017 15:13:17 +0000 Subject: [builtins] Fixup emulated TLS for mingw. Enabled emulated TLS on WOA for mingw Fix include for mingw Reviewed By: chapuni, mstorsjo Subscribers: compnerd, llvm-commits Differential Revision: https://reviews.llvm.org/D32681 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302340 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 3 ++- lib/builtins/emutls.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 74a6531b0..e3779ca79 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -410,7 +410,8 @@ if(MINGW) udivmoddi4.c udivmodsi4.c udivsi3.c - umoddi3.c) + umoddi3.c + emutls.c) elseif(NOT WIN32) # TODO the EABI sources should only be added to EABI targets set(arm_SOURCES diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index e8d5ddb22..12aad3a42 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -98,7 +98,7 @@ static __inline emutls_address_array* emutls_getspecific() { #else -#include +#include #include #include #include -- cgit v1.2.1 From 8743216952949d4569124930b5a8c0a5be79a5cf Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 8 May 2017 00:38:13 +0000 Subject: [XRay][compiler-rt] XFAIL on ppc Follow-up on D32846. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302392 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/func-id-utils.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc index 1183d01c7..82ba34d30 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -3,6 +3,8 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t +// FIXME: When we know why this fails in ppc, un-xfail it. +// XFAIL: powerpc64le #include "xray/xray_interface.h" #include -- cgit v1.2.1 From 9e6ab92e426d17d7c1962c4fee4ffa2084bcac30 Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Mon, 8 May 2017 15:17:43 +0000 Subject: [powerpc] Remove XFAIL for sanitizer_coverage_no_prune.cc on powerpc64 This test case works fine on powerpc64 (both BE and LE). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302430 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 843053982..96547f97b 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -2,7 +2,7 @@ // // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin -// XFAIL: tsan,powerpc64,s390x,mips +// XFAIL: tsan,s390x,mips // // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 -- cgit v1.2.1 From e12d24d3e1b367c601b6b9b6f45ede69ff03deee Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 9 May 2017 14:10:30 +0000 Subject: Avoid unnecessary calls to vm_region_recurse Summary: This should significantly improve darwin lsan performance in cases where root regions are not used. Reviewers: alekseyshl, kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32966 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302530 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index a9adcdfff..5ee1e2286 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -144,6 +144,11 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { ScanRangeForPointers(address, end_address, frontier, "GLOBAL", kReachable); + + // Recursing over the full memory map is very slow, break out + // early if we don't need the full iteration. + if (!flags()->use_root_regions || !root_regions->size()) + break; } // This additional root region scan is required on Darwin in order to -- cgit v1.2.1 From b5a980955aabf4d683d37ebbc9d48a724428786b Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 9 May 2017 15:12:38 +0000 Subject: [scudo] CRC32 optimizations Summary: This change optimizes several aspects of the checksum used for chunk headers. First, there is no point in checking the weak symbol `computeHardwareCRC32` everytime, it will either be there or not when we start, so check it once during initialization and set the checksum type accordingly. Then, the loading of `HashAlgorithm` for SSE versions (and ARM equivalent) was not optimized out, while not necessary. So I reshuffled that part of the code, which duplicates a tiny bit of code, but ends up in a much cleaner assembly (and faster as we avoid an extraneous load and some calls). The following code is the checksum at the end of `scudoMalloc` for x86_64 with full SSE 4.2, before: ``` mov rax, 0FFFFFFFFFFFFFFh shl r10, 38h mov edi, dword ptr cs:_ZN7__scudoL6CookieE ; __scudo::Cookie and r14, rax lea rsi, [r13-10h] movzx eax, cs:_ZN7__scudoL13HashAlgorithmE ; __scudo::HashAlgorithm or r14, r10 mov rbx, r14 xor bx, bx call _ZN7__scudo20computeHardwareCRC32Ejm ; __scudo::computeHardwareCRC32(uint,ulong) mov rsi, rbx mov edi, eax call _ZN7__scudo20computeHardwareCRC32Ejm ; __scudo::computeHardwareCRC32(uint,ulong) mov r14w, ax mov rax, r13 mov [r13-10h], r14 ``` After: ``` mov rax, cs:_ZN7__scudoL6CookieE ; __scudo::Cookie lea rcx, [rbx-10h] mov rdx, 0FFFFFFFFFFFFFFh and r14, rdx shl r9, 38h or r14, r9 crc32 eax, rcx mov rdx, r14 xor dx, dx mov eax, eax crc32 eax, rdx mov r14w, ax mov rax, rbx mov [rbx-10h], r14 ``` Reviewers: dvyukov, alekseyshl, kcc Reviewed By: alekseyshl Subscribers: aemerson, rengolin, llvm-commits Differential Revision: https://reviews.llvm.org/D32971 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302538 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 48 +++++++++++--------- lib/scudo/scudo_crc32.cpp | 19 +------- lib/scudo/scudo_crc32.h | 101 ++++++++++++++++++++++++++++++++++++++++++ lib/scudo/scudo_utils.h | 59 ------------------------ 4 files changed, 129 insertions(+), 98 deletions(-) create mode 100644 lib/scudo/scudo_crc32.h diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 5420fc964..2b7f099df 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "scudo_allocator.h" +#include "scudo_crc32.h" #include "scudo_tls.h" #include "scudo_utils.h" @@ -34,21 +35,28 @@ static uptr Cookie; // at compilation or at runtime. static atomic_uint8_t HashAlgorithm = { CRC32Software }; -SANITIZER_WEAK_ATTRIBUTE u32 computeHardwareCRC32(u32 Crc, uptr Data); - -INLINE u32 computeCRC32(u32 Crc, uptr Data, u8 HashType) { - // If SSE4.2 is defined here, it was enabled everywhere, as opposed to only - // for scudo_crc32.cpp. This means that other SSE instructions were likely - // emitted at other places, and as a result there is no reason to not use - // the hardware version of the CRC32. +INLINE u32 computeCRC32(uptr Crc, uptr Value, uptr *Array, uptr ArraySize) { + // If the hardware CRC32 feature is defined here, it was enabled everywhere, + // as opposed to only for scudo_crc32.cpp. This means that other hardware + // specific instructions were likely emitted at other places, and as a + // result there is no reason to not use it here. #if defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) - return computeHardwareCRC32(Crc, Data); + Crc = CRC32_INTRINSIC(Crc, Value); + for (uptr i = 0; i < ArraySize; i++) + Crc = CRC32_INTRINSIC(Crc, Array[i]); + return Crc; #else - if (computeHardwareCRC32 && HashType == CRC32Hardware) - return computeHardwareCRC32(Crc, Data); - else - return computeSoftwareCRC32(Crc, Data); -#endif // defined(__SSE4_2__) + if (atomic_load_relaxed(&HashAlgorithm) == CRC32Hardware) { + Crc = computeHardwareCRC32(Crc, Value); + for (uptr i = 0; i < ArraySize; i++) + Crc = computeHardwareCRC32(Crc, Array[i]); + return Crc; + } + Crc = computeSoftwareCRC32(Crc, Value); + for (uptr i = 0; i < ArraySize; i++) + Crc = computeSoftwareCRC32(Crc, Array[i]); + return Crc; +#endif // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) } static ScudoBackendAllocator &getBackendAllocator(); @@ -78,10 +86,8 @@ struct ScudoChunk : UnpackedHeader { ZeroChecksumHeader.Checksum = 0; uptr HeaderHolder[sizeof(UnpackedHeader) / sizeof(uptr)]; memcpy(&HeaderHolder, &ZeroChecksumHeader, sizeof(HeaderHolder)); - u8 HashType = atomic_load_relaxed(&HashAlgorithm); - u32 Crc = computeCRC32(Cookie, reinterpret_cast(this), HashType); - for (uptr i = 0; i < ARRAY_SIZE(HeaderHolder); i++) - Crc = computeCRC32(Crc, HeaderHolder[i], HashType); + u32 Crc = computeCRC32(Cookie, reinterpret_cast(this), HeaderHolder, + ARRAY_SIZE(HeaderHolder)); return static_cast(Crc); } @@ -195,10 +201,10 @@ void initScudo() { CHECK(!ScudoInitIsRunning && "Scudo init calls itself!"); ScudoInitIsRunning = true; - // Check is SSE4.2 is supported, if so, opt for the CRC32 hardware version. - if (testCPUFeature(CRC32CPUFeature)) { + // Check if hardware CRC32 is supported in the binary and by the platform, if + // so, opt for the CRC32 hardware version of the checksum. + if (computeHardwareCRC32 && testCPUFeature(CRC32CPUFeature)) atomic_store_relaxed(&HashAlgorithm, CRC32Hardware); - } initFlags(); @@ -228,7 +234,7 @@ struct QuarantineCallback { getBackendAllocator().Deallocate(Cache_, Ptr); } - /// Internal quarantine allocation and deallocation functions. + // Internal quarantine allocation and deallocation functions. void *Allocate(uptr Size) { // TODO(kostyak): figure out the best way to protect the batches. return getBackendAllocator().Allocate(Cache_, Size, MinAlignment); diff --git a/lib/scudo/scudo_crc32.cpp b/lib/scudo/scudo_crc32.cpp index 56be22f4e..a267dc4e3 100644 --- a/lib/scudo/scudo_crc32.cpp +++ b/lib/scudo/scudo_crc32.cpp @@ -12,24 +12,7 @@ /// //===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_internal_defs.h" - -// Hardware CRC32 is supported at compilation via the following: -// - for i386 & x86_64: -msse4.2 -// - for ARM & AArch64: -march=armv8-a+crc or -mcrc -// An additional check must be performed at runtime as well to make sure the -// emitted instructions are valid on the target host. - -#if defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) -# ifdef __SSE4_2__ -# include -# define CRC32_INTRINSIC FIRST_32_SECOND_64(_mm_crc32_u32, _mm_crc32_u64) -# endif -# ifdef __ARM_FEATURE_CRC32 -# include -# define CRC32_INTRINSIC FIRST_32_SECOND_64(__crc32cw, __crc32cd) -# endif -#endif // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) +#include "scudo_crc32.h" namespace __scudo { diff --git a/lib/scudo/scudo_crc32.h b/lib/scudo/scudo_crc32.h new file mode 100644 index 000000000..5ffcc6265 --- /dev/null +++ b/lib/scudo/scudo_crc32.h @@ -0,0 +1,101 @@ +//===-- scudo_crc32.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo chunk header checksum related definitions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_CRC32_H_ +#define SCUDO_CRC32_H_ + +#include "sanitizer_common/sanitizer_internal_defs.h" + +// Hardware CRC32 is supported at compilation via the following: +// - for i386 & x86_64: -msse4.2 +// - for ARM & AArch64: -march=armv8-a+crc or -mcrc +// An additional check must be performed at runtime as well to make sure the +// emitted instructions are valid on the target host. + +#if defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) +# ifdef __SSE4_2__ +# include +# define CRC32_INTRINSIC FIRST_32_SECOND_64(_mm_crc32_u32, _mm_crc32_u64) +# endif +# ifdef __ARM_FEATURE_CRC32 +# include +# define CRC32_INTRINSIC FIRST_32_SECOND_64(__crc32cw, __crc32cd) +# endif +#endif // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) + +namespace __scudo { + +enum : u8 { + CRC32Software = 0, + CRC32Hardware = 1, +}; + +const static u32 CRC32Table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +INLINE u32 computeSoftwareCRC32(u32 Crc, uptr Data) { + for (uptr i = 0; i < sizeof(Data); i++) { + Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8); + Data >>= 8; + } + return Crc; +} + +SANITIZER_WEAK_ATTRIBUTE u32 computeHardwareCRC32(u32 Crc, uptr Data); + +} // namespace __scudo + +#endif // SCUDO_CRC32_H_ diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index 484b0c859..7198476f4 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -53,65 +53,6 @@ struct Xorshift128Plus { u64 State[2]; }; -enum : u8 { - CRC32Software = 0, - CRC32Hardware = 1, -}; - -const static u32 CRC32Table[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -INLINE u32 computeSoftwareCRC32(u32 Crc, uptr Data) { - for (uptr i = 0; i < sizeof(Data); i++) { - Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8); - Data >>= 8; - } - return Crc; -} - } // namespace __scudo #endif // SCUDO_UTILS_H_ -- cgit v1.2.1 From 5a934669af71790533036d143eb26355e2b4e253 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 9 May 2017 15:54:57 +0000 Subject: Allow compiler-rt to find lld and libc++ parallel to LLVM, as in the monorepo git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302541 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32358a126..4247b40dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,14 +239,24 @@ set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx) if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) else() - set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE) + set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/../libcxx) + if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) + set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) + else() + set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE) + endif() endif() set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) set(COMPILER_RT_HAS_LLD TRUE) else() - set(COMPILER_RT_HAS_LLD FALSE) + set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld) + if(EXISTS ${COMPILER_RT_LLD_PATH}/) + set(COMPILER_RT_HAS_LLD TRUE) + else() + set(COMPILER_RT_HAS_LLD FALSE) + endif() endif() pythonize_bool(COMPILER_RT_HAS_LLD) -- cgit v1.2.1 From 91b57908e70bac0b29affae914f9da49d60d0e37 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Tue, 9 May 2017 17:58:33 +0000 Subject: [compiler-rt][mips] Fix a test for mips. GCC 4.9.2 likes the specialize one of the memcpys in msan_interceptors.cc, leading to test failure. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302561 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/chained_origin_memcpy.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc index bfe50dfec..0c94f2b13 100644 --- a/test/msan/chained_origin_memcpy.cc +++ b/test/msan/chained_origin_memcpy.cc @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { // CHECK: Uninitialized value was stored to memory at // CHECK-FULL-STACK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:}}[[@LINE-15]] -// CHECK-SHORT-STACK: {{#0 .* in __msan_memcpy .*msan_interceptors.cc:}} +// CHECK-SHORT-STACK: {{#0 .* in __msan_memcpy.*msan_interceptors.cc:}} // CHECK: Uninitialized value was stored to memory at // CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:}}[[@LINE-29]] -- cgit v1.2.1 From 6e815d2efad5e8aba85a165dfdedb871a473d283 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Tue, 9 May 2017 18:07:50 +0000 Subject: [SystemZ] Fix failures after D32542 This commit made ubsan use the fast unwinder. On SystemZ this requires test cases to be compiled with -mbackchain. That was already done for asan, but not ubsan. Add the flag for ubsan as well. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302562 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/lit.common.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index cd6d209ee..cb6a8e442 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -38,6 +38,9 @@ else: lit_config.fatal("Unknown UBSan test mode: %r" % ubsan_lit_test_mode) # Platform-specific default for lit tests. +if config.target_arch == 's390x': + # On SystemZ we need -mbackchain to make the fast unwinder work. + clang_ubsan_cflags.append("-mbackchain") if config.host_os == 'Darwin': # On Darwin, we default to `abort_on_error=1`, which would make tests run # much slower. Let's override this and run lit tests with 'abort_on_error=0'. -- cgit v1.2.1 From aac85b1c9f14e2ec088ec85c10dfe5dac0ee6f6d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Tue, 9 May 2017 18:17:26 +0000 Subject: [SystemZ] Remove XFAIL on sanitizer_coverage_no_prune.cc This test case works fine on SystemZ as well. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302563 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 96547f97b..2be8388a2 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -2,7 +2,7 @@ // // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin -// XFAIL: tsan,s390x,mips +// XFAIL: tsan,mips // // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 -- cgit v1.2.1 From dc29e454d586bbeab483418aa43c759969bcf91a Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Tue, 9 May 2017 18:29:44 +0000 Subject: [mips] Remove XFAIL from sanitizer_coverage_no_prune.cc Test is XPASSing, so remove the XFAIL marker. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302567 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 2be8388a2..875193034 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -2,7 +2,7 @@ // // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin -// XFAIL: tsan,mips +// XFAIL: tsan // // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 -- cgit v1.2.1 From 92760a25363fbcd3c9214ffe0d139c8b0f1defa1 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Tue, 9 May 2017 19:17:16 +0000 Subject: [mips] XFAIL dfsan's custom.cc test on mips64. Test was already marked as failing for mips64el. Now that it's being tested on mips64, it has to be XFAILed there as well. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302570 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/dfsan/custom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc index c96d94053..b36db01bc 100644 --- a/test/dfsan/custom.cc +++ b/test/dfsan/custom.cc @@ -3,7 +3,7 @@ // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t -// XFAIL: target-is-mips64el +// XFAIL: target-is-mips64,target-is-mips64el // Tests custom implementations of various glibc functions. -- cgit v1.2.1 From 24981c0ced4c5d8b40125c45a48a0c78f984ad4a Mon Sep 17 00:00:00 2001 From: "Ivan A. Kosarev" Date: Wed, 10 May 2017 08:06:42 +0000 Subject: [Safestack] Fix the canary test to catch the libc's message regarding stack smashing By default glibc writes its diagnostics directly to tty so the `2>&1 |` redirection in the test doesn't catch the *** stack smashing detected *** message, which in turn breaks printing the lit's progress bar. By defining the LIBC_FATAL_STDERR_ environment variable we force glibc to direct diagnostic messages to stderr. Differential Revision: https://reviews.llvm.org/D32599 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302628 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/safestack/canary.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/safestack/canary.c b/test/safestack/canary.c index c6b81f243..1ceaa5065 100644 --- a/test/safestack/canary.c +++ b/test/safestack/canary.c @@ -2,7 +2,8 @@ // RUN: %run %t.nossp 2>&1 | FileCheck --check-prefix=NOSSP %s // RUN: %clang_safestack -fstack-protector-all -D_FORTIFY_SOURCE=0 -g %s -o %t.ssp -// RUN: not --crash %run %t.ssp 2>&1 | FileCheck -check-prefix=SSP %s +// RUN: env LIBC_FATAL_STDERR_=1 not --crash %run %t.ssp 2>&1 | \ +// RUN: FileCheck -check-prefix=SSP %s // Test stack canaries on the unsafe stack. -- cgit v1.2.1 From 717ebcab7a515628f9a31e1fadeb9e8fe3c9572d Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Wed, 10 May 2017 10:58:11 +0000 Subject: [mips] XFAIL getpwnam_r_invalid_user.cc test XFAIL this test while we investigate the root cause. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302635 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc index c0d6cfea1..5bee1fb4b 100644 --- a/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc +++ b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc @@ -1,6 +1,8 @@ // Regression test for a crash in getpwnam_r and similar interceptors. // RUN: %clangxx -O0 -g %s -o %t && %run %t +// XFAIL: mips + #include #include #include -- cgit v1.2.1 From 9fc1f73b6690df0b72e7434e6bde2ca4b6f86c86 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 10 May 2017 12:18:25 +0000 Subject: [msan] Fix getmntent{_r} for empty /etc/fstab Some configuration (for instance default docker ubuntu images) uses a default empty and invalid /etc/fstab configuration file. It makes any call to getmntent return NULL and it leads to failures on Msan-aarch64{-with-call}-Test/MemorySanitizer.getmntent{_r}. This patch fixes it by creating a temporary file with some valid entries (although not valid for the system) to use along with setmntent/getmntent. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302639 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 48 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index dd81c4d79..6cae2182d 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -2203,10 +2203,51 @@ TEST(MemorySanitizer, localtime_r) { EXPECT_NE(0U, strlen(time.tm_zone)); } +#if !defined(__FreeBSD__) +/* Creates a temporary file with contents similar to /etc/fstab to be used + with getmntent{_r}. */ +class TempFstabFile { + public: + TempFstabFile() : fd (-1) { } + ~TempFstabFile() { + if (fd >= 0) + close (fd); + } + + bool Create(void) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/msan.getmntent.tmp.XXXXXX"); + + fd = mkstemp(tmpfile); + if (fd == -1) + return false; + + const char entry[] = "/dev/root / ext4 errors=remount-ro 0 1"; + size_t entrylen = sizeof(entry); + + size_t bytesWritten = write(fd, entry, entrylen); + if (entrylen != bytesWritten) + return false; + + return true; + } + + const char* FileName(void) { + return tmpfile; + } + + private: + char tmpfile[128]; + int fd; +}; +#endif + // There's no getmntent() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, getmntent) { - FILE *fp = setmntent("/etc/fstab", "r"); + TempFstabFile fstabtmp; + ASSERT_TRUE(fstabtmp.Create()); + FILE *fp = setmntent(fstabtmp.FileName(), "r"); + struct mntent *mnt = getmntent(fp); ASSERT_TRUE(mnt != NULL); ASSERT_NE(0U, strlen(mnt->mnt_fsname)); @@ -2222,7 +2263,10 @@ TEST(MemorySanitizer, getmntent) { // There's no getmntent_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, getmntent_r) { - FILE *fp = setmntent("/etc/fstab", "r"); + TempFstabFile fstabtmp; + ASSERT_TRUE(fstabtmp.Create()); + FILE *fp = setmntent(fstabtmp.FileName(), "r"); + struct mntent mntbuf; char buf[1000]; struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf)); -- cgit v1.2.1 From 45eb470c3e9e8f6993a204e247c33d4092237efe Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 10 May 2017 14:38:04 +0000 Subject: Add dyld to sanitizer procmaps on darwin Summary: Sanitizer procmaps uses dyld apis to iterate over the list of images in the process. This is much more performan than manually recursing over all of the memory regions in the process, however, dyld does not report itself in the list of images. In order to prevent reporting leaks from dyld globals and to symbolize dyld functions in stack traces, this patch special-cases dyld and ensures that it is added to the list of modules. This is accomplished by recursing through the memory map of the process until a dyld Mach header is found. While this recursion is expensive, it is run before the full set of images has been loaded in the process, so only a few calls are required. The result is cached so that it never needs to be searched for when the full process memory map exists, as this would be incredibly slow, on the order of minutes for leak sanitizer with only 25 or so libraries loaded. Reviewers: alekseyshl, kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32968 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302673 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 1 + lib/sanitizer_common/sanitizer_procmaps_mac.cc | 86 +++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 9dbb5ef0f..5aad6b959 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -70,6 +70,7 @@ class MemoryMappingLayout { bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, ModuleArch *arch, u8 *uuid, uptr *protection); + void GetSegmentAddrRange(uptr *start, uptr *end, uptr vmaddr, uptr vmsize); int current_image_; u32 current_magic_; u32 current_filetype_; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index be59b481f..edb14c304 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -18,6 +18,7 @@ #include #include +#include // These are not available in older macOS SDKs. #ifndef CPU_SUBTYPE_X86_64_H @@ -71,6 +72,9 @@ void MemoryMappingLayout::Reset() { internal_memset(current_uuid_, 0, kModuleUUIDSize); } +static const char kDyldPath[] = "/usr/lib/dyld"; +static const int kDyldImageIdx = -1; + // static void MemoryMappingLayout::CacheMemoryMappings() { // No-op on Mac for now. @@ -95,14 +99,12 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, const char *lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); const SegmentCommand* sc = (const SegmentCommand *)lc; - if (start) *start = sc->vmaddr + dlloff; + GetSegmentAddrRange(start, end, sc->vmaddr, sc->vmsize); if (protection) { // Return the initial protection. *protection = sc->initprot; } - if (end) *end = sc->vmaddr + sc->vmsize + dlloff; if (offset) { if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { *offset = sc->vmaddr; @@ -111,8 +113,12 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, } } if (filename) { - internal_strncpy(filename, _dyld_get_image_name(current_image_), - filename_size); + if (current_image_ == kDyldImageIdx) { + internal_strncpy(filename, kDyldPath, filename_size); + } else { + internal_strncpy(filename, _dyld_get_image_name(current_image_), + filename_size); + } } if (arch) { *arch = current_arch_; @@ -180,11 +186,77 @@ static bool IsModuleInstrumented(const load_command *first_lc) { return false; } +// _dyld_get_image_header() and related APIs don't report dyld itself. +// We work around this by manually recursing through the memory map +// until we hit a Mach header matching dyld instead. These recurse +// calls are expensive, but the first memory map generation occurs +// early in the process, when dyld is one of the only images loaded, +// so it will be hit after only a few iterations. +static const struct mach_header *get_dyld_image_header() { + mach_port_name_t port; + if (task_for_pid(mach_task_self(), internal_getpid(), &port) != + KERN_SUCCESS) { + return nullptr; + } + + unsigned depth = 1; + vm_size_t size = 0; + vm_address_t address = 0; + kern_return_t err = KERN_SUCCESS; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + while (true) { + struct vm_region_submap_info_64 info; + err = vm_region_recurse_64(port, &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (err != KERN_SUCCESS) return nullptr; + + if (size >= sizeof(struct mach_header) && + info.protection & MemoryMappingLayout::kProtectionRead) { + struct mach_header *hdr = (struct mach_header *)address; + if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && + hdr->filetype == MH_DYLINKER) { + return hdr; + } + } + address += size; + } +} + +// The dyld load address should be unchanged throughout process execution, +// and it is expensive to compute once many libraries have been loaded, +// so cache it here and do not reset. +static const struct mach_header *get_dyld_hdr() { + static const struct mach_header *header = get_dyld_image_header(); + return header; +} + +void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, + uptr vmaddr, uptr vmsize) { + if (current_image_ == kDyldImageIdx) { + // vmaddr is masked with 0xfffff because on macOS versions < 10.12, + // it contains an absolute address rather than an offset for dyld. + // To make matters even more complicated, this absolute address + // isn't actually the absolute segment address, but the offset portion + // of the address is accurate when combined with the dyld base address, + // and the mask will give just this offset. + if (start) *start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + if (end) *end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); + } else { + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + if (start) *start = vmaddr + dlloff; + if (end) *end = vmaddr + vmsize + dlloff; + } +} + bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, uptr *protection, ModuleArch *arch, u8 *uuid) { - for (; current_image_ >= 0; current_image_--) { - const mach_header* hdr = _dyld_get_image_header(current_image_); + for (; current_image_ >= kDyldImageIdx; current_image_--) { + const struct mach_header *hdr = + (current_image_ == kDyldImageIdx) + ? get_dyld_hdr() + : _dyld_get_image_header(current_image_); if (!hdr) continue; if (current_load_cmd_count_ < 0) { // Set up for this image; -- cgit v1.2.1 From 575a392a3cd8a1669f1665ba510c346507044061 Mon Sep 17 00:00:00 2001 From: Catherine Moore Date: Wed, 10 May 2017 15:34:25 +0000 Subject: [cmake] Disable building enable_execute_stack.c for baremetal targets. Disable building enable_execute_stack.c for targets that do not have support for mprotect(). Differential Revision: https://reviews.llvm.org/D33018 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302680 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 3 +++ lib/builtins/CMakeLists.txt | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4247b40dc..b522c340d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,9 @@ mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS) option(COMPILER_RT_BUILD_XRAY "Build xray" ON) mark_as_advanced(COMPILER_RT_BUILD_XRAY) +set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN + "Build for a bare-metal target.") + if (COMPILER_RT_STANDALONE_BUILD) load_llvm_config() diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index e3779ca79..946b912ae 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -66,7 +66,6 @@ set(GENERIC_SOURCES divti3.c divtf3.c divxc3.c - enable_execute_stack.c eprintf.c extendsfdf2.c extendhfsf2.c @@ -191,6 +190,12 @@ option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" Off) +if(NOT COMPILER_RT_BAREMETAL_BUILD) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} + enable_execute_stack.c) +endif() + if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN) set(GENERIC_SOURCES ${GENERIC_SOURCES} -- cgit v1.2.1 From ae4021dc255683b963bb012c7a4be821ea9d145d Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 10 May 2017 15:40:29 +0000 Subject: Disable static caching of dyld header on Go sanitizers This causes buildbot failures due to undefined __cxa_guard_acquire git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302681 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index edb14c304..0b2193ae7 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -227,8 +227,12 @@ static const struct mach_header *get_dyld_image_header() { // and it is expensive to compute once many libraries have been loaded, // so cache it here and do not reset. static const struct mach_header *get_dyld_hdr() { +#if !SANITIZER_GO static const struct mach_header *header = get_dyld_image_header(); return header; +#else + return get_dyld_image_header(); +#endif } void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, -- cgit v1.2.1 From 1846d403b631a38e8e4429b5c31e2c37132e416e Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Wed, 10 May 2017 16:07:03 +0000 Subject: [XRay] Fix the test func-id-utils.cc on PPC. Summary: The test fails on PPC, because the address of a function may vary depending on whether the "taker" shares the same ToC (roughly, in the same "module") as the function. Therefore the addresses of the functions taken in func-id-utils.cc may be different from the addresses taken in xray runtime. Change the test to be permissive on address comparison. Reviewers: dberris, echristo Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33026 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302686 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/func-id-utils.cc | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc index 82ba34d30..c9a2952c6 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -3,8 +3,6 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t -// FIXME: When we know why this fails in ppc, un-xfail it. -// XFAIL: powerpc64le #include "xray/xray_interface.h" #include @@ -32,13 +30,21 @@ assert(all_instrumented.size() == __xray_max_function_id() && "each function id must be assigned to a unique function"); - std::set common; - std::set_intersection(all_instrumented.begin(), all_instrumented.end(), - must_be_instrumented.begin(), - must_be_instrumented.end(), - std::inserter(common, common.begin())); + std::set not_instrumented; + const auto comp = [](void *lhs, void *rhs) { +#ifdef __PPC__ + return reinterpret_cast(lhs) + 8 < + reinterpret_cast(rhs); +#else + return lhs < rhs; +#endif + }; + std::set_difference(must_be_instrumented.begin(), must_be_instrumented.end(), + all_instrumented.begin(), all_instrumented.end(), + std::inserter(not_instrumented, not_instrumented.begin()), + comp); assert( - common == must_be_instrumented && + not_instrumented.empty() && "we should see all explicitly instrumented functions with function ids"); - return common == must_be_instrumented ? 0 : 1; + return not_instrumented.empty() ? 0 : 1; } -- cgit v1.2.1 From dedf34d8265822fc7db648a2a21245851dca2ccf Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Wed, 10 May 2017 16:28:21 +0000 Subject: [XRay] Fix XRay PPC return value bug. Summary: This bug is caused by the incorrect handling of return-value registers. According to OpenPOWER 64-Bit ELF V2 ABI 2.2.5, up to 2 general-purpose registers are going to be used for return values, and up to 8 floating point registers or vector registers are going to be used for return values. Reviewers: dberris, echristo Subscribers: nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D33027 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302691 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_trampoline_powerpc64_asm.S | 90 ++++++++++++++++++++++++---- test/xray/TestCases/Linux/coverage-sample.cc | 3 - 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/lib/xray/xray_trampoline_powerpc64_asm.S b/lib/xray/xray_trampoline_powerpc64_asm.S index d43231ead..250e2e5be 100644 --- a/lib/xray/xray_trampoline_powerpc64_asm.S +++ b/lib/xray/xray_trampoline_powerpc64_asm.S @@ -145,27 +145,91 @@ __xray_FunctionEntry: .p2align 4 __xray_FunctionExit: std 0, 16(1) - ld 0, -8(1) # FuncId - stdu 1, -72(1) -# Spill r3, f1, and vsr34, the return value registers. + stdu 1, -256(1) +# Spill r3-r4, f1-f8, and vsr34-vsr41, which are return registers. +# If this appears to be slow, the caller needs to pass in number of generic, +# floating point, and vector parameters, so that we only spill those live ones. std 3, 32(1) - mr 3, 0 - addi 4, 1, 40 - stxsdx 1, 0, 4 + ld 3, 248(1) # FuncId + std 4, 40(1) addi 4, 1, 48 + stxsdx 1, 0, 4 + addi 4, 1, 56 + stxsdx 2, 0, 4 + addi 4, 1, 64 + stxsdx 3, 0, 4 + addi 4, 1, 72 + stxsdx 4, 0, 4 + addi 4, 1, 80 + stxsdx 5, 0, 4 + addi 4, 1, 88 + stxsdx 6, 0, 4 + addi 4, 1, 96 + stxsdx 7, 0, 4 + addi 4, 1, 104 + stxsdx 8, 0, 4 + addi 4, 1, 112 stxvd2x 34, 0, 4 + addi 4, 1, 128 + stxvd2x 35, 0, 4 + addi 4, 1, 144 + stxvd2x 36, 0, 4 + addi 4, 1, 160 + stxvd2x 37, 0, 4 + addi 4, 1, 176 + stxvd2x 38, 0, 4 + addi 4, 1, 192 + stxvd2x 39, 0, 4 + addi 4, 1, 208 + stxvd2x 40, 0, 4 + addi 4, 1, 224 + stxvd2x 41, 0, 4 + std 2, 240(1) mflr 0 - std 0, 64(1) + std 0, 248(1) + li 4, 1 bl _ZN6__xray23CallXRayPatchedFunctionEi13XRayEntryType nop - ld 0, 64(1) - mtlr 0 - ld 3, 32(1) - addi 4, 1, 40 - lxsdx 1, 0, 4 + addi 4, 1, 48 + lxsdx 1, 0, 4 + addi 4, 1, 56 + lxsdx 2, 0, 4 + addi 4, 1, 64 + lxsdx 3, 0, 4 + addi 4, 1, 72 + lxsdx 4, 0, 4 + addi 4, 1, 80 + lxsdx 5, 0, 4 + addi 4, 1, 88 + lxsdx 6, 0, 4 + addi 4, 1, 96 + lxsdx 7, 0, 4 + addi 4, 1, 104 + lxsdx 8, 0, 4 + addi 4, 1, 112 lxvd2x 34, 0, 4 - addi 1, 1, 72 + addi 4, 1, 128 + lxvd2x 35, 0, 4 + addi 4, 1, 144 + lxvd2x 36, 0, 4 + addi 4, 1, 160 + lxvd2x 37, 0, 4 + addi 4, 1, 176 + lxvd2x 38, 0, 4 + addi 4, 1, 192 + lxvd2x 39, 0, 4 + addi 4, 1, 208 + lxvd2x 40, 0, 4 + addi 4, 1, 224 + lxvd2x 41, 0, 4 + ld 0, 248(1) + mtlr 0 + ld 2, 240(1) + ld 3, 32(1) + ld 4, 40(1) + + addi 1, 1, 256 ld 0, 16(1) blr diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Linux/coverage-sample.cc index df23d9f73..623b4e345 100644 --- a/test/xray/TestCases/Linux/coverage-sample.cc +++ b/test/xray/TestCases/Linux/coverage-sample.cc @@ -2,9 +2,6 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s -// FIXME: When run this test case causes a segementation fault on powerpc64le. -// Remove the xfail when the problem is fixed. -// XFAIL: powerpc64le #include "xray/xray_interface.h" -- cgit v1.2.1 From d1423875f45a73ff2f35cde0ca05feccbf318911 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 10 May 2017 16:33:43 +0000 Subject: Revert "Disable static caching of dyld header on Go sanitizers" This is a problem on more than just the go sanitizers, so it's not a good enough fix for the issue. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302692 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 0b2193ae7..edb14c304 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -227,12 +227,8 @@ static const struct mach_header *get_dyld_image_header() { // and it is expensive to compute once many libraries have been loaded, // so cache it here and do not reset. static const struct mach_header *get_dyld_hdr() { -#if !SANITIZER_GO static const struct mach_header *header = get_dyld_image_header(); return header; -#else - return get_dyld_image_header(); -#endif } void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, -- cgit v1.2.1 From 7ccb9077f2356b7c26c0715f5fd42b4c9c867944 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 10 May 2017 16:33:46 +0000 Subject: Revert "Add dyld to sanitizer procmaps on darwin" This breaks several tests because we don't always have access to __cxa_guard functions This reverts commit 45eb470c3e9e8f6993a204e247c33d4092237efe. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302693 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 1 - lib/sanitizer_common/sanitizer_procmaps_mac.cc | 86 +++----------------------- 2 files changed, 7 insertions(+), 80 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 5aad6b959..9dbb5ef0f 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -70,7 +70,6 @@ class MemoryMappingLayout { bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, ModuleArch *arch, u8 *uuid, uptr *protection); - void GetSegmentAddrRange(uptr *start, uptr *end, uptr vmaddr, uptr vmsize); int current_image_; u32 current_magic_; u32 current_filetype_; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index edb14c304..be59b481f 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -18,7 +18,6 @@ #include #include -#include // These are not available in older macOS SDKs. #ifndef CPU_SUBTYPE_X86_64_H @@ -72,9 +71,6 @@ void MemoryMappingLayout::Reset() { internal_memset(current_uuid_, 0, kModuleUUIDSize); } -static const char kDyldPath[] = "/usr/lib/dyld"; -static const int kDyldImageIdx = -1; - // static void MemoryMappingLayout::CacheMemoryMappings() { // No-op on Mac for now. @@ -99,12 +95,14 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, const char *lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); const SegmentCommand* sc = (const SegmentCommand *)lc; - GetSegmentAddrRange(start, end, sc->vmaddr, sc->vmsize); + if (start) *start = sc->vmaddr + dlloff; if (protection) { // Return the initial protection. *protection = sc->initprot; } + if (end) *end = sc->vmaddr + sc->vmsize + dlloff; if (offset) { if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { *offset = sc->vmaddr; @@ -113,12 +111,8 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, } } if (filename) { - if (current_image_ == kDyldImageIdx) { - internal_strncpy(filename, kDyldPath, filename_size); - } else { - internal_strncpy(filename, _dyld_get_image_name(current_image_), - filename_size); - } + internal_strncpy(filename, _dyld_get_image_name(current_image_), + filename_size); } if (arch) { *arch = current_arch_; @@ -186,77 +180,11 @@ static bool IsModuleInstrumented(const load_command *first_lc) { return false; } -// _dyld_get_image_header() and related APIs don't report dyld itself. -// We work around this by manually recursing through the memory map -// until we hit a Mach header matching dyld instead. These recurse -// calls are expensive, but the first memory map generation occurs -// early in the process, when dyld is one of the only images loaded, -// so it will be hit after only a few iterations. -static const struct mach_header *get_dyld_image_header() { - mach_port_name_t port; - if (task_for_pid(mach_task_self(), internal_getpid(), &port) != - KERN_SUCCESS) { - return nullptr; - } - - unsigned depth = 1; - vm_size_t size = 0; - vm_address_t address = 0; - kern_return_t err = KERN_SUCCESS; - mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; - - while (true) { - struct vm_region_submap_info_64 info; - err = vm_region_recurse_64(port, &address, &size, &depth, - (vm_region_info_t)&info, &count); - if (err != KERN_SUCCESS) return nullptr; - - if (size >= sizeof(struct mach_header) && - info.protection & MemoryMappingLayout::kProtectionRead) { - struct mach_header *hdr = (struct mach_header *)address; - if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && - hdr->filetype == MH_DYLINKER) { - return hdr; - } - } - address += size; - } -} - -// The dyld load address should be unchanged throughout process execution, -// and it is expensive to compute once many libraries have been loaded, -// so cache it here and do not reset. -static const struct mach_header *get_dyld_hdr() { - static const struct mach_header *header = get_dyld_image_header(); - return header; -} - -void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, - uptr vmaddr, uptr vmsize) { - if (current_image_ == kDyldImageIdx) { - // vmaddr is masked with 0xfffff because on macOS versions < 10.12, - // it contains an absolute address rather than an offset for dyld. - // To make matters even more complicated, this absolute address - // isn't actually the absolute segment address, but the offset portion - // of the address is accurate when combined with the dyld base address, - // and the mask will give just this offset. - if (start) *start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - if (end) *end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); - } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - if (start) *start = vmaddr + dlloff; - if (end) *end = vmaddr + vmsize + dlloff; - } -} - bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, uptr *protection, ModuleArch *arch, u8 *uuid) { - for (; current_image_ >= kDyldImageIdx; current_image_--) { - const struct mach_header *hdr = - (current_image_ == kDyldImageIdx) - ? get_dyld_hdr() - : _dyld_get_image_header(current_image_); + for (; current_image_ >= 0; current_image_--) { + const mach_header* hdr = _dyld_get_image_header(current_image_); if (!hdr) continue; if (current_load_cmd_count_ < 0) { // Set up for this image; -- cgit v1.2.1 From d414238504257845036359ce99e871f6832e7f54 Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Thu, 11 May 2017 08:53:24 +0000 Subject: [asan] Recommit of r301904: Add strndup/__strndup interceptors Fix undeclared __interceptor_malloc in esan_interceptors.cc Fix undeclared strnlen on OSX Differential Revision: https://reviews.llvm.org/D31457 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302781 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 ++ lib/asan/tests/asan_str_test.cc | 21 +++++++++++ lib/esan/esan_interceptors.cpp | 2 + lib/msan/msan_interceptors.cc | 36 ++++-------------- lib/msan/tests/msan_test.cc | 6 ++- .../sanitizer_common_interceptors.inc | 43 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_flags.inc | 3 ++ .../sanitizer_platform_interceptors.h | 14 +++++++ lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 +++ test/asan/TestCases/Posix/strndup_oob_test.cc | 26 +++++++++++++ test/msan/strndup.cc | 28 ++++++++++++++ 11 files changed, 158 insertions(+), 31 deletions(-) create mode 100644 test/asan/TestCases/Posix/strndup_oob_test.cc create mode 100644 test/msan/strndup.cc diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index c8ae3faed..6be0d6e94 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,6 +194,10 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } + if (!f->replace_str && common_flags()->intercept_strndup) { + Report("WARNING: strndup* interceptors are enabled even though " + "replace_str=0. Use intercept_strndup=0 to disable them."); + } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index c790088f8..8f4911fd9 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,6 +154,27 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } +#if SANITIZER_TEST_HAS_STRNDUP +TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { + size_t size = Ident(42); + char *str = MallocAndMemsetString(size); + char *new_str; + // Normal strndup calls. + str[size - 1] = '\0'; + new_str = strndup(str, size - 13); + free(new_str); + new_str = strndup(str + size - 1, 13); + free(new_str); + // Argument points to not allocated memory. + EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); + // Overwrite the terminating '\0' and hit unallocated memory. + str[size - 1] = 'z'; + EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); + free(str); +} +#endif // SANITIZER_TEST_HAS_STRNDUP + TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/esan/esan_interceptors.cpp b/lib/esan/esan_interceptors.cpp index 9740f4dae..62fa13c83 100644 --- a/lib/esan/esan_interceptors.cpp +++ b/lib/esan/esan_interceptors.cpp @@ -31,6 +31,8 @@ using namespace __esan; // NOLINT // Get the per-platform defines for what is possible to intercept #include "sanitizer_common/sanitizer_platform_interceptors.h" +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) + // TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming // that interception is a perf hit: should we do the same? diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 15543bd91..0f5069344 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,33 +341,6 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif -INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - // On FreeBSD strndup() leverages strnlen(). - InterceptorScope interceptor_scope; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} - -#if !SANITIZER_FREEBSD -INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(__strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} -#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) -#else -#define MSAN_MAYBE_INTERCEPT___STRNDUP -#endif - INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1371,6 +1344,13 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1538,8 +1518,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; - INTERCEPT_FUNCTION(strndup); - MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 6cae2182d..40f56270a 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,7 +1581,8 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 3); + char *x; + EXPECT_UMR(x = strndup(buf, 3)); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); @@ -1593,7 +1594,8 @@ TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 2); + char *x; + EXPECT_UMR(x = strndup(buf, 2)); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 53204b48e..3c69726d7 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,8 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_COPY_STRING +// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -217,6 +219,25 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif +#ifndef COMMON_INTERCEPTOR_COPY_STRING +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr from_length = internal_strnlen(s, size); \ + uptr copy_length = Min(size, from_length); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, copy_length + 1); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ + return new_mem; +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -300,6 +321,26 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif +#if SANITIZER_INTERCEPT_STRNDUP +INTERCEPTOR(char*, strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) +#else +#define INIT_STRNDUP +#endif // SANITIZER_INTERCEPT_STRNDUP + +#if SANITIZER_INTERCEPT___STRNDUP +INTERCEPTOR(char*, __strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) +#else +#define INIT___STRNDUP +#endif // SANITIZER_INTERCEPT___STRNDUP + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6163,6 +6204,8 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; + INIT_STRNDUP; + INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 7a5fffcf6..67a0a5810 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -195,6 +195,9 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index e5644ef25..a95497467 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,6 +25,12 @@ # define SI_NOT_WINDOWS 0 #endif +#if SANITIZER_POSIX +# define SI_POSIX 1 +#else +# define SI_POSIX 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -69,6 +75,12 @@ # define SI_UNIX_NOT_MAC 0 #endif +#if SANITIZER_LINUX && !SANITIZER_FREEBSD +# define SI_LINUX_NOT_FREEBSD 1 +# else +# define SI_LINUX_NOT_FREEBSD 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -86,6 +98,8 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX +#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index 9c162a66f..b7728d9ea 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,4 +124,10 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif +#if !defined(_MSC_VER) +# define SANITIZER_TEST_HAS_STRNDUP 1 +#else +# define SANITIZER_TEST_HAS_STRNDUP 0 +#endif + #endif // SANITIZER_TEST_UTILS_H diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc new file mode 100644 index 000000000..4367e2474 --- /dev/null +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s + +// UNSUPPORTED: win32 + +#include + +char kString[] = "foo"; + +int main(int argc, char **argv) { + char *copy = strndup(kString, 2); + int x = copy[2 + argc]; // BOOM + // CHECK: AddressSanitizer: heap-buffer-overflow + // CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]] + // CHECK-LABEL: allocated by thread T{{.*}} here: + // CHECK: #{{[01]}} {{.*}}strndup + // CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]] + // CHECK-LABEL: SUMMARY + // CHECK: strndup_oob_test.cc:[[@LINE-7]] + return x; +} diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc new file mode 100644 index 000000000..d4b9af1a9 --- /dev/null +++ b/test/msan/strndup.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s +// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s + +// UNSUPPORTED: win32 + +#include +#include +#include +#include + +int main(int argc, char **argv) { + char kString[4] = "abc"; + __msan_poison(kString + 2, 1); + char *copy = strndup(kString, 4); // BOOM + assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved. + free(copy); + return 0; + // ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4) + // ON: MemorySanitizer: use-of-uninitialized-value + // ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]] + // ON-LABEL: SUMMARY + // ON: {{.*}}strndup.cc:[[@LINE-8]] + // OFF-NOT: MemorySanitizer +} + -- cgit v1.2.1 From 236529c6cbf952c3e4a007be125629df895805d7 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Thu, 11 May 2017 09:56:01 +0000 Subject: mips] XFAIL wcsncpy.cc test. The stack unwinder fails to unwind the stack past the interceptor stack frame, resulting in a test failure. XFAIL this for now. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302783 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/wcsncpy.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/msan/wcsncpy.cc b/test/msan/wcsncpy.cc index f582c37b7..eaffbe78d 100644 --- a/test/msan/wcsncpy.cc +++ b/test/msan/wcsncpy.cc @@ -1,6 +1,8 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out +// XFAIL: mips + #include #include -- cgit v1.2.1 From 350aee2f9e695db3dd856f04dedea4bfa4b8fa86 Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Thu, 11 May 2017 11:05:52 +0000 Subject: [MSAN] test failed randomly on ARM when XFAILED for MIPS git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302786 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/wcsncpy.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/msan/wcsncpy.cc b/test/msan/wcsncpy.cc index eaffbe78d..b54ff0069 100644 --- a/test/msan/wcsncpy.cc +++ b/test/msan/wcsncpy.cc @@ -2,6 +2,7 @@ // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out // XFAIL: mips +// REQUIRES: stable-runtime #include #include -- cgit v1.2.1 From a4934b161e69be902ff13712b9feba07def0784d Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Thu, 11 May 2017 11:12:26 +0000 Subject: [msan] add a regression test for PR32842 Make sure MSan doesn't miss a bug comparing two integers with defined low bits. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302788 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/pr32842.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/msan/pr32842.c diff --git a/test/msan/pr32842.c b/test/msan/pr32842.c new file mode 100644 index 000000000..b0a05f751 --- /dev/null +++ b/test/msan/pr32842.c @@ -0,0 +1,22 @@ +// Regression test for https://bugs.llvm.org/show_bug.cgi?id=32842 +// +// RUN: %clang_msan -g %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +struct iphdr { + unsigned char pad1: 2, ihl:4, pad2: 2; +}; + +int raw_send_hdrinc(unsigned long int length) { + struct iphdr iph; + if (iph.ihl * 4 > length) { + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) { + return raw_send_hdrinc(12); +} + +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -- cgit v1.2.1 From 2536fe88a101dc259e3fb4b770a4fde935e975e6 Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Thu, 11 May 2017 11:22:04 +0000 Subject: [asan] Test 'strndup_oob_test.cc' added in r302781 fails on clang-s390x-linux. Marking it as unsupported for now to hopefully make the bot green. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302789 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/strndup_oob_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc index 4367e2474..eaed8200c 100644 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -6,7 +6,7 @@ // When built as C on Linux, strndup is transformed to __strndup. // RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: win32 +// UNSUPPORTED: win32,s390 #include -- cgit v1.2.1 From e91e7587bd44b0a99a7bbd915a7fe8cd4f1a8716 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 11 May 2017 14:04:23 +0000 Subject: Renumber test line number expectations after r302783. Also remove a confused stable-runtimes requirement. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302801 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/wcsncpy.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/msan/wcsncpy.cc b/test/msan/wcsncpy.cc index b54ff0069..6471371de 100644 --- a/test/msan/wcsncpy.cc +++ b/test/msan/wcsncpy.cc @@ -2,7 +2,6 @@ // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out // XFAIL: mips -// REQUIRES: stable-runtime #include #include @@ -30,12 +29,12 @@ int main() { } // CHECK: Uninitialized bytes in __msan_check_mem_is_initialized // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -// CHECK: in main {{.*}}wcsncpy.cc:26 +// CHECK: in main {{.*}}wcsncpy.cc:28 // CHECK: Uninitialized value was stored to memory at // CHECK: in {{[^\s]*}}wcsncpy -// CHECK: in main {{.*}}wcsncpy.cc:25 +// CHECK: in main {{.*}}wcsncpy.cc:27 // CHECK: Memory was marked as uninitialized // CHECK: in __msan_allocated_memory -// CHECK: in main {{.*}}wcsncpy.cc:23 +// CHECK: in main {{.*}}wcsncpy.cc:25 -- cgit v1.2.1 From 39596416fe951311daf94abb3ac269dcbb694735 Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Thu, 11 May 2017 16:26:50 +0000 Subject: [asan] Test 'strndup_oob_test.cc' added in r302781 fails on the clang-cmake-thumbv7-a15-full-sh bot. Marking as unsupported on armv7l-unknown-linux-gnueabihf, same as strdup_oob_test.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302807 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/strndup_oob_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc index eaed8200c..7ea0b7a33 100644 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -6,7 +6,8 @@ // When built as C on Linux, strndup is transformed to __strndup. // RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: win32,s390 +// Unwind problem on arm: "main" is missing from the allocation stack trace. +// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf #include -- cgit v1.2.1 From a5c91c22f175eddf6f2d4d244dce6ce6a2e3c9e1 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 11 May 2017 21:40:45 +0000 Subject: [scudo] Use our own combined allocator Summary: The reasoning behind this change is twofold: - the current combined allocator (sanitizer_allocator_combined.h) implements features that are not relevant for Scudo, making some code redundant, and some restrictions not pertinent (alignments for example). This forced us to do some weird things between the frontend and our secondary to make things work; - we have enough information to be able to know if a chunk will be serviced by the Primary or Secondary, allowing us to avoid extraneous calls to functions such as `PointerIsMine` or `CanAllocate`. As a result, the new scudo-specific combined allocator is very straightforward, and allows us to remove some now unnecessary code both in the frontend and the secondary. Unused functions have been left in as unimplemented for now. It turns out to also be a sizeable performance gain (3% faster in some Android memory_replay benchmarks, doing some more on other platforms). Reviewers: alekseyshl, kcc, dvyukov Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33007 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302830 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 80 ++++++++++++++------------- lib/scudo/scudo_allocator.h | 5 +- lib/scudo/scudo_allocator_combined.h | 84 ++++++++++++++++++++++++++++ lib/scudo/scudo_allocator_secondary.h | 101 +++++++++------------------------- 4 files changed, 155 insertions(+), 115 deletions(-) create mode 100644 lib/scudo/scudo_allocator_combined.h diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 2b7f099df..ce69ddf55 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -73,8 +73,9 @@ struct ScudoChunk : UnpackedHeader { // Returns the usable size for a chunk, meaning the amount of bytes from the // beginning of the user data to the end of the backend allocated chunk. uptr getUsableSize(UnpackedHeader *Header) { - uptr Size = getBackendAllocator().GetActuallyAllocatedSize( - getAllocBeg(Header)); + uptr Size = + getBackendAllocator().GetActuallyAllocatedSize(getAllocBeg(Header), + Header->FromPrimary); if (Size == 0) return 0; return Size - AlignedChunkHeaderSize - (Header->Offset << MinAlignmentLog); @@ -221,7 +222,8 @@ struct QuarantineCallback { explicit QuarantineCallback(AllocatorCache *Cache) : Cache_(Cache) {} - // Chunk recycling function, returns a quarantined chunk to the backend. + // Chunk recycling function, returns a quarantined chunk to the backend, + // first making sure it hasn't been tampered with. void Recycle(ScudoChunk *Chunk) { UnpackedHeader Header; Chunk->loadHeader(&Header); @@ -231,17 +233,19 @@ struct QuarantineCallback { } Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(&Header); - getBackendAllocator().Deallocate(Cache_, Ptr); + getBackendAllocator().Deallocate(Cache_, Ptr, Header.FromPrimary); } - // Internal quarantine allocation and deallocation functions. + // Internal quarantine allocation and deallocation functions. We first check + // that the batches are indeed serviced by the Primary. + // TODO(kostyak): figure out the best way to protect the batches. + COMPILER_CHECK(sizeof(QuarantineBatch) < SizeClassMap::kMaxSize); void *Allocate(uptr Size) { - // TODO(kostyak): figure out the best way to protect the batches. - return getBackendAllocator().Allocate(Cache_, Size, MinAlignment); + return getBackendAllocator().Allocate(Cache_, Size, MinAlignment, true); } void Deallocate(void *Ptr) { - getBackendAllocator().Deallocate(Cache_, Ptr); + getBackendAllocator().Deallocate(Cache_, Ptr, true); } AllocatorCache *Cache_; @@ -359,58 +363,55 @@ struct ScudoAllocator { Size = 1; uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize; - if (Alignment > MinAlignment) - NeededSize += Alignment; - if (NeededSize >= MaxAllowedMallocSize) + uptr AlignedSize = (Alignment > MinAlignment) ? + NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; + if (AlignedSize >= MaxAllowedMallocSize) return BackendAllocator.ReturnNullOrDieOnBadRequest(); - // Primary backed and Secondary backed allocations have a different - // treatment. We deal with alignment requirements of Primary serviced - // allocations here, but the Secondary will take care of its own alignment - // needs, which means we also have to work around some limitations of the - // combined allocator to accommodate the situation. - bool FromPrimary = PrimaryAllocator::CanAllocate(NeededSize, MinAlignment); + // Primary and Secondary backed allocations have a different treatment. We + // deal with alignment requirements of Primary serviced allocations here, + // but the Secondary will take care of its own alignment needs. + bool FromPrimary = PrimaryAllocator::CanAllocate(AlignedSize, MinAlignment); void *Ptr; uptr Salt; + uptr AllocationSize = FromPrimary ? AlignedSize : NeededSize; uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { Salt = getPrng(ThreadContext)->getNext(); Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), - NeededSize, AllocationAlignment); + AllocationSize, AllocationAlignment, + FromPrimary); ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); Salt = FallbackPrng.getNext(); - Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, NeededSize, - AllocationAlignment); + Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize, + AllocationAlignment, FromPrimary); } if (!Ptr) return BackendAllocator.ReturnNullOrDieOnOOM(); - uptr AllocBeg = reinterpret_cast(Ptr); - // If the allocation was serviced by the secondary, the returned pointer - // accounts for ChunkHeaderSize to pass the alignment check of the combined - // allocator. Adjust it here. - if (!FromPrimary) { - AllocBeg -= AlignedChunkHeaderSize; - if (Alignment > MinAlignment) - NeededSize -= Alignment; - } - // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && FromPrimary) - memset(Ptr, 0, BackendAllocator.GetActuallyAllocatedSize(Ptr)); + memset(Ptr, 0, + BackendAllocator.GetActuallyAllocatedSize(Ptr, FromPrimary)); + UnpackedHeader Header = {}; + uptr AllocBeg = reinterpret_cast(Ptr); uptr UserBeg = AllocBeg + AlignedChunkHeaderSize; - if (!IsAligned(UserBeg, Alignment)) + if (!IsAligned(UserBeg, Alignment)) { + // Since the Secondary takes care of alignment, a non-aligned pointer + // means it is from the Primary. It is also the only case where the offset + // field of the header would be non-zero. + CHECK(FromPrimary); UserBeg = RoundUpTo(UserBeg, Alignment); - CHECK_LE(UserBeg + Size, AllocBeg + NeededSize); - UnpackedHeader Header = {}; + uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg; + Header.Offset = Offset >> MinAlignmentLog; + } + CHECK_LE(UserBeg + Size, AllocBeg + AllocationSize); Header.State = ChunkAllocated; - uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg; - Header.Offset = Offset >> MinAlignmentLog; Header.AllocType = Type; if (FromPrimary) { Header.FromPrimary = FromPrimary; @@ -437,17 +438,20 @@ struct ScudoAllocator { // with no additional security value. void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header, uptr Size) { + bool FromPrimary = Header->FromPrimary; bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0); if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { - getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr); + getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr, + FromPrimary); ThreadContext->unlock(); } else { SpinMutexLock Lock(&FallbackMutex); - getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr); + getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr, + FromPrimary); } } else { UnpackedHeader NewHeader = *Header; diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index f159deffb..2dad7320c 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -107,11 +107,12 @@ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap, #endif // SANITIZER_CAN_USE_ALLOCATOR64 #include "scudo_allocator_secondary.h" +#include "scudo_allocator_combined.h" typedef SizeClassAllocatorLocalCache AllocatorCache; typedef ScudoLargeMmapAllocator SecondaryAllocator; -typedef CombinedAllocator - ScudoBackendAllocator; +typedef ScudoCombinedAllocator ScudoBackendAllocator; void initScudo(); diff --git a/lib/scudo/scudo_allocator_combined.h b/lib/scudo/scudo_allocator_combined.h new file mode 100644 index 000000000..c978db55a --- /dev/null +++ b/lib/scudo/scudo_allocator_combined.h @@ -0,0 +1,84 @@ +//===-- scudo_allocator_combined.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo Combined Allocator, dispatches allocation & deallocation requests to +/// the Primary or the Secondary backend allocators. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_ALLOCATOR_COMBINED_H_ +#define SCUDO_ALLOCATOR_COMBINED_H_ + +#ifndef SCUDO_ALLOCATOR_H_ +#error "This file must be included inside scudo_allocator.h." +#endif + +template +class ScudoCombinedAllocator { + public: + void Init(bool AllocatorMayReturnNull, s32 ReleaseToOSIntervalMs) { + Primary.Init(ReleaseToOSIntervalMs); + Secondary.Init(AllocatorMayReturnNull); + Stats.Init(); + atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); + } + + void *Allocate(AllocatorCache *Cache, uptr Size, uptr Alignment, + bool FromPrimary) { + if (FromPrimary) + return Cache->Allocate(&Primary, Primary.ClassID(Size)); + return Secondary.Allocate(&Stats, Size, Alignment); + } + + void *ReturnNullOrDieOnBadRequest() { + if (atomic_load_relaxed(&MayReturnNull)) + return nullptr; + ReportAllocatorCannotReturnNull(false); + } + + void *ReturnNullOrDieOnOOM() { + if (atomic_load_relaxed(&MayReturnNull)) + return nullptr; + ReportAllocatorCannotReturnNull(true); + } + + void Deallocate(AllocatorCache *Cache, void *Ptr, bool FromPrimary) { + if (FromPrimary) + Cache->Deallocate(&Primary, Primary.GetSizeClass(Ptr), Ptr); + else + Secondary.Deallocate(&Stats, Ptr); + } + + uptr GetActuallyAllocatedSize(void *Ptr, bool FromPrimary) { + if (FromPrimary) + return Primary.GetActuallyAllocatedSize(Ptr); + return Secondary.GetActuallyAllocatedSize(Ptr); + } + + void InitCache(AllocatorCache *Cache) { + Cache->Init(&Stats); + } + + void DestroyCache(AllocatorCache *Cache) { + Cache->Destroy(&Primary, &Stats); + } + + void GetStats(AllocatorStatCounters StatType) const { + Stats.Get(StatType); + } + + private: + PrimaryAllocator Primary; + SecondaryAllocator Secondary; + AllocatorGlobalStats Stats; + atomic_uint8_t MayReturnNull; +}; + +#endif // SCUDO_ALLOCATOR_COMBINED_H_ diff --git a/lib/scudo/scudo_allocator_secondary.h b/lib/scudo/scudo_allocator_secondary.h index fbc7f247d..2950909b5 100644 --- a/lib/scudo/scudo_allocator_secondary.h +++ b/lib/scudo/scudo_allocator_secondary.h @@ -26,20 +26,19 @@ class ScudoLargeMmapAllocator { void Init(bool AllocatorMayReturnNull) { PageSize = GetPageSizeCached(); - atomic_store(&MayReturnNull, AllocatorMayReturnNull, memory_order_relaxed); + atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); } void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) { + uptr UserSize = Size - AlignedChunkHeaderSize; // The Scudo frontend prevents us from allocating more than // MaxAllowedMallocSize, so integer overflow checks would be superfluous. uptr MapSize = Size + SecondaryHeaderSize; + if (Alignment > MinAlignment) + MapSize += Alignment; MapSize = RoundUpTo(MapSize, PageSize); // Account for 2 guard pages, one before and one after the chunk. MapSize += 2 * PageSize; - // The size passed to the Secondary comprises the alignment, if large - // enough. Subtract it here to get the requested size, including header. - if (Alignment > MinAlignment) - Size -= Alignment; uptr MapBeg = reinterpret_cast(MmapNoAccess(MapSize)); if (MapBeg == ~static_cast(0)) @@ -51,32 +50,32 @@ class ScudoLargeMmapAllocator { // initial guard page, and both headers. This is the pointer that has to // abide by alignment requirements. uptr UserBeg = MapBeg + PageSize + HeadersSize; + uptr UserEnd = UserBeg + UserSize; // In the rare event of larger alignments, we will attempt to fit the mmap // area better and unmap extraneous memory. This will also ensure that the // offset and unused bytes field of the header stay small. if (Alignment > MinAlignment) { - if (UserBeg & (Alignment - 1)) - UserBeg += Alignment - (UserBeg & (Alignment - 1)); - CHECK_GE(UserBeg, MapBeg); - uptr NewMapBeg = RoundDownTo(UserBeg - HeadersSize, PageSize) - PageSize; - CHECK_GE(NewMapBeg, MapBeg); - uptr NewMapEnd = RoundUpTo(UserBeg + (Size - AlignedChunkHeaderSize), - PageSize) + PageSize; - CHECK_LE(NewMapEnd, MapEnd); - // Unmap the extra memory if it's large enough, on both sides. - uptr Diff = NewMapBeg - MapBeg; - if (Diff > PageSize) - UnmapOrDie(reinterpret_cast(MapBeg), Diff); - Diff = MapEnd - NewMapEnd; - if (Diff > PageSize) - UnmapOrDie(reinterpret_cast(NewMapEnd), Diff); - MapBeg = NewMapBeg; - MapEnd = NewMapEnd; - MapSize = NewMapEnd - NewMapBeg; + if (!IsAligned(UserBeg, Alignment)) { + UserBeg = RoundUpTo(UserBeg, Alignment); + CHECK_GE(UserBeg, MapBeg); + uptr NewMapBeg = RoundDownTo(UserBeg - HeadersSize, PageSize) - + PageSize; + CHECK_GE(NewMapBeg, MapBeg); + if (NewMapBeg != MapBeg) { + UnmapOrDie(reinterpret_cast(MapBeg), NewMapBeg - MapBeg); + MapBeg = NewMapBeg; + } + UserEnd = UserBeg + UserSize; + } + uptr NewMapEnd = RoundUpTo(UserEnd, PageSize) + PageSize; + if (NewMapEnd != MapEnd) { + UnmapOrDie(reinterpret_cast(NewMapEnd), MapEnd - NewMapEnd); + MapEnd = NewMapEnd; + } + MapSize = MapEnd - MapBeg; } - uptr UserEnd = UserBeg + (Size - AlignedChunkHeaderSize); CHECK_LE(UserEnd, MapEnd - PageSize); // Actually mmap the memory, preserving the guard pages on either side. CHECK_EQ(MapBeg + PageSize, reinterpret_cast( @@ -94,25 +93,15 @@ class ScudoLargeMmapAllocator { Stats->Add(AllocatorStatMapped, MapSize - 2 * PageSize); } - return reinterpret_cast(UserBeg); - } - - void *ReturnNullOrDieOnBadRequest() { - if (atomic_load(&MayReturnNull, memory_order_acquire)) - return nullptr; - ReportAllocatorCannotReturnNull(false); + return reinterpret_cast(Ptr); } void *ReturnNullOrDieOnOOM() { - if (atomic_load(&MayReturnNull, memory_order_acquire)) + if (atomic_load_relaxed(&MayReturnNull)) return nullptr; ReportAllocatorCannotReturnNull(true); } - void SetMayReturnNull(bool AllocatorMayReturnNull) { - atomic_store(&MayReturnNull, AllocatorMayReturnNull, memory_order_release); - } - void Deallocate(AllocatorStats *Stats, void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); { @@ -123,14 +112,6 @@ class ScudoLargeMmapAllocator { UnmapOrDie(reinterpret_cast(Header->MapBeg), Header->MapSize); } - uptr TotalMemoryUsed() { - UNIMPLEMENTED(); - } - - bool PointerIsMine(const void *Ptr) { - UNIMPLEMENTED(); - } - uptr GetActuallyAllocatedSize(void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); // Deduct PageSize as MapSize includes the trailing guard page. @@ -138,39 +119,9 @@ class ScudoLargeMmapAllocator { return MapEnd - reinterpret_cast(Ptr); } - void *GetMetaData(const void *Ptr) { - UNIMPLEMENTED(); - } - - void *GetBlockBegin(const void *Ptr) { - UNIMPLEMENTED(); - } - - void *GetBlockBeginFastLocked(void *Ptr) { - UNIMPLEMENTED(); - } - - void PrintStats() { - UNIMPLEMENTED(); - } - - void ForceLock() { - UNIMPLEMENTED(); - } - - void ForceUnlock() { - UNIMPLEMENTED(); - } - - void ForEachChunk(ForEachChunkCallback Callback, void *Arg) { - UNIMPLEMENTED(); - } - private: // A Secondary allocated chunk header contains the base of the mapping and - // its size. Currently, the base is always a page before the header, but - // we might want to extend that number in the future based on the size of - // the allocation. + // its size, which comprises the guard pages. struct SecondaryHeader { uptr MapBeg; uptr MapSize; -- cgit v1.2.1 From f9947480f58b10f2460df24287f95357082b6563 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 12 May 2017 01:07:41 +0000 Subject: [XRay][compiler-rt] Runtime changes to support custom event logging Summary: This change implements support for the custom event logging sleds and intrinsics at runtime. For now it only supports handling the sleds in x86_64, with the implementations for other architectures stubbed out to do nothing. NOTE: Work in progress, uploaded for exposition/exploration purposes. Depends on D27503, D30018, and D33032. Reviewers: echristo, javed.absar, timshen Subscribers: mehdi_amini, nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D30630 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302857 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 4 + lib/xray/xray_AArch64.cc | 13 +- lib/xray/xray_arm.cc | 12 +- lib/xray/xray_fdr_log_records.h | 1 + lib/xray/xray_fdr_logging.cc | 150 ++++++++++----- lib/xray/xray_fdr_logging_impl.h | 223 ++++++++++++++-------- lib/xray/xray_interface.cc | 21 +- lib/xray/xray_interface_internal.h | 2 + lib/xray/xray_mips.cc | 9 +- lib/xray/xray_mips64.cc | 8 +- lib/xray/xray_powerpc64.cc | 6 + lib/xray/xray_trampoline_x86_64.S | 46 ++++- lib/xray/xray_x86_64.cc | 36 ++++ test/xray/TestCases/Linux/custom-event-logging.cc | 38 ++++ 14 files changed, 429 insertions(+), 140 deletions(-) create mode 100644 test/xray/TestCases/Linux/custom-event-logging.cc diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index c90025e38..aea43517d 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -25,6 +25,7 @@ enum XRayEntryType { EXIT = 1, TAIL = 2, LOG_ARGS_ENTRY = 3, + CUSTOM_EVENT = 4, }; /// Provide a function to invoke for when instrumentation points are hit. This @@ -64,6 +65,9 @@ extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); /// Returns 1 on success, 0 on error. extern int __xray_remove_handler_arg1(); +/// Provide a function to invoke when XRay encounters a custom event. +extern int __xray_set_customevent_handler(void (*entry)(void*, std::size_t)); + enum XRayPatchingStatus { NOT_INITIALIZED = 0, SUCCESS = 1, diff --git a/lib/xray/xray_AArch64.cc b/lib/xray/xray_AArch64.cc index 8d1c7c5d8..372c1ad87 100644 --- a/lib/xray/xray_AArch64.cc +++ b/lib/xray/xray_AArch64.cc @@ -18,8 +18,7 @@ #include #include - -extern "C" void __clear_cache(void* start, void* end); +extern "C" void __clear_cache(void *start, void *end); namespace __xray { @@ -86,8 +85,8 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, reinterpret_cast *>(FirstAddress), uint32_t(PatchOpcodes::PO_B32), std::memory_order_release); } - __clear_cache(reinterpret_cast(FirstAddress), - reinterpret_cast(CurAddress)); + __clear_cache(reinterpret_cast(FirstAddress), + reinterpret_cast(CurAddress)); return true; } @@ -107,6 +106,12 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit); } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySled &Sled) + XRAY_NEVER_INSTRUMENT { // FIXME: Implement in aarch64? + return false; +} + // FIXME: Maybe implement this better? bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } diff --git a/lib/xray/xray_arm.cc b/lib/xray/xray_arm.cc index 26d673ec2..94e1c2638 100644 --- a/lib/xray/xray_arm.cc +++ b/lib/xray/xray_arm.cc @@ -18,7 +18,7 @@ #include #include -extern "C" void __clear_cache(void* start, void* end); +extern "C" void __clear_cache(void *start, void *end); namespace __xray { @@ -122,8 +122,8 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, reinterpret_cast *>(FirstAddress), uint32_t(PatchOpcodes::PO_B20), std::memory_order_release); } - __clear_cache(reinterpret_cast(FirstAddress), - reinterpret_cast(CurAddress)); + __clear_cache(reinterpret_cast(FirstAddress), + reinterpret_cast(CurAddress)); return true; } @@ -143,6 +143,12 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit); } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySled &Sled) + XRAY_NEVER_INSTRUMENT { // FIXME: Implement in arm? + return false; +} + // FIXME: Maybe implement this better? bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } diff --git a/lib/xray/xray_fdr_log_records.h b/lib/xray/xray_fdr_log_records.h index 36d9410d1..3d6d38892 100644 --- a/lib/xray/xray_fdr_log_records.h +++ b/lib/xray/xray_fdr_log_records.h @@ -29,6 +29,7 @@ struct alignas(16) MetadataRecord { NewCPUId, TSCWrap, WalltimeMarker, + CustomEventMarker, }; // Use 7 bits to identify this record type. /* RecordKinds */ uint8_t RecordKind : 7; diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index e538b477a..a7e1382c3 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -41,45 +41,12 @@ namespace __xray { // Global BufferQueue. std::shared_ptr BQ; -__sanitizer::atomic_sint32_t LoggingStatus = { - XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; - __sanitizer::atomic_sint32_t LogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; -std::unique_ptr FDROptions; - -XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, - void *Options, - size_t OptionsSize) XRAY_NEVER_INSTRUMENT { - if (OptionsSize != sizeof(FDRLoggingOptions)) - return static_cast(__sanitizer::atomic_load( - &LoggingStatus, __sanitizer::memory_order_acquire)); - s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; - if (!__sanitizer::atomic_compare_exchange_strong( - &LoggingStatus, &CurrentStatus, - XRayLogInitStatus::XRAY_LOG_INITIALIZING, - __sanitizer::memory_order_release)) - return static_cast(CurrentStatus); - - FDROptions.reset(new FDRLoggingOptions()); - memcpy(FDROptions.get(), Options, OptionsSize); - bool Success = false; - BQ = std::make_shared(BufferSize, BufferMax, Success); - if (!Success) { - Report("BufferQueue init failed.\n"); - return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; - } - - // Install the actual handleArg0 handler after initialising the buffers. - __xray_set_handler(fdrLoggingHandleArg0); +FDRLoggingOptions FDROptions; - __sanitizer::atomic_store(&LoggingStatus, - XRayLogInitStatus::XRAY_LOG_INITIALIZED, - __sanitizer::memory_order_release); - Report("XRay FDR init successful.\n"); - return XRayLogInitStatus::XRAY_LOG_INITIALIZED; -} +__sanitizer::SpinMutex FDROptionsMutex; // Must finalize before flushing. XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { @@ -108,7 +75,11 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { // (fixed-sized) and let the tools reading the buffers deal with the data // afterwards. // - int Fd = FDROptions->Fd; + int Fd = -1; + { + __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); + Fd = FDROptions.Fd; + } if (Fd == -1) Fd = getLogFD(); if (Fd == -1) { @@ -120,8 +91,8 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { // Test for required CPU features and cache the cycle frequency static bool TSCSupported = probeRequiredCPUFeatures(); - static uint64_t CycleFrequency = TSCSupported ? getTSCFrequency() - : __xray::NanosecondsPerSecond; + static uint64_t CycleFrequency = + TSCSupported ? getTSCFrequency() : __xray::NanosecondsPerSecond; XRayFileHeader Header; Header.Version = 1; @@ -192,8 +163,8 @@ XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; } -void fdrLoggingHandleArg0(int32_t FuncId, - XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { +static std::tuple +getTimestamp() XRAY_NEVER_INSTRUMENT { // We want to get the TSC as early as possible, so that we can check whether // we've seen this CPU before. We also do it before we load anything else, to // allow for forward progress with the scheduling. @@ -203,7 +174,7 @@ void fdrLoggingHandleArg0(int32_t FuncId, // Test once for required CPU features static bool TSCSupported = probeRequiredCPUFeatures(); - if(TSCSupported) { + if (TSCSupported) { TSC = __xray::readTSC(CPU); } else { // FIXME: This code needs refactoring as it appears in multiple locations @@ -216,9 +187,102 @@ void fdrLoggingHandleArg0(int32_t FuncId, CPU = 0; TSC = TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; } + return std::make_tuple(TSC, CPU); +} + +void fdrLoggingHandleArg0(int32_t FuncId, + XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { + auto TSC_CPU = getTimestamp(); + __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), + std::get<1>(TSC_CPU), clock_gettime, + LoggingStatus, BQ); +} - __xray_fdr_internal::processFunctionHook(FuncId, Entry, TSC, CPU, - clock_gettime, LoggingStatus, BQ); +void fdrLoggingHandleCustomEvent(void *Event, + std::size_t EventSize) XRAY_NEVER_INSTRUMENT { + using namespace __xray_fdr_internal; + auto TSC_CPU = getTimestamp(); + auto &TSC = std::get<0>(TSC_CPU); + auto &CPU = std::get<1>(TSC_CPU); + thread_local bool Running = false; + RecursionGuard Guard{Running}; + if (!Guard) { + assert(Running && "RecursionGuard is buggy!"); + return; + } + if (EventSize > std::numeric_limits::max()) { + using Empty = struct {}; + static Empty Once = [&] { + Report("Event size too large = %zu ; > max = %d\n", EventSize, + std::numeric_limits::max()); + return Empty(); + }(); + (void)Once; + } + int32_t ReducedEventSize = static_cast(EventSize); + if (!isLogInitializedAndReady(LocalBQ, TSC, CPU, clock_gettime)) + return; + + // Here we need to prepare the log to handle: + // - The metadata record we're going to write. (16 bytes) + // - The additional data we're going to write. Currently, that's the size of + // the event we're going to dump into the log as free-form bytes. + if (!prepareBuffer(clock_gettime, MetadataRecSize + EventSize)) { + LocalBQ = nullptr; + return; + } + + // Write the custom event metadata record, which consists of the following + // information: + // - 8 bytes (64-bits) for the full TSC when the event started. + // - 4 bytes (32-bits) for the length of the data. + MetadataRecord CustomEvent; + CustomEvent.Type = uint8_t(RecordType::Metadata); + CustomEvent.RecordKind = + uint8_t(MetadataRecord::RecordKinds::CustomEventMarker); + constexpr auto TSCSize = sizeof(std::get<0>(TSC_CPU)); + std::memcpy(&CustomEvent.Data, &ReducedEventSize, sizeof(int32_t)); + std::memcpy(&CustomEvent.Data[sizeof(int32_t)], &TSC, TSCSize); + std::memcpy(RecordPtr, &CustomEvent, sizeof(CustomEvent)); + RecordPtr += sizeof(CustomEvent); + std::memcpy(RecordPtr, Event, ReducedEventSize); + endBufferIfFull(); +} + +XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, + void *Options, + size_t OptionsSize) XRAY_NEVER_INSTRUMENT { + if (OptionsSize != sizeof(FDRLoggingOptions)) + return static_cast(__sanitizer::atomic_load( + &LoggingStatus, __sanitizer::memory_order_acquire)); + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + if (!__sanitizer::atomic_compare_exchange_strong( + &LoggingStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZING, + __sanitizer::memory_order_release)) + return static_cast(CurrentStatus); + + { + __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); + memcpy(&FDROptions, Options, OptionsSize); + } + + bool Success = false; + BQ = std::make_shared(BufferSize, BufferMax, Success); + if (!Success) { + Report("BufferQueue init failed.\n"); + return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + } + + // Install the actual handleArg0 handler after initialising the buffers. + __xray_set_handler(fdrLoggingHandleArg0); + __xray_set_customevent_handler(fdrLoggingHandleCustomEvent); + + __sanitizer::atomic_store(&LoggingStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZED, + __sanitizer::memory_order_release); + Report("XRay FDR init successful.\n"); + return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } } // namespace __xray diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index ce360cb03..c801babc3 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -37,6 +37,9 @@ namespace __xray { +__sanitizer::atomic_sint32_t LoggingStatus = { + XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; + /// We expose some of the state transitions when FDR logging mode is operating /// such that we can simulate a series of log events that may occur without /// and test with determinism without worrying about the real CPU time. @@ -123,12 +126,21 @@ thread_local uint8_t NumTailCalls = 0; constexpr auto MetadataRecSize = sizeof(MetadataRecord); constexpr auto FunctionRecSize = sizeof(FunctionRecord); +// We use a thread_local variable to keep track of which CPUs we've already +// run, and the TSC times for these CPUs. This allows us to stop repeating the +// CPU field in the function records. +// +// We assume that we'll support only 65536 CPUs for x86_64. +thread_local uint16_t CurrentCPU = std::numeric_limits::max(); +thread_local uint64_t LastTSC = 0; +thread_local uint64_t LastFunctionEntryTSC = 0; + class ThreadExitBufferCleanup { - std::weak_ptr Buffers; + std::shared_ptr &Buffers; BufferQueue::Buffer &Buffer; public: - explicit ThreadExitBufferCleanup(std::weak_ptr BQ, + explicit ThreadExitBufferCleanup(std::shared_ptr &BQ, BufferQueue::Buffer &Buffer) XRAY_NEVER_INSTRUMENT : Buffers(BQ), Buffer(Buffer) {} @@ -142,17 +154,24 @@ public: // the queue. assert((RecordPtr + MetadataRecSize) - static_cast(Buffer.Buffer) >= static_cast(MetadataRecSize)); - if (auto BQ = Buffers.lock()) { + if (Buffers) { writeEOBMetadata(); - auto EC = BQ->releaseBuffer(Buffer); + auto EC = Buffers->releaseBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, BufferQueue::getErrorString(EC)); + Buffers = nullptr; return; } } }; +// Make sure a thread that's ever called handleArg0 has a thread-local +// live reference to the buffer queue for this particular instance of +// FDRLogging, and that we're going to clean it up when the thread exits. +thread_local std::shared_ptr LocalBQ = nullptr; +thread_local ThreadExitBufferCleanup Cleanup(LocalBQ, Buffer); + class RecursionGuard { bool &Running; const bool Valid; @@ -176,7 +195,7 @@ public: } }; -static inline bool loggingInitialized( +inline bool loggingInitialized( const __sanitizer::atomic_sint32_t &LoggingStatus) XRAY_NEVER_INSTRUMENT { return __sanitizer::atomic_load(&LoggingStatus, __sanitizer::memory_order_acquire) == @@ -185,7 +204,7 @@ static inline bool loggingInitialized( } // namespace -static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, +inline void writeNewBufferPreamble(pid_t Tid, timespec TS, char *&MemPtr) XRAY_NEVER_INSTRUMENT { static constexpr int InitRecordsCount = 2; std::aligned_storage::type Records[InitRecordsCount]; @@ -222,9 +241,8 @@ static inline void writeNewBufferPreamble(pid_t Tid, timespec TS, NumTailCalls = 0; } -static inline void setupNewBuffer(int (*wall_clock_reader)(clockid_t, - struct timespec *)) - XRAY_NEVER_INSTRUMENT { +inline void setupNewBuffer(int (*wall_clock_reader)( + clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { RecordPtr = static_cast(Buffer.Buffer); pid_t Tid = syscall(SYS_gettid); timespec TS{0, 0}; @@ -235,7 +253,7 @@ static inline void setupNewBuffer(int (*wall_clock_reader)(clockid_t, NumTailCalls = 0; } -static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, +inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, char *&MemPtr) XRAY_NEVER_INSTRUMENT { MetadataRecord NewCPUId; NewCPUId.Type = uint8_t(RecordType::Metadata); @@ -253,12 +271,12 @@ static inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, NumTailCalls = 0; } -static inline void writeNewCPUIdMetadata(uint16_t CPU, +inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC) XRAY_NEVER_INSTRUMENT { writeNewCPUIdMetadata(CPU, TSC, RecordPtr); } -static inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { +inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { MetadataRecord EOBMeta; EOBMeta.Type = uint8_t(RecordType::Metadata); EOBMeta.RecordKind = uint8_t(MetadataRecord::RecordKinds::EndOfBuffer); @@ -269,11 +287,11 @@ static inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { NumTailCalls = 0; } -static inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { +inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { writeEOBMetadata(RecordPtr); } -static inline void writeTSCWrapMetadata(uint64_t TSC, +inline void writeTSCWrapMetadata(uint64_t TSC, char *&MemPtr) XRAY_NEVER_INSTRUMENT { MetadataRecord TSCWrap; TSCWrap.Type = uint8_t(RecordType::Metadata); @@ -289,11 +307,11 @@ static inline void writeTSCWrapMetadata(uint64_t TSC, NumTailCalls = 0; } -static inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { +inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { writeTSCWrapMetadata(TSC, RecordPtr); } -static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, +inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, XRayEntryType EntryType, char *&MemPtr) XRAY_NEVER_INSTRUMENT { std::aligned_storage::type @@ -339,6 +357,17 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); break; + case XRayEntryType::CUSTOM_EVENT: { + // This is a bug in patching, so we'll report it once and move on. + static bool Once = [&] { + Report("Internal error: patched an XRay custom event call as a function; " + "func id = %d\n", + FuncId); + return true; + }(); + (void)Once; + return; + } } std::memcpy(MemPtr, &AlignedFuncRecordBuffer, sizeof(FunctionRecord)); @@ -346,8 +375,9 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, } static uint64_t thresholdTicks() { - static uint64_t TicksPerSec = probeRequiredCPUFeatures() ? getTSCFrequency() : - __xray::NanosecondsPerSecond; + static uint64_t TicksPerSec = probeRequiredCPUFeatures() + ? getTSCFrequency() + : __xray::NanosecondsPerSecond; static const uint64_t ThresholdTicks = TicksPerSec * flags()->xray_fdr_log_func_duration_threshold_us / 1000000; return ThresholdTicks; @@ -397,9 +427,8 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, RewindingRecordPtr -= FunctionRecSize; RewindingTSC -= ExpectedTailExit.TSCDelta; AlignedFuncStorage FunctionEntryBuffer; - const auto &ExpectedFunctionEntry = - *reinterpret_cast(std::memcpy( - &FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); + const auto &ExpectedFunctionEntry = *reinterpret_cast( + std::memcpy(&FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); assert(ExpectedFunctionEntry.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && "Expected to find function entry when rewinding tail call."); @@ -422,7 +451,7 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, } } -static inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { +inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { auto EC = BQ->releaseBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, @@ -432,11 +461,29 @@ static inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { return true; } -static inline void processFunctionHook( - int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, - int (*wall_clock_reader)(clockid_t, struct timespec *), - __sanitizer::atomic_sint32_t &LoggingStatus, - const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { +inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, + struct timespec *), + size_t MaxSize) XRAY_NEVER_INSTRUMENT { + char *BufferStart = static_cast(Buffer.Buffer); + if ((RecordPtr + MaxSize) > (BufferStart + Buffer.Size - MetadataRecSize)) { + writeEOBMetadata(); + if (!releaseThreadLocalBuffer(LocalBQ.get())) + return false; + auto EC = LocalBQ->getBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) { + Report("Failed to acquire a buffer; error=%s\n", + BufferQueue::getErrorString(EC)); + return false; + } + setupNewBuffer(wall_clock_reader); + } + return true; +} + +inline bool isLogInitializedAndReady( + std::shared_ptr &LocalBQ, uint64_t TSC, unsigned char CPU, + int (*wall_clock_reader)(clockid_t, + struct timespec *)) XRAY_NEVER_INSTRUMENT { // Bail out right away if logging is not initialized yet. // We should take the opportunity to release the buffer though. auto Status = __sanitizer::atomic_load(&LoggingStatus, @@ -446,44 +493,19 @@ static inline void processFunctionHook( (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(BQ.get())) - return; + if (!releaseThreadLocalBuffer(LocalBQ.get())) + return false; RecordPtr = nullptr; + LocalBQ = nullptr; + return false; } - return; - } - - // We use a thread_local variable to keep track of which CPUs we've already - // run, and the TSC times for these CPUs. This allows us to stop repeating the - // CPU field in the function records. - // - // We assume that we'll support only 65536 CPUs for x86_64. - thread_local uint16_t CurrentCPU = std::numeric_limits::max(); - thread_local uint64_t LastTSC = 0; - thread_local uint64_t LastFunctionEntryTSC = 0; - - // Make sure a thread that's ever called handleArg0 has a thread-local - // live reference to the buffer queue for this particular instance of - // FDRLogging, and that we're going to clean it up when the thread exits. - thread_local auto LocalBQ = BQ; - thread_local ThreadExitBufferCleanup Cleanup(LocalBQ, Buffer); - - // Prevent signal handler recursion, so in case we're already in a log writing - // mode and the signal handler comes in (and is also instrumented) then we - // don't want to be clobbering potentially partial writes already happening in - // the thread. We use a simple thread_local latch to only allow one on-going - // handleArg0 to happen at any given time. - thread_local bool Running = false; - RecursionGuard Guard{Running}; - if (!Guard) { - assert(Running == true && "RecursionGuard is buggy!"); - return; + return false; } if (!loggingInitialized(LoggingStatus) || LocalBQ->finalizing()) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(BQ.get())) - return; + if (!releaseThreadLocalBuffer(LocalBQ.get())) + return false; RecordPtr = nullptr; } @@ -496,19 +518,57 @@ static inline void processFunctionHook( LS != XRayLogInitStatus::XRAY_LOG_FINALIZED) Report("Failed to acquire a buffer; error=%s\n", BufferQueue::getErrorString(EC)); - return; + return false; } setupNewBuffer(wall_clock_reader); } if (CurrentCPU == std::numeric_limits::max()) { - // This means this is the first CPU this thread has ever run on. We set the - // current CPU and record this as the first TSC we've seen. + // This means this is the first CPU this thread has ever run on. We set + // the current CPU and record this as the first TSC we've seen. CurrentCPU = CPU; writeNewCPUIdMetadata(CPU, TSC); } + return true; +} // namespace __xray_fdr_internal + +inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { + auto BufferStart = static_cast(Buffer.Buffer); + if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { + writeEOBMetadata(); + if (!releaseThreadLocalBuffer(LocalBQ.get())) + return; + RecordPtr = nullptr; + } +} + +inline void processFunctionHook( + int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, + int (*wall_clock_reader)(clockid_t, struct timespec *), + __sanitizer::atomic_sint32_t &LoggingStatus, + const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { + // Prevent signal handler recursion, so in case we're already in a log writing + // mode and the signal handler comes in (and is also instrumented) then we + // don't want to be clobbering potentially partial writes already happening in + // the thread. We use a simple thread_local latch to only allow one on-going + // handleArg0 to happen at any given time. + thread_local bool Running = false; + RecursionGuard Guard{Running}; + if (!Guard) { + assert(Running == true && "RecursionGuard is buggy!"); + return; + } + + // In case the reference has been cleaned up before, we make sure we + // initialize it to the provided BufferQueue. + if (LocalBQ == nullptr) + LocalBQ = BQ; + + if (!isLogInitializedAndReady(LocalBQ, TSC, CPU, wall_clock_reader)) + return; + // Before we go setting up writing new function entries, we need to be really // careful about the pointer math we're doing. This means we need to ensure // that the record we are about to write is going to fit into the buffer, @@ -545,24 +605,14 @@ static inline void processFunctionHook( // bytes in the end of the buffer, we need to write out the EOB, get a new // Buffer, set it up properly before doing any further writing. // - char *BufferStart = static_cast(Buffer.Buffer); - if ((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart < - static_cast(MetadataRecSize)) { - writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) - return; - auto EC = LocalBQ->getBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed to acquire a buffer; error=%s\n", - BufferQueue::getErrorString(EC)); - return; - } - setupNewBuffer(wall_clock_reader); + if (!prepareBuffer(wall_clock_reader, FunctionRecSize + MetadataRecSize)) { + LocalBQ = nullptr; + return; } // By this point, we are now ready to write at most 24 bytes (one metadata // record and one function record). - BufferStart = static_cast(Buffer.Buffer); + auto BufferStart = static_cast(Buffer.Buffer); assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart >= static_cast(MetadataRecSize) && "Misconfigured BufferQueue provided; Buffer size not large enough."); @@ -586,7 +636,6 @@ static inline void processFunctionHook( // FunctionRecord. In this case we write down just a FunctionRecord with // the correct TSC delta. // - uint32_t RecordTSCDelta = 0; if (CPU != CurrentCPU) { // We've moved to a new CPU. @@ -619,21 +668,27 @@ static inline void processFunctionHook( break; rewindRecentCall(TSC, LastTSC, LastFunctionEntryTSC, FuncId); return; // without writing log. + case XRayEntryType::CUSTOM_EVENT: { + // This is a bug in patching, so we'll report it once and move on. + static bool Once = [&] { + Report("Internal error: patched an XRay custom event call as a function; " + "func id = %d", + FuncId); + return true; + }(); + (void)Once; + return; + } } writeFunctionRecord(FuncId, RecordTSCDelta, Entry, RecordPtr); // If we've exhausted the buffer by this time, we then release the buffer to // make sure that other threads may start using this buffer. - if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { - writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) - return; - RecordPtr = nullptr; - } + endBufferIfFull(); } } // namespace __xray_fdr_internal - } // namespace __xray + #endif // XRAY_XRAY_FDR_LOGGING_IMPL_H diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 26f0ab122..c437a72e3 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -50,6 +50,9 @@ __sanitizer::atomic_uintptr_t XRayPatchedFunction{0}; // This is the function to call from the arg1-enabled sleds/trampolines. __sanitizer::atomic_uintptr_t XRayArgLogger{0}; +// This is the function to call when we encounter a custom event log call. +__sanitizer::atomic_uintptr_t XRayPatchedCustomEvent{0}; + // MProtectHelper is an RAII wrapper for calls to mprotect(...) that will undo // any successful mprotect(...) changes. This is used to make a page writeable // and executable, and upon destruction if it was successful in doing so returns @@ -97,7 +100,19 @@ int __xray_set_handler(void (*entry)(int32_t, __sanitizer::memory_order_acquire)) { __sanitizer::atomic_store(&__xray::XRayPatchedFunction, - reinterpret_cast(entry), + reinterpret_cast(entry), + __sanitizer::memory_order_release); + return 1; + } + return 0; +} + +int __xray_set_customevent_handler(void (*entry)(void *, size_t)) + XRAY_NEVER_INSTRUMENT { + if (__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) { + __sanitizer::atomic_store(&__xray::XRayPatchedCustomEvent, + reinterpret_cast(entry), __sanitizer::memory_order_release); return 1; } @@ -161,6 +176,9 @@ inline bool patchSled(const XRaySledEntry &Sled, bool Enable, case XRayEntryType::LOG_ARGS_ENTRY: Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); break; + case XRayEntryType::CUSTOM_EVENT: + Success = patchCustomEvent(Enable, FuncId, Sled); + break; default: Report("Unsupported sled kind '%d' @%04x\n", Sled.Address, int(Sled.Kind)); return false; @@ -301,6 +319,7 @@ int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { __sanitizer::memory_order_release); return 1; } + int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index ef0c6b158..4a2784612 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -60,6 +60,7 @@ bool patchFunctionEntry(bool Enable, uint32_t FuncId, bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); bool patchFunctionTailExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); +bool patchCustomEvent(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); } // namespace __xray @@ -70,6 +71,7 @@ extern void __xray_FunctionEntry(); extern void __xray_FunctionExit(); extern void __xray_FunctionTailExit(); extern void __xray_ArgLoggerEntry(); +extern void __xray_CustomEvent(); } #endif diff --git a/lib/xray/xray_mips.cc b/lib/xray/xray_mips.cc index c8ff39936..cd863304d 100644 --- a/lib/xray/xray_mips.cc +++ b/lib/xray/xray_mips.cc @@ -95,7 +95,8 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, // B #44 if (Enable) { - uint32_t LoTracingHookAddr = reinterpret_cast(TracingHook) & 0xffff; + uint32_t LoTracingHookAddr = + reinterpret_cast(TracingHook) & 0xffff; uint32_t HiTracingHookAddr = (reinterpret_cast(TracingHook) >> 16) & 0xffff; uint32_t LoFunctionID = FuncId & 0xffff; @@ -151,6 +152,12 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // FIXME: Implement in mips? + return false; +} + } // namespace __xray extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_mips64.cc b/lib/xray/xray_mips64.cc index 21136848c..fa8fdd5ab 100644 --- a/lib/xray/xray_mips64.cc +++ b/lib/xray/xray_mips64.cc @@ -93,7 +93,8 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, if (Enable) { uint32_t LoTracingHookAddr = reinterpret_cast(TracingHook) & 0xffff; - uint32_t HiTracingHookAddr = (reinterpret_cast(TracingHook) >> 16) & 0xffff; + uint32_t HiTracingHookAddr = + (reinterpret_cast(TracingHook) >> 16) & 0xffff; uint32_t HigherTracingHookAddr = (reinterpret_cast(TracingHook) >> 32) & 0xffff; uint32_t HighestTracingHookAddr = @@ -160,6 +161,11 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // FIXME: Implement in mips64? + return false; +} } // namespace __xray extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_powerpc64.cc b/lib/xray/xray_powerpc64.cc index 6a7554cfc..ab03cb100 100644 --- a/lib/xray/xray_powerpc64.cc +++ b/lib/xray/xray_powerpc64.cc @@ -93,6 +93,12 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, // FIXME: Maybe implement this better? bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // FIXME: Implement in powerpc64? + return false; +} + } // namespace __xray extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index 847ecef8d..b59eedc4b 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -176,9 +176,15 @@ __xray_ArgLoggerEntry: je .Larg1entryFail .Larg1entryLog: - movq %rdi, %rdx // first argument will become the third - xorq %rsi, %rsi // XRayEntryType::ENTRY into the second - movl %r10d, %edi // 32-bit function ID becomes the first + + // First argument will become the third + movq %rdi, %rdx + + // XRayEntryType::ENTRY into the second + xorq %rsi, %rsi + + // 32-bit function ID becomes the first + movl %r10d, %edi callq *%rax .Larg1entryFail: @@ -189,4 +195,38 @@ __xray_ArgLoggerEntry: .size __xray_ArgLoggerEntry, .Larg1entryEnd-__xray_ArgLoggerEntry .cfi_endproc +//===----------------------------------------------------------------------===// + + .global __xray_CustomEvent + .align 16, 0x90 + .type __xray_CustomEvent,@function +__xray_CustomEvent: + .cfi_startproc + subq $16, %rsp + .cfi_def_cfa_offset 24 + movq %rbp, 8(%rsp) + movq %rax, 0(%rsp) + + // We take two arguments to this trampoline, which should be in rdi and rsi + // already. We also make sure that we stash %rax because we use that register + // to call the logging handler. + movq _ZN6__xray22XRayPatchedCustomEventE(%rip), %rax + testq %rax,%rax + je .LcustomEventCleanup + + // At this point we know that rcx and rdx already has the data, so we just + // call the logging handler. + callq *%rax + +.LcustomEventCleanup: + movq 0(%rsp), %rax + movq 8(%rsp), %rbp + addq $16, %rsp + .cfi_def_cfa_offset 8 + retq + +.Ltmp8: + .size __xray_CustomEvent, .Ltmp8-__xray_CustomEvent + .cfi_endproc + NO_EXEC_STACK_DIRECTIVE diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index 2e9a8d270..e34806fa1 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -75,8 +75,10 @@ uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { static constexpr uint8_t CallOpCode = 0xe8; static constexpr uint16_t MovR10Seq = 0xba41; static constexpr uint16_t Jmp9Seq = 0x09eb; +static constexpr uint16_t Jmp20Seq = 0x14eb; static constexpr uint8_t JmpOpCode = 0xe9; static constexpr uint8_t RetOpCode = 0xc3; +static constexpr uint16_t NopwSeq = 0x9066; static constexpr int64_t MinOffset{std::numeric_limits::min()}; static constexpr int64_t MaxOffset{std::numeric_limits::max()}; @@ -201,6 +203,40 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, return true; } +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + // Here we do the dance of replacing the following sled: + // + // xray_sled_n: + // jmp +19 // 2 bytes + // ... + // + // With the following: + // + // nopw // 2 bytes* + // ... + // + // We need to do this in the following order: + // + // 1. Overwrite the 5-byte nop with the call (relative), where (relative) is + // the relative offset to the __xray_CustomEvent trampoline. + // 2. Do a two-byte atomic write over the 'jmp +24' to turn it into a 'nopw'. + // This allows us to "enable" this code once the changes have committed. + // + // The "unpatch" should just turn the 'nopw' back to a 'jmp +24'. + // + if (Enable) { + std::atomic_store_explicit( + reinterpret_cast *>(Sled.Address), NopwSeq, + std::memory_order_release); + } else { + std::atomic_store_explicit( + reinterpret_cast *>(Sled.Address), Jmp20Seq, + std::memory_order_release); + } + return false; +} + // We determine whether the CPU we're running on has the correct features we // need. In x86_64 this will be rdtscp support. bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { diff --git a/test/xray/TestCases/Linux/custom-event-logging.cc b/test/xray/TestCases/Linux/custom-event-logging.cc new file mode 100644 index 000000000..29d177b9e --- /dev/null +++ b/test/xray/TestCases/Linux/custom-event-logging.cc @@ -0,0 +1,38 @@ +// Use the clang feature for custom xray event logging. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s +// +#include +#include "xray/xray_interface.h" + +[[clang::xray_always_instrument]] void foo() { + static constexpr char CustomLogged[] = "hello custom logging!"; + printf("before calling the custom logging...\n"); + __xray_customevent(CustomLogged, sizeof(CustomLogged)); + printf("after calling the custom logging...\n"); +} + +void myprinter(void* ptr, size_t size) { + printf("%.*s\n", static_cast(size), static_cast(ptr)); +} + +int main() { + foo(); + // CHECK: before calling the custom logging... + // CHECK-NEXT: after calling the custom logging... + printf("setting up custom event handler...\n"); + // CHECK-NEXT: setting up custom event handler... + __xray_set_customevent_handler(myprinter); + __xray_patch(); + // CHECK-NEXT: before calling the custom logging... + foo(); + // CHECK-NEXT: hello custom logging! + // CHECK-NEXT: after calling the custom logging... + printf("removing custom event handler...\n"); + // CHECK-NEXT: removing custom event handler... + __xray_set_customevent_handler(nullptr); + foo(); + // CHECK-NEXT: before calling the custom logging... + // CHECK-NEXT: after calling the custom logging... +} -- cgit v1.2.1 From 017000bfead7338536d35c99d5e5b98348bf9fa3 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 12 May 2017 01:33:55 +0000 Subject: [XRay][compiler-rt] Fix misspeling of XRaySledEntry Follow-up to D30630. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302860 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_AArch64.cc | 2 +- lib/xray/xray_arm.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/xray/xray_AArch64.cc b/lib/xray/xray_AArch64.cc index 372c1ad87..f26e77dd7 100644 --- a/lib/xray/xray_AArch64.cc +++ b/lib/xray/xray_AArch64.cc @@ -107,7 +107,7 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, - const XRaySled &Sled) + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { // FIXME: Implement in aarch64? return false; } diff --git a/lib/xray/xray_arm.cc b/lib/xray/xray_arm.cc index 94e1c2638..da4efcdd2 100644 --- a/lib/xray/xray_arm.cc +++ b/lib/xray/xray_arm.cc @@ -144,7 +144,7 @@ bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, - const XRaySled &Sled) + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { // FIXME: Implement in arm? return false; } -- cgit v1.2.1 From 5f20748c2f1bbf6801523c8d562f36f75793fcb3 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 12 May 2017 01:43:20 +0000 Subject: [XRay][compiler-rt] Remove unused variable after refactoring Follow-up to D30630. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302861 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index c801babc3..4a1d80fd0 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -205,7 +205,7 @@ inline bool loggingInitialized( } // namespace inline void writeNewBufferPreamble(pid_t Tid, timespec TS, - char *&MemPtr) XRAY_NEVER_INSTRUMENT { + char *&MemPtr) XRAY_NEVER_INSTRUMENT { static constexpr int InitRecordsCount = 2; std::aligned_storage::type Records[InitRecordsCount]; { @@ -254,7 +254,7 @@ inline void setupNewBuffer(int (*wall_clock_reader)( } inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, - char *&MemPtr) XRAY_NEVER_INSTRUMENT { + char *&MemPtr) XRAY_NEVER_INSTRUMENT { MetadataRecord NewCPUId; NewCPUId.Type = uint8_t(RecordType::Metadata); NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); @@ -272,7 +272,7 @@ inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, } inline void writeNewCPUIdMetadata(uint16_t CPU, - uint64_t TSC) XRAY_NEVER_INSTRUMENT { + uint64_t TSC) XRAY_NEVER_INSTRUMENT { writeNewCPUIdMetadata(CPU, TSC, RecordPtr); } @@ -292,7 +292,7 @@ inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { } inline void writeTSCWrapMetadata(uint64_t TSC, - char *&MemPtr) XRAY_NEVER_INSTRUMENT { + char *&MemPtr) XRAY_NEVER_INSTRUMENT { MetadataRecord TSCWrap; TSCWrap.Type = uint8_t(RecordType::Metadata); TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); @@ -312,8 +312,8 @@ inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { } inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, - XRayEntryType EntryType, - char *&MemPtr) XRAY_NEVER_INSTRUMENT { + XRayEntryType EntryType, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { std::aligned_storage::type AlignedFuncRecordBuffer; auto &FuncRecord = @@ -462,8 +462,8 @@ inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { } inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, - struct timespec *), - size_t MaxSize) XRAY_NEVER_INSTRUMENT { + struct timespec *), + size_t MaxSize) XRAY_NEVER_INSTRUMENT { char *BufferStart = static_cast(Buffer.Buffer); if ((RecordPtr + MaxSize) > (BufferStart + Buffer.Size - MetadataRecSize)) { writeEOBMetadata(); @@ -612,8 +612,8 @@ inline void processFunctionHook( // By this point, we are now ready to write at most 24 bytes (one metadata // record and one function record). - auto BufferStart = static_cast(Buffer.Buffer); - assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - BufferStart >= + assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - + static_cast(Buffer.Buffer) >= static_cast(MetadataRecSize) && "Misconfigured BufferQueue provided; Buffer size not large enough."); -- cgit v1.2.1 From 7fdfa4b8d87e169d47e17c9997528546282a57b5 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 12 May 2017 05:13:11 +0000 Subject: [XRay][compiler-rt] Only run custom event logging in x86_64-linux We only have an implementation in x86_64 that works for the patching/unpatching and runtime support (trampolines). Follow-up to D30630. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302873 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/custom-event-logging.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/xray/TestCases/Linux/custom-event-logging.cc b/test/xray/TestCases/Linux/custom-event-logging.cc index 29d177b9e..b1a766d46 100644 --- a/test/xray/TestCases/Linux/custom-event-logging.cc +++ b/test/xray/TestCases/Linux/custom-event-logging.cc @@ -2,7 +2,9 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s -// +// FIXME: Support this in non-x86_64 as well +// REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree #include #include "xray/xray_interface.h" -- cgit v1.2.1 From 929d2ccbf3afd1fc69a91aca258c177175ff900e Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 12 May 2017 09:39:32 +0000 Subject: [msan] Remove a failing test from MemorySanitizer.ICmpRelational This is a follow-up to r302787, which broke MemorySanitizer.ICmpRelational. MSan is now reporting a false positive on the following test case: TestForNotPoisoned((poisoned(-1, 0x80000000U) >= poisoned(-1, 0U))) , which is sort of anticipated, because we're approximating the comparison with an OR of the arguments' shadow values. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302887 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 40f56270a..58f695e69 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3724,8 +3724,10 @@ TEST(MemorySanitizer, ICmpRelational) { EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0)); EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0)); - - EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U)); + // Note that "icmp op X, Y" is approximated with "or shadow(X), shadow(Y)" + // and therefore may generate false positives in some cases, e.g. the + // following one: + // EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U)); } #if MSAN_HAS_M128 -- cgit v1.2.1 From bb2563f2a2344a34f49c7007560b268d4f1359ae Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 12 May 2017 14:10:51 +0000 Subject: Account for stack redzone when computing sp on darwin thread_get_register_pointer_values handles the redzone computation automatically, but is marked as an unavailable API function. This patch replicates its logic accounting for the stack redzone on x86_64. Should fix flakiness in the use_stack_threaded test for lsan on darwin. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302898 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 20b876093..0c27c472f 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -170,6 +170,10 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( internal_memcpy(buffer, ®s, sizeof(regs)); *sp = regs.SP_REG; + // On x86_64 and aarch64, we must account for the stack redzone, which is 128 + // bytes. + if (SANITIZER_WORDSIZE == 64) *sp -= 128; + return REGISTERS_AVAILABLE; } -- cgit v1.2.1 From 508f038326752ed694ea9ae0daf75ddf540ddd3d Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 12 May 2017 14:10:53 +0000 Subject: Add dyld to sanitizer procmaps on darwin Summary: Sanitizer procmaps uses dyld apis to iterate over the list of images in the process. This is much more performan than manually recursing over all of the memory regions in the process, however, dyld does not report itself in the list of images. In order to prevent reporting leaks from dyld globals and to symbolize dyld functions in stack traces, this patch special-cases dyld and ensures that it is added to the list of modules. This is accomplished by recursing through the memory map of the process until a dyld Mach header is found. While this recursion is expensive, it is run before the full set of images has been loaded in the process, so only a few calls are required. The result is cached so that it never needs to be searched for when the full process memory map exists, as this would be incredibly slow, on the order of minutes for leak sanitizer with only 25 or so libraries loaded. Reviewers: alekseyshl, kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32968 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302899 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 1 + lib/sanitizer_common/sanitizer_procmaps_mac.cc | 87 +++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 9dbb5ef0f..5aad6b959 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -70,6 +70,7 @@ class MemoryMappingLayout { bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, ModuleArch *arch, u8 *uuid, uptr *protection); + void GetSegmentAddrRange(uptr *start, uptr *end, uptr vmaddr, uptr vmsize); int current_image_; u32 current_magic_; u32 current_filetype_; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index be59b481f..0b4171a90 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -18,6 +18,7 @@ #include #include +#include // These are not available in older macOS SDKs. #ifndef CPU_SUBTYPE_X86_64_H @@ -71,6 +72,13 @@ void MemoryMappingLayout::Reset() { internal_memset(current_uuid_, 0, kModuleUUIDSize); } +// The dyld load address should be unchanged throughout process execution, +// and it is expensive to compute once many libraries have been loaded, +// so cache it here and do not reset. +static mach_header *dyld_hdr = 0; +static const char kDyldPath[] = "/usr/lib/dyld"; +static const int kDyldImageIdx = -1; + // static void MemoryMappingLayout::CacheMemoryMappings() { // No-op on Mac for now. @@ -95,14 +103,12 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, const char *lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); const SegmentCommand* sc = (const SegmentCommand *)lc; - if (start) *start = sc->vmaddr + dlloff; + GetSegmentAddrRange(start, end, sc->vmaddr, sc->vmsize); if (protection) { // Return the initial protection. *protection = sc->initprot; } - if (end) *end = sc->vmaddr + sc->vmsize + dlloff; if (offset) { if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { *offset = sc->vmaddr; @@ -111,8 +117,12 @@ bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, } } if (filename) { - internal_strncpy(filename, _dyld_get_image_name(current_image_), - filename_size); + if (current_image_ == kDyldImageIdx) { + internal_strncpy(filename, kDyldPath, filename_size); + } else { + internal_strncpy(filename, _dyld_get_image_name(current_image_), + filename_size); + } } if (arch) { *arch = current_arch_; @@ -180,11 +190,74 @@ static bool IsModuleInstrumented(const load_command *first_lc) { return false; } +// _dyld_get_image_header() and related APIs don't report dyld itself. +// We work around this by manually recursing through the memory map +// until we hit a Mach header matching dyld instead. These recurse +// calls are expensive, but the first memory map generation occurs +// early in the process, when dyld is one of the only images loaded, +// so it will be hit after only a few iterations. +static mach_header *get_dyld_image_header() { + mach_port_name_t port; + if (task_for_pid(mach_task_self(), internal_getpid(), &port) != + KERN_SUCCESS) { + return nullptr; + } + + unsigned depth = 1; + vm_size_t size = 0; + vm_address_t address = 0; + kern_return_t err = KERN_SUCCESS; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + while (true) { + struct vm_region_submap_info_64 info; + err = vm_region_recurse_64(port, &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (err != KERN_SUCCESS) return nullptr; + + if (size >= sizeof(mach_header) && + info.protection & MemoryMappingLayout::kProtectionRead) { + mach_header *hdr = (mach_header *)address; + if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && + hdr->filetype == MH_DYLINKER) { + return hdr; + } + } + address += size; + } +} + +const mach_header *get_dyld_hdr() { + if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); + + return dyld_hdr; +} + +void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, + uptr vmaddr, uptr vmsize) { + if (current_image_ == kDyldImageIdx) { + // vmaddr is masked with 0xfffff because on macOS versions < 10.12, + // it contains an absolute address rather than an offset for dyld. + // To make matters even more complicated, this absolute address + // isn't actually the absolute segment address, but the offset portion + // of the address is accurate when combined with the dyld base address, + // and the mask will give just this offset. + if (start) *start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + if (end) *end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); + } else { + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + if (start) *start = vmaddr + dlloff; + if (end) *end = vmaddr + vmsize + dlloff; + } +} + bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, uptr *protection, ModuleArch *arch, u8 *uuid) { - for (; current_image_ >= 0; current_image_--) { - const mach_header* hdr = _dyld_get_image_header(current_image_); + for (; current_image_ >= kDyldImageIdx; current_image_--) { + const mach_header *hdr = (current_image_ == kDyldImageIdx) + ? get_dyld_hdr() + : _dyld_get_image_header(current_image_); if (!hdr) continue; if (current_load_cmd_count_ < 0) { // Set up for this image; -- cgit v1.2.1 From 47c47778c3ba54cd5190e4630ae517be78842676 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 12 May 2017 15:10:05 +0000 Subject: Enable lsan test suite on Darwin x86_64 builds Reviewers: kubamracek, alekseyshl Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D32191 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302904 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/asan/lit.cfg | 9 ++++++++- test/lsan/lit.common.cfg | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 60cb39a93..ae2a262a1 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -476,7 +476,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD") + OS_NAME MATCHES "Darwin|Linux|FreeBSD") set(COMPILER_RT_HAS_LSAN TRUE) else() set(COMPILER_RT_HAS_LSAN FALSE) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index b433a91e8..063c33b02 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -38,6 +38,11 @@ if config.host_os == 'Darwin': # Also, make sure we do not overwhelm the syslog while testing. default_asan_opts = 'abort_on_error=0' default_asan_opts += ':log_to_syslog=0' + + # On Darwin, leak checking is not enabled by default. Enable for x86_64 + # tests to prevent regressions + if config.target_arch == 'x86_64': + default_asan_opts += ':detect_leaks=1' elif config.android: # The same as on Darwin, we default to "abort_on_error=1" which slows down # testing. Also, all existing tests are using "not" instead of "not --crash" @@ -215,7 +220,9 @@ if re.search('mthumb', config.target_cflags) is not None: config.available_features.add('fast-unwinder-works') # Turn on leak detection on 64-bit Linux. -if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'): +leak_detection_linux = (config.host_os == 'Linux') and (config.target_arch == 'x86_64' or config.target_arch == 'i386') +leak_detection_mac = (config.host_os == 'Darwin') and (config.target_arch == 'x86_64') +if leak_detection_linux or leak_detection_mac: config.available_features.add('leak-detection') # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index da439d4c0..309e8f27b 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -67,9 +67,10 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) -# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, and mips64 Linux only. +# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin. supported_linux = config.host_os is 'Linux' and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l'] -if not (supported_linux): +supported_darwin = config.host_os is 'Darwin' and config.target_arch is 'x86_64' +if not (supported_linux or supported_darwin): config.unsupported = True # Don't support Thumb due to broken fast unwinder -- cgit v1.2.1 From 2ea389217fb76b4fb8cd72b0a30bb686e4b1bcfe Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 12 May 2017 16:01:15 +0000 Subject: Disable two failing darwin lsan tests These are causing buildbot failures, disable for now. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302912 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/link_turned_off.cc | 2 ++ test/lsan/TestCases/recoverable_leak_check.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index b8458de63..325de18fb 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -3,6 +3,8 @@ // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// +// XFAIL: darwin #include diff --git a/test/lsan/TestCases/recoverable_leak_check.cc b/test/lsan/TestCases/recoverable_leak_check.cc index 909698561..7a51b5cc0 100644 --- a/test/lsan/TestCases/recoverable_leak_check.cc +++ b/test/lsan/TestCases/recoverable_leak_check.cc @@ -3,6 +3,8 @@ // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s +// +// XFAIL: darwin #include #include -- cgit v1.2.1 From 088c87e0fb81485d8e5b37f6761bd41782b1570f Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 12 May 2017 16:30:56 +0000 Subject: [asan/win] Re-enable Win64 asan tests on Win8+ Our theory is that reserving large amounts of shadow memory isn't reliable on Win7 and earlier NT kernels. This affects the clang-x64-ninja-win7 buildbot, which uses Windows 7. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302917 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/CMakeLists.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index b8e365227..87fa9d138 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -3,9 +3,17 @@ set(ASAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(ASAN_TESTSUITES) set(ASAN_DYNAMIC_TESTSUITES) -# FIXME: Shadow memory for 64-bit asan easily exhausts swap on most machines. -# Find a way to make these tests pass reliably, and re-enable them. -if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8) +# Before Windows 8 (CMAKE_SYSTEM_VERSION 6.2), reserving large regions of shadow +# memory allocated physical memory for page tables, which made it very +# unreliable. Remove the asan tests from check-all in this configuration. +set(SHADOW_MAPPING_UNRELIABLE FALSE) +if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND + ${CMAKE_SYSTEM_VERSION} LESS 6.2) + set(SHADOW_MAPPING_UNRELIABLE TRUE) + message(WARNING "Disabling ASan tests because they are unreliable on Windows 7 and earlier") +endif() + +if (SHADOW_MAPPING_UNRELIABLE) set(EXCLUDE_FROM_ALL TRUE) endif() @@ -165,7 +173,6 @@ if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) endif() # Reset EXCLUDE_FROM_ALL to its initial value. -# FIXME: Remove when we run Win64 asan tests. -if(OS_NAME MATCHES "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 8) +if (SHADOW_MAPPING_UNRELIABLE) set(EXCLUDE_FROM_ALL FALSE) endif() -- cgit v1.2.1 From ec190012e56077b3c7e4b70869864f17a7dbbd01 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 12 May 2017 16:52:19 +0000 Subject: Disable two failing darwin lsan tests These tests don't fail consistently in all cases, but they fail most of the time on the buildbots. Mark as UNSUPPORTED for now to avoid buildbots failing due to XPASS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302920 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/link_turned_off.cc | 2 +- test/lsan/TestCases/recoverable_leak_check.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index 325de18fb..fd11272ce 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -4,7 +4,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s // -// XFAIL: darwin +// UNSUPPORTED: darwin #include diff --git a/test/lsan/TestCases/recoverable_leak_check.cc b/test/lsan/TestCases/recoverable_leak_check.cc index 7a51b5cc0..85988e2c1 100644 --- a/test/lsan/TestCases/recoverable_leak_check.cc +++ b/test/lsan/TestCases/recoverable_leak_check.cc @@ -4,7 +4,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s // -// XFAIL: darwin +// UNSUPPORTED: darwin #include #include -- cgit v1.2.1 From d6fba16de31942928c75edadba648c84b552040d Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 12 May 2017 17:06:16 +0000 Subject: [ubsan] Enable debug info in test binaries This fixes tests that use debug info to check ubsan stack traces. One was XFAILd on Windows and the other was actively failing for weeks. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302924 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/misaligned.cpp | 6 +----- test/ubsan/lit.common.cfg | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp index b3ff3588b..471338604 100644 --- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -1,8 +1,4 @@ -// FIXME: This test currently fails on Windows because we use the MSVC linker, -// which throws away DWARF debug info. -// XFAIL: win32 -// -// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t +// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t // RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0 // RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace // RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index cb6a8e442..0fa2e01a1 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -57,7 +57,7 @@ config.substitutions.append(('%env_ubsan_opts=', def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " -target_cflags = [get_required_attr(config, "target_cflags")] +target_cflags = [get_required_attr(config, "target_cflags")] + config.debug_info_flags clang_ubsan_cflags += target_cflags clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags -- cgit v1.2.1 From e380523e9bd4a7869ff782048fb6a12959ca4513 Mon Sep 17 00:00:00 2001 From: Eugene Zelenko Date: Fri, 12 May 2017 22:26:42 +0000 Subject: [XRay] Fix build with libc++ (NFC). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@302962 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index aea43517d..c3833f0be 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -1,4 +1,4 @@ -//===-- xray_interface.h ----------------------------------------*- C++ -*-===// +//===- xray_interface.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,11 +11,12 @@ // // APIs for controlling XRay functionality explicitly. //===----------------------------------------------------------------------===// + #ifndef XRAY_XRAY_INTERFACE_H #define XRAY_XRAY_INTERFACE_H +#include #include -#include extern "C" { @@ -100,6 +101,6 @@ extern uintptr_t __xray_function_address(int32_t FuncId); /// encounter errors (when there are no instrumented functions, etc.). extern size_t __xray_max_function_id(); -} +} // end extern "C" -#endif +#endif // XRAY_XRAY_INTERFACE_H -- cgit v1.2.1 From 9d786d9ab2ef785cabb11d28c98c708a4c4be03e Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 15 May 2017 14:47:19 +0000 Subject: [sanitizer] Change SizeClassAllocator32 to accept just one template Summary: With rL279771, SizeClassAllocator64 was changed to accept only one template instead of 5, for the following reasons: "First, this will make the mangled names shorter. Second, this will make adding more parameters simpler". This patch mirrors that work for SizeClassAllocator32. This is in preparation for introducing the randomization of chunks in the 32-bit SizeClassAllocator in a later patch. Reviewers: kcc, alekseyshl, dvyukov Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33141 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303071 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.h | 15 ++++++--- lib/lsan/lsan_allocator.h | 16 ++++++--- lib/msan/msan_allocator.cc | 31 +++++++++++++----- .../sanitizer_allocator_internal.h | 22 ++++++++----- .../sanitizer_allocator_primary32.h | 27 +++++++++++---- .../tests/sanitizer_allocator_test.cc | 38 +++++++++++++--------- lib/scudo/scudo_allocator.h | 18 +++++++--- lib/tsan/rtl/tsan_rtl.h | 18 ++++++---- 8 files changed, 127 insertions(+), 58 deletions(-) diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index ee28ecf98..ad1aeb58a 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -161,10 +161,17 @@ typedef FlatByteMap ByteMap; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; # endif typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16, - SizeClassMap, kRegionSizeLog, - ByteMap, - AsanMapUnmapCallback> PrimaryAllocator; +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = 16; + typedef __asan::SizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __asan::kRegionSizeLog; + typedef __asan::ByteMap ByteMap; + typedef AsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses; diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index fad5adb01..5a0d94c71 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -55,10 +55,18 @@ struct ChunkMetadata { static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; -typedef CompactSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, - sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> - PrimaryAllocator; + +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __lsan::kRegionSizeLog; + typedef __lsan::ByteMap ByteMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 PrimaryAllocator; #elif defined(__x86_64__) || defined(__powerpc64__) struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = 0x600000000000ULL; diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 6c389f008..1be573faa 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -47,12 +47,18 @@ struct MsanMapUnmapCallback { static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - typedef CompactSizeClassMap SizeClassMap; - - typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata), - SizeClassMap, kRegionSizeLog, ByteMap, - MsanMapUnmapCallback> PrimaryAllocator; + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; #elif defined(__x86_64__) #if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) static const uptr kAllocatorSpace = 0x700000000000ULL; @@ -90,11 +96,18 @@ struct MsanMapUnmapCallback { static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - typedef CompactSizeClassMap SizeClassMap; - typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata), - SizeClassMap, kRegionSizeLog, ByteMap, - MsanMapUnmapCallback> PrimaryAllocator; + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; #endif typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator SecondaryAllocator; diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h index e939cbe01..d1890f20f 100644 --- a/lib/sanitizer_common/sanitizer_allocator_internal.h +++ b/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -23,21 +23,25 @@ namespace __sanitizer { // purposes. typedef CompactSizeClassMap InternalSizeClassMap; -static const uptr kInternalAllocatorSpace = 0; -static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; static const uptr kInternalAllocatorRegionSizeLog = 20; -#if SANITIZER_WORDSIZE == 32 static const uptr kInternalAllocatorNumRegions = - kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog; + SANITIZER_MMAP_RANGE_SIZE >> kInternalAllocatorRegionSizeLog; +#if SANITIZER_WORDSIZE == 32 typedef FlatByteMap ByteMap; #else -static const uptr kInternalAllocatorNumRegions = - kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog; typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap; #endif -typedef SizeClassAllocator32< - kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap, - kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator; +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = 0; + typedef InternalSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = kInternalAllocatorRegionSizeLog; + typedef __sanitizer::ByteMap ByteMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 PrimaryInternalAllocator; typedef SizeClassAllocatorLocalCache InternalAllocatorCache; diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index 2882afd1f..0f6f4f7f8 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -36,13 +36,27 @@ template struct SizeClassAllocator32LocalCache; // // In order to avoid false sharing the objects of this class should be // chache-line aligned. -template + +struct SizeClassAllocator32FlagMasks { // Bit masks. + enum { + kRandomShuffleChunks = 1, + }; +}; + +template class SizeClassAllocator32 { public: + static const uptr kSpaceBeg = Params::kSpaceBeg; + static const u64 kSpaceSize = Params::kSpaceSize; + static const uptr kMetadataSize = Params::kMetadataSize; + typedef typename Params::SizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = Params::kRegionSizeLog; + typedef typename Params::ByteMap ByteMap; + typedef typename Params::MapUnmapCallback MapUnmapCallback; + + static const bool kRandomShuffleChunks = + Params::kFlags & SizeClassAllocator32FlagMasks::kRandomShuffleChunks; + struct TransferBatch { static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2; void SetFromArray(uptr region_beg_unused, void *batch[], uptr count) { @@ -86,8 +100,7 @@ class SizeClassAllocator32 { return SizeClassMap::Size(class_id); } - typedef SizeClassAllocator32 ThisT; + typedef SizeClassAllocator32 ThisT; typedef SizeClassAllocator32LocalCache AllocatorCache; void Init(s32 release_to_os_interval_ms) { diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index e14517fca..b28159a2a 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -108,13 +108,17 @@ static const u64 kAddressSpaceSize = 1ULL << 32; static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24); static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog; -typedef SizeClassAllocator32< - 0, kAddressSpaceSize, - /*kMetadataSize*/16, - CompactSizeClassMap, - kRegionSizeLog, - FlatByteMap > - Allocator32Compact; +struct AP32Compact { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = kAddressSpaceSize; + static const uptr kMetadataSize = 16; + typedef CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = ::kRegionSizeLog; + typedef FlatByteMap ByteMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 Allocator32Compact; template void TestSizeClassMap() { @@ -386,17 +390,21 @@ TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) { #endif #endif +struct AP32WithCallback { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = kAddressSpaceSize; + static const uptr kMetadataSize = 16; + typedef CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = ::kRegionSizeLog; + typedef FlatByteMap ByteMap; + typedef TestMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) { TestMapUnmapCallback::map_count = 0; TestMapUnmapCallback::unmap_count = 0; - typedef SizeClassAllocator32< - 0, kAddressSpaceSize, - /*kMetadataSize*/16, - CompactSizeClassMap, - kRegionSizeLog, - FlatByteMap, - TestMapUnmapCallback> - Allocator32WithCallBack; + typedef SizeClassAllocator32 Allocator32WithCallBack; Allocator32WithCallBack *a = new Allocator32WithCallBack; a->Init(kReleaseToOSIntervalNever); EXPECT_EQ(TestMapUnmapCallback::map_count, 0); diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 2dad7320c..523808750 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -80,7 +80,7 @@ const uptr AllocatorSize = 0x10000000000ULL; // 1T. const uptr AllocatorSize = 0x40000000000ULL; // 4T. # endif typedef DefaultSizeClassMap SizeClassMap; -struct AP { +struct AP64 { static const uptr kSpaceBeg = AllocatorSpace; static const uptr kSpaceSize = AllocatorSize; static const uptr kMetadataSize = 0; @@ -89,7 +89,7 @@ struct AP { static const uptr kFlags = SizeClassAllocator64FlagMasks::kRandomShuffleChunks; }; -typedef SizeClassAllocator64 PrimaryAllocator; +typedef SizeClassAllocator64 PrimaryAllocator; #else // Currently, the 32-bit Sanitizer allocator has not yet benefited from all the // security improvements brought to the 64-bit one. This makes the 32-bit @@ -102,8 +102,18 @@ typedef FlatByteMap ByteMap; typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap; # endif // SANITIZER_WORDSIZE typedef DefaultSizeClassMap SizeClassMap; -typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap, - RegionSizeLog, ByteMap> PrimaryAllocator; +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = 0; + typedef __scudo::SizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = RegionSizeLog; + typedef __scudo::ByteMap ByteMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = + SizeClassAllocator32FlagMasks::kRandomShuffleChunks; +}; +typedef SizeClassAllocator32 PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 #include "scudo_allocator_secondary.h" diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index e92a0f357..2cf2e1684 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -55,16 +55,22 @@ namespace __tsan { #if !SANITIZER_GO struct MapUnmapCallback; #if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__) -static const uptr kAllocatorSpace = 0; -static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; static const uptr kAllocatorRegionSizeLog = 20; static const uptr kAllocatorNumRegions = - kAllocatorSize >> kAllocatorRegionSizeLog; + SANITIZER_MMAP_RANGE_SIZE >> kAllocatorRegionSizeLog; typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12, MapUnmapCallback> ByteMap; -typedef SizeClassAllocator32 PrimaryAllocator; +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = 0; + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = kAllocatorRegionSizeLog; + typedef __tsan::ByteMap ByteMap; + typedef __tsan::MapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32 PrimaryAllocator; #else struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = Mapping::kHeapMemBeg; -- cgit v1.2.1 From 0479fb714d0d780fadf6cdac65f993d2bb876664 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 15 May 2017 17:25:10 +0000 Subject: [ubsan] Don't enable debug info in all tests Add a lit substitution (I chose %gmlt) so that only stack trace tests get debug info. We need a lit substition so that this expands to -gline-tables-only -gcodeview on Windows. I think in the future we should reconsider the need for -gcodeview from the GCC driver, but for now, this is necessary. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303083 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/Misc/missing_return.cpp | 2 +- test/ubsan/TestCases/TypeCheck/misaligned.cpp | 2 +- test/ubsan/lit.common.cfg | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp index 7b56b9704..5c5b286f1 100644 --- a/test/ubsan/TestCases/Misc/missing_return.cpp +++ b/test/ubsan/TestCases/Misc/missing_return.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t +// RUN: %clangxx -fsanitize=return %gmlt %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s // RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-STACKTRACE diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 471338604..4eaedf37e 100644 --- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t +// RUN: %clangxx %gmlt -fsanitize=alignment %s -O3 -o %t // RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0 // RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace // RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 0fa2e01a1..e3a1367e7 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -57,13 +57,14 @@ config.substitutions.append(('%env_ubsan_opts=', def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " -target_cflags = [get_required_attr(config, "target_cflags")] + config.debug_info_flags +target_cflags = [get_required_attr(config, "target_cflags")] clang_ubsan_cflags += target_cflags clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags # Define %clang and %clangxx substitutions to use in test RUN lines. config.substitutions.append( ("%clang ", build_invocation(clang_ubsan_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags)) ) +config.substitutions.append( ("%gmlt ", " ".join(config.debug_info_flags) + " ") ) # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -- cgit v1.2.1 From 80a73416a2949684dda1dba5e7a3ffb253e0eabf Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 15 May 2017 19:09:13 +0000 Subject: builtins: fix filtering aliased targets Some build targets (e.g. i686) have aliased names (e.g. i386). We would get multiple definitions previously and have the linker arbitrarily select a definition on those aliased targets. Make this more deterministic by checking those aliases. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303103 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 946b912ae..df80a5044 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -483,11 +483,18 @@ else () foreach (arch ${BUILTIN_SUPPORTED_ARCH}) if (CAN_TARGET_${arch}) + # NOTE: some architectures (e.g. i386) have multiple names. Ensure that + # we catch them all. + set(_arch ${arch}) + if("${arch}" STREQUAL "i686") + set(_arch "i386|i686") + 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. foreach (_file ${${arch}_SOURCES}) - if (${_file} MATCHES ${arch}/*) + if (${_file} MATCHES ${_arch}/*) get_filename_component(_name ${_file} NAME) string(REPLACE ".S" ".c" _cname "${_name}") list(REMOVE_ITEM ${arch}_SOURCES ${_cname}) -- cgit v1.2.1 From 96eed06b6e57a3c8e2593e73d6f33bdd407f43b9 Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Mon, 15 May 2017 20:41:17 +0000 Subject: [builtins] Fix a check from __GNU__ to __GNUC__ for disabling executable stack. Summary: Neither GCC nor Clang define __GNU__. Instead use __GNUC__ for the check. Reviewers: echristo, rengolin, compnerd Subscribers: srhines, krytarowski, llvm-commits Differential Revision: https://reviews.llvm.org/D33211 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303112 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 29d9f8844..eafbe7de6 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -44,7 +44,7 @@ #endif #define CONST_SECTION .section .rodata -#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) +#if defined(__GNUC__) || defined(__ANDROID__) || defined(__FreeBSD__) #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else #define NO_EXEC_STACK_DIRECTIVE -- cgit v1.2.1 From 4ba4036348a95faa781fa13f0c27ed4b120188fe Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 15 May 2017 23:11:01 +0000 Subject: [lsan] Report the missing linker only when the linker is actually missing. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33218 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303129 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_linux.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index fadd0263d..c903be42d 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -62,8 +62,10 @@ void InitializePlatformSpecificModules() { return; } } - VReport(1, "LeakSanitizer: Dynamic linker not found. " - "TLS will not be handled correctly.\n"); + if (linker == nullptr) { + VReport(1, "LeakSanitizer: Dynamic linker not found. " + "TLS will not be handled correctly.\n"); + } } static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, -- cgit v1.2.1 From 0bbb5570008543a77479f2944189a8b508dbe16f Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Mon, 15 May 2017 23:13:54 +0000 Subject: Fix executable stack directive on Linux. Summary: Use __linux__ to check for Linux and bring back the check for __GNU__. Reviewers: echristo, krytarowski, compnerd, rengolin Reviewed By: krytarowski Subscribers: phosek, llvm-commits, srhines Differential Revision: https://reviews.llvm.org/D33219 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303131 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index eafbe7de6..12c13c495 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -44,7 +44,8 @@ #endif #define CONST_SECTION .section .rodata -#if defined(__GNUC__) || defined(__ANDROID__) || defined(__FreeBSD__) +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + defined(__linux__) #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else #define NO_EXEC_STACK_DIRECTIVE -- cgit v1.2.1 From 17a5de7a0d190454d00e7d093a60c679598f5f2e Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 15 May 2017 23:37:54 +0000 Subject: [asan] make asan under sandboxes more robust git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303132 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_linux.cc | 4 +-- .../Linux/sanbox_read_proc_self_maps_test.cc | 30 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc index fdf85b77a..7e4a44be9 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -18,8 +18,8 @@ namespace __sanitizer { void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - CHECK(ReadFileToBuffer("/proc/self/maps", &proc_maps->data, - &proc_maps->mmaped_size, &proc_maps->len)); + ReadFileToBuffer("/proc/self/maps", &proc_maps->data, &proc_maps->mmaped_size, + &proc_maps->len); } static bool IsOneOf(char c, char c1, char c2) { diff --git a/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc b/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc new file mode 100644 index 000000000..a845721d5 --- /dev/null +++ b/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc @@ -0,0 +1,30 @@ +// REQUIRES: x86_64-target-arch +// RUN: %clangxx_asan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +#include +#include +#include +#include +#include + +int main() { + __sanitizer_sandbox_arguments args = {0}; + // should cache /proc/self/maps + __sanitizer_sandbox_on_notify(&args); + + if (unshare(CLONE_NEWUSER)) { + printf("unshare failed\n"); + abort(); + } + + // remove access to /proc/self/maps + if (chroot("/tmp")) { + printf("chroot failed\n"); + abort(); + } + + *(volatile int*)0x42 = 0; +// CHECK: AddressSanitizer: SEGV on unknown address 0x000000000042 +// CHECK-NOT: AddressSanitizer CHECK failed +// CHECK: SUMMARY: AddressSanitizer: SEGV +} -- cgit v1.2.1 From 1f7b0d2bc796b293d56a99354bb78750a8e47558 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 16 May 2017 02:06:15 +0000 Subject: [tsan] Update tsan test for r303084 Tail duplication changed number of pop instruction, but TSAN performance was not affected. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303136 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/check_analyze.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh index d454ec2dd..22eb44419 100755 --- a/lib/tsan/check_analyze.sh +++ b/lib/tsan/check_analyze.sh @@ -29,7 +29,7 @@ check() { for f in write1 write2 write4 write8; do check $f rsp 1 check $f push 2 - check $f pop 2 + check $f pop 12 done for f in read1 read2 read4 read8; do -- cgit v1.2.1 From 5c1b8654b63c99930f442de2e79b179e6150d725 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 16 May 2017 04:17:12 +0000 Subject: builtins: use reserved spelling (NFC) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303138 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/int_lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h index 8a202dde7..63d911a20 100644 --- a/lib/builtins/int_lib.h +++ b/lib/builtins/int_lib.h @@ -35,7 +35,7 @@ # ifdef COMPILER_RT_ARMHF_TARGET # define COMPILER_RT_ABI # else -# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +# define COMPILER_RT_ABI __attribute__((__pcs__("aapcs"))) # endif #else # define ARM_EABI_FNALIAS(aeabi_name, name) -- cgit v1.2.1 From 99e2e66daf8d334858cec4f6e8e7a39d6a535a55 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 16 May 2017 16:41:37 +0000 Subject: builtins: expand out the AEABI function stubs These actually may change calling conventions. We cannot simply provide function aliases as the aliased function may have a different calling convention. Provide a forwarding function instead to permit the compiler to synthesize the calling convention adjustment thunk. Remove the `ARM_EABI_FNALIAS` macro as that is not safe to use. Resolves PR33030! git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303188 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/adddf3.c | 9 +++++++-- lib/builtins/addsf3.c | 9 +++++++-- lib/builtins/arm/aeabi_cdcmpeq_check_nan.c | 3 +-- lib/builtins/arm/aeabi_cfcmpeq_check_nan.c | 3 +-- lib/builtins/arm/aeabi_div0.c | 4 ++-- lib/builtins/arm/aeabi_drsub.c | 4 ++-- lib/builtins/arm/aeabi_frsub.c | 4 ++-- lib/builtins/ashldi3.c | 9 +++++++-- lib/builtins/ashrdi3.c | 9 +++++++-- lib/builtins/comparedf2.c | 8 ++++++-- lib/builtins/comparesf2.c | 9 +++++++-- lib/builtins/divdf3.c | 9 +++++++-- lib/builtins/divsf3.c | 9 +++++++-- lib/builtins/divsi3.c | 9 +++++++-- lib/builtins/extendhfsf2.c | 9 +++++++-- lib/builtins/extendsfdf2.c | 9 +++++++-- lib/builtins/fixdfdi.c | 13 ++++++++++++- lib/builtins/fixdfsi.c | 9 +++++++-- lib/builtins/fixsfdi.c | 14 ++++++++++++-- lib/builtins/fixsfsi.c | 9 +++++++-- lib/builtins/fixunsdfdi.c | 14 ++++++++++++-- lib/builtins/fixunsdfsi.c | 9 +++++++-- lib/builtins/fixunssfdi.c | 14 ++++++++++++-- lib/builtins/fixunssfsi.c | 9 +++++++-- lib/builtins/floatdidf.c | 9 +++++++-- lib/builtins/floatdisf.c | 9 +++++++-- lib/builtins/floatsidf.c | 9 +++++++-- lib/builtins/floatsisf.c | 9 +++++++-- lib/builtins/floatundidf.c | 9 +++++++-- lib/builtins/floatundisf.c | 9 +++++++-- lib/builtins/floatunsidf.c | 9 +++++++-- lib/builtins/floatunsisf.c | 9 +++++++-- lib/builtins/int_lib.h | 5 ++--- lib/builtins/lshrdi3.c | 9 +++++++-- lib/builtins/muldf3.c | 9 +++++++-- lib/builtins/muldi3.c | 9 +++++++-- lib/builtins/mulsf3.c | 9 +++++++-- lib/builtins/negdf2.c | 9 +++++++-- lib/builtins/negsf2.c | 9 +++++++-- lib/builtins/subdf3.c | 8 ++++++-- lib/builtins/subsf3.c | 8 ++++++-- lib/builtins/truncdfhf2.c | 9 +++++++-- lib/builtins/truncdfsf2.c | 9 +++++++-- lib/builtins/truncsfhf2.c | 9 +++++++-- lib/builtins/udivsi3.c | 9 +++++++-- 45 files changed, 300 insertions(+), 90 deletions(-) diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c index 8b7aae0a6..c528e9e21 100644 --- a/lib/builtins/adddf3.c +++ b/lib/builtins/adddf3.c @@ -15,8 +15,13 @@ #define DOUBLE_PRECISION #include "fp_add_impl.inc" -ARM_EABI_FNALIAS(dadd, adddf3) - COMPILER_RT_ABI double __adddf3(double a, double b){ return __addXf3__(a, b); } + +#if defined(__ARM_EABI__) +AEABI_RTABI double __aeabi_dadd(double a, double b) { + return __adddf3(a, b); +} +#endif + diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c index 0f5d6ea40..fe570687a 100644 --- a/lib/builtins/addsf3.c +++ b/lib/builtins/addsf3.c @@ -15,8 +15,13 @@ #define SINGLE_PRECISION #include "fp_add_impl.inc" -ARM_EABI_FNALIAS(fadd, addsf3) - COMPILER_RT_ABI float __addsf3(float a, float b) { return __addXf3__(a, b); } + +#if defined(__ARM_EABI__) +AEABI_RTABI float __aeabi_fadd(float a, float b) { + return __addsf3(a, b); +} +#endif + diff --git a/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c index 577f6b2c5..b640f9776 100644 --- a/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c +++ b/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c @@ -9,8 +9,7 @@ #include -__attribute__((pcs("aapcs"))) -__attribute__((visibility("hidden"))) +AEABI_RTABI __attribute__((visibility("hidden"))) int __aeabi_cdcmpeq_check_nan(double a, double b) { return __builtin_isnan(a) || __builtin_isnan(b); } diff --git a/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c index 992e31fbd..f1729997a 100644 --- a/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c +++ b/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c @@ -9,8 +9,7 @@ #include -__attribute__((pcs("aapcs"))) -__attribute__((visibility("hidden"))) +AEABI_RTABI __attribute__((visibility("hidden"))) int __aeabi_cfcmpeq_check_nan(float a, float b) { return __builtin_isnan(a) || __builtin_isnan(b); } diff --git a/lib/builtins/arm/aeabi_div0.c b/lib/builtins/arm/aeabi_div0.c index ccc95fa5c..6cc3505dc 100644 --- a/lib/builtins/arm/aeabi_div0.c +++ b/lib/builtins/arm/aeabi_div0.c @@ -30,12 +30,12 @@ extern unsigned char declaration; #if defined(__ARM_EABI__) -int __attribute__((weak)) __attribute__((visibility("hidden"))) +AEABI_RTABI int __attribute__((weak)) __attribute__((visibility("hidden"))) __aeabi_idiv0(int return_value) { return return_value; } -long long __attribute__((weak)) __attribute__((visibility("hidden"))) +AEABI_RTABI long long __attribute__((weak)) __attribute__((visibility("hidden"))) __aeabi_ldiv0(long long return_value) { return return_value; } diff --git a/lib/builtins/arm/aeabi_drsub.c b/lib/builtins/arm/aeabi_drsub.c index fc17d5a4c..125488608 100644 --- a/lib/builtins/arm/aeabi_drsub.c +++ b/lib/builtins/arm/aeabi_drsub.c @@ -10,10 +10,10 @@ #define DOUBLE_PRECISION #include "../fp_lib.h" -COMPILER_RT_ABI fp_t +AEABI_RTABI fp_t __aeabi_dsub(fp_t, fp_t); -COMPILER_RT_ABI fp_t +AEABI_RTABI fp_t __aeabi_drsub(fp_t a, fp_t b) { return __aeabi_dsub(b, a); } diff --git a/lib/builtins/arm/aeabi_frsub.c b/lib/builtins/arm/aeabi_frsub.c index 64258dc7e..34f230374 100644 --- a/lib/builtins/arm/aeabi_frsub.c +++ b/lib/builtins/arm/aeabi_frsub.c @@ -10,10 +10,10 @@ #define SINGLE_PRECISION #include "../fp_lib.h" -COMPILER_RT_ABI fp_t +AEABI_RTABI fp_t __aeabi_fsub(fp_t, fp_t); -COMPILER_RT_ABI fp_t +AEABI_RTABI fp_t __aeabi_frsub(fp_t a, fp_t b) { return __aeabi_fsub(b, a); } diff --git a/lib/builtins/ashldi3.c b/lib/builtins/ashldi3.c index eb4698ac5..fcb0abdb1 100644 --- a/lib/builtins/ashldi3.c +++ b/lib/builtins/ashldi3.c @@ -18,8 +18,6 @@ /* Precondition: 0 <= b < bits_in_dword */ -ARM_EABI_FNALIAS(llsl, ashldi3) - COMPILER_RT_ABI di_int __ashldi3(di_int a, si_int b) { @@ -41,3 +39,10 @@ __ashldi3(di_int a, si_int b) } return result.all; } + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) { + return __ashldi3(a, b); +} +#endif + diff --git a/lib/builtins/ashrdi3.c b/lib/builtins/ashrdi3.c index 14c878bb7..b4ab4c617 100644 --- a/lib/builtins/ashrdi3.c +++ b/lib/builtins/ashrdi3.c @@ -18,8 +18,6 @@ /* Precondition: 0 <= b < bits_in_dword */ -ARM_EABI_FNALIAS(lasr, ashrdi3) - COMPILER_RT_ABI di_int __ashrdi3(di_int a, si_int b) { @@ -42,3 +40,10 @@ __ashrdi3(di_int a, si_int b) } return result.all; } + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) { + return __ashrdi3(a, b); +} +#endif + diff --git a/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c index 9e2975223..c5bb169d0 100644 --- a/lib/builtins/comparedf2.c +++ b/lib/builtins/comparedf2.c @@ -113,8 +113,6 @@ __gedf2(fp_t a, fp_t b) { } } -ARM_EABI_FNALIAS(dcmpun, unorddf2) - COMPILER_RT_ABI int __unorddf2(fp_t a, fp_t b) { const rep_t aAbs = toRep(a) & absMask; @@ -144,3 +142,9 @@ __gtdf2(fp_t a, fp_t b) { return __gedf2(a, b); } +#if defined(__ARM_EABI__) +AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) { + return __unorddf2(a, b); +} +#endif + diff --git a/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c index 1fd50636a..4badb5e1b 100644 --- a/lib/builtins/comparesf2.c +++ b/lib/builtins/comparesf2.c @@ -113,8 +113,6 @@ __gesf2(fp_t a, fp_t b) { } } -ARM_EABI_FNALIAS(fcmpun, unordsf2) - COMPILER_RT_ABI int __unordsf2(fp_t a, fp_t b) { const rep_t aAbs = toRep(a) & absMask; @@ -143,3 +141,10 @@ COMPILER_RT_ABI enum GE_RESULT __gtsf2(fp_t a, fp_t b) { return __gesf2(a, b); } + +#if defined(__ARM_EABI__) +AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) { + return __unordsf2(a, b); +} +#endif + diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c index ab44c2b25..492e32b85 100644 --- a/lib/builtins/divdf3.c +++ b/lib/builtins/divdf3.c @@ -19,8 +19,6 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(ddiv, divdf3) - COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) { @@ -183,3 +181,10 @@ __divdf3(fp_t a, fp_t b) { return result; } } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) { + return __divdf3(a, b); +} +#endif + diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c index de2e37612..aa6289a6d 100644 --- a/lib/builtins/divsf3.c +++ b/lib/builtins/divsf3.c @@ -19,8 +19,6 @@ #define SINGLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(fdiv, divsf3) - COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) { @@ -167,3 +165,10 @@ __divsf3(fp_t a, fp_t b) { return fromRep(absResult | quotientSign); } } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) { + return __divsf3(a, b); +} +#endif + diff --git a/lib/builtins/divsi3.c b/lib/builtins/divsi3.c index bab4aefda..3852e3990 100644 --- a/lib/builtins/divsi3.c +++ b/lib/builtins/divsi3.c @@ -16,8 +16,6 @@ /* Returns: a / b */ -ARM_EABI_FNALIAS(idiv, divsi3) - COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { @@ -35,3 +33,10 @@ __divsi3(si_int a, si_int b) */ return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */ } + +#if defined(__ARM_EABI__) +AEABI_RTABI si_int __aeabi_idiv(si_int a, si_int b) { + return __divsi3(a, b); +} +#endif + diff --git a/lib/builtins/extendhfsf2.c b/lib/builtins/extendhfsf2.c index 27115a48c..e7d9fde8a 100644 --- a/lib/builtins/extendhfsf2.c +++ b/lib/builtins/extendhfsf2.c @@ -12,8 +12,6 @@ #define DST_SINGLE #include "fp_extend_impl.inc" -ARM_EABI_FNALIAS(h2f, extendhfsf2) - // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) { @@ -23,3 +21,10 @@ COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) { COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) { return __extendhfsf2(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI float __aeabi_h2f(uint16_t a) { + return __extendhfsf2(a); +} +#endif + diff --git a/lib/builtins/extendsfdf2.c b/lib/builtins/extendsfdf2.c index 7a267c2f4..b9e7a7471 100644 --- a/lib/builtins/extendsfdf2.c +++ b/lib/builtins/extendsfdf2.c @@ -12,8 +12,13 @@ #define DST_DOUBLE #include "fp_extend_impl.inc" -ARM_EABI_FNALIAS(f2d, extendsfdf2) - COMPILER_RT_ABI double __extendsfdf2(float a) { return __extendXfYf2__(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI double __aeabi_f2d(float a) { + return __extendsfdf2(a); +} +#endif + diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c index 14283ef42..31d76df28 100644 --- a/lib/builtins/fixdfdi.c +++ b/lib/builtins/fixdfdi.c @@ -10,7 +10,6 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(d2lz, fixdfdi) #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; can set the invalid @@ -44,3 +43,15 @@ __fixdfdi(fp_t a) { } #endif + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int +#if defined(__SOFT_FP__) +__aeabi_d2lz(fp_t a) { +#else +__aeabi_d2lz(double a) { +#endif + return __fixdfdi(a); +} +#endif + diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c index 704e65bc4..fc316dcd0 100644 --- a/lib/builtins/fixdfsi.c +++ b/lib/builtins/fixdfsi.c @@ -14,9 +14,14 @@ typedef si_int fixint_t; typedef su_int fixuint_t; #include "fp_fixint_impl.inc" -ARM_EABI_FNALIAS(d2iz, fixdfsi) - COMPILER_RT_ABI si_int __fixdfsi(fp_t a) { return __fixint(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI si_int __aeabi_d2iz(fp_t a) { + return __fixdfsi(a); +} +#endif + diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c index fab47e272..c43473637 100644 --- a/lib/builtins/fixsfdi.c +++ b/lib/builtins/fixsfdi.c @@ -11,8 +11,6 @@ #define SINGLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(f2lz, fixsfdi) - #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; can set the invalid * flag as a side-effect of computation. @@ -45,3 +43,15 @@ __fixsfdi(fp_t a) { } #endif + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int +#if defined(__SOFT_FP__) +__aeabi_f2lz(fp_t a) { +#else +__aeabi_f2lz(float a) { +#endif + return __fixsfdi(a); +} +#endif + diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c index f045536d6..3276df966 100644 --- a/lib/builtins/fixsfsi.c +++ b/lib/builtins/fixsfsi.c @@ -14,9 +14,14 @@ typedef si_int fixint_t; typedef su_int fixuint_t; #include "fp_fixint_impl.inc" -ARM_EABI_FNALIAS(f2iz, fixsfsi) - COMPILER_RT_ABI si_int __fixsfsi(fp_t a) { return __fixint(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI si_int __aeabi_f2iz(fp_t a) { + return __fixsfsi(a); +} +#endif + diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c index 4b0bc9e1d..b73440970 100644 --- a/lib/builtins/fixunsdfdi.c +++ b/lib/builtins/fixunsdfdi.c @@ -11,8 +11,6 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(d2ulz, fixunsdfdi) - #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; can set the invalid * flag as a side-effect of computation. @@ -42,3 +40,15 @@ __fixunsdfdi(fp_t a) { } #endif + +#if defined(__ARM_EABI__) +AEABI_RTABI du_int +#if defined(__SOFT_FP__) +__aeabi_d2ulz(fp_t a) { +#else +__aeabi_d2ulz(double a) { +#endif + return __fixunsdfdi(a); +} +#endif + diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c index 232d342d7..bb3d8e0f8 100644 --- a/lib/builtins/fixunsdfsi.c +++ b/lib/builtins/fixunsdfsi.c @@ -13,9 +13,14 @@ typedef su_int fixuint_t; #include "fp_fixuint_impl.inc" -ARM_EABI_FNALIAS(d2uiz, fixunsdfsi) - COMPILER_RT_ABI su_int __fixunsdfsi(fp_t a) { return __fixuint(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) { + return __fixunsdfsi(a); +} +#endif + diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c index f8ebab854..5d92245df 100644 --- a/lib/builtins/fixunssfdi.c +++ b/lib/builtins/fixunssfdi.c @@ -11,8 +11,6 @@ #define SINGLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(f2ulz, fixunssfdi) - #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; can set the invalid * flag as a side-effect of computation. @@ -43,3 +41,15 @@ __fixunssfdi(fp_t a) { } #endif + +#if defined(__ARM_EABI__) +AEABI_RTABI du_int +#if defined(__SOFT_FP__) +__aeabi_f2ulz(fp_t a) { +#else +__aeabi_f2ulz(float a) { +#endif + return __fixunssfdi(a); +} +#endif + diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c index cc2b05bd8..91d5e8ae5 100644 --- a/lib/builtins/fixunssfsi.c +++ b/lib/builtins/fixunssfsi.c @@ -17,9 +17,14 @@ typedef su_int fixuint_t; #include "fp_fixuint_impl.inc" -ARM_EABI_FNALIAS(f2uiz, fixunssfsi) - COMPILER_RT_ABI su_int __fixunssfsi(fp_t a) { return __fixuint(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) { + return __fixunssfsi(a); +} +#endif + diff --git a/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c index 2b023ad08..fccb29072 100644 --- a/lib/builtins/floatdidf.c +++ b/lib/builtins/floatdidf.c @@ -22,8 +22,6 @@ /* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ -ARM_EABI_FNALIAS(l2d, floatdidf) - #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; we'll set the inexact flag * as a side-effect of this computation. @@ -105,3 +103,10 @@ __floatdidf(di_int a) return fb.f; } #endif + +#if defined(__AEABI__) +AEABI_RTABI double __aeabi_l2d(di_int a) { + return __floatdidf(a); +} +#endif + diff --git a/lib/builtins/floatdisf.c b/lib/builtins/floatdisf.c index 3e47580ef..dd548165c 100644 --- a/lib/builtins/floatdisf.c +++ b/lib/builtins/floatdisf.c @@ -22,8 +22,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(l2f, floatdisf) - COMPILER_RT_ABI float __floatdisf(di_int a) { @@ -78,3 +76,10 @@ __floatdisf(di_int a) ((su_int)a & 0x007FFFFF); /* mantissa */ return fb.f; } + +#if defined(__ARM_EABI__) +AEABI_RTABI float __aeabi_l2f(di_int a) { + return __floatdisf(a); +} +#endif + diff --git a/lib/builtins/floatsidf.c b/lib/builtins/floatsidf.c index 1cf99b782..2ae395bdc 100644 --- a/lib/builtins/floatsidf.c +++ b/lib/builtins/floatsidf.c @@ -18,8 +18,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(i2d, floatsidf) - COMPILER_RT_ABI fp_t __floatsidf(int a) { @@ -51,3 +49,10 @@ __floatsidf(int a) { // Insert the sign bit and return return fromRep(result | sign); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_i2d(int a) { + return __floatsidf(a); +} +#endif + diff --git a/lib/builtins/floatsisf.c b/lib/builtins/floatsisf.c index 467dd1d1e..08891fcdf 100644 --- a/lib/builtins/floatsisf.c +++ b/lib/builtins/floatsisf.c @@ -18,8 +18,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(i2f, floatsisf) - COMPILER_RT_ABI fp_t __floatsisf(int a) { @@ -57,3 +55,10 @@ __floatsisf(int a) { // Insert the sign bit and return return fromRep(result | sign); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_i2f(int a) { + return __floatsisf(a); +} +#endif + diff --git a/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c index cfd3a7a3b..6c1a931ef 100644 --- a/lib/builtins/floatundidf.c +++ b/lib/builtins/floatundidf.c @@ -22,8 +22,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(ul2d, floatundidf) - #ifndef __SOFT_FP__ /* Support for systems that have hardware floating-point; we'll set the inexact flag * as a side-effect of this computation. @@ -104,3 +102,10 @@ __floatundidf(du_int a) return fb.f; } #endif + +#if defined(__ARM_EABI__) +AEABI_RTABI double __aeabi_ul2d(du_int a) { + return __floatundidf(a); +} +#endif + diff --git a/lib/builtins/floatundisf.c b/lib/builtins/floatundisf.c index 713a44abc..86841a75d 100644 --- a/lib/builtins/floatundisf.c +++ b/lib/builtins/floatundisf.c @@ -22,8 +22,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(ul2f, floatundisf) - COMPILER_RT_ABI float __floatundisf(du_int a) { @@ -75,3 +73,10 @@ __floatundisf(du_int a) ((su_int)a & 0x007FFFFF); /* mantissa */ return fb.f; } + +#if defined(__ARM_EABI__) +AEABI_RTABI float __aeabi_ul2f(du_int a) { + return __floatundisf(a); +} +#endif + diff --git a/lib/builtins/floatunsidf.c b/lib/builtins/floatunsidf.c index 445e18041..8d4807194 100644 --- a/lib/builtins/floatunsidf.c +++ b/lib/builtins/floatunsidf.c @@ -18,8 +18,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(ui2d, floatunsidf) - COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) { @@ -40,3 +38,10 @@ __floatunsidf(unsigned int a) { result += (rep_t)(exponent + exponentBias) << significandBits; return fromRep(result); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) { + return __floatunsidf(a); +} +#endif + diff --git a/lib/builtins/floatunsisf.c b/lib/builtins/floatunsisf.c index ea6f161ad..f194c046d 100644 --- a/lib/builtins/floatunsisf.c +++ b/lib/builtins/floatunsisf.c @@ -18,8 +18,6 @@ #include "int_lib.h" -ARM_EABI_FNALIAS(ui2f, floatunsisf) - COMPILER_RT_ABI fp_t __floatunsisf(unsigned int a) { @@ -48,3 +46,10 @@ __floatunsisf(unsigned int a) { result += (rep_t)(exponent + exponentBias) << significandBits; return fromRep(result); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) { + return __floatunsisf(a); +} +#endif + diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h index 63d911a20..9a8092d50 100644 --- a/lib/builtins/int_lib.h +++ b/lib/builtins/int_lib.h @@ -30,18 +30,17 @@ /* ABI macro definitions */ #if __ARM_EABI__ -# define ARM_EABI_FNALIAS(aeabi_name, name) \ - void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); # ifdef COMPILER_RT_ARMHF_TARGET # define COMPILER_RT_ABI # else # define COMPILER_RT_ABI __attribute__((__pcs__("aapcs"))) # endif #else -# define ARM_EABI_FNALIAS(aeabi_name, name) # define COMPILER_RT_ABI #endif +#define AEABI_RTABI __attribute__((__pcs__("aapcs"))) + #ifdef _MSC_VER #define ALWAYS_INLINE __forceinline #define NOINLINE __declspec(noinline) diff --git a/lib/builtins/lshrdi3.c b/lib/builtins/lshrdi3.c index 6b1ea923b..becbbef4e 100644 --- a/lib/builtins/lshrdi3.c +++ b/lib/builtins/lshrdi3.c @@ -18,8 +18,6 @@ /* Precondition: 0 <= b < bits_in_dword */ -ARM_EABI_FNALIAS(llsr, lshrdi3) - COMPILER_RT_ABI di_int __lshrdi3(di_int a, si_int b) { @@ -41,3 +39,10 @@ __lshrdi3(di_int a, si_int b) } return result.all; } + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) { + return __lshrdi3(a, b); +} +#endif + diff --git a/lib/builtins/muldf3.c b/lib/builtins/muldf3.c index 1eb733849..59a60190e 100644 --- a/lib/builtins/muldf3.c +++ b/lib/builtins/muldf3.c @@ -15,8 +15,13 @@ #define DOUBLE_PRECISION #include "fp_mul_impl.inc" -ARM_EABI_FNALIAS(dmul, muldf3) - COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) { return __mulXf3__(a, b); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) { + return __muldf3(a, b); +} +#endif + diff --git a/lib/builtins/muldi3.c b/lib/builtins/muldi3.c index 2dae44c11..6818a9e2f 100644 --- a/lib/builtins/muldi3.c +++ b/lib/builtins/muldi3.c @@ -40,8 +40,6 @@ __muldsi3(su_int a, su_int b) /* Returns: a * b */ -ARM_EABI_FNALIAS(lmul, muldi3) - COMPILER_RT_ABI di_int __muldi3(di_int a, di_int b) { @@ -54,3 +52,10 @@ __muldi3(di_int a, di_int b) r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; return r.all; } + +#if defined(__ARM_EABI__) +AEABI_RTABI di_int __aeabi_lmul(di_int a, di_int b) { + return __muldi3(a, b); +} +#endif + diff --git a/lib/builtins/mulsf3.c b/lib/builtins/mulsf3.c index 478b3bc0e..f141af1ac 100644 --- a/lib/builtins/mulsf3.c +++ b/lib/builtins/mulsf3.c @@ -15,8 +15,13 @@ #define SINGLE_PRECISION #include "fp_mul_impl.inc" -ARM_EABI_FNALIAS(fmul, mulsf3) - COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) { return __mulXf3__(a, b); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) { + return __mulsf3(a, b); +} +#endif + diff --git a/lib/builtins/negdf2.c b/lib/builtins/negdf2.c index d634b421c..5e2544cdb 100644 --- a/lib/builtins/negdf2.c +++ b/lib/builtins/negdf2.c @@ -14,9 +14,14 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(dneg, negdf2) - COMPILER_RT_ABI fp_t __negdf2(fp_t a) { return fromRep(toRep(a) ^ signBit); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_dneg(fp_t a) { + return __negdf2(a); +} +#endif + diff --git a/lib/builtins/negsf2.c b/lib/builtins/negsf2.c index 29c17be41..f90b34335 100644 --- a/lib/builtins/negsf2.c +++ b/lib/builtins/negsf2.c @@ -14,9 +14,14 @@ #define SINGLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(fneg, negsf2) - COMPILER_RT_ABI fp_t __negsf2(fp_t a) { return fromRep(toRep(a) ^ signBit); } + +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_fneg(fp_t a) { + return __negsf2(a); +} +#endif + diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c index 7a79e5e77..38340dfab 100644 --- a/lib/builtins/subdf3.c +++ b/lib/builtins/subdf3.c @@ -15,11 +15,15 @@ #define DOUBLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(dsub, subdf3) - // Subtraction; flip the sign bit of b and add. COMPILER_RT_ABI fp_t __subdf3(fp_t a, fp_t b) { return __adddf3(a, fromRep(toRep(b) ^ signBit)); } +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) { + return __subdf3(a, b); +} +#endif + diff --git a/lib/builtins/subsf3.c b/lib/builtins/subsf3.c index c3b85144a..34276b144 100644 --- a/lib/builtins/subsf3.c +++ b/lib/builtins/subsf3.c @@ -15,11 +15,15 @@ #define SINGLE_PRECISION #include "fp_lib.h" -ARM_EABI_FNALIAS(fsub, subsf3) - // Subtraction; flip the sign bit of b and add. COMPILER_RT_ABI fp_t __subsf3(fp_t a, fp_t b) { return __addsf3(a, fromRep(toRep(b) ^ signBit)); } +#if defined(__ARM_EABI__) +AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) { + return __subsf3(a, b); +} +#endif + diff --git a/lib/builtins/truncdfhf2.c b/lib/builtins/truncdfhf2.c index 17195cd9e..4bb71aa17 100644 --- a/lib/builtins/truncdfhf2.c +++ b/lib/builtins/truncdfhf2.c @@ -11,8 +11,13 @@ #define DST_HALF #include "fp_trunc_impl.inc" -ARM_EABI_FNALIAS(d2h, truncdfhf2) - COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { return __truncXfYf2__(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI uint16_t __aeabi_d2h(double a) { + return __truncdfhf2(a); +} +#endif + diff --git a/lib/builtins/truncdfsf2.c b/lib/builtins/truncdfsf2.c index 46ec11dcc..8bf58bb23 100644 --- a/lib/builtins/truncdfsf2.c +++ b/lib/builtins/truncdfsf2.c @@ -11,8 +11,13 @@ #define DST_SINGLE #include "fp_trunc_impl.inc" -ARM_EABI_FNALIAS(d2f, truncdfsf2) - COMPILER_RT_ABI float __truncdfsf2(double a) { return __truncXfYf2__(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI float __aeabi_d2f(double a) { + return __truncdfsf2(a); +} +#endif + diff --git a/lib/builtins/truncsfhf2.c b/lib/builtins/truncsfhf2.c index 9d61895bf..f6ce1fa1d 100644 --- a/lib/builtins/truncsfhf2.c +++ b/lib/builtins/truncsfhf2.c @@ -11,8 +11,6 @@ #define DST_HALF #include "fp_trunc_impl.inc" -ARM_EABI_FNALIAS(f2h, truncsfhf2) - // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) { @@ -22,3 +20,10 @@ COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) { COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); } + +#if defined(__ARM_EABI__) +AEABI_RTABI uint16_t __aeabi_f2h(float a) { + return __truncsfhf2(a); +} +#endif + diff --git a/lib/builtins/udivsi3.c b/lib/builtins/udivsi3.c index 5d0140cc3..8eccf102c 100644 --- a/lib/builtins/udivsi3.c +++ b/lib/builtins/udivsi3.c @@ -18,8 +18,6 @@ /* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ -ARM_EABI_FNALIAS(uidiv, udivsi3) - /* This function should not call __divsi3! */ COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d) @@ -64,3 +62,10 @@ __udivsi3(su_int n, su_int d) q = (q << 1) | carry; return q; } + +#if defined(__ARM_EABI__) +AEABI_RTABI su_int __aeabi_uidiv(su_int n, su_int d) { + return __udivsi3(n, d); +} +#endif + -- cgit v1.2.1 From c74078b0a058c70de3504cb2533352ee48e71836 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 16 May 2017 17:06:48 +0000 Subject: builtins: add missing includes This inclusion is needed to fix the ARM build. The int_lib.h include is slightly ugly, but allows us to use the `AEABI_RTABI` macro to decorate the CC for the functions. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303190 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_cdcmpeq_check_nan.c | 1 + lib/builtins/arm/aeabi_cfcmpeq_check_nan.c | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c index b640f9776..7578433a1 100644 --- a/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c +++ b/lib/builtins/arm/aeabi_cdcmpeq_check_nan.c @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include +#include "../int_lib.h" AEABI_RTABI __attribute__((visibility("hidden"))) int __aeabi_cdcmpeq_check_nan(double a, double b) { diff --git a/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c b/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c index f1729997a..43dde9a49 100644 --- a/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c +++ b/lib/builtins/arm/aeabi_cfcmpeq_check_nan.c @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include +#include "../int_lib.h" AEABI_RTABI __attribute__((visibility("hidden"))) int __aeabi_cfcmpeq_check_nan(float a, float b) { -- cgit v1.2.1 From e60a00c0dfb05bad4912315912b70fa35050a058 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 16 May 2017 18:19:44 +0000 Subject: builtins: one more case of a missing header git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303195 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_div0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/builtins/arm/aeabi_div0.c b/lib/builtins/arm/aeabi_div0.c index 6cc3505dc..dc3031326 100644 --- a/lib/builtins/arm/aeabi_div0.c +++ b/lib/builtins/arm/aeabi_div0.c @@ -26,6 +26,8 @@ * line. */ +#include "../int_lib.h" + /* provide an unused declaration to pacify pendantic compilation */ extern unsigned char declaration; -- cgit v1.2.1 From 016b0e306f2357455655c7d07a03bb1e8353c71b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 16 May 2017 20:25:07 +0000 Subject: builtins: fix guard __AEABI__ -> __ARM_EABI__ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303207 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/floatdidf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c index fccb29072..681fecef9 100644 --- a/lib/builtins/floatdidf.c +++ b/lib/builtins/floatdidf.c @@ -104,7 +104,7 @@ __floatdidf(di_int a) } #endif -#if defined(__AEABI__) +#if defined(__ARM_EABI__) AEABI_RTABI double __aeabi_l2d(di_int a) { return __floatdidf(a); } -- cgit v1.2.1 From 38cc92468ebb3b822a4ae9387939ad99b06fe56a Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 17 May 2017 14:35:17 +0000 Subject: Implement tls scanning for darwin LSan Summary: This required for any users who call exit() after creating thread-specific data, as tls destructors are only called when pthread_exit() or pthread_cancel() are used. This should also match tls behavior on linux. Getting the base address of the tls section is straightforward, as it's stored as a section offset in %gs. The size is a bit trickier to work out, as there doesn't appear to be any official documentation or source code referring to it. The size used in this patch was determined by taking the difference between the base address and the address of the subsequent memory region returned by vm_region_recurse_64, which was 1024 * sizeof(uptr) on all threads except the main thread, where it was larger. Since the section must be the same size on all of the threads, 1024 * sizeof(uptr) seemed to be a reasonable size to use, barring a more programtic way to get the size. 1024 seems like a reasonable number, given that PTHREAD_KEYS_MAX is 512 on darwin, so pthread keys will fit inside the region while leaving space for other tls data. A larger size would overflow the memory region returned by vm_region_recurse_64, and a smaller size wouldn't leave room for all the pthread keys. In addition, the stress test added here passes, which means that we are scanning at least the full set of possible pthread keys, and probably the full tls section. Reviewers: alekseyshl, kubamracek Subscribers: krytarowski, llvm-commits Differential Revision: https://reviews.llvm.org/D33215 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303262 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 28 ++++++----- lib/lsan/lsan_common_mac.cc | 7 +-- lib/lsan/lsan_flags.inc | 2 +- lib/sanitizer_common/sanitizer_mac.cc | 25 +++++++++- test/lsan/TestCases/many_tls_keys.cc | 94 +++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 test/lsan/TestCases/many_tls_keys.cc diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a6b3453f5..9f862ac96 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -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_end > 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) { diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 5ee1e2286..839dea4ad 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -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) { diff --git a/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc index 8135bdcff..e390e2ae5 100644 --- a/lib/lsan/lsan_flags.inc +++ b/lib/lsan/lsan_flags.inc @@ -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().") diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 2f990b805..6fa2e4a66 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -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; diff --git a/test/lsan/TestCases/many_tls_keys.cc b/test/lsan/TestCases/many_tls_keys.cc new file mode 100644 index 000000000..ae5776770 --- /dev/null +++ b/test/lsan/TestCases/many_tls_keys.cc @@ -0,0 +1,94 @@ +// 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 + +#include +#include +#include +#include +#include + +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: -- cgit v1.2.1 From ea3b9d9e843576962991c63e7e644fe507775db0 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 17 May 2017 15:25:41 +0000 Subject: Revert "Implement tls scanning for darwin LSan" This reverts r303262, due to TSan buildbot breakages. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303266 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 28 +++++------ lib/lsan/lsan_common_mac.cc | 7 ++- lib/lsan/lsan_flags.inc | 2 +- lib/sanitizer_common/sanitizer_mac.cc | 25 +--------- test/lsan/TestCases/many_tls_keys.cc | 94 ----------------------------------- 5 files changed, 22 insertions(+), 134 deletions(-) delete mode 100644 test/lsan/TestCases/many_tls_keys.cc diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 9f862ac96..a6b3453f5 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -265,21 +265,19 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } if (flags()->use_tls) { - 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_end > 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); - } + 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 (dtls && !DTLSInDestruction(dtls)) { for (uptr j = 0; j < dtls->dtv_size; ++j) { diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 839dea4ad..5ee1e2286 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -91,7 +91,12 @@ LoadedModule *GetLinker() { return nullptr; } // Required on Linux for initialization of TLS behavior, but should not be // required on Darwin. -void InitializePlatformSpecificModules() {} +void InitializePlatformSpecificModules() { + if (flags()->use_tls) { + Report("use_tls=1 is not supported on Darwin.\n"); + Die(); + } +} // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { diff --git a/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc index e390e2ae5..8135bdcff 100644 --- a/lib/lsan/lsan_flags.inc +++ b/lib/lsan/lsan_flags.inc @@ -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, true, +LSAN_FLAG(bool, use_tls, !SANITIZER_MAC, "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().") diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 6fa2e4a66..2f990b805 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -370,27 +370,6 @@ 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 @@ -398,8 +377,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 = TlsBaseAddr(); - *tls_size = TlsSize(); + *tls_addr = 0; + *tls_size = 0; #else *stk_addr = 0; *stk_size = 0; diff --git a/test/lsan/TestCases/many_tls_keys.cc b/test/lsan/TestCases/many_tls_keys.cc deleted file mode 100644 index ae5776770..000000000 --- a/test/lsan/TestCases/many_tls_keys.cc +++ /dev/null @@ -1,94 +0,0 @@ -// 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 - -#include -#include -#include -#include -#include - -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: -- cgit v1.2.1 From 63fe54047c4144770a23b3319cea468e58b00c90 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Wed, 17 May 2017 16:44:08 +0000 Subject: Include setjmp.h unconditionally in asan_test_utils.h It's used in asan_test.cc also on Windows, and my build was failing with: C:/src/llvm/projects/compiler-rt/lib/asan/tests/asan_test.cc:549:28: error: unknown type name 'jmp_buf' NOINLINE void LongJmpFunc1(jmp_buf buf) { ^ C:/src/llvm/projects/compiler-rt/lib/asan/tests/asan_test.cc:569:10: error: unknown type name 'jmp_buf' static jmp_buf buf; ^ I couldn't find what changed to make this not work anymore, but this should fix it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303273 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h index f16d939c9..c29246722 100644 --- a/lib/asan/tests/asan_test_utils.h +++ b/lib/asan/tests/asan_test_utils.h @@ -30,11 +30,11 @@ #include #include #include +#include #if !defined(_WIN32) # include # include -# include #endif #ifdef __linux__ -- cgit v1.2.1 From 065bca6ffc04e16b759b8396716394dccbbe6d7b Mon Sep 17 00:00:00 2001 From: Leo Li Date: Wed, 17 May 2017 17:17:41 +0000 Subject: Generate ubsan shared libraries. Summary: Those libraries are required by aosp (https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+/master/Android.mk). Currenly the shared libraries are generated by aosp Makefile system. We are looking forward to using cmake to generate them. Reviewers: llvm-commits, vsk Reviewed By: vsk Subscribers: filcab, vsk, srhines, kubamracek, mgorny, krytarowski Differential Revision: https://reviews.llvm.org/D33216 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303276 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 7e10456e3..103972a49 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -34,6 +34,14 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) +append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBC c UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBM m UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) + add_compiler_rt_component(ubsan) if(APPLE) @@ -144,6 +152,27 @@ else() CFLAGS ${UBSAN_CXXFLAGS} PARENT_TARGET ubsan) + add_compiler_rt_runtime(clang_rt.ubsan_standalone + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTSanitizerCommon + RTSanitizerCommonLibc + RTUbsan + CFLAGS ${UBSAN_CFLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan) + + add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTSanitizerCommon + RTSanitizerCommonLibc + RTUbsan + RTUbsan_cxx + CFLAGS ${UBSAN_CXXFLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan) + if (UNIX) set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) -- cgit v1.2.1 From 3cd2b8fb91fd44fcd076ad4fe747922710c0f74e Mon Sep 17 00:00:00 2001 From: Leo Li Date: Wed, 17 May 2017 19:37:27 +0000 Subject: [Ubsan]Remove unused link libraries. Summary: Remove unused link libraries metioned in D33216. Reviewers: llvm-commits, vsk Reviewed By: vsk Subscribers: vsk, kubamracek, mgorny, filcab Differential Revision: https://reviews.llvm.org/D33292 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303286 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 103972a49..457a6b475 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -35,13 +35,9 @@ append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBC c UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBM m UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) - + add_compiler_rt_component(ubsan) if(APPLE) -- cgit v1.2.1 From e1cd1705926eb39307a7239bf0531c55940a3639 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Wed, 17 May 2017 21:20:00 +0000 Subject: [XRay] Fix __xray_function_address on PPC reguarding local entry points. Reviewers: echristo, dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33266 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303302 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_interface.cc | 9 ++++++++- test/xray/TestCases/Linux/func-id-utils.cc | 16 ++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index c437a72e3..523ed16b9 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -326,7 +326,14 @@ uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); if (FuncId <= 0 || static_cast(FuncId) > XRayInstrMap.Functions) return 0; - return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Address; + return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Address +// On PPC, function entries are always aligned to 16 bytes. The beginning of a +// sled might be a local entry, which is always +8 based on the global entry. +// Always return the global entry. +#ifdef __PPC__ + & ~0xf +#endif + ; } size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc index c9a2952c6..17185c34c 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -31,18 +31,10 @@ "each function id must be assigned to a unique function"); std::set not_instrumented; - const auto comp = [](void *lhs, void *rhs) { -#ifdef __PPC__ - return reinterpret_cast(lhs) + 8 < - reinterpret_cast(rhs); -#else - return lhs < rhs; -#endif - }; - std::set_difference(must_be_instrumented.begin(), must_be_instrumented.end(), - all_instrumented.begin(), all_instrumented.end(), - std::inserter(not_instrumented, not_instrumented.begin()), - comp); + std::set_difference( + must_be_instrumented.begin(), must_be_instrumented.end(), + all_instrumented.begin(), all_instrumented.end(), + std::inserter(not_instrumented, not_instrumented.begin())); assert( not_instrumented.empty() && "we should see all explicitly instrumented functions with function ids"); -- cgit v1.2.1 From 8fa13187fafaa413e9b2eeda84b66dfc4ac7275c Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 18 May 2017 03:00:07 +0000 Subject: temporary disable stndup interceptor, due to r302781 being buggy git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303324 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform_interceptors.h | 5 +++-- lib/sanitizer_common/tests/sanitizer_test_utils.h | 3 ++- test/asan/TestCases/Posix/strndup_oob_test.cc | 11 ++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a95497467..a1a0f4391 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -98,8 +98,9 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 -#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD +// temporary disabled until r302781 is reverted or fixed. +#define SANITIZER_INTERCEPT_STRNDUP (0 && SI_POSIX) +#define SANITIZER_INTERCEPT___STRNDUP (0 && SI_LINUX_NOT_FREEBSD) #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index b7728d9ea..f42142aaa 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -125,7 +125,8 @@ static inline uint32_t my_rand() { #endif #if !defined(_MSC_VER) -# define SANITIZER_TEST_HAS_STRNDUP 1 +// Test temporary disabled until r302781 is reverted or fixed. +# define SANITIZER_TEST_HAS_STRNDUP 0 #else # define SANITIZER_TEST_HAS_STRNDUP 0 #endif diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc index 7ea0b7a33..09df96471 100644 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -1,10 +1,11 @@ -// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: echo DISABLED +// DISABLED: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// DISABLED: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// DISABLED: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// DISABLED: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s // When built as C on Linux, strndup is transformed to __strndup. -// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s +// DISABLED: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s // Unwind problem on arm: "main" is missing from the allocation stack trace. // UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf -- cgit v1.2.1 From db37b96cbef5ca2abec3bd3f9956c29ff64dd37f Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Thu, 18 May 2017 09:12:27 +0000 Subject: Fixup r303324 - temporary disable stndup interceptor, due to r302781 being buggy r303324 missed one of the tests added by r302781. This commit applies the same fix as r303324 to the missed test (strndup.cc). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303338 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/strndup.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc index d4b9af1a9..4b133ae49 100644 --- a/test/msan/strndup.cc +++ b/test/msan/strndup.cc @@ -1,8 +1,9 @@ -// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s -// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s +// RUN: echo DISABLED +// DISABLED: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s +// DISABLED: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s // When built as C on Linux, strndup is transformed to __strndup. -// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s +// DISABLED: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s // UNSUPPORTED: win32 -- cgit v1.2.1 From 17219d802f003f2e21fd5432d7cd19501b61acad Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Thu, 18 May 2017 09:31:37 +0000 Subject: Revert r302781 and subsequent attempts to disable part of it. The Msan unit tests are still broken and by this point, I think we should start over. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303339 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 -- lib/asan/tests/asan_str_test.cc | 21 ----------- lib/msan/msan_interceptors.cc | 36 ++++++++++++++---- lib/msan/tests/msan_test.cc | 6 +-- .../sanitizer_common_interceptors.inc | 43 ---------------------- lib/sanitizer_common/sanitizer_flags.inc | 3 -- .../sanitizer_platform_interceptors.h | 15 -------- lib/sanitizer_common/tests/sanitizer_test_utils.h | 7 ---- test/asan/TestCases/Posix/strndup_oob_test.cc | 28 -------------- test/msan/strndup.cc | 29 --------------- 10 files changed, 31 insertions(+), 161 deletions(-) delete mode 100644 test/asan/TestCases/Posix/strndup_oob_test.cc delete mode 100644 test/msan/strndup.cc diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 6be0d6e94..c8ae3faed 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,10 +194,6 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } - if (!f->replace_str && common_flags()->intercept_strndup) { - Report("WARNING: strndup* interceptors are enabled even though " - "replace_str=0. Use intercept_strndup=0 to disable them."); - } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index 8f4911fd9..c790088f8 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,27 +154,6 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } -#if SANITIZER_TEST_HAS_STRNDUP -TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { - size_t size = Ident(42); - char *str = MallocAndMemsetString(size); - char *new_str; - // Normal strndup calls. - str[size - 1] = '\0'; - new_str = strndup(str, size - 13); - free(new_str); - new_str = strndup(str + size - 1, 13); - free(new_str); - // Argument points to not allocated memory. - EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); - EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); - // Overwrite the terminating '\0' and hit unallocated memory. - str[size - 1] = 'z'; - EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); - free(str); -} -#endif // SANITIZER_TEST_HAS_STRNDUP - TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 0f5069344..15543bd91 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,6 +341,33 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif +INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + // On FreeBSD strndup() leverages strnlen(). + InterceptorScope interceptor_scope; + SIZE_T copy_size = REAL(strnlen)(src, n); + char *res = REAL(strndup)(src, n); + CopyShadowAndOrigin(res, src, copy_size, &stack); + __msan_unpoison(res + copy_size, 1); // \0 + return res; +} + +#if !SANITIZER_FREEBSD +INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = REAL(strnlen)(src, n); + char *res = REAL(__strndup)(src, n); + CopyShadowAndOrigin(res, src, copy_size, &stack); + __msan_unpoison(res + copy_size, 1); // \0 + return res; +} +#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) +#else +#define MSAN_MAYBE_INTERCEPT___STRNDUP +#endif + INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1344,13 +1371,6 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } -#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ - do { \ - GET_STORE_STACK_TRACE; \ - CopyShadowAndOrigin(to, from, size, &stack); \ - __msan_unpoison(to + size, 1); \ - } while (false) - #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1518,6 +1538,8 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; + INTERCEPT_FUNCTION(strndup); + MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 58f695e69..c7c91324a 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,8 +1581,7 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x; - EXPECT_UMR(x = strndup(buf, 3)); + char *x = strndup(buf, 3); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); @@ -1594,8 +1593,7 @@ TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x; - EXPECT_UMR(x = strndup(buf, 2)); + char *x = strndup(buf, 2); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 3c69726d7..53204b48e 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,8 +34,6 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL -// COMMON_INTERCEPTOR_COPY_STRING -// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -219,25 +217,6 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif -#ifndef COMMON_INTERCEPTOR_COPY_STRING -#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} -#endif - -#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL -#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ - COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ - uptr from_length = internal_strnlen(s, size); \ - uptr copy_length = Min(size, from_length); \ - char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ - if (common_flags()->intercept_strndup) { \ - COMMON_INTERCEPTOR_READ_RANGE(ctx, s, copy_length + 1); \ - } \ - COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ - internal_memcpy(new_mem, s, copy_length); \ - new_mem[copy_length] = '\0'; \ - return new_mem; -#endif - struct FileMetadata { // For open_memstream(). char **addr; @@ -321,26 +300,6 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif -#if SANITIZER_INTERCEPT_STRNDUP -INTERCEPTOR(char*, strndup, const char *s, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); -} -#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) -#else -#define INIT_STRNDUP -#endif // SANITIZER_INTERCEPT_STRNDUP - -#if SANITIZER_INTERCEPT___STRNDUP -INTERCEPTOR(char*, __strndup, const char *s, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); -} -#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) -#else -#define INIT___STRNDUP -#endif // SANITIZER_INTERCEPT___STRNDUP - #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6204,8 +6163,6 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; - INIT_STRNDUP; - INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 67a0a5810..7a5fffcf6 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -195,9 +195,6 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") -COMMON_FLAG(bool, intercept_strndup, true, - "If set, uses custom wrappers for strndup functions " - "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a1a0f4391..e5644ef25 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,12 +25,6 @@ # define SI_NOT_WINDOWS 0 #endif -#if SANITIZER_POSIX -# define SI_POSIX 1 -#else -# define SI_POSIX 0 -#endif - #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -75,12 +69,6 @@ # define SI_UNIX_NOT_MAC 0 #endif -#if SANITIZER_LINUX && !SANITIZER_FREEBSD -# define SI_LINUX_NOT_FREEBSD 1 -# else -# define SI_LINUX_NOT_FREEBSD 0 -#endif - #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -98,9 +86,6 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 -// temporary disabled until r302781 is reverted or fixed. -#define SANITIZER_INTERCEPT_STRNDUP (0 && SI_POSIX) -#define SANITIZER_INTERCEPT___STRNDUP (0 && SI_LINUX_NOT_FREEBSD) #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index f42142aaa..9c162a66f 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,11 +124,4 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif -#if !defined(_MSC_VER) -// Test temporary disabled until r302781 is reverted or fixed. -# define SANITIZER_TEST_HAS_STRNDUP 0 -#else -# define SANITIZER_TEST_HAS_STRNDUP 0 -#endif - #endif // SANITIZER_TEST_UTILS_H diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc deleted file mode 100644 index 09df96471..000000000 --- a/test/asan/TestCases/Posix/strndup_oob_test.cc +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: echo DISABLED -// DISABLED: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// DISABLED: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s -// DISABLED: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s -// DISABLED: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s - -// When built as C on Linux, strndup is transformed to __strndup. -// DISABLED: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s - -// Unwind problem on arm: "main" is missing from the allocation stack trace. -// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf - -#include - -char kString[] = "foo"; - -int main(int argc, char **argv) { - char *copy = strndup(kString, 2); - int x = copy[2 + argc]; // BOOM - // CHECK: AddressSanitizer: heap-buffer-overflow - // CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]] - // CHECK-LABEL: allocated by thread T{{.*}} here: - // CHECK: #{{[01]}} {{.*}}strndup - // CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]] - // CHECK-LABEL: SUMMARY - // CHECK: strndup_oob_test.cc:[[@LINE-7]] - return x; -} diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc deleted file mode 100644 index 4b133ae49..000000000 --- a/test/msan/strndup.cc +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: echo DISABLED -// DISABLED: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s -// DISABLED: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s - -// When built as C on Linux, strndup is transformed to __strndup. -// DISABLED: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s - -// UNSUPPORTED: win32 - -#include -#include -#include -#include - -int main(int argc, char **argv) { - char kString[4] = "abc"; - __msan_poison(kString + 2, 1); - char *copy = strndup(kString, 4); // BOOM - assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved. - free(copy); - return 0; - // ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4) - // ON: MemorySanitizer: use-of-uninitialized-value - // ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]] - // ON-LABEL: SUMMARY - // ON: {{.*}}strndup.cc:[[@LINE-8]] - // OFF-NOT: MemorySanitizer -} - -- cgit v1.2.1 From f658c0403041f2be54d78cf03b4bf7848a7ab2bc Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Thu, 18 May 2017 13:19:35 +0000 Subject: [compiler-rt][cmake] Build unit tests conditionally with _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE The sanitizer library unit tests for libc can get a different definition of 'struct stat' to what the sanitizer library is built with for certain targets. For MIPS the size element of 'struct stat' is after a macro guarded explicit padding element. This patch resolves any possible inconsistency by adding the same _FILE_OFFSET_BITS=64 and _LARGE_SOURCE with the same conditions as the sanitizer library to the build flags for the unit tests. This resolves a recurring build failure on the MIPS buildbots due to 'struct stat' defintion differences. Reviewers: slthakur Differential Revision: https://reviews.llvm.org/D33131 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303350 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/tests/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index b310f9374..2acedd0ef 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -146,6 +146,15 @@ set_target_properties(SanitizerUnitTests PROPERTIES FOLDER "Compiler-RT Tests") # Adds sanitizer tests for architecture. macro(add_sanitizer_tests_for_arch arch) get_target_flags_for_arch(${arch} TARGET_FLAGS) + + # If the sanitizer library was built with _FILE_OFFSET_BITS=64 we need + # to ensure that the library and tests agree on the layout of certain + # structures such as 'struct stat'. + if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) + list(APPEND TARGET_FLAGS "-D_LARGEFILE_SOURCE") + list(APPEND TARGET_FLAGS "-D_FILE_OFFSET_BITS=64") + endif() + set(SANITIZER_TEST_SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE}) set(SANITIZER_TEST_COMPILE_DEPS ${SANITIZER_TEST_HEADERS}) -- cgit v1.2.1 From 0d7dff4046c8b3f24c84375bacef7079cf56f2a5 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 18 May 2017 20:47:35 +0000 Subject: [scudo] lower quarantine default sizes Summary: After discussing the current defaults with a couple of parties, the consensus is that they are too high. 1Mb of quarantine has about a 4Mb impact on PSS, so memory usage goes up quickly. This is obviously configurable, but the default value should be more "approachable", so both the global size and the thread local size are 1/4 of what they used to be. Reviewers: alekseyshl, kcc Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33321 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303380 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_flags.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scudo/scudo_flags.cpp b/lib/scudo/scudo_flags.cpp index 64da1d9d8..90f0cbf4b 100644 --- a/lib/scudo/scudo_flags.cpp +++ b/lib/scudo/scudo_flags.cpp @@ -68,7 +68,7 @@ void initFlags() { // Sanity checks and default settings for the Quarantine parameters. if (f->QuarantineSizeMb < 0) { - const int DefaultQuarantineSizeMb = FIRST_32_SECOND_64(16, 64); + const int DefaultQuarantineSizeMb = FIRST_32_SECOND_64(4, 16); f->QuarantineSizeMb = DefaultQuarantineSizeMb; } // We enforce an upper limit for the quarantine size of 4Gb. @@ -77,7 +77,7 @@ void initFlags() { } if (f->ThreadLocalQuarantineSizeKb < 0) { const int DefaultThreadLocalQuarantineSizeKb = - FIRST_32_SECOND_64(256, 1024); + FIRST_32_SECOND_64(64, 256); f->ThreadLocalQuarantineSizeKb = DefaultThreadLocalQuarantineSizeKb; } // And an upper limit of 128Mb for the thread quarantine cache. -- cgit v1.2.1 From a0acb10461b015a3d1b8483f2d498f24479314c5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 18 May 2017 23:13:22 +0000 Subject: [compiler-rt] Replace ifs with switch statement in IsHandledDeadlySignal Reviewers: eugenis Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D33158 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303392 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 22 +++++++++++++--------- lib/sanitizer_common/sanitizer_mac.cc | 24 ++++++++++++++---------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index fce78fe59..87f32c44d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1395,15 +1395,19 @@ AndroidApiLevel AndroidGetApiLevel() { #endif bool IsHandledDeadlySignal(int signum) { - if (common_flags()->handle_abort && signum == SIGABRT) - return true; - if (common_flags()->handle_sigill && signum == SIGILL) - return true; - if (common_flags()->handle_sigfpe && signum == SIGFPE) - return true; - if (common_flags()->handle_segv && signum == SIGSEGV) - return true; - return common_flags()->handle_sigbus && signum == SIGBUS; + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return false; } #if !SANITIZER_GO diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 2f990b805..f1a6bf916 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -394,18 +394,22 @@ void ListOfModules::init() { } bool IsHandledDeadlySignal(int signum) { + // Handling fatal signals on watchOS and tvOS devices is disallowed. if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) - // Handling fatal signals on watchOS and tvOS devices is disallowed. return false; - if (common_flags()->handle_abort && signum == SIGABRT) - return true; - if (common_flags()->handle_sigill && signum == SIGILL) - return true; - if (common_flags()->handle_sigfpe && signum == SIGFPE) - return true; - if (common_flags()->handle_segv && signum == SIGSEGV) - return true; - return common_flags()->handle_sigbus && signum == SIGBUS; + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return false; } MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; -- cgit v1.2.1 From 53f2f17bfb164310f560aa6f38665b4e994807f5 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 19 May 2017 13:34:02 +0000 Subject: Use write instead of read permissions to check for global sections on mac Summary: The LINKEDIT section is very large and is read-only. Scanning this section caused LSan on darwin to be very slow. When only writable sections are scanned for global pointers, performance improved by a factor of about 25x. Reviewers: alekseyshl, kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33322 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303422 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 3 ++- lib/sanitizer_common/sanitizer_common.cc | 4 ++-- lib/sanitizer_common/sanitizer_common.h | 8 ++++---- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 4 ++-- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 5ee1e2286..ae1095543 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -110,7 +110,8 @@ void ProcessGlobalRegions(Frontier *frontier) { for (const __sanitizer::LoadedModule::AddressRange &range : modules[i].ranges()) { - if (range.executable || !range.readable) continue; + // Sections storing global variables are writable and non-executable + if (range.executable || !range.writable) continue; ScanGlobalRange(range.beg, range.end, frontier); } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 471c3ded2..7e6f8fce7 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -285,9 +285,9 @@ void LoadedModule::clear() { } void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, - bool readable) { + bool writable) { void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = new(mem) AddressRange(beg, end, executable, readable); + AddressRange *r = new(mem) AddressRange(beg, end, executable, writable); ranges_.push_back(r); if (executable && end > max_executable_address_) max_executable_address_ = end; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index bbe7aebf3..33e652e6c 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -717,7 +717,7 @@ class LoadedModule { void set(const char *module_name, uptr base_address, ModuleArch arch, u8 uuid[kModuleUUIDSize], bool instrumented); void clear(); - void addAddressRange(uptr beg, uptr end, bool executable, bool readable); + void addAddressRange(uptr beg, uptr end, bool executable, bool writable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } @@ -732,14 +732,14 @@ class LoadedModule { uptr beg; uptr end; bool executable; - bool readable; + bool writable; - AddressRange(uptr beg, uptr end, bool executable, bool readable) + AddressRange(uptr beg, uptr end, bool executable, bool writable) : next(nullptr), beg(beg), end(end), executable(executable), - readable(readable) {} + writable(writable) {} }; const IntrusiveList &ranges() const { return ranges_; } diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 25f1e12c0..a15b5858a 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -447,9 +447,9 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; bool executable = phdr->p_flags & PF_X; - bool readable = phdr->p_flags & PF_R; + bool writable = phdr->p_flags & PF_W; cur_module.addAddressRange(cur_beg, cur_end, executable, - readable); + writable); } } data->modules->push_back(cur_module); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 67a659010..c583f42f2 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -142,7 +142,7 @@ void MemoryMappingLayout::DumpListOfModules( LoadedModule cur_module; cur_module.set(cur_name, base_address); cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, - prot & kProtectionRead); + prot & kProtectionWrite); modules->push_back(cur_module); } } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 0b4171a90..131017458 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -336,7 +336,7 @@ void MemoryMappingLayout::DumpListOfModules( current_instrumented_); } cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, - prot & kProtectionRead); + prot & kProtectionWrite); } } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 1a454ba42..d0a5c078c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -554,7 +554,7 @@ void ListOfModules::init() { cur_module.set(module_name, adjusted_base); // We add the whole module as one single address range. cur_module.addAddressRange(base_address, end_address, /*executable*/ true, - /*readable*/ true); + /*writable*/ true); modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -- cgit v1.2.1 From c36f54d7dfb0604b2273981e8a2709e43db1141e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 19 May 2017 22:37:13 +0000 Subject: [compiler-rt] Add negative test for boolean flags. Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D33344 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303462 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/tests/sanitizer_flags_test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc index 24a3f3d3c..d510a3555 100644 --- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -59,6 +59,14 @@ TEST(SanitizerCommon, BooleanFlags) { TestFlag(true, "flag_name=0", false); TestFlag(true, "flag_name=no", false); TestFlag(true, "flag_name=false", false); + + EXPECT_DEATH(TestFlag(false, "flag_name", true), "expected '='"); + EXPECT_DEATH(TestFlag(false, "flag_name=", true), + "Invalid value for bool option: ''"); + EXPECT_DEATH(TestFlag(false, "flag_name=2", true), + "Invalid value for bool option: '2'"); + EXPECT_DEATH(TestFlag(false, "flag_name=-1", true), + "Invalid value for bool option: '-1'"); } TEST(SanitizerCommon, IntFlags) { -- cgit v1.2.1 From 6ed02973ac38d9432948dce571e95131abf6dc00 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 19 May 2017 22:37:16 +0000 Subject: [compiler-rt] Switch handle_ flags from bool to enum. Summary: We are going to make it tri-state and remove allow_user_segv_handler. Reviewers: eugenis, alekseys, kcc Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D33159 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303464 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flag_parser.h | 24 ++++++++++++++++++---- lib/sanitizer_common/sanitizer_flags.h | 5 +++++ lib/sanitizer_common/sanitizer_flags.inc | 24 +++++++++++++--------- lib/sanitizer_common/tests/sanitizer_flags_test.cc | 22 ++++++++++++++++++++ test/asan/TestCases/Posix/asan-sigbus.cpp | 2 +- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 2477aeddb..b6ae307fc 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -34,24 +34,40 @@ class FlagHandler : public FlagHandlerBase { bool Parse(const char *value) final; }; -template <> -inline bool FlagHandler::Parse(const char *value) { +inline bool ParseBool(const char *value, bool *b) { if (internal_strcmp(value, "0") == 0 || internal_strcmp(value, "no") == 0 || internal_strcmp(value, "false") == 0) { - *t_ = false; + *b = false; return true; } if (internal_strcmp(value, "1") == 0 || internal_strcmp(value, "yes") == 0 || internal_strcmp(value, "true") == 0) { - *t_ = true; + *b = true; return true; } + return false; +} + +template <> +inline bool FlagHandler::Parse(const char *value) { + if (ParseBool(value, t_)) return true; Printf("ERROR: Invalid value for bool option: '%s'\n", value); return false; } +template <> +inline bool FlagHandler::Parse(const char *value) { + bool b; + if (ParseBool(value, &b)) { + *t_ = b ? kHandleSignalYes : kHandleSignalNo; + return true; + } + Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); + return false; +} + template <> inline bool FlagHandler::Parse(const char *value) { *t_ = internal_strdup(value); diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h index 503126bbe..f22593395 100644 --- a/lib/sanitizer_common/sanitizer_flags.h +++ b/lib/sanitizer_common/sanitizer_flags.h @@ -18,6 +18,11 @@ namespace __sanitizer { +enum HandleSignalMode { + kHandleSignalNo, + kHandleSignalYes, +}; + struct CommonFlags { #define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name; #include "sanitizer_flags.inc" diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 7a5fffcf6..c5aaf411f 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -78,16 +78,20 @@ 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.") COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") -COMMON_FLAG(bool, handle_segv, true, - "If set, registers the tool's custom SIGSEGV handler.") -COMMON_FLAG(bool, handle_sigbus, true, - "If set, registers the tool's custom SIGBUS handler.") -COMMON_FLAG(bool, handle_abort, false, - "If set, registers the tool's custom SIGABRT handler.") -COMMON_FLAG(bool, handle_sigill, false, - "If set, registers the tool's custom SIGILL handler.") -COMMON_FLAG(bool, handle_sigfpe, true, - "If set, registers the tool's custom SIGFPE handler.") +#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ + "Controls custom tool's " #signal " handler (0 - do not registers the " \ + "handler, 1 - register the handler). " +COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV)) +COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGBUS)) +COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT)) +COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL)) +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.") diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc index d510a3555..34d7067f8 100644 --- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -67,6 +67,28 @@ TEST(SanitizerCommon, BooleanFlags) { "Invalid value for bool option: '2'"); EXPECT_DEATH(TestFlag(false, "flag_name=-1", true), "Invalid value for bool option: '-1'"); + EXPECT_DEATH(TestFlag(false, "flag_name=on", true), + "Invalid value for bool option: 'on'"); +} + +TEST(SanitizerCommon, HandleSignalMode) { + TestFlag(kHandleSignalNo, "flag_name=1", kHandleSignalYes); + TestFlag(kHandleSignalNo, "flag_name=yes", kHandleSignalYes); + TestFlag(kHandleSignalNo, "flag_name=true", kHandleSignalYes); + TestFlag(kHandleSignalYes, "flag_name=0", kHandleSignalNo); + TestFlag(kHandleSignalYes, "flag_name=no", kHandleSignalNo); + TestFlag(kHandleSignalYes, "flag_name=false", kHandleSignalNo); + + 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=-1", kHandleSignalNo), + "Invalid value for signal handler option: '-1'"); + EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=on", kHandleSignalNo), + "Invalid value for signal handler option: 'on'"); } TEST(SanitizerCommon, IntFlags) { diff --git a/test/asan/TestCases/Posix/asan-sigbus.cpp b/test/asan/TestCases/Posix/asan-sigbus.cpp index a7d032ace..d02ebbd9d 100644 --- a/test/asan/TestCases/Posix/asan-sigbus.cpp +++ b/test/asan/TestCases/Posix/asan-sigbus.cpp @@ -2,7 +2,7 @@ // Defaults to true // RUN: %clangxx_asan -std=c++11 %s -o %t // RUN: not %run %t %T/file 2>&1 | FileCheck %s -check-prefix=CHECK-BUS -// RUN: %env_asan_opts=handle_sigbus=false not --crash %run %t %T/file 2>&1 | FileCheck %s +// RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t %T/file 2>&1 | FileCheck %s // UNSUPPORTED: ios -- cgit v1.2.1 From 4991f9f1750bf19481ed9a220356b6a8f4c85f3d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 20 May 2017 01:04:59 +0000 Subject: [compiler-rt] Change default of allow_user_segv_handler to true Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32443 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303476 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 5 ----- lib/asan/tests/asan_test.cc | 21 +++++++++++++-------- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index fdfc46f6e..c807df3cd 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -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 diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7ac72955f..d0128e34d 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -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 diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index c5aaf411f..1972bdafd 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -92,7 +92,7 @@ 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, +COMMON_FLAG(bool, allow_user_segv_handler, true, "If set, allows user to register a SEGV handler even if the tool " "registers one.") COMMON_FLAG(bool, use_sigaltstack, true, -- cgit v1.2.1 From 0793ce266476247913c67258562069bad41260f9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 20 May 2017 02:09:25 +0000 Subject: Revert "[compiler-rt] Change default of allow_user_segv_handler to true" Failed libFuzzer tests on Windows. This reverts commit r303476. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303481 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 5 +++++ lib/asan/tests/asan_test.cc | 21 ++++++++------------- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index c807df3cd..fdfc46f6e 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -327,6 +327,11 @@ 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 diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index d0128e34d..7ac72955f 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -251,8 +251,7 @@ TEST(AddressSanitizer, BitFieldNegativeTest) { namespace { const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address"; -const char kOverriddenSigactionHandler[] = "Test sigaction handler\n"; -const char kOverriddenSignalHandler[] = "Test signal handler\n"; +const char kOverriddenHandler[] = "ASan signal handler has been overridden\n"; TEST(AddressSanitizer, WildAddressTest) { char *c = (char*)0x123; @@ -260,12 +259,12 @@ TEST(AddressSanitizer, WildAddressTest) { } void my_sigaction_sighandler(int, siginfo_t*, void*) { - fprintf(stderr, kOverriddenSigactionHandler); + fprintf(stderr, kOverriddenHandler); exit(1); } void my_signal_sighandler(int signum) { - fprintf(stderr, kOverriddenSignalHandler); + fprintf(stderr, kOverriddenHandler); exit(1); } @@ -274,20 +273,16 @@ TEST(AddressSanitizer, SignalTest) { memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = my_sigaction_sighandler; sigact.sa_flags = SA_SIGINFO; - char *c = (char *)0x123; - - EXPECT_DEATH(*c = 0, kSEGVCrash); - - // ASan should allow to set sigaction()... + // ASan should silently ignore sigaction()... EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0)); #ifdef __APPLE__ EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0)); #endif - EXPECT_DEATH(*c = 0, kOverriddenSigactionHandler); - + char *c = (char*)0x123; + EXPECT_DEATH(*c = 0, kSEGVCrash); // ... and signal(). - EXPECT_NE(SIG_ERR, signal(SIGSEGV, my_signal_sighandler)); - EXPECT_DEATH(*c = 0, kOverriddenSignalHandler); + EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler)); + EXPECT_DEATH(*c = 0, kSEGVCrash); } } // namespace #endif diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 1972bdafd..c5aaf411f 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -92,7 +92,7 @@ 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, true, +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, -- cgit v1.2.1 From 06f1c090cb4e27ea82320bfa7af1e3cfb681edeb Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 22 May 2017 03:23:54 +0000 Subject: [XRay][compiler-rt] Add __xray_remove_customevent_handler(...) This change adds __xray_remove_customevent_handler(...) to be consistent with other APIs that add/remove handlers. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303526 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 4 ++++ lib/xray/xray_interface.cc | 5 +++++ test/xray/TestCases/Linux/custom-event-logging.cc | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index c3833f0be..dc0c277aa 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -69,6 +69,10 @@ extern int __xray_remove_handler_arg1(); /// Provide a function to invoke when XRay encounters a custom event. extern int __xray_set_customevent_handler(void (*entry)(void*, std::size_t)); +/// This removes whatever the currently provided custom event handler is. +/// Returns 1 on success, 0 on error. +extern int __xray_remove_customevent_handler(); + enum XRayPatchingStatus { NOT_INITIALIZED = 0, SUCCESS = 1, diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 523ed16b9..e912b6e47 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -119,10 +119,15 @@ int __xray_set_customevent_handler(void (*entry)(void *, size_t)) return 0; } + int __xray_remove_handler() XRAY_NEVER_INSTRUMENT { return __xray_set_handler(nullptr); } +int __xray_remove_customevent_handler() XRAY_NEVER_INSTRUMENT { + return __xray_set_customevent_handler(nullptr); +} + __sanitizer::atomic_uint8_t XRayPatching{0}; using namespace __xray; diff --git a/test/xray/TestCases/Linux/custom-event-logging.cc b/test/xray/TestCases/Linux/custom-event-logging.cc index b1a766d46..9bb5d44e1 100644 --- a/test/xray/TestCases/Linux/custom-event-logging.cc +++ b/test/xray/TestCases/Linux/custom-event-logging.cc @@ -33,7 +33,7 @@ int main() { // CHECK-NEXT: after calling the custom logging... printf("removing custom event handler...\n"); // CHECK-NEXT: removing custom event handler... - __xray_set_customevent_handler(nullptr); + __xray_remove_customevent_handler(); foo(); // CHECK-NEXT: before calling the custom logging... // CHECK-NEXT: after calling the custom logging... -- cgit v1.2.1 From 25efabe94f93114add3e4982ea1ee3e214378d85 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Tue, 23 May 2017 17:50:48 +0000 Subject: Disable flaky ASan tests temporarily on darwin git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303662 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/wait3.cc | 2 +- test/asan/TestCases/Posix/wait4.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Posix/wait3.cc b/test/asan/TestCases/Posix/wait3.cc index 2da816fed..081a73e16 100644 --- a/test/asan/TestCases/Posix/wait3.cc +++ b/test/asan/TestCases/Posix/wait3.cc @@ -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 #include diff --git a/test/asan/TestCases/Posix/wait4.cc b/test/asan/TestCases/Posix/wait4.cc index b95246efa..aee5570b8 100644 --- a/test/asan/TestCases/Posix/wait4.cc +++ b/test/asan/TestCases/Posix/wait4.cc @@ -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 #include -- cgit v1.2.1 From 3a807e357f6575ea1e290ed122ee05504f109dae Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 24 May 2017 07:17:27 +0000 Subject: [asan] Remove allow_user_segv_handler on Windows. Summary: This flags is not covered by tests on Windows and looks like it's implemented incorrectly. Switching its default breaks some tests. Taking into account that related handle_segv flag is not supported on Windows it's safer to remove it until we commit to support it. Reviewers: eugenis, zturner, rnk Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D33471 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303728 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_win.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 4ab535c42..26db32465 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -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. -- cgit v1.2.1 From 397099e7e747869a3c85c6d5cc1c1d7947666fc6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 24 May 2017 07:21:39 +0000 Subject: [compiler-rt] Change default of allow_user_segv_handler to true Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32443 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303729 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 5 ----- lib/asan/tests/asan_test.cc | 21 +++++++++++++-------- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index fdfc46f6e..c807df3cd 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -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 diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7ac72955f..d0128e34d 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -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 diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index c5aaf411f..1972bdafd 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -92,7 +92,7 @@ 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, +COMMON_FLAG(bool, allow_user_segv_handler, true, "If set, allows user to register a SEGV handler even if the tool " "registers one.") COMMON_FLAG(bool, use_sigaltstack, true, -- cgit v1.2.1 From b3d9ce6c036f6d2006efbd3282fd5806dc5dd15d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 24 May 2017 15:06:33 +0000 Subject: [sanitizer] [SystemZ] Update CVE-2016-2143 check for Ubuntu 16.04 The Ubuntu 16.04 kernel contains a backport of the CVE check starting with version 4.4.0-13. Update FixedCVE_2016_2143. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303757 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux_s390.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_linux_s390.cc b/lib/sanitizer_common/sanitizer_linux_s390.cc index c2b03b27e..a6da82ecb 100644 --- a/lib/sanitizer_common/sanitizer_linux_s390.cc +++ b/lib/sanitizer_common/sanitizer_linux_s390.cc @@ -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 { -- cgit v1.2.1 From 3e7872b74ef1fcfeaf5ac743afd9b6c66e36fb7d Mon Sep 17 00:00:00 2001 From: Jonathan Roelofs Date: Wed, 24 May 2017 15:53:24 +0000 Subject: Allow armv{7,7s,7k,7m,7em} builds git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303765 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/builtin-config-ix.cmake | 2 +- lib/builtins/arm/aeabi_cdcmp.S | 11 +++++++++++ lib/builtins/arm/aeabi_cfcmp.S | 11 +++++++++++ lib/builtins/arm/eqdf2vfp.S | 1 + lib/builtins/arm/eqsf2vfp.S | 1 + lib/builtins/arm/gedf2vfp.S | 1 + lib/builtins/arm/gesf2vfp.S | 1 + lib/builtins/arm/gtdf2vfp.S | 1 + lib/builtins/arm/gtsf2vfp.S | 1 + lib/builtins/arm/ledf2vfp.S | 1 + lib/builtins/arm/lesf2vfp.S | 1 + lib/builtins/arm/ltdf2vfp.S | 1 + lib/builtins/arm/ltsf2vfp.S | 1 + lib/builtins/arm/nedf2vfp.S | 1 + lib/builtins/arm/nesf2vfp.S | 1 + lib/builtins/arm/unorddf2vfp.S | 1 + lib/builtins/arm/unordsf2vfp.S | 1 + lib/builtins/assembly.h | 2 ++ 18 files changed, 39 insertions(+), 1 deletion(-) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index dc2ec1694..20bc68476 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -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) diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S index b67814d9f..3e7a8b86b 100644 --- a/lib/builtins/arm/aeabi_cdcmp.S +++ b/lib/builtins/arm/aeabi_cdcmp.S @@ -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 diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S index e37aa3d06..1f304ffd9 100644 --- a/lib/builtins/arm/aeabi_cfcmp.S +++ b/lib/builtins/arm/aeabi_cfcmp.S @@ -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 diff --git a/lib/builtins/arm/eqdf2vfp.S b/lib/builtins/arm/eqdf2vfp.S index 8fa0b2deb..d50706570 100644 --- a/lib/builtins/arm/eqdf2vfp.S +++ b/lib/builtins/arm/eqdf2vfp.S @@ -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 diff --git a/lib/builtins/arm/eqsf2vfp.S b/lib/builtins/arm/eqsf2vfp.S index 3776bf487..fd72b2fdb 100644 --- a/lib/builtins/arm/eqsf2vfp.S +++ b/lib/builtins/arm/eqsf2vfp.S @@ -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 diff --git a/lib/builtins/arm/gedf2vfp.S b/lib/builtins/arm/gedf2vfp.S index 14899f00a..364fc5b24 100644 --- a/lib/builtins/arm/gedf2vfp.S +++ b/lib/builtins/arm/gedf2vfp.S @@ -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 diff --git a/lib/builtins/arm/gesf2vfp.S b/lib/builtins/arm/gesf2vfp.S index b49d04d1c..346c3473a 100644 --- a/lib/builtins/arm/gesf2vfp.S +++ b/lib/builtins/arm/gesf2vfp.S @@ -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 diff --git a/lib/builtins/arm/gtdf2vfp.S b/lib/builtins/arm/gtdf2vfp.S index 8166305e3..3389c3ad9 100644 --- a/lib/builtins/arm/gtdf2vfp.S +++ b/lib/builtins/arm/gtdf2vfp.S @@ -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 diff --git a/lib/builtins/arm/gtsf2vfp.S b/lib/builtins/arm/gtsf2vfp.S index d2d8a2380..afdba8b01 100644 --- a/lib/builtins/arm/gtsf2vfp.S +++ b/lib/builtins/arm/gtsf2vfp.S @@ -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 diff --git a/lib/builtins/arm/ledf2vfp.S b/lib/builtins/arm/ledf2vfp.S index a9dab77c1..4bbe4c868 100644 --- a/lib/builtins/arm/ledf2vfp.S +++ b/lib/builtins/arm/ledf2vfp.S @@ -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 diff --git a/lib/builtins/arm/lesf2vfp.S b/lib/builtins/arm/lesf2vfp.S index 7e127f465..51232bd8c 100644 --- a/lib/builtins/arm/lesf2vfp.S +++ b/lib/builtins/arm/lesf2vfp.S @@ -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 diff --git a/lib/builtins/arm/ltdf2vfp.S b/lib/builtins/arm/ltdf2vfp.S index 8b6f8e4cc..8e2928c81 100644 --- a/lib/builtins/arm/ltdf2vfp.S +++ b/lib/builtins/arm/ltdf2vfp.S @@ -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 diff --git a/lib/builtins/arm/ltsf2vfp.S b/lib/builtins/arm/ltsf2vfp.S index c4ff812b4..59c00c6ba 100644 --- a/lib/builtins/arm/ltsf2vfp.S +++ b/lib/builtins/arm/ltsf2vfp.S @@ -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 diff --git a/lib/builtins/arm/nedf2vfp.S b/lib/builtins/arm/nedf2vfp.S index 7d884e072..aef72eb00 100644 --- a/lib/builtins/arm/nedf2vfp.S +++ b/lib/builtins/arm/nedf2vfp.S @@ -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 diff --git a/lib/builtins/arm/nesf2vfp.S b/lib/builtins/arm/nesf2vfp.S index 97c764f63..50d60f493 100644 --- a/lib/builtins/arm/nesf2vfp.S +++ b/lib/builtins/arm/nesf2vfp.S @@ -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 diff --git a/lib/builtins/arm/unorddf2vfp.S b/lib/builtins/arm/unorddf2vfp.S index 855637547..6625fa8a3 100644 --- a/lib/builtins/arm/unorddf2vfp.S +++ b/lib/builtins/arm/unorddf2vfp.S @@ -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 diff --git a/lib/builtins/arm/unordsf2vfp.S b/lib/builtins/arm/unordsf2vfp.S index 2b16b4905..0b5da2ba3 100644 --- a/lib/builtins/arm/unordsf2vfp.S +++ b/lib/builtins/arm/unordsf2vfp.S @@ -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 diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 12c13c495..b15da5234 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -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 -- cgit v1.2.1 From 03968223b794e6c6f9e482b7e05b2446966e76c3 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 24 May 2017 19:09:24 +0000 Subject: Revert "[compiler-rt] Change default of allow_user_segv_handler to true" Breaks sanitizer-x86_64-linux-fuzzer bot. This reverts commit r303729. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303795 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 5 +++++ lib/asan/tests/asan_test.cc | 21 ++++++++------------- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index c807df3cd..fdfc46f6e 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -327,6 +327,11 @@ 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 diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index d0128e34d..7ac72955f 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -251,8 +251,7 @@ TEST(AddressSanitizer, BitFieldNegativeTest) { namespace { const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address"; -const char kOverriddenSigactionHandler[] = "Test sigaction handler\n"; -const char kOverriddenSignalHandler[] = "Test signal handler\n"; +const char kOverriddenHandler[] = "ASan signal handler has been overridden\n"; TEST(AddressSanitizer, WildAddressTest) { char *c = (char*)0x123; @@ -260,12 +259,12 @@ TEST(AddressSanitizer, WildAddressTest) { } void my_sigaction_sighandler(int, siginfo_t*, void*) { - fprintf(stderr, kOverriddenSigactionHandler); + fprintf(stderr, kOverriddenHandler); exit(1); } void my_signal_sighandler(int signum) { - fprintf(stderr, kOverriddenSignalHandler); + fprintf(stderr, kOverriddenHandler); exit(1); } @@ -274,20 +273,16 @@ TEST(AddressSanitizer, SignalTest) { memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = my_sigaction_sighandler; sigact.sa_flags = SA_SIGINFO; - char *c = (char *)0x123; - - EXPECT_DEATH(*c = 0, kSEGVCrash); - - // ASan should allow to set sigaction()... + // ASan should silently ignore sigaction()... EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0)); #ifdef __APPLE__ EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0)); #endif - EXPECT_DEATH(*c = 0, kOverriddenSigactionHandler); - + char *c = (char*)0x123; + EXPECT_DEATH(*c = 0, kSEGVCrash); // ... and signal(). - EXPECT_NE(SIG_ERR, signal(SIGSEGV, my_signal_sighandler)); - EXPECT_DEATH(*c = 0, kOverriddenSignalHandler); + EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler)); + EXPECT_DEATH(*c = 0, kSEGVCrash); } } // namespace #endif diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 1972bdafd..c5aaf411f 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -92,7 +92,7 @@ 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, true, +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, -- cgit v1.2.1 From 303455b44a7a76147e230dea64091ea2f6614f60 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Wed, 24 May 2017 21:52:40 +0000 Subject: Fix negate-overflow.cpp test on Windows after r303440 lit would interpret the exit code as failuire. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303809 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/Integer/negate-overflow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/ubsan/TestCases/Integer/negate-overflow.cpp b/test/ubsan/TestCases/Integer/negate-overflow.cpp index 628291eb4..72438d3fb 100644 --- a/test/ubsan/TestCases/Integer/negate-overflow.cpp +++ b/test/ubsan/TestCases/Integer/negate-overflow.cpp @@ -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; } -- cgit v1.2.1 From 0ee4ae2feb4ed95e62b131fef4c5bf43890cae84 Mon Sep 17 00:00:00 2001 From: Jonathan Roelofs Date: Wed, 24 May 2017 22:41:49 +0000 Subject: Allow builds to set COMPILER_RT_OS_DIR differently from CMAKE_SYSTEM_NAME git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303817 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/base-config-ix.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 6f9f15139..b38c6ca96 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -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 -- cgit v1.2.1 From 6b09b9e2f0d280aa933c522066f5c68299f40833 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 25 May 2017 06:29:30 +0000 Subject: [compiler-rt] Change default of allow_user_segv_handler to true Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32443 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303842 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 5 ----- lib/asan/tests/asan_test.cc | 21 +++++++++++++-------- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index fdfc46f6e..c807df3cd 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -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 diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7ac72955f..d0128e34d 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -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 diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index c5aaf411f..1972bdafd 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -92,7 +92,7 @@ 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, +COMMON_FLAG(bool, allow_user_segv_handler, true, "If set, allows user to register a SEGV handler even if the tool " "registers one.") COMMON_FLAG(bool, use_sigaltstack, true, -- cgit v1.2.1 From 370ca3548b9b57aaaa36f65655ce0c2722e18b9a Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Thu, 25 May 2017 14:32:22 +0000 Subject: [PowerPC] Fix test case sem_init_glibc.cc for powerpc64be This test case fails on powerpc64be with older glibcs because of the glibc version test. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303863 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc index 92557b759..b7e8721a1 100644 --- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc +++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -8,8 +8,12 @@ #include #include +// 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; -- cgit v1.2.1 From a568c294917d4a2d20b3afd7cfb47fd49a640ece Mon Sep 17 00:00:00 2001 From: Bill Seurer Date: Thu, 25 May 2017 14:41:58 +0000 Subject: [powerpc] deactivate flakey test halt_on_error-torture.cc on powerpc64 be This test case occassionally fails when run on powerpc64 be. asan/TestCases/Posix/halt_on_error-torture.cc The failure causes false problem reports to be sent to developers whose code had nothing to do with the failures. Reactivate it when the real problem is fixed. This could also be related to the same problems as with the tests ThreadedOneSizeMallocStressTest, ThreadedMallocStressTest, ManyThreadsTest, and several others that do not run reliably on powerpc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303864 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 1b26173d7..275115052 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -18,6 +18,10 @@ // RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >>20.txt 2>&1 || true // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt +// UNSUPPORTED: powerpc64-unknown-linux-gnu +// FIXME: This test regularly fails on powerpc64 BE. Re-enable the test once +// the problem(s) have been fixed. + #include #include #include -- cgit v1.2.1 From 41e921aae202b41ccb0dde05e824bcd6f7f3e0b6 Mon Sep 17 00:00:00 2001 From: Catherine Moore Date: Thu, 25 May 2017 14:45:54 +0000 Subject: [cmake] Disable building emutls.c for baremetal targets. Differential Revision: https://reviews.llvm.org/D33199 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303865 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index df80a5044..02c5b48dd 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -163,8 +163,7 @@ set(GENERIC_SOURCES udivti3.c umoddi3.c umodsi3.c - umodti3.c - emutls.c) + umodti3.c) set(GENERIC_TF_SOURCES comparetf2.c @@ -193,6 +192,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() -- cgit v1.2.1 From cb42103777b0fa8b8f38a7bfe5592ed8e3e48388 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 25 May 2017 14:52:14 +0000 Subject: Add generic __bswap[ds]i2 implementations Summary: In FreeBSD we needed to add generic implementations for `__bswapdi2` and `__bswapsi2`, since gcc 6.x for mips is emitting calls to these. See: https://reviews.freebsd.org/D10838 and https://reviews.freebsd.org/rS318601 The actual mips code generated for these generic C versions is pretty OK, as can be seen in the (FreeBSD) review. I checked over gcc sources, and it seems that it can emit these calls on more architectures, so maybe it's best to simply always add them to the compiler-rt builtins library. Reviewers: howard.hinnant, compnerd, petarj, emaste Reviewed By: compnerd, emaste Subscribers: mgorny, llvm-commits, arichardson Differential Revision: https://reviews.llvm.org/D33516 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303866 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 2 ++ lib/builtins/README.txt | 4 ++-- lib/builtins/bswapdi2.c | 27 +++++++++++++++++++++++++++ lib/builtins/bswapsi2.c | 23 +++++++++++++++++++++++ test/builtins/Unit/bswapdi2_test.c | 37 ++++++++++++++----------------------- test/builtins/Unit/bswapsi2_test.c | 37 ++++++++++++++----------------------- 6 files changed, 82 insertions(+), 48 deletions(-) create mode 100644 lib/builtins/bswapdi2.c create mode 100644 lib/builtins/bswapsi2.c diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 02c5b48dd..6556e7ac6 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -42,6 +42,8 @@ set(GENERIC_SOURCES ashlti3.c ashrdi3.c ashrti3.c + bswapdi2.c + bswapsi2.c clear_cache.c clzdi2.c clzsi2.c diff --git a/lib/builtins/README.txt b/lib/builtins/README.txt index b3d083614..e603dfa05 100644 --- a/lib/builtins/README.txt +++ b/lib/builtins/README.txt @@ -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 diff --git a/lib/builtins/bswapdi2.c b/lib/builtins/bswapdi2.c new file mode 100644 index 000000000..eb220007b --- /dev/null +++ b/lib/builtins/bswapdi2.c @@ -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)); +} diff --git a/lib/builtins/bswapsi2.c b/lib/builtins/bswapsi2.c new file mode 100644 index 000000000..5d941e69f --- /dev/null +++ b/lib/builtins/bswapsi2.c @@ -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)); +} diff --git a/test/builtins/Unit/bswapdi2_test.c b/test/builtins/Unit/bswapdi2_test.c index 6881c8092..57ee38b78 100644 --- a/test/builtins/Unit/bswapdi2_test.c +++ b/test/builtins/Unit/bswapdi2_test.c @@ -13,34 +13,25 @@ // //===----------------------------------------------------------------------===// -#include +#include #include #include -#include - +#include 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; } diff --git a/test/builtins/Unit/bswapsi2_test.c b/test/builtins/Unit/bswapsi2_test.c index c32cbb442..899c251d9 100644 --- a/test/builtins/Unit/bswapsi2_test.c +++ b/test/builtins/Unit/bswapsi2_test.c @@ -13,34 +13,25 @@ // //===----------------------------------------------------------------------===// -#include +#include #include #include -#include - +#include 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; } -- cgit v1.2.1 From ff9d73170248a3443753cd508c27b420c66f34f9 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 25 May 2017 15:07:07 +0000 Subject: [sanitizer] Pair atomic acquire with release in BlockingMutex::Unlock Summary: Dmitry, seeking your expertise. I believe, the proper way to implement Lock/Unlock here would be to use acquire/release semantics. Am I missing something? Reviewers: dvyukov Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33521 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303869 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 87f32c44d..5198b55bd 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -549,7 +549,7 @@ void BlockingMutex::Lock() { void BlockingMutex::Unlock() { atomic_uint32_t *m = reinterpret_cast(&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 -- cgit v1.2.1 From a6bbfb5d985e5cd09375d6a0aa801e0763f5b999 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 25 May 2017 16:19:57 +0000 Subject: [sanitizer] Change the 32-bit Primary AllocateRegion to reduce fragmentation Summary: Currently, AllocateRegion has a tendency to fragment memory: it allocates `2*kRegionSize`, and if the memory is aligned, will unmap `kRegionSize` bytes, thus creating a hole, which can't itself be reused for another region. This is exacerbated by the fact that if 2 regions get allocated one after another without any `mmap` in between, the second will be aligned due to mappings generally being contiguous. An idea, suggested by @alekseyshl, to prevent such a behavior is to have a stash of regions: if the `2*kRegionSize` allocation is properly aligned, split it in two, and stash the second part to be returned next time a region is requested. At this point, I thought about a couple of ways to implement this: - either an `IntrusiveList` of regions candidates, storing `next` at the begining of the region; - a small array of regions candidates existing in the Primary. While the second option is more constrained in terms of size, it offers several advantages: - security wise, a pointer in a region candidate could be overflowed into, and abused when popping an element; - we do not dirty the first page of the region by storing something in it; - unless several threads request regions simultaneously from different size classes, the stash rarely goes above 1 entry. I am not certain about the Windows impact of this change, as `sanitizer_win.cc` has its own version of MmapAlignedOrDie, maybe someone could chime in on this. MmapAlignedOrDie is effectively unused after this change and could be removed at a later point. I didn't notice any sizeable performance gain, even though we are saving a few `mmap`/`munmap` syscalls. Reviewers: alekseyshl, kcc, dvyukov Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33454 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303879 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary32.h | 63 ++++++++++++++++++---- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index 0f6f4f7f8..d006e64d3 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,7 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). +// a result of an allocation of kRegionSize bytes aligned on kRegionSize. // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -106,6 +106,7 @@ class SizeClassAllocator32 { void Init(s32 release_to_os_interval_ms) { possible_regions.TestOnlyInit(); internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); + num_stashed_regions = 0; } s32 ReleaseToOSIntervalMs() const { @@ -275,15 +276,52 @@ class SizeClassAllocator32 { return mem & ~(kRegionSize - 1); } + // Allocates a region of kRegionSize bytes, aligned on kRegionSize, by first + // allocating 2 * kRegionSize. If the result of the initial allocation is + // aligned, split it in two, and attempt to store the second part into a + // stash. In the event the stash is full, just unmap the superfluous memory. + // If the initial allocation is not aligned, trim the memory before and after. + uptr AllocateRegionSlow(AllocatorStats *stat) { + uptr map_size = 2 * kRegionSize; + uptr map_res = (uptr)MmapOrDie(map_size, "SizeClassAllocator32"); + uptr region = map_res; + bool trim_region = true; + if (IsAligned(region, kRegionSize)) { + // We are aligned, attempt to stash the second half. + SpinMutexLock l(®ions_stash_mutex); + if (num_stashed_regions < kMaxStashedRegions) { + regions_stash[num_stashed_regions++] = region + kRegionSize; + trim_region = false; + } + } + // Trim the superfluous memory in front and behind us. + if (trim_region) { + // If map_res is already aligned on kRegionSize (in the event of a full + // stash), the following two lines amount to a no-op. + region = (map_res + kRegionSize - 1) & ~(kRegionSize - 1); + UnmapOrDie((void*)map_res, region - map_res); + uptr end = region + kRegionSize; + UnmapOrDie((void*)end, map_res + map_size - end); + map_size = kRegionSize; + } + MapUnmapCallback().OnMap(region, map_size); + stat->Add(AllocatorStatMapped, map_size); + return region; + } + uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, - "SizeClassAllocator32")); - MapUnmapCallback().OnMap(res, kRegionSize); - stat->Add(AllocatorStatMapped, kRegionSize); - CHECK_EQ(0U, (res & (kRegionSize - 1))); - possible_regions.set(ComputeRegionId(res), static_cast(class_id)); - return res; + uptr region = 0; + { + SpinMutexLock l(®ions_stash_mutex); + if (num_stashed_regions > 0) + region = regions_stash[--num_stashed_regions]; + } + if (!region) + region = AllocateRegionSlow(stat); + CHECK(IsAligned(region, kRegionSize)); + possible_regions.set(ComputeRegionId(region), static_cast(class_id)); + return region; } SizeClassInfo *GetSizeClassInfo(uptr class_id) { @@ -316,8 +354,13 @@ class SizeClassAllocator32 { } } + // Unless several threads request regions simultaneously from different size + // classes, the stash rarely contains more than 1 entry. + static const uptr kMaxStashedRegions = 8; + SpinMutex regions_stash_mutex; + uptr num_stashed_regions; + uptr regions_stash[kMaxStashedRegions]; + ByteMap possible_regions; SizeClassInfo size_class_info_array[kNumClasses]; }; - - -- cgit v1.2.1 From b9bf72bbd5ac1c49fc66234e332631eb89e33928 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 25 May 2017 16:54:44 +0000 Subject: [sanitizer] Revert rL303879 as it breaks Windows Summary: Apparently Windows's `UnmapOrDie` doesn't support partial unmapping. Which makes the new region allocation technique not Windows compliant. Reviewers: alekseyshl, dvyukov Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33554 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303883 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary32.h | 61 +++------------------- 1 file changed, 8 insertions(+), 53 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index d006e64d3..e13510ba3 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,7 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of an allocation of kRegionSize bytes aligned on kRegionSize. +// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -106,7 +106,6 @@ class SizeClassAllocator32 { void Init(s32 release_to_os_interval_ms) { possible_regions.TestOnlyInit(); internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); - num_stashed_regions = 0; } s32 ReleaseToOSIntervalMs() const { @@ -276,52 +275,15 @@ class SizeClassAllocator32 { return mem & ~(kRegionSize - 1); } - // Allocates a region of kRegionSize bytes, aligned on kRegionSize, by first - // allocating 2 * kRegionSize. If the result of the initial allocation is - // aligned, split it in two, and attempt to store the second part into a - // stash. In the event the stash is full, just unmap the superfluous memory. - // If the initial allocation is not aligned, trim the memory before and after. - uptr AllocateRegionSlow(AllocatorStats *stat) { - uptr map_size = 2 * kRegionSize; - uptr map_res = (uptr)MmapOrDie(map_size, "SizeClassAllocator32"); - uptr region = map_res; - bool trim_region = true; - if (IsAligned(region, kRegionSize)) { - // We are aligned, attempt to stash the second half. - SpinMutexLock l(®ions_stash_mutex); - if (num_stashed_regions < kMaxStashedRegions) { - regions_stash[num_stashed_regions++] = region + kRegionSize; - trim_region = false; - } - } - // Trim the superfluous memory in front and behind us. - if (trim_region) { - // If map_res is already aligned on kRegionSize (in the event of a full - // stash), the following two lines amount to a no-op. - region = (map_res + kRegionSize - 1) & ~(kRegionSize - 1); - UnmapOrDie((void*)map_res, region - map_res); - uptr end = region + kRegionSize; - UnmapOrDie((void*)end, map_res + map_size - end); - map_size = kRegionSize; - } - MapUnmapCallback().OnMap(region, map_size); - stat->Add(AllocatorStatMapped, map_size); - return region; - } - uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr region = 0; - { - SpinMutexLock l(®ions_stash_mutex); - if (num_stashed_regions > 0) - region = regions_stash[--num_stashed_regions]; - } - if (!region) - region = AllocateRegionSlow(stat); - CHECK(IsAligned(region, kRegionSize)); - possible_regions.set(ComputeRegionId(region), static_cast(class_id)); - return region; + uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, + "SizeClassAllocator32")); + MapUnmapCallback().OnMap(res, kRegionSize); + stat->Add(AllocatorStatMapped, kRegionSize); + CHECK_EQ(0U, (res & (kRegionSize - 1))); + possible_regions.set(ComputeRegionId(res), static_cast(class_id)); + return res; } SizeClassInfo *GetSizeClassInfo(uptr class_id) { @@ -354,13 +316,6 @@ class SizeClassAllocator32 { } } - // Unless several threads request regions simultaneously from different size - // classes, the stash rarely contains more than 1 entry. - static const uptr kMaxStashedRegions = 8; - SpinMutex regions_stash_mutex; - uptr num_stashed_regions; - uptr regions_stash[kMaxStashedRegions]; - ByteMap possible_regions; SizeClassInfo size_class_info_array[kNumClasses]; }; -- cgit v1.2.1 From fb4eba778e0c186c425870e3b89855caed182cb7 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Thu, 25 May 2017 17:24:54 +0000 Subject: Disable two more flaky ASan wait* tests temporarily on Darwin git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303885 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/wait.cc | 1 + test/asan/TestCases/Posix/waitid.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/asan/TestCases/Posix/wait.cc b/test/asan/TestCases/Posix/wait.cc index ed6f326b5..85e819369 100644 --- a/test/asan/TestCases/Posix/wait.cc +++ b/test/asan/TestCases/Posix/wait.cc @@ -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 #include diff --git a/test/asan/TestCases/Posix/waitid.cc b/test/asan/TestCases/Posix/waitid.cc index 8b516dca9..20fb0c694 100644 --- a/test/asan/TestCases/Posix/waitid.cc +++ b/test/asan/TestCases/Posix/waitid.cc @@ -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 #include #include -- cgit v1.2.1 From 5bde87f9d1581fc2c8deb1022b25eb8e76c0d3ce Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 25 May 2017 17:41:10 +0000 Subject: Don't require ThreadState to be contained within tls on all platforms The existing implementation ran CHECKs to assert that the thread state was stored inside the tls. However, the mac implementation of tsan doesn't store the thread state in tls, so these checks fail once darwin tls support is added to the sanitizers. Only run these checks on platforms where the thread state is expected to be contained in the tls. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303886 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform.h | 1 + lib/tsan/rtl/tsan_platform_linux.cc | 14 +++++++++++++ lib/tsan/rtl/tsan_platform_mac.cc | 41 +++++++++++++++++++++++++++++++------ lib/tsan/rtl/tsan_rtl_thread.cc | 14 +------------ 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index 1dd9d91d4..60d9b9d8c 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -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, diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 2d488cadd..d05c0e701 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -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, diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index b8d3d5528..a82bcd01b 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -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. diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index 6a0943c49..edb60980c 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -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 -- cgit v1.2.1 From 8c920732ad3a0f254c5d538c330a0f4984369047 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 25 May 2017 17:41:13 +0000 Subject: Implement tls scanning for darwin LSan Summary: This required for any users who call exit() after creating thread-specific data, as tls destructors are only called when pthread_exit() or pthread_cancel() are used. This should also match tls behavior on linux. Getting the base address of the tls section is straightforward, as it's stored as a section offset in %gs. The size is a bit trickier to work out, as there doesn't appear to be any official documentation or source code referring to it. The size used in this patch was determined by taking the difference between the base address and the address of the subsequent memory region returned by vm_region_recurse_64, which was 1024 * sizeof(uptr) on all threads except the main thread, where it was larger. Since the section must be the same size on all of the threads, 1024 * sizeof(uptr) seemed to be a reasonable size to use, barring a more programtic way to get the size. 1024 seems like a reasonable number, given that PTHREAD_KEYS_MAX is 512 on darwin, so pthread keys will fit inside the region while leaving space for other tls data. A larger size would overflow the memory region returned by vm_region_recurse_64, and a smaller size wouldn't leave room for all the pthread keys. In addition, the stress test added here passes, which means that we are scanning at least the full set of possible pthread keys, and probably the full tls section. Reviewers: alekseyshl, kubamracek Subscribers: krytarowski, llvm-commits Differential Revision: https://reviews.llvm.org/D33215 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303887 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 28 ++++++----- lib/lsan/lsan_common_mac.cc | 7 +-- lib/lsan/lsan_flags.inc | 2 +- lib/sanitizer_common/sanitizer_mac.cc | 25 +++++++++- test/lsan/TestCases/many_tls_keys.cc | 94 +++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 test/lsan/TestCases/many_tls_keys.cc diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a6b3453f5..9f862ac96 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -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_end > 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) { diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index ae1095543..114dd8c90 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -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) { diff --git a/lib/lsan/lsan_flags.inc b/lib/lsan/lsan_flags.inc index 8135bdcff..e390e2ae5 100644 --- a/lib/lsan/lsan_flags.inc +++ b/lib/lsan/lsan_flags.inc @@ -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().") diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index f1a6bf916..2c194b263 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -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; diff --git a/test/lsan/TestCases/many_tls_keys.cc b/test/lsan/TestCases/many_tls_keys.cc new file mode 100644 index 000000000..ae5776770 --- /dev/null +++ b/test/lsan/TestCases/many_tls_keys.cc @@ -0,0 +1,94 @@ +// 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 + +#include +#include +#include +#include +#include + +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: -- cgit v1.2.1 From 2319b5f3cb1ad942ea66e7aae0e4aa3b56f4bc5e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 25 May 2017 18:07:48 +0000 Subject: [compiler-rt] Make print_module_map description consistent with the rest. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33160 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303892 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flags.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 1972bdafd..dad0813d2 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -75,8 +75,8 @@ 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 " \ -- cgit v1.2.1 From 963904ec1f640dc7151684f029fd3348f0c5bf3c Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 25 May 2017 19:55:44 +0000 Subject: Fix typo in tls patch git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303906 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 9f862ac96..a5ffc6835 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -270,7 +270,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, // 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_end > cache_end) { + tls_begin > cache_end) { ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); } else { if (tls_begin < cache_begin) -- cgit v1.2.1 From 881a838f9708a006f12976457d7dceb8843eca97 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 25 May 2017 20:50:36 +0000 Subject: [asan] relax sanbox_read_proc_self_maps_test to pass even if unshare() fails. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303911 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc b/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc index a845721d5..d9099edff 100644 --- a/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc +++ b/test/asan/TestCases/Linux/sanbox_read_proc_self_maps_test.cc @@ -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 } -- cgit v1.2.1 From 71817390840f0d28d18090fc94127e4e3e60091f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 25 May 2017 23:42:33 +0000 Subject: [compiler-rt] Replace allow_user_segv_handler=0 with kHandleSignalExclusive Summary: allow_user_segv_handler had confusing name did not allow to control behavior for signals separately. Reviewers: eugenis, alekseyshl, kcc Subscribers: llvm-commits, dberris, kubamracek Differential Revision: https://reviews.llvm.org/D33371 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303941 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 12 ++--- lib/sanitizer_common/sanitizer_common.h | 2 +- lib/sanitizer_common/sanitizer_flag_parser.h | 5 ++ lib/sanitizer_common/sanitizer_flags.h | 1 + lib/sanitizer_common/sanitizer_flags.inc | 6 +-- lib/sanitizer_common/sanitizer_linux.cc | 4 +- lib/sanitizer_common/sanitizer_mac.cc | 6 +-- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 7 +-- lib/sanitizer_common/sanitizer_win.cc | 4 +- lib/sanitizer_common/tests/sanitizer_flags_test.cc | 6 ++- test/asan/TestCases/Posix/allow_user_segv.cc | 53 +++++++++++++++------- .../TestCases/Linux/signal_segv_handler.cc | 2 +- 12 files changed, 65 insertions(+), 43 deletions(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index c6969c979..cb2214f96 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -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; } diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 33e652e6c..a1c9c5a57 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -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). diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index b6ae307fc..4988fbb7a 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -64,6 +64,11 @@ inline bool FlagHandler::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; } diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h index f22593395..c2ec29d16 100644 --- a/lib/sanitizer_common/sanitizer_flags.h +++ b/lib/sanitizer_common/sanitizer_flags.h @@ -21,6 +21,7 @@ namespace __sanitizer { enum HandleSignalMode { kHandleSignalNo, kHandleSignalYes, + kHandleSignalExclusive, }; struct CommonFlags { diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index dad0813d2..12c126fa7 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -80,7 +80,8 @@ COMMON_FLAG(int, print_module_map, 0, 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, true, - "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, diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 5198b55bd..3bda35655 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -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 diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 2c194b263..f1b9e5fda 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -414,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; @@ -430,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; diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 8d688f377..21178c46a 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -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,8 @@ void UnsetAlternateSignalStack() { static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { - if (!IsHandledDeadlySignal(signum)) - return; + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; + struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)handler; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index d0a5c078c..c912e8fa2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -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. diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc index 34d7067f8..0af84a20b 100644 --- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -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), diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc index 69c1df9a1..52f4f046d 100644 --- a/test/asan/TestCases/Posix/allow_user_segv.cc +++ b/test/asan/TestCases/Posix/allow_user_segv.cc @@ -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 #include @@ -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 diff --git a/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc index 643fb48ae..51e8bdb6e 100644 --- a/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc +++ b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc @@ -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. -- cgit v1.2.1 From 9233cd47d86013b406b7ae0b6c3280a51c256ae0 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 26 May 2017 14:49:42 +0000 Subject: [asan] Enable back some ASan tests disabled on PowerPC. Summary: D33521 addressed a memory ordering issue in BlockingMutex, which seems to be the cause of a flakiness of a few ASan tests on PowerPC. Reviewers: eugenis Subscribers: kubamracek, nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D33569 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303995 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_interface_test.cc | 4 ---- lib/asan/tests/asan_noinst_test.cc | 9 --------- test/asan/TestCases/Posix/current_allocated_bytes.cc | 3 --- 3 files changed, 16 deletions(-) diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc index d13962b8f..7d3e520d8 100644 --- a/lib/asan/tests/asan_interface_test.cc +++ b/lib/asan/tests/asan_interface_test.cc @@ -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); diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index b3a235e47..65acb2839 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -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; diff --git a/test/asan/TestCases/Posix/current_allocated_bytes.cc b/test/asan/TestCases/Posix/current_allocated_bytes.cc index 51630cfd8..c49e433b1 100644 --- a/test/asan/TestCases/Posix/current_allocated_bytes.cc +++ b/test/asan/TestCases/Posix/current_allocated_bytes.cc @@ -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 #include -- cgit v1.2.1 From 29e1a9ca086738e000a2a7c3e366453fe56f4ed9 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 26 May 2017 15:39:22 +0000 Subject: [scudo] Check the return values of the pthread_* functions Summary: Currently we are not enforcing the success of `pthread_once`, and `pthread_setspecific`. Errors could lead to harder to debug issues later in the thread's life. This adds checks for a 0 return value for both. If `pthread_setspecific` fails in the teardown path, opt for an immediate teardown as opposed to a fatal failure. Reviewers: alekseyshl, kcc Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33555 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@303998 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_tls_linux.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index 5a9cc998b..1e38233f3 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -18,7 +18,6 @@ #include "scudo_tls.h" -#include #include namespace __scudo { @@ -32,15 +31,17 @@ __attribute__((tls_model("initial-exec"))) THREADLOCAL ScudoThreadContext ThreadLocalContext; static void teardownThread(void *Ptr) { - uptr Iteration = reinterpret_cast(Ptr); + uptr I = reinterpret_cast(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(Iteration + 1)); - return; + if (I > 1) { + // If pthread_setspecific fails, we will go ahead with the teardown. + if (LIKELY(pthread_setspecific(PThreadKey, + reinterpret_cast(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(1)); + CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0); + CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( + GetPthreadDestructorIterations())), 0); ThreadLocalContext.init(); ScudoThreadState = ThreadInitialized; } -- cgit v1.2.1 From 0338f3e77f7589bc43a1a9b38e7324334da1939c Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Fri, 26 May 2017 17:31:33 +0000 Subject: [LSAN-ARM] Marking new test unsupported on ARMHF due to bot failures The test was meant for Darwin anyway, so I'm not even sure it's supposed to run on Linux. If it was, then we need time to investigate, but since the test is new, there's no point in reverting the whole patch because of it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304010 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/many_tls_keys.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/lsan/TestCases/many_tls_keys.cc b/test/lsan/TestCases/many_tls_keys.cc index ae5776770..5b5d692a5 100644 --- a/test/lsan/TestCases/many_tls_keys.cc +++ b/test/lsan/TestCases/many_tls_keys.cc @@ -9,6 +9,9 @@ // 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 #include #include -- cgit v1.2.1 From f9198fc26c8e502bffa758b451b8ded20bb9a7f4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 26 May 2017 21:51:26 +0000 Subject: [compiler-rt] Don't reset non-default user handler if allow_user_segv_handler is true. Reviewers: eugenis, kcc Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D32457 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304039 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 20 ++++- test/asan/TestCases/Linux/preinstalled_signal.cc | 105 +++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 test/asan/TestCases/Linux/preinstalled_signal.cc diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 21178c46a..791ff4481 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -189,7 +189,25 @@ void UnsetAlternateSignalStack() { static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { - if (GetHandleSignalMode(signum) == kHandleSignalNo) 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)); diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc new file mode 100644 index 000000000..40dadf43d --- /dev/null +++ b/test/asan/TestCases/Linux/preinstalled_signal.cc @@ -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 +#include +#include +#include +#include +#include +#include + +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 -- cgit v1.2.1 From 679ac907b094e59fae38f1ecbd28ed638a9c22b0 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 26 May 2017 23:14:06 +0000 Subject: [asan] Enable back halt_on_error-torture.cc disabled on PowerPC. Summary: D33521 addressed a memory ordering issue in BlockingMutex, which seems to be the cause of a flakiness of a few ASan tests on PowerPC. Reviewers: eugenis Subscribers: kubamracek, nemanjai, llvm-commits Differential Revision: https://reviews.llvm.org/D33611 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304045 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 275115052..1b26173d7 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -18,10 +18,6 @@ // RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >>20.txt 2>&1 || true // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt -// UNSUPPORTED: powerpc64-unknown-linux-gnu -// FIXME: This test regularly fails on powerpc64 BE. Re-enable the test once -// the problem(s) have been fixed. - #include #include #include -- cgit v1.2.1 From 97fc005f646a7ce2ee15b97bb7e015a812eb2421 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 30 May 2017 19:52:34 +0000 Subject: [sanitizer] Add "isapla" to symbolizer's global symbols whitelist. Summary: D33637 introduced isalpha, whitelist need to reflect that. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D33687 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304234 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/symbolizer/scripts/global_symbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt index 737f9459d..a23c95347 100644 --- a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt +++ b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt @@ -59,6 +59,7 @@ getpagesize U getpid U gettimeofday U ioctl U +isalpha U isatty U isprint U isupper U -- cgit v1.2.1 From e1a8ef98132e737d3e7c4045a3e6e6e7ae20242e Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Wed, 31 May 2017 07:28:09 +0000 Subject: [sanitizer] Avoid possible deadlock in child process after fork This patch addresses https://github.com/google/sanitizers/issues/774. When we fork a multi-threaded process it's possible to deadlock if some thread acquired StackDepot or allocator internal lock just before fork. In this case the lock will never be released in child process causing deadlock on following memory alloc/dealloc routine. While calling alloc/dealloc routines after multi-threaded fork is not allowed, most of modern allocators (Glibc, tcmalloc, jemalloc) are actually fork safe. Let's do the same for sanitizers except TSan that has complex locking rules. Differential Revision: https://reviews.llvm.org/D33325 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304285 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 4 +- lib/asan/asan_allocator.h | 2 + lib/asan/asan_interceptors.cc | 13 +++ lib/lsan/lsan_interceptors.cc | 20 ++++ lib/msan/msan_allocator.cc | 96 +---------------- lib/msan/msan_allocator.h | 97 +++++++++++++++++ lib/msan/msan_interceptors.cc | 2 + .../TestCases/Linux/allocator_fork_no_hang.cc | 118 +++++++++++++++++++++ 8 files changed, 255 insertions(+), 97 deletions(-) create mode 100644 test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 7010b6023..db5a683e2 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -47,8 +47,6 @@ static u32 RZSize2Log(u32 rz_size) { return res; } -static AsanAllocator &get_allocator(); - // The memory chunk allocated from the underlying allocator looks like this: // L L L L L L H H U U U U U U R R // L -- left redzone words (0 or more bytes) @@ -719,7 +717,7 @@ struct Allocator { static Allocator instance(LINKER_INITIALIZED); -static AsanAllocator &get_allocator() { +AsanAllocator &get_allocator() { return instance.allocator; } diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index ad1aeb58a..ce3e25dc5 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -213,5 +213,7 @@ void asan_mz_force_unlock(); void PrintInternalAllocatorStats(); void AsanSoftRssLimitExceededCallback(bool exceeded); +AsanAllocator &get_allocator(); + } // namespace __asan #endif // ASAN_ALLOCATOR_H diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index cb2214f96..1f0dc9e2d 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -22,6 +22,7 @@ #include "asan_stats.h" #include "asan_suppressions.h" #include "lsan/lsan_common.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX @@ -705,11 +706,23 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #endif // ASAN_INTERCEPT___CXA_ATEXIT #if ASAN_INTERCEPT_FORK +static void BeforeFork() { + get_allocator().ForceLock(); + StackDepotLockAll(); +} + +static void AfterFork() { + StackDepotUnlockAll(); + get_allocator().ForceUnlock(); +} + INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); + BeforeFork(); if (common_flags()->coverage) CovBeforeFork(); int pid = REAL(fork)(); if (common_flags()->coverage) CovAfterFork(pid); + AfterFork(); return pid; } #endif // ASAN_INTERCEPT_FORK diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 9e39a7d19..b8cf6ae07 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -22,6 +22,7 @@ #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_posix.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" @@ -97,6 +98,24 @@ INTERCEPTOR(void*, valloc, uptr size) { } #endif +static void BeforeFork() { + LockAllocator(); + StackDepotLockAll(); +} + +static void AfterFork() { + StackDepotUnlockAll(); + UnlockAllocator(); +} + +INTERCEPTOR(int, fork, void) { + ENSURE_LSAN_INITED; + BeforeFork(); + int pid = REAL(fork)(); + AfterFork(); + return pid; +} + #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; @@ -336,6 +355,7 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_MALLOPT; INTERCEPT_FUNCTION(pthread_create); INTERCEPT_FUNCTION(pthread_join); + INTERCEPT_FUNCTION(fork); if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 1be573faa..f76b01de0 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -12,8 +12,6 @@ // MemorySanitizer allocator. //===----------------------------------------------------------------------===// -#include "sanitizer_common/sanitizer_allocator.h" -#include "sanitizer_common/sanitizer_allocator_interface.h" #include "msan.h" #include "msan_allocator.h" #include "msan_origin.h" @@ -22,102 +20,12 @@ namespace __msan { -struct Metadata { - uptr requested_size; -}; - -struct MsanMapUnmapCallback { - void OnMap(uptr p, uptr size) const {} - void OnUnmap(uptr p, uptr size) const { - __msan_unpoison((void *)p, size); - - // We are about to unmap a chunk of user memory. - // Mark the corresponding shadow memory as not needed. - uptr shadow_p = MEM_TO_SHADOW(p); - ReleaseMemoryPagesToOS(shadow_p, shadow_p + size); - if (__msan_get_track_origins()) { - uptr origin_p = MEM_TO_ORIGIN(p); - ReleaseMemoryPagesToOS(origin_p, origin_p + size); - } - } -}; - -#if defined(__mips64) - static const uptr kMaxAllowedMallocSize = 2UL << 30; - static const uptr kRegionSizeLog = 20; - static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; - typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - - struct AP32 { - static const uptr kSpaceBeg = 0; - static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; - static const uptr kMetadataSize = sizeof(Metadata); - typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = __msan::kRegionSizeLog; - typedef __msan::ByteMap ByteMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - typedef SizeClassAllocator32 PrimaryAllocator; -#elif defined(__x86_64__) -#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) - static const uptr kAllocatorSpace = 0x700000000000ULL; -#else - static const uptr kAllocatorSpace = 0x600000000000ULL; -#endif - static const uptr kMaxAllowedMallocSize = 8UL << 30; - - struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = kAllocatorSpace; - static const uptr kSpaceSize = 0x40000000000; // 4T. - static const uptr kMetadataSize = sizeof(Metadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - - typedef SizeClassAllocator64 PrimaryAllocator; - -#elif defined(__powerpc64__) - static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G - - struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x300000000000; - static const uptr kSpaceSize = 0x020000000000; // 2T. - static const uptr kMetadataSize = sizeof(Metadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - - typedef SizeClassAllocator64 PrimaryAllocator; -#elif defined(__aarch64__) - static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G - static const uptr kRegionSizeLog = 20; - static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; - typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - - struct AP32 { - static const uptr kSpaceBeg = 0; - static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; - static const uptr kMetadataSize = sizeof(Metadata); - typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = __msan::kRegionSizeLog; - typedef __msan::ByteMap ByteMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - typedef SizeClassAllocator32 PrimaryAllocator; -#endif -typedef SizeClassAllocatorLocalCache AllocatorCache; -typedef LargeMmapAllocator SecondaryAllocator; -typedef CombinedAllocator Allocator; - static Allocator allocator; static AllocatorCache fallback_allocator_cache; static SpinMutex fallback_mutex; +Allocator &get_allocator() { return allocator; } + void MsanAllocatorInit() { allocator.Init( common_flags()->allocator_may_return_null, diff --git a/lib/msan/msan_allocator.h b/lib/msan/msan_allocator.h index 407942e54..abd4ea678 100644 --- a/lib/msan/msan_allocator.h +++ b/lib/msan/msan_allocator.h @@ -15,9 +15,106 @@ #define MSAN_ALLOCATOR_H #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" namespace __msan { +struct Metadata { + uptr requested_size; +}; + +struct MsanMapUnmapCallback { + void OnMap(uptr p, uptr size) const {} + void OnUnmap(uptr p, uptr size) const { + __msan_unpoison((void *)p, size); + + // We are about to unmap a chunk of user memory. + // Mark the corresponding shadow memory as not needed. + uptr shadow_p = MEM_TO_SHADOW(p); + ReleaseMemoryPagesToOS(shadow_p, shadow_p + size); + if (__msan_get_track_origins()) { + uptr origin_p = MEM_TO_ORIGIN(p); + ReleaseMemoryPagesToOS(origin_p, origin_p + size); + } + } +}; + +#if defined(__mips64) + static const uptr kMaxAllowedMallocSize = 2UL << 30; + static const uptr kRegionSizeLog = 20; + static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; + typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; + + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; +#elif defined(__x86_64__) +#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) + static const uptr kAllocatorSpace = 0x700000000000ULL; +#else + static const uptr kAllocatorSpace = 0x600000000000ULL; +#endif + static const uptr kMaxAllowedMallocSize = 8UL << 30; + + struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = 0x40000000000; // 4T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + + typedef SizeClassAllocator64 PrimaryAllocator; + +#elif defined(__powerpc64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + + struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x300000000000; + static const uptr kSpaceSize = 0x020000000000; // 2T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + + typedef SizeClassAllocator64 PrimaryAllocator; +#elif defined(__aarch64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + static const uptr kRegionSizeLog = 20; + static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; + typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; + + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; +typedef LargeMmapAllocator SecondaryAllocator; +typedef CombinedAllocator Allocator; + + +Allocator &get_allocator(); + struct MsanThreadLocalMallocStorage { uptr quarantine_cache[16]; // Allocator cache contains atomic_uint64_t which must be 8-byte aligned. diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 15543bd91..ab08744a7 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -1228,6 +1228,7 @@ INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) { } static void BeforeFork() { + get_allocator().ForceLock(); StackDepotLockAll(); ChainedOriginDepotLockAll(); } @@ -1235,6 +1236,7 @@ static void BeforeFork() { static void AfterFork() { ChainedOriginDepotUnlockAll(); StackDepotUnlockAll(); + get_allocator().ForceUnlock(); } INTERCEPTOR(int, fork, void) { diff --git a/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc b/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc new file mode 100644 index 000000000..d159d85ee --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc @@ -0,0 +1,118 @@ +// https://github.com/google/sanitizers/issues/774 +// Test that sanitizer allocator is fork-safe. +// Run a number of threads that perform memory allocation/deallocation, then fork +// and verify that malloc/free do not deadlock in the child process. + +// RUN: %clangxx -std=c++11 -O0 %s -o %t +// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t 2>&1 | FileCheck %s + +// Fun fact: if test output is redirected to a file (as opposed to +// being piped directly to FileCheck), we may lose some "done"s due to +// a kernel bug: +// https://lkml.org/lkml/2014/2/17/324 + +// UNSUPPORTED: tsan + +// Flaky on PPC64. +// UNSUPPORTED: powerpc64-target-arch +// UNSUPPORTED: powerpc64le-target-arch + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int done; + +void *worker(void *arg) { + while (true) { + void *p = malloc(4); + if (__atomic_load_n(&done, __ATOMIC_RELAXED)) + return 0; + } + return 0; +} + +// Run through malloc/free in the child process. +// This can deadlock on allocator cache refilling. +void child() { + for (int i = 0; i < 10000; ++i) { + void *p = malloc(4); + } + write(2, "done\n", 5); +} + +void test() { + const int kThreads = 10; + pthread_t t[kThreads]; + for (int i = 0; i < kThreads; ++i) + pthread_create(&t[i], NULL, worker, (void*)(long)i); + usleep(100000); + pid_t pid = fork(); + if (pid) { + // parent + __atomic_store_n(&done, 1, __ATOMIC_RELAXED); + pid_t p; + while ((p = wait(NULL)) == -1) { } + } else { + // child + child(); + } +} + +int main() { + const int kChildren = 30; + for (int i = 0; i < kChildren; ++i) { + pid_t pid = fork(); + if (pid) { + // parent + } else { + test(); + exit(0); + } + } + + for (int i = 0; i < kChildren; ++i) { + pid_t p; + while ((p = wait(NULL)) == -1) { } + } + + return 0; +} + +// Expect 30 (== kChildren) "done" messages. +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done +// CHECK: done -- cgit v1.2.1 From e1dfaf677272ae85e80cae9a72295e5fede40192 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Wed, 31 May 2017 11:40:57 +0000 Subject: [sanitizer] Trying to fix MAC buildbots after r304285 It seems that on MAC allocator already locks on fork thus adding another ForceLock in fork interceptor will cause a deadlock. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304297 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 12 ++++++++---- lib/lsan/lsan_interceptors.cc | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 1f0dc9e2d..e82a5a4a7 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -707,13 +707,17 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #if ASAN_INTERCEPT_FORK static void BeforeFork() { - get_allocator().ForceLock(); - StackDepotLockAll(); + if (SANITIZER_LINUX) { + get_allocator().ForceLock(); + StackDepotLockAll(); + } } static void AfterFork() { - StackDepotUnlockAll(); - get_allocator().ForceUnlock(); + if (SANITIZER_LINUX) { + StackDepotUnlockAll(); + get_allocator().ForceUnlock(); + } } INTERCEPTOR(int, fork, void) { diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index b8cf6ae07..a0a59daa0 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -99,13 +99,17 @@ INTERCEPTOR(void*, valloc, uptr size) { #endif static void BeforeFork() { - LockAllocator(); - StackDepotLockAll(); + if (SANITIZER_LINUX) { + LockAllocator(); + StackDepotLockAll(); + } } static void AfterFork() { - StackDepotUnlockAll(); - UnlockAllocator(); + if (SANITIZER_LINUX) { + StackDepotUnlockAll(); + UnlockAllocator(); + } } INTERCEPTOR(int, fork, void) { -- cgit v1.2.1 From 9b2c60be6745a807592f96e7238c331c2308f615 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 31 May 2017 18:26:32 +0000 Subject: [sanitizer-coverage] remove stale code (old coverage); compiler-rt part git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304318 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 3 - lib/dfsan/done_abilist.txt | 2 - .../sanitizer_coverage_interface.inc | 5 -- lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 47 ++---------- .../sanitizer_coverage_libcdep_new.cc | 4 +- lib/sanitizer_common/scripts/sancov.py | 2 +- test/asan/TestCases/Linux/coverage-missing.cc | 6 +- test/asan/TestCases/Posix/coverage-fork.cc | 10 ++- .../TestCases/Posix/coverage-module-unloaded.cc | 20 ++--- test/asan/TestCases/Posix/coverage-sandboxing.cc | 87 ---------------------- test/asan/TestCases/Posix/coverage.cc | 19 ++--- test/asan/TestCases/coverage-and-lsan.cc | 4 +- test/asan/TestCases/coverage-order-pcs.cc | 57 -------------- .../TestCases/sanitizer_coverage_symbolize.cc | 2 +- .../sanitizer_coverage_trace_pc_guard-dso.cc | 6 +- .../TestCases/sanitizer_coverage_trace_pc_guard.cc | 2 +- 16 files changed, 41 insertions(+), 235 deletions(-) delete mode 100644 test/asan/TestCases/Posix/coverage-sandboxing.cc delete mode 100644 test/asan/TestCases/coverage-order-pcs.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index 911a3e854..bdb113728 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -32,9 +32,6 @@ extern "C" { // descriptor. Returns -1 on failure, or if coverage dumping is disabled. // This is intended for use by sandboxing code. intptr_t __sanitizer_maybe_open_cov_file(const char *name); - // Get the number of unique covered blocks (or edges). - // This can be useful for coverage-directed in-process fuzzers. - uintptr_t __sanitizer_get_total_unique_coverage(); #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index cbbedbc33..a560cd7b4 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -287,8 +287,6 @@ fun:__sanitizer_cov_with_check=uninstrumented fun:__sanitizer_cov_with_check=discard fun:__sanitizer_set_death_callback=uninstrumented fun:__sanitizer_set_death_callback=discard -fun:__sanitizer_get_total_unique_coverage=uninstrumented -fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented fun:__sanitizer_update_counter_bitset_and_clear_counters=discard diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 42b4d3aba..70c10e04b 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -8,14 +8,9 @@ //===----------------------------------------------------------------------===// // Sanitizer Coverage interface list. //===----------------------------------------------------------------------===// -INTERFACE_FUNCTION(__sanitizer_cov) INTERFACE_FUNCTION(__sanitizer_cov_dump) -INTERFACE_FUNCTION(__sanitizer_cov_init) -INTERFACE_FUNCTION(__sanitizer_cov_module_init) -INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) -INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_WEAK_FUNCTION(__sancov_default_options) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 754ece984..abfdf3d02 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -155,13 +155,6 @@ void CoverageData::DirectOpen() { void CoverageData::Init() { pc_fd = kInvalidFd; - - if (!common_flags()->coverage) return; - Printf("**\n***\n***\n"); - Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n"); - Printf("**WARNING: and will be removed in future versions\n"); - Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n"); - Printf("**\n***\n***\n"); } void CoverageData::Enable() { @@ -495,6 +488,12 @@ static void GenerateHtmlReport(const InternalMmapVector &cov_files) { void CoverageData::DumpOffsets() { auto sym = Symbolizer::GetOrInit(); if (!common_flags()->coverage_pcs) return; + Printf("**\n***\n***\n"); + Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n"); + Printf("**WARNING: and will be removed in future versions\n"); + Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n"); + Printf("**\n***\n***\n"); + CHECK_NE(sym, nullptr); InternalMmapVector offsets(0); InternalScopedString path(kMaxPathLength); @@ -607,47 +606,13 @@ void CoverageUpdateMapping() { } // namespace __sanitizer extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) { - coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), - guard); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) { - atomic_uint32_t *atomic_guard = reinterpret_cast(guard); - if (static_cast( - __sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) < 0) - coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), - guard); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { - coverage_enabled = true; - coverage_dir = common_flags()->coverage_dir; - coverage_data.Init(); -} SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { - coverage_data.DumpAll(); __sanitizer_dump_trace_pc_guard_coverage(); } -SANITIZER_INTERFACE_ATTRIBUTE void -__sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters, - const char *comp_unit_name) { - coverage_data.InitializeGuards(guards, npcs, comp_unit_name, GET_CALLER_PC()); - if (!common_flags()->coverage_direct) return; - if (SANITIZER_ANDROID && coverage_enabled) { - // dlopen/dlclose interceptors do not work on Android, so we rely on - // Extend() calls to update .sancov.map. - CovUpdateMapping(coverage_dir, GET_CALLER_PC()); - } - coverage_data.Extend(npcs); -} SANITIZER_INTERFACE_ATTRIBUTE sptr __sanitizer_maybe_open_cov_file(const char *name) { return (sptr)MaybeOpenCovFile(name); } -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_total_unique_coverage() { - return atomic_load(&coverage_counter, memory_order_relaxed); -} - // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 6d8e3e041..a98dde76e 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -49,7 +49,7 @@ static void WriteModuleCoverage(char* file_path, const char* module_name, WriteToFile(fd, &Magic, sizeof(Magic)); WriteToFile(fd, pcs, len * sizeof(*pcs)); CloseFile(fd); - Printf("SanitizerCoverage: %s %zd PCs written\n", file_path, len); + Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); } static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { @@ -71,7 +71,7 @@ static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { if (!pc) continue; if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { - Printf("ERROR: bad pc %x\n", pc); + Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc); continue; } uptr module_base = pc - pcs[i]; diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py index e2eba36a8..35606396b 100755 --- a/lib/sanitizer_common/scripts/sancov.py +++ b/lib/sanitizer_common/scripts/sancov.py @@ -194,7 +194,7 @@ def GetInstrumentedPCs(binary): # - with call or callq, # - directly or via PLT. cmd = "objdump -d %s | " \ - "grep '^\s\+[0-9a-f]\+:.*\scall\(q\|\)\s\+[0-9a-f]\+ <__sanitizer_cov\(_with_check\|\)\(@plt\|\)>' | " \ + "grep '^\s\+[0-9a-f]\+:.*\scall\(q\|\)\s\+[0-9a-f]\+ <__sanitizer_cov\(_with_check\|\|_trace_pc_guard\)\(@plt\|\)>' | " \ "grep '^\s\+[0-9a-f]\+' -o" % binary proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) diff --git a/test/asan/TestCases/Linux/coverage-missing.cc b/test/asan/TestCases/Linux/coverage-missing.cc index 16093498f..585aee69a 100644 --- a/test/asan/TestCases/Linux/coverage-missing.cc +++ b/test/asan/TestCases/Linux/coverage-missing.cc @@ -1,7 +1,7 @@ // Test for "sancov.py missing ...". // First case: coverage from executable. main() is called on every code path. -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -DFOOBAR -DMAIN +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t -DFOOBAR -DMAIN // RUN: rm -rf %T/coverage-missing // RUN: mkdir -p %T/coverage-missing // RUN: cd %T/coverage-missing @@ -27,8 +27,8 @@ // Second case: coverage from DSO. // cd %T -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %dynamiclib -DFOOBAR -shared -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func %s %dynamiclib -o %t -DMAIN +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %dynamiclib -DFOOBAR -shared -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %dynamiclib -o %t -DMAIN // RUN: cd .. // RUN: rm -rf %T/coverage-missing // RUN: mkdir -p %T/coverage-missing diff --git a/test/asan/TestCases/Posix/coverage-fork.cc b/test/asan/TestCases/Posix/coverage-fork.cc index 40ce72ef5..da6e3c2c1 100644 --- a/test/asan/TestCases/Posix/coverage-fork.cc +++ b/test/asan/TestCases/Posix/coverage-fork.cc @@ -1,9 +1,13 @@ -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t // RUN: rm -rf %T/coverage-fork // RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork -// RUN: %env_asan_opts=coverage=1:coverage_direct=0:verbosity=1 %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s // // UNSUPPORTED: android +// +// Ideally a forked-subprocess should only report it's own coverage, +// not parent's one. But trace-pc-guard currently does nothing special for fork, +// and thus this test is relaxed. #include #include @@ -32,6 +36,6 @@ int main(int argc, char **argv) { } // CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] -// CHECK-DAG: [[ChildPID]].sancov: 1 PCs written +// CHECK-DAG: [[ChildPID]].sancov: {{.*}} PCs written // CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] // CHECK-DAG: [[ParentPID]].sancov: 3 PCs written diff --git a/test/asan/TestCases/Posix/coverage-module-unloaded.cc b/test/asan/TestCases/Posix/coverage-module-unloaded.cc index db27283a6..322a1bad1 100644 --- a/test/asan/TestCases/Posix/coverage-module-unloaded.cc +++ b/test/asan/TestCases/Posix/coverage-module-unloaded.cc @@ -1,12 +1,11 @@ // Check that unloading a module doesn't break coverage dumping for remaining // modules. -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib1 -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib2 -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func %s %libdl -o %t -// RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t %dynamiclib1 %dynamiclib2 2>&1 | FileCheck %s -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t %dynamiclib1 %dynamiclib2 foo 2>&1 | FileCheck %s -// RUN: rm -r %T/coverage-module-unloaded +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib1 -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib2 -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %libdl -o %t.exe +// RUN: mkdir -p %t.tmp/coverage-module-unloaded && cd %t.tmp/coverage-module-unloaded +// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t.exe %dynamiclib1 %dynamiclib2 2>&1 | FileCheck %s +// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t.exe %dynamiclib1 %dynamiclib2 foo 2>&1 | FileCheck %s // // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android @@ -48,8 +47,5 @@ int main(int argc, char **argv) { #endif // CHECK: PID: [[PID:[0-9]+]] -// CHECK: [[PID]].sancov: 1 PCs written -// CHECK: coverage-module-unloaded{{.*}}1.[[PID]] -// CHECK: coverage-module-unloaded{{.*}}2.[[PID]] -// Even though we've unloaded one of the libs we still dump the coverage file -// for that lib (although the data will be inaccurate, if at all useful) +// CHECK-DAG: exe{{.*}}[[PID]].sancov: {{.*}}PCs written +// CHECK-DAG: dynamic{{.*}}[[PID]].sancov: {{.*}}PCs written diff --git a/test/asan/TestCases/Posix/coverage-sandboxing.cc b/test/asan/TestCases/Posix/coverage-sandboxing.cc deleted file mode 100644 index 354070708..000000000 --- a/test/asan/TestCases/Posix/coverage-sandboxing.cc +++ /dev/null @@ -1,87 +0,0 @@ -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t %ld_flags_rpath_exe - -// RUN: rm -rf %T/coverage_sandboxing_test -// RUN: mkdir %T/coverage_sandboxing_test && cd %T/coverage_sandboxing_test -// RUN: mkdir vanilla && cd vanilla -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-vanilla -// RUN: mkdir ../sandbox1 && cd ../sandbox1 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t a 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox -// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed -// RUN: mkdir ../sandbox2 && cd ../sandbox2 -// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t a b 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox -// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed -// RUN: cd .. -// RUN: %sancov print vanilla/%xdynamiclib_filename*.sancov > vanilla.txt -// RUN: %sancov print sandbox1/%xdynamiclib_filename*.sancov > sandbox1.txt -// RUN: %sancov print sandbox2/%xdynamiclib_filename*.sancov > sandbox2.txt -// RUN: diff vanilla.txt sandbox1.txt -// RUN: diff vanilla.txt sandbox2.txt -// RUN: rm -r %T/coverage_sandboxing_test - -// https://code.google.com/p/address-sanitizer/issues/detail?id=263 -// XFAIL: android -// UNSUPPORTED: ios - -#include -#include -#include -#include -#include - -#include - -#define bb0(n) \ - case n: \ - fprintf(stderr, "foo: %d\n", n); \ - break; - -#define bb1(n) bb0(n) bb0(n + 1) -#define bb2(n) bb1(n) bb1(n + 2) -#define bb3(n) bb2(n) bb2(n + 4) -#define bb4(n) bb3(n) bb3(n + 8) -#define bb5(n) bb4(n) bb4(n + 16) -#define bb6(n) bb5(n) bb5(n + 32) -#define bb7(n) bb6(n) bb6(n + 64) -#define bb8(n) bb7(n) bb7(n + 128) - -#ifdef SHARED -void foo(int i) { - switch(i) { - // 256 basic blocks - bb8(0) - } -} -#else -extern void foo(int i); - -int main(int argc, char **argv) { - assert(argc <= 3); - for (int i = 0; i < 256; i++) foo(i); - fprintf(stderr, "PID: %d\n", getpid()); - if (argc == 1) { - // Vanilla mode, dump to individual files. - return 0; - } - // Dump to packed file. - int fd = creat("coverage_sandboxing_test.sancov.packed", 0660); - __sanitizer_sandbox_arguments args = {0}; - args.coverage_sandboxed = 1; - args.coverage_fd = fd; - if (argc == 2) - // Write to packed file, do not split into blocks. - args.coverage_max_block_size = 0; - else if (argc == 3) - // Write to packed file, split into blocks (as if writing to a socket). - args.coverage_max_block_size = 100; - __sanitizer_sandbox_on_notify(&args); - return 0; -} -#endif - -// CHECK-vanilla: PID: [[PID:[0-9]+]] -// CHECK-vanilla: .so.[[PID]].sancov: 257 PCs written -// CHECK-vanilla: [[PID]].sancov: 1 PCs written - -// CHECK-sandbox: PID: [[PID:[0-9]+]] -// CHECK-sandbox: 257 PCs written to packed file diff --git a/test/asan/TestCases/Posix/coverage.cc b/test/asan/TestCases/Posix/coverage.cc index bff060968..a78560a72 100644 --- a/test/asan/TestCases/Posix/coverage.cc +++ b/test/asan/TestCases/Posix/coverage.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so -// RUN: %clangxx_asan -fsanitize-coverage=func %s %ld_flags_rpath_exe -o %t +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %ld_flags_rpath_exe -o %t // RUN: rm -rf %T/coverage && mkdir -p %T/coverage && cd %T/coverage // RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main // RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 @@ -20,7 +20,6 @@ // XFAIL: android // UNSUPPORTED: ios -#include #include #include #include @@ -38,12 +37,8 @@ int G[4]; int main(int argc, char **argv) { fprintf(stderr, "PID: %d\n", getpid()); for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i], "foo")) { - uintptr_t old_coverage = __sanitizer_get_total_unique_coverage(); + if (!strcmp(argv[i], "foo")) foo(); - uintptr_t new_coverage = __sanitizer_get_total_unique_coverage(); - assert(new_coverage > old_coverage); - } if (!strcmp(argv[i], "bar")) bar(); } @@ -64,12 +59,12 @@ int main(int argc, char **argv) { // CHECK-foo-NOT: .so.[[PID]] // // CHECK-bar: PID: [[PID:[0-9]+]] -// CHECK-bar: .so.[[PID]].sancov: 1 PCs written -// CHECK-bar: [[PID]].sancov: 1 PCs written +// CHECK-bar-DAG: .so.[[PID]].sancov: 1 PCs written +// CHECK-bar-DAG: [[PID]].sancov: 1 PCs written // // CHECK-foo-bar: PID: [[PID:[0-9]+]] -// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written -// CHECK-foo-bar: [[PID]].sancov: 2 PCs written +// CHECK-foo-bar-DAG: so.[[PID]].sancov: 1 PCs written +// CHECK-foo-bar-DAG: [[PID]].sancov: 2 PCs written // // CHECK-report: AddressSanitizer: global-buffer-overflow // CHECK-report: PCs written diff --git a/test/asan/TestCases/coverage-and-lsan.cc b/test/asan/TestCases/coverage-and-lsan.cc index 081f493ee..591b4e93f 100644 --- a/test/asan/TestCases/coverage-and-lsan.cc +++ b/test/asan/TestCases/coverage-and-lsan.cc @@ -1,6 +1,6 @@ // Make sure coverage is dumped even if there are reported leaks. // -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s -o %t // // RUN: rm -rf %T/coverage-and-lsan // @@ -17,4 +17,4 @@ int main(int argc, char **argv) { } // CHECK: LeakSanitizer: detected memory leaks -// CHECK: CovDump: +// CHECK: SanitizerCoverage: {{.*}}PCs written diff --git a/test/asan/TestCases/coverage-order-pcs.cc b/test/asan/TestCases/coverage-order-pcs.cc deleted file mode 100644 index e81c91045..000000000 --- a/test/asan/TestCases/coverage-order-pcs.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Test coverage_order_pcs=1 flag which orders the PCs by their appearance. -// RUN: DIR=%T/coverage-order-pcs -// RUN: rm -rf $DIR -// RUN: mkdir $DIR -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -// RUN: %env_asan_opts=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %run %t -// RUN: mv $DIR/*sancov $DIR/A - -// RUN: %env_asan_opts=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %run %t 1 -// RUN: mv $DIR/*sancov $DIR/B - -// RUN: %env_asan_opts=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %run %t -// RUN: mv $DIR/*sancov $DIR/C - -// RUN: %env_asan_opts=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %run %t 1 -// RUN: mv $DIR/*sancov $DIR/D -// -// RUN: (%sancov print $DIR/A; %sancov print $DIR/B; %sancov print $DIR/C; %sancov print $DIR/D) | FileCheck %s -// -// RUN: rm -rf $DIR -// Ordering works only in 64-bit mode for now. -// REQUIRES: asan-64-bits, shell -// UNSUPPORTED: android -#include - -void foo() { fprintf(stderr, "FOO\n"); } -void bar() { fprintf(stderr, "BAR\n"); } - -int main(int argc, char **argv) { - if (argc == 2) { - foo(); - bar(); - } else { - bar(); - foo(); - } -} - -// Run A: no ordering -// CHECK: [[FOO:0x[0-9a-f]*]] -// CHECK-NEXT: [[BAR:0x[0-9a-f]*]] -// CHECK-NEXT: [[MAIN:0x[0-9a-f]*]] -// -// Run B: still no ordering -// CHECK-NEXT: [[FOO]] -// CHECK-NEXT: [[BAR]] -// CHECK-NEXT: [[MAIN]] -// -// Run C: MAIN, BAR, FOO -// CHECK-NEXT: [[MAIN]] -// CHECK-NEXT: [[BAR]] -// CHECK-NEXT: [[FOO]] -// -// Run D: MAIN, FOO, BAR -// CHECK-NEXT: [[MAIN]] -// CHECK-NEXT: [[FOO]] -// CHECK-NEXT: [[BAR]] diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc index 266dc3f0e..28e237802 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc @@ -25,4 +25,4 @@ int main() { } // CHECK: main -// CHECK: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov 2 PCs written +// CHECK: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov: 2 PCs written diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc index 68459b19a..6185177a1 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -62,9 +62,9 @@ int baz() { // CHECK-NEXT: foo // CHECK-NEXT: bar // CHECK-NEXT: baz -// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}.sancov 2 PCs written -// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_2.so.{{.*}}.sancov 1 PCs written -// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_1.so.{{.*}}.sancov 1 PCs written +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}.sancov: 2 PCs written +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_2.so.{{.*}}.sancov: 1 PCs written +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_1.so.{{.*}}.sancov: 1 PCs written // // CHECK-SANCOV: Ignoring {{.*}}_1.so and its coverage because __sanitizer_cov* functions were not found. // CHECK-SANCOV: Ignoring {{.*}}_2.so and its coverage because __sanitizer_cov* functions were not found. diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc index 9dcbe6fa0..2d6d00b6a 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -34,7 +34,7 @@ int main() { // CHECK: main // CHECK-NEXT: foo // CHECK-NEXT: foo -// CHECK-NEXT: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard.{{.*}}.sancov 2 PCs written +// CHECK-NEXT: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard.{{.*}}.sancov: 2 PCs written // // CHECK-SANCOV: sanitizer_coverage_trace_pc_guard.cc:23 foo // CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard.cc:28 main -- cgit v1.2.1 From 27c8277872fdff5466439844251c9c52ec37dadb Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Thu, 1 Jun 2017 09:37:22 +0000 Subject: [asan] Add strndup/__strndup interceptors. Recommit of r302781 with Vitaly Buka's fix for non zero terminated strings. Differential Revision: https://reviews.llvm.org/D31457 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304399 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 +++ lib/asan/tests/asan_str_test.cc | 27 ++++++++++++++ lib/msan/msan_interceptors.cc | 36 ++++--------------- lib/msan/tests/msan_test.cc | 13 +++++-- .../sanitizer_common_interceptors.inc | 42 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_flags.inc | 3 ++ .../sanitizer_platform_interceptors.h | 14 ++++++++ lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 ++++ test/asan/TestCases/Posix/strndup_oob_test.cc | 27 ++++++++++++++ test/asan/TestCases/Posix/strndup_oob_test2.cc | 22 ++++++++++++ test/msan/strndup.cc | 28 +++++++++++++++ 11 files changed, 191 insertions(+), 31 deletions(-) create mode 100644 test/asan/TestCases/Posix/strndup_oob_test.cc create mode 100644 test/asan/TestCases/Posix/strndup_oob_test2.cc create mode 100644 test/msan/strndup.cc diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index c8ae3faed..6be0d6e94 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,6 +194,10 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } + if (!f->replace_str && common_flags()->intercept_strndup) { + Report("WARNING: strndup* interceptors are enabled even though " + "replace_str=0. Use intercept_strndup=0 to disable them."); + } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index c790088f8..964f6da02 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,6 +154,33 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } +#if SANITIZER_TEST_HAS_STRNDUP +TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { + size_t size = Ident(42); + char *str = MallocAndMemsetString(size); + char *new_str; + // Normal strndup calls. + str[size - 1] = '\0'; + new_str = strndup(str, size - 13); + free(new_str); + new_str = strndup(str + size - 1, 13); + free(new_str); + // Argument points to not allocated memory. + EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); + // Overwrite the terminating '\0' and hit unallocated memory. + str[size - 1] = 'z'; + EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); + // Check handling of non 0 terminated strings. + Ident(new_str = strndup(str + size - 1, 0)); + free(new_str); + Ident(new_str = strndup(str + size - 1, 1)); + free(new_str); + EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0)); + free(str); +} +#endif // SANITIZER_TEST_HAS_STRNDUP + TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index ab08744a7..fbc2ea4fe 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,33 +341,6 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif -INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - // On FreeBSD strndup() leverages strnlen(). - InterceptorScope interceptor_scope; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} - -#if !SANITIZER_FREEBSD -INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(__strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} -#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) -#else -#define MSAN_MAYBE_INTERCEPT___STRNDUP -#endif - INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1373,6 +1346,13 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1540,8 +1520,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; - INTERCEPT_FUNCTION(strndup); - MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index c7c91324a..543a7eb98 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,19 +1581,28 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 3); + char *x; + EXPECT_UMR(x = strndup(buf, 3)); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); EXPECT_NOT_POISONED(x[3]); free(x); + // Check handling of non 0 terminated strings. + buf[3] = 'z'; + __msan_poison(buf + 3, sizeof(*buf)); + EXPECT_UMR(x = strndup(buf + 3, 1)); + EXPECT_POISONED(x[0]); + EXPECT_NOT_POISONED(x[1]); + free(x); } TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 2); + char *x; + EXPECT_UMR(x = strndup(buf, 2)); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 53204b48e..c0c08a031 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,8 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_COPY_STRING +// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -217,6 +219,24 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif +#ifndef COMMON_INTERCEPTOR_COPY_STRING +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr copy_length = internal_strnlen(s, size); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ + return new_mem; +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -300,6 +320,26 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif +#if SANITIZER_INTERCEPT_STRNDUP +INTERCEPTOR(char*, strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) +#else +#define INIT_STRNDUP +#endif // SANITIZER_INTERCEPT_STRNDUP + +#if SANITIZER_INTERCEPT___STRNDUP +INTERCEPTOR(char*, __strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) +#else +#define INIT___STRNDUP +#endif // SANITIZER_INTERCEPT___STRNDUP + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6163,6 +6203,8 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; + INIT_STRNDUP; + INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 12c126fa7..f87d8b643 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -197,6 +197,9 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index e5644ef25..a95497467 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,6 +25,12 @@ # define SI_NOT_WINDOWS 0 #endif +#if SANITIZER_POSIX +# define SI_POSIX 1 +#else +# define SI_POSIX 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -69,6 +75,12 @@ # define SI_UNIX_NOT_MAC 0 #endif +#if SANITIZER_LINUX && !SANITIZER_FREEBSD +# define SI_LINUX_NOT_FREEBSD 1 +# else +# define SI_LINUX_NOT_FREEBSD 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -86,6 +98,8 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX +#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index 9c162a66f..b7728d9ea 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,4 +124,10 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif +#if !defined(_MSC_VER) +# define SANITIZER_TEST_HAS_STRNDUP 1 +#else +# define SANITIZER_TEST_HAS_STRNDUP 0 +#endif + #endif // SANITIZER_TEST_UTILS_H diff --git a/test/asan/TestCases/Posix/strndup_oob_test.cc b/test/asan/TestCases/Posix/strndup_oob_test.cc new file mode 100644 index 000000000..7ea0b7a33 --- /dev/null +++ b/test/asan/TestCases/Posix/strndup_oob_test.cc @@ -0,0 +1,27 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Unwind problem on arm: "main" is missing from the allocation stack trace. +// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf + +#include + +char kString[] = "foo"; + +int main(int argc, char **argv) { + char *copy = strndup(kString, 2); + int x = copy[2 + argc]; // BOOM + // CHECK: AddressSanitizer: heap-buffer-overflow + // CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]] + // CHECK-LABEL: allocated by thread T{{.*}} here: + // CHECK: #{{[01]}} {{.*}}strndup + // CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]] + // CHECK-LABEL: SUMMARY + // CHECK: strndup_oob_test.cc:[[@LINE-7]] + return x; +} diff --git a/test/asan/TestCases/Posix/strndup_oob_test2.cc b/test/asan/TestCases/Posix/strndup_oob_test2.cc new file mode 100644 index 000000000..0a1afe285 --- /dev/null +++ b/test/asan/TestCases/Posix/strndup_oob_test2.cc @@ -0,0 +1,22 @@ +// RUN: %clang_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clang_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clang_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clang_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clang_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Unwind problem on arm: "main" is missing from the allocation stack trace. +// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf + +#include + +char kChars[] = { 'f', 'o', 'o' }; + +int main(int argc, char **argv) { + char *copy = strndup(kChars, 3); + copy = strndup(kChars, 10); + // CHECK: AddressSanitizer: global-buffer-overflow + // CHECK: {{.*}}main {{.*}}.cc:[[@LINE-2]] + return *copy; +} \ No newline at end of file diff --git a/test/msan/strndup.cc b/test/msan/strndup.cc new file mode 100644 index 000000000..d4b9af1a9 --- /dev/null +++ b/test/msan/strndup.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s +// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s + +// When built as C on Linux, strndup is transformed to __strndup. +// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s + +// UNSUPPORTED: win32 + +#include +#include +#include +#include + +int main(int argc, char **argv) { + char kString[4] = "abc"; + __msan_poison(kString + 2, 1); + char *copy = strndup(kString, 4); // BOOM + assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved. + free(copy); + return 0; + // ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4) + // ON: MemorySanitizer: use-of-uninitialized-value + // ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]] + // ON-LABEL: SUMMARY + // ON: {{.*}}strndup.cc:[[@LINE-8]] + // OFF-NOT: MemorySanitizer +} + -- cgit v1.2.1 From bfeededd7ee43fe38262619ec200687875ae82a1 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 1 Jun 2017 16:44:11 +0000 Subject: Bug 33221 [UBSAN] segfault with -fsanitize=undefined There is can be a situation when vptr is not initializing by constructor of the object, and has a junk data which should be properly checked, because c++ standard says: "if default constructor is not specified 16 (7.3) no initialization is performed." Patch by Denis Khalikov! Differential Revision: https://reviews.llvm.org/D33712 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304437 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_type_hash_itanium.cc | 2 +- test/ubsan/TestCases/TypeCheck/PR33221.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 test/ubsan/TestCases/TypeCheck/PR33221.cpp diff --git a/lib/ubsan/ubsan_type_hash_itanium.cc b/lib/ubsan/ubsan_type_hash_itanium.cc index 5ae5ae0dc..729c4a0f3 100644 --- a/lib/ubsan/ubsan_type_hash_itanium.cc +++ b/lib/ubsan/ubsan_type_hash_itanium.cc @@ -197,7 +197,7 @@ struct VtablePrefix { }; VtablePrefix *getVtablePrefix(void *Vtable) { VtablePrefix *Vptr = reinterpret_cast(Vtable); - if (!Vptr) + if (!IsAccessibleMemoryRange((uptr)Vptr, sizeof(VtablePrefix))) return nullptr; VtablePrefix *Prefix = Vptr - 1; if (!Prefix->TypeInfo) diff --git a/test/ubsan/TestCases/TypeCheck/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/PR33221.cpp new file mode 100644 index 000000000..17e35a6d9 --- /dev/null +++ b/test/ubsan/TestCases/TypeCheck/PR33221.cpp @@ -0,0 +1,24 @@ +// RUN: %clangxx -frtti -fsanitize=undefined -g %s -O3 -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// REQUIRES: cxxabi + +class Base { +public: + int i; + virtual void print() {} +}; + +class Derived : public Base { +public: + void print() {} +}; + +int main() { + Derived *list = (Derived *)new char[sizeof(Derived)]; + +// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base' +// CHECK-NEXT: object has invalid vptr + int foo = list->i; + return 0; +} -- cgit v1.2.1 From 0c1676c0068c7bda6cba4a7d24ba1aa500201086 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 1 Jun 2017 17:56:12 +0000 Subject: Tighten up test to address bot failure. NFC. http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/32035 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304440 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/PR33221.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/ubsan/TestCases/TypeCheck/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/PR33221.cpp index 17e35a6d9..09411aa50 100644 --- a/test/ubsan/TestCases/TypeCheck/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/PR33221.cpp @@ -1,8 +1,10 @@ -// RUN: %clangxx -frtti -fsanitize=undefined -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=vptr -g %s -O3 -o %t // RUN: %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi +#include + class Base { public: int i; @@ -15,10 +17,12 @@ public: }; int main() { - Derived *list = (Derived *)new char[sizeof(Derived)]; + char *c = new char[sizeof(Derived)]; + memset((void *)c, 0, sizeof(Derived)); + Derived *list = (Derived *)c; // CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base' -// CHECK-NEXT: object has invalid vptr +// CHECK-NEXT: invalid vptr int foo = list->i; return 0; } -- cgit v1.2.1 From efd9e1ef2ba69497829dde2af6a879b789662e9b Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 1 Jun 2017 19:40:59 +0000 Subject: [ubsan] Runtime support for pointer overflow checking Patch by John Regehr and Will Dietz! Differential Revision: https://reviews.llvm.org/D20323 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304461 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_checks.inc | 1 + lib/ubsan/ubsan_handlers.cc | 31 +++++++++++++++++++++++++ lib/ubsan/ubsan_handlers.h | 7 ++++++ lib/ubsan/ubsan_interface.inc | 2 ++ test/ubsan/TestCases/Pointer/index-overflow.cpp | 19 +++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 test/ubsan/TestCases/Pointer/index-overflow.cpp diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc index 6e0864140..0a87e6e8e 100644 --- a/lib/ubsan/ubsan_checks.inc +++ b/lib/ubsan/ubsan_checks.inc @@ -19,6 +19,7 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") +UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size") UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow", diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index d6a8f52a2..80cc8ad25 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -554,6 +554,37 @@ void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { Die(); } +static void handlePointerOverflowImpl(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result, + ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + ErrorType ET = ErrorType::PointerOverflow; + + if (ignoreReport(Loc, Opts, ET)) + return; + + ScopedReport R(Opts, Loc, ET); + + Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1") + << (void *)Base << (void*)Result; +} + +void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result) { + GET_REPORT_OPTIONS(false); + handlePointerOverflowImpl(Data, Base, Result, Opts); +} + +void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result) { + GET_REPORT_OPTIONS(true); + handlePointerOverflowImpl(Data, Base, Result, Opts); + Die(); +} + static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, ReportOptions Opts) { if (Data->CheckKind != CFITCK_ICall) diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 5857bc249..483c18ced 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -152,6 +152,13 @@ struct NonNullArgData { RECOVERABLE(nonnull_arg, NonNullArgData *Data) RECOVERABLE(nullability_arg, NonNullArgData *Data) +struct PointerOverflowData { + SourceLocation Loc; +}; + +RECOVERABLE(pointer_overflow, PointerOverflowData *Data, ValueHandle Base, + ValueHandle Result) + /// \brief Known CFI check kinds. /// Keep in sync with the enum of the same name in CodeGenFunction.h enum CFITypeCheckKind : unsigned char { diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 0e43ebc68..681476b3c 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -36,6 +36,8 @@ INTERFACE_FUNCTION(__ubsan_handle_nullability_return) INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) +INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow) +INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_sub_overflow) diff --git a/test/ubsan/TestCases/Pointer/index-overflow.cpp b/test/ubsan/TestCases/Pointer/index-overflow.cpp new file mode 100644 index 000000000..eb7f95e85 --- /dev/null +++ b/test/ubsan/TestCases/Pointer/index-overflow.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx -fsanitize=pointer-overflow %s -o %t +// RUN: %t 1 2>&1 | FileCheck %s --check-prefix=ERR +// RUN: %t 0 2>&1 | FileCheck %s --check-prefix=SAFE +// RUN: %t -1 2>&1 | FileCheck %s --check-prefix=SAFE + +#include +#include +#include + +int main(int argc, char *argv[]) { + // SAFE-NOT: runtime error + // ERR: runtime error: pointer index expression with base {{.*}} overflowed to + + char *p = (char *)(UINTPTR_MAX); + + printf("%p\n", p + atoi(argv[1])); + + return 0; +} -- cgit v1.2.1 From cb4adfe6e93bdfe31737c3019516cdf6dcd2d808 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 1 Jun 2017 23:56:49 +0000 Subject: [sanitizer-coverage] nuke more stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304500 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 4 --- .../sanitizer_coverage_interface.inc | 1 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 4 --- .../TestCases/Posix/coverage-maybe-open-file.cc | 34 ---------------------- 4 files changed, 43 deletions(-) delete mode 100644 test/asan/TestCases/Posix/coverage-maybe-open-file.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index bdb113728..c4f999081 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -28,10 +28,6 @@ extern "C" { // .sancov files. void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len); - // Open .sancov.packed in the coverage directory and return the file - // descriptor. Returns -1 on failure, or if coverage dumping is disabled. - // This is intended for use by sandboxing code. - intptr_t __sanitizer_maybe_open_cov_file(const char *name); #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 70c10e04b..d4749000d 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -11,7 +11,6 @@ INTERFACE_FUNCTION(__sanitizer_cov_dump) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) -INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_WEAK_FUNCTION(__sancov_default_options) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index abfdf3d02..211ddcbff 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -609,10 +609,6 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { __sanitizer_dump_trace_pc_guard_coverage(); } -SANITIZER_INTERFACE_ATTRIBUTE -sptr __sanitizer_maybe_open_cov_file(const char *name) { - return (sptr)MaybeOpenCovFile(name); -} // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} diff --git a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc deleted file mode 100644 index ee2977af1..000000000 --- a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc +++ /dev/null @@ -1,34 +0,0 @@ -// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 -// XFAIL: android -// UNSUPPORTED: ios -// -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -// RUN: rm -rf %T/coverage-maybe-open-file -// RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file -// RUN: %env_asan_opts=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success -// RUN: %env_asan_opts=coverage=0 %run %t | FileCheck %s --check-prefix=CHECK-fail -// RUN: FileCheck %s < test.sancov.packed -implicit-check-not={{.}} --check-prefix=CHECK-test -// RUN: cd .. && rm -rf %T/coverage-maybe-open-file - -#include -#include -#include - -#include - -// FIXME: the code below might not work on Windows. -int main(int argc, char **argv) { - int fd = __sanitizer_maybe_open_cov_file("test"); - if (fd > 0) { - printf("SUCCESS\n"); - const char s[] = "test\n"; - write(fd, s, strlen(s)); - close(fd); - } else { - printf("FAIL\n"); - } -} - -// CHECK-success: SUCCESS -// CHECK-fail: FAIL -// CHECK-test: {{^}}test{{$}} -- cgit v1.2.1 From cdad12420e89bc6ee67ebcc6cb04763604535bdf Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 2 Jun 2017 00:17:54 +0000 Subject: [sanitizer-coverage] nuke more stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304503 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 5 +- lib/sanitizer_common/CMakeLists.txt | 1 - lib/sanitizer_common/sanitizer_common.h | 1 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 13 --- .../sanitizer_coverage_mapping_libcdep.cc | 122 --------------------- 5 files changed, 2 insertions(+), 140 deletions(-) delete mode 100644 lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index e82a5a4a7..25974535b 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -242,9 +242,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) CheckNoDeepBind(filename, flag); \ } while (false) #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() -#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ - CoverageUpdateMapping() -#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping() +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ if (AsanThread *t = GetCurrentThread()) { \ diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 6cdc91897..7255a5727 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -56,7 +56,6 @@ set(SANITIZER_LIBCDEP_SOURCES sancov_flags.cc sanitizer_coverage_libcdep.cc sanitizer_coverage_libcdep_new.cc - sanitizer_coverage_mapping_libcdep.cc sanitizer_coverage_win_sections.cc sanitizer_linux_libcdep.cc sanitizer_posix_libcdep.cc diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index a1c9c5a57..57d87a2ef 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -320,7 +320,6 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); -void CoverageUpdateMapping(); void CovBeforeFork(); void CovAfterFork(int child_pid); diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 211ddcbff..b819e5837 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -62,10 +62,6 @@ static atomic_uintptr_t coverage_counter; // To make the pc_array thread- and async-signal-safe it has to be large enough. // 128M counters "ought to be enough for anybody" (4M on 32-bit). -// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file. -// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping() -// dump current memory layout to another file. - static bool cov_sandboxed = false; static fd_t cov_fd = kInvalidFd; static unsigned int cov_max_block_size = 0; @@ -137,8 +133,6 @@ class CoverageData { static CoverageData coverage_data; -void CovUpdateMapping(const char *path, uptr caller_pc = 0); - void CoverageData::DirectOpen() { InternalScopedString path(kMaxPathLength); internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", @@ -150,7 +144,6 @@ void CoverageData::DirectOpen() { } pc_array_mapped_size = 0; - CovUpdateMapping(coverage_dir); } void CoverageData::Init() { @@ -210,7 +203,6 @@ void CoverageData::ReInit() { uptr npcs = size / sizeof(uptr); Enable(); if (size) Extend(npcs); - if (coverage_enabled) CovUpdateMapping(coverage_dir); } else { Enable(); } @@ -598,11 +590,6 @@ void ReInitializeCoverage(bool enabled, const char *dir) { coverage_data.ReInit(); } -void CoverageUpdateMapping() { - if (coverage_enabled) - CovUpdateMapping(coverage_dir); -} - } // namespace __sanitizer extern "C" { diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc deleted file mode 100644 index 3477b065b..000000000 --- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc +++ /dev/null @@ -1,122 +0,0 @@ -//===-- sanitizer_coverage_mapping.cc -------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Mmap-based implementation of sanitizer coverage. -// -// This is part of the implementation of code coverage that does not require -// __sanitizer_cov_dump() call. Data is stored in 2 files per process. -// -// $pid.sancov.map describes process memory layout in the following text-based -// format: -// // 1 line, 32 or 64 -// // repeated -// ... -// Mapping lines are NOT sorted. This file is updated every time memory layout -// is changed (i.e. in dlopen() and dlclose() interceptors). -// -// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not -// sorted. This file is extended by 64Kb at a time and mapped into memory. It -// contains one or more 0 words at the end, up to the next 64Kb aligned offset. -// -// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack -// $pid.sancov.raw. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_libc.h" -#include "sanitizer_procmaps.h" - -namespace __sanitizer { - -static const uptr kMaxTextSize = 64 * 1024; - -struct CachedMapping { - public: - bool NeedsUpdate(uptr pc) { - int new_pid = internal_getpid(); - if (last_pid == new_pid && pc && pc >= last_range_start && - pc < last_range_end) - return false; - last_pid = new_pid; - return true; - } - - void SetModuleRange(uptr start, uptr end) { - last_range_start = start; - last_range_end = end; - } - - private: - uptr last_range_start, last_range_end; - int last_pid; -}; - -static CachedMapping cached_mapping; -static StaticSpinMutex mapping_mu; - -void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) { - if (!common_flags()->coverage_direct) return; - - SpinMutexLock l(&mapping_mu); - - if (!cached_mapping.NeedsUpdate(caller_pc)) - return; - - InternalScopedString text(kMaxTextSize); - - { - text.append("%d\n", sizeof(uptr) * 8); - ListOfModules modules; - modules.init(); - for (const LoadedModule &module : modules) { - const char *module_name = StripModuleName(module.full_name()); - uptr base = module.base_address(); - for (const auto &range : module.ranges()) { - if (range.executable) { - uptr start = range.beg; - uptr end = range.end; - text.append("%zx %zx %zx %s\n", start, end, base, module_name); - if (caller_pc && caller_pc >= start && caller_pc < end) - cached_mapping.SetModuleRange(start, end); - } - } - } - } - - error_t err; - InternalScopedString tmp_path(64 + internal_strlen(coverage_dir)); - uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(), - "%s/%zd.sancov.map.tmp", coverage_dir, - internal_getpid()); - CHECK_LE(res, tmp_path.size()); - fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err); - if (map_fd == kInvalidFd) { - Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(), - err); - Die(); - } - - if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) { - Printf("sancov.map write failed: %d\n", err); - Die(); - } - CloseFile(map_fd); - - InternalScopedString path(64 + internal_strlen(coverage_dir)); - res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map", - coverage_dir, internal_getpid()); - CHECK_LE(res, path.size()); - if (!RenameFile(tmp_path.data(), path.data(), &err)) { - Printf("sancov.map rename failed: %d\n", err); - Die(); - } -} - -} // namespace __sanitizer -- cgit v1.2.1 From c760b288470e6d7bf6308dc23aa884e47befadb5 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 2 Jun 2017 00:52:35 +0000 Subject: [sanitizer-coverage] nuke more stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304504 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 2 - lib/asan/asan_activation.cc | 3 - lib/asan/asan_interceptors.cc | 2 - lib/sanitizer_common/CMakeLists.txt | 1 - lib/sanitizer_common/sanitizer_common.h | 5 - lib/sanitizer_common/sanitizer_coverage_libcdep.cc | 610 --------------------- .../sanitizer_coverage_libcdep_new.cc | 25 + lib/sanitizer_common/sanitizer_posix_libcdep.cc | 1 - lib/sanitizer_common/sanitizer_win.cc | 3 - 9 files changed, 25 insertions(+), 627 deletions(-) delete mode 100644 lib/sanitizer_common/sanitizer_coverage_libcdep.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index c4f999081..637379d47 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -19,8 +19,6 @@ extern "C" { #endif - // Initialize coverage. - void __sanitizer_cov_init(); // Record and dump coverage info. void __sanitizer_cov_dump(); diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc index 7e4e604dc..66eba9ce2 100644 --- a/lib/asan/asan_activation.cc +++ b/lib/asan/asan_activation.cc @@ -106,7 +106,6 @@ void AsanDeactivate() { // Deactivate the runtime. SetCanPoisonMemory(false); SetMallocContextSize(1); - ReInitializeCoverage(false, nullptr); AllocatorOptions disabled = asan_deactivated_flags.allocator_options; disabled.quarantine_size_mb = 0; @@ -130,8 +129,6 @@ void AsanActivate() { SetCanPoisonMemory(asan_deactivated_flags.poison_heap); SetMallocContextSize(asan_deactivated_flags.malloc_context_size); - ReInitializeCoverage(asan_deactivated_flags.coverage, - asan_deactivated_flags.coverage_dir); ReInitializeAllocator(asan_deactivated_flags.allocator_options); asan_is_deactivated = false; diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 25974535b..4682fba33 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -722,9 +722,7 @@ static void AfterFork() { INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); BeforeFork(); - if (common_flags()->coverage) CovBeforeFork(); int pid = REAL(fork)(); - if (common_flags()->coverage) CovAfterFork(pid); AfterFork(); return pid; } diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 7255a5727..bf8459ef5 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -54,7 +54,6 @@ set(SANITIZER_NOLIBC_SOURCES set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc sancov_flags.cc - sanitizer_coverage_libcdep.cc sanitizer_coverage_libcdep_new.cc sanitizer_coverage_win_sections.cc sanitizer_linux_libcdep.cc diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 57d87a2ef..79ee6873b 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -317,14 +317,9 @@ bool AddressSpaceIsUnlimited(); void SetAddressSpaceUnlimited(); void AdjustStackSize(void *attr); void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); -void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); -void CovBeforeFork(); -void CovAfterFork(int child_pid); - void InitializeCoverage(bool enabled, const char *coverage_dir); -void ReInitializeCoverage(bool enabled, const char *coverage_dir); void InitTlsSize(); uptr GetTlsSize(); diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc deleted file mode 100644 index b819e5837..000000000 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ /dev/null @@ -1,610 +0,0 @@ -//===-- sanitizer_coverage.cc ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Sanitizer Coverage. -// This file implements run-time support for a poor man's coverage tool. -// -// Compiler instrumentation: -// For every interesting basic block the compiler injects the following code: -// if (Guard < 0) { -// __sanitizer_cov(&Guard); -// } -// At the module start up time __sanitizer_cov_module_init sets the guards -// to consecutive negative numbers (-1, -2, -3, ...). -// It's fine to call __sanitizer_cov more than once for a given block. -// -// Run-time: -// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC). -// and atomically set Guard to -Guard. -// - __sanitizer_cov_dump: dump the coverage data to disk. -// For every module of the current process that has coverage data -// this will create a file module_name.PID.sancov. -// -// The file format is simple: the first 8 bytes is the magic, -// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the -// magic defines the size of the following offsets. -// The rest of the data is the offsets in the module. -// -// Eventually, this coverage implementation should be obsoleted by a more -// powerful general purpose Clang/LLVM coverage instrumentation. -// Consider this implementation as prototype. -// -// FIXME: support (or at least test with) dlclose. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" -#include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" -#include "sanitizer_flags.h" - -using namespace __sanitizer; - -static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL; -static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL; -static const uptr kNumWordsForMagic = SANITIZER_WORDSIZE == 64 ? 1 : 2; -static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32; - -static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. - -static atomic_uintptr_t coverage_counter; - -// pc_array is the array containing the covered PCs. -// To make the pc_array thread- and async-signal-safe it has to be large enough. -// 128M counters "ought to be enough for anybody" (4M on 32-bit). - -static bool cov_sandboxed = false; -static fd_t cov_fd = kInvalidFd; -static unsigned int cov_max_block_size = 0; -static bool coverage_enabled = false; -static const char *coverage_dir; - -namespace __sanitizer { - -class CoverageData { - public: - void Init(); - void Enable(); - void Disable(); - void ReInit(); - void BeforeFork(); - void AfterFork(int child_pid); - void Extend(uptr npcs); - void Add(uptr pc, u32 *guard); - void DumpOffsets(); - void DumpAll(); - - void InitializeGuardArray(s32 *guards); - void InitializeGuards(s32 *guards, uptr n, const char *module_name, - uptr caller_pc); - void ReinitializeGuards(); - - uptr *data(); - uptr size() const; - - private: - struct NamedPcRange { - const char *copied_module_name; - uptr beg, end; // elements [beg,end) in pc_array. - }; - - void DirectOpen(); - void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end); - void GetRangeOffsets(const NamedPcRange& r, Symbolizer* s, - InternalMmapVector* offsets) const; - - // Maximal size pc array may ever grow. - // We MmapNoReserve this space to ensure that the array is contiguous. - static const uptr kPcArrayMaxSize = - FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27); - // The amount file mapping for the pc array is grown by. - static const uptr kPcArrayMmapSize = 64 * 1024; - - // pc_array is allocated with MmapNoReserveOrDie and so it uses only as - // much RAM as it really needs. - uptr *pc_array; - // Index of the first available pc_array slot. - atomic_uintptr_t pc_array_index; - // Array size. - atomic_uintptr_t pc_array_size; - // Current file mapped size of the pc array. - uptr pc_array_mapped_size; - // Descriptor of the file mapped pc array. - fd_t pc_fd; - - // Vector of coverage guard arrays, protected by mu. - InternalMmapVectorNoCtor guard_array_vec; - - // Vector of module and compilation unit pc ranges. - InternalMmapVectorNoCtor comp_unit_name_vec; - InternalMmapVectorNoCtor module_name_vec; - - StaticSpinMutex mu; -}; - -static CoverageData coverage_data; - -void CoverageData::DirectOpen() { - InternalScopedString path(kMaxPathLength); - internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", - coverage_dir, internal_getpid()); - pc_fd = OpenFile(path.data(), RdWr); - if (pc_fd == kInvalidFd) { - Report("Coverage: failed to open %s for reading/writing\n", path.data()); - Die(); - } - - pc_array_mapped_size = 0; -} - -void CoverageData::Init() { - pc_fd = kInvalidFd; -} - -void CoverageData::Enable() { - if (pc_array) - return; - pc_array = reinterpret_cast( - MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); - atomic_store(&pc_array_index, 0, memory_order_relaxed); - if (common_flags()->coverage_direct) { - Report("coverage_direct=1 is deprecated, don't use it.\n"); - Die(); - atomic_store(&pc_array_size, 0, memory_order_relaxed); - } else { - atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); - } -} - -void CoverageData::InitializeGuardArray(s32 *guards) { - Enable(); // Make sure coverage is enabled at this point. - s32 n = guards[0]; - for (s32 j = 1; j <= n; j++) { - uptr idx = atomic_load_relaxed(&pc_array_index); - atomic_store_relaxed(&pc_array_index, idx + 1); - guards[j] = -static_cast(idx + 1); - } -} - -void CoverageData::Disable() { - if (pc_array) { - UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize); - pc_array = nullptr; - } - if (pc_fd != kInvalidFd) { - CloseFile(pc_fd); - pc_fd = kInvalidFd; - } -} - -void CoverageData::ReinitializeGuards() { - // Assuming single thread. - atomic_store(&pc_array_index, 0, memory_order_relaxed); - for (uptr i = 0; i < guard_array_vec.size(); i++) - InitializeGuardArray(guard_array_vec[i]); -} - -void CoverageData::ReInit() { - Disable(); - if (coverage_enabled) { - if (common_flags()->coverage_direct) { - // In memory-mapped mode we must extend the new file to the known array - // size. - uptr size = atomic_load(&pc_array_size, memory_order_relaxed); - uptr npcs = size / sizeof(uptr); - Enable(); - if (size) Extend(npcs); - } else { - Enable(); - } - } - // Re-initialize the guards. - // We are single-threaded now, no need to grab any lock. - CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0); - ReinitializeGuards(); -} - -void CoverageData::BeforeFork() { - mu.Lock(); -} - -void CoverageData::AfterFork(int child_pid) { - // We are single-threaded so it's OK to release the lock early. - mu.Unlock(); - if (child_pid == 0) ReInit(); -} - -// Extend coverage PC array to fit additional npcs elements. -void CoverageData::Extend(uptr npcs) { - if (!common_flags()->coverage_direct) return; - SpinMutexLock l(&mu); - - uptr size = atomic_load(&pc_array_size, memory_order_relaxed); - size += npcs * sizeof(uptr); - - if (coverage_enabled && size > pc_array_mapped_size) { - if (pc_fd == kInvalidFd) DirectOpen(); - CHECK_NE(pc_fd, kInvalidFd); - - uptr new_mapped_size = pc_array_mapped_size; - while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize; - CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize); - - // Extend the file and map the new space at the end of pc_array. - uptr res = internal_ftruncate(pc_fd, new_mapped_size); - int err; - if (internal_iserror(res, &err)) { - Printf("failed to extend raw coverage file: %d\n", err); - Die(); - } - - uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size; - void *p = MapWritableFileToMemory((void *)next_map_base, - new_mapped_size - pc_array_mapped_size, - pc_fd, pc_array_mapped_size); - CHECK_EQ((uptr)p, next_map_base); - pc_array_mapped_size = new_mapped_size; - } - - atomic_store(&pc_array_size, size, memory_order_release); -} - -void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg, - uptr range_end) { - auto sym = Symbolizer::GetOrInit(); - if (!sym) - return; - const char *module_name = sym->GetModuleNameForPc(caller_pc); - if (!module_name) return; - if (module_name_vec.empty() || - module_name_vec.back().copied_module_name != module_name) - module_name_vec.push_back({module_name, range_beg, range_end}); - else - module_name_vec.back().end = range_end; -} - -void CoverageData::InitializeGuards(s32 *guards, uptr n, - const char *comp_unit_name, - uptr caller_pc) { - // The array 'guards' has n+1 elements, we use the element zero - // to store 'n'. - CHECK_LT(n, 1 << 30); - guards[0] = static_cast(n); - InitializeGuardArray(guards); - SpinMutexLock l(&mu); - uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed); - uptr range_beg = range_end - n; - comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end}); - guard_array_vec.push_back(guards); - UpdateModuleNameVec(caller_pc, range_beg, range_end); -} - -static const uptr kBundleCounterBits = 16; - -// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64 -// we insert the global counter into the first 16 bits of the PC. -uptr BundlePcAndCounter(uptr pc, uptr counter) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return pc; - static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1; - if (counter > kMaxCounter) - counter = kMaxCounter; - CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits)); - return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits)); -} - -uptr UnbundlePc(uptr bundle) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return bundle; - return (bundle << kBundleCounterBits) >> kBundleCounterBits; -} - -uptr UnbundleCounter(uptr bundle) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return 0; - return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits); -} - -// If guard is negative, atomically set it to -guard and store the PC in -// pc_array. -void CoverageData::Add(uptr pc, u32 *guard) { - atomic_uint32_t *atomic_guard = reinterpret_cast(guard); - s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed); - if (guard_value >= 0) return; - - atomic_store(atomic_guard, -guard_value, memory_order_relaxed); - if (!pc_array) return; - - uptr idx = -guard_value - 1; - if (idx >= atomic_load(&pc_array_index, memory_order_acquire)) - return; // May happen after fork when pc_array_index becomes 0. - CHECK_LT(idx, atomic_load(&pc_array_size, memory_order_acquire)); - uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); - pc_array[idx] = BundlePcAndCounter(pc, counter); -} - -uptr *CoverageData::data() { - return pc_array; -} - -uptr CoverageData::size() const { - return atomic_load(&pc_array_index, memory_order_relaxed); -} - -// Block layout for packed file format: header, followed by module name (no -// trailing zero), followed by data blob. -struct CovHeader { - int pid; - unsigned int module_name_length; - unsigned int data_length; -}; - -static void CovWritePacked(int pid, const char *module, const void *blob, - unsigned int blob_size) { - if (cov_fd == kInvalidFd) return; - unsigned module_name_length = internal_strlen(module); - CovHeader header = {pid, module_name_length, blob_size}; - - if (cov_max_block_size == 0) { - // Writing to a file. Just go ahead. - WriteToFile(cov_fd, &header, sizeof(header)); - WriteToFile(cov_fd, module, module_name_length); - WriteToFile(cov_fd, blob, blob_size); - } else { - // Writing to a socket. We want to split the data into appropriately sized - // blocks. - InternalScopedBuffer block(cov_max_block_size); - CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data()); - uptr header_size_with_module = sizeof(header) + module_name_length; - CHECK_LT(header_size_with_module, cov_max_block_size); - unsigned int max_payload_size = - cov_max_block_size - header_size_with_module; - char *block_pos = block.data(); - internal_memcpy(block_pos, &header, sizeof(header)); - block_pos += sizeof(header); - internal_memcpy(block_pos, module, module_name_length); - block_pos += module_name_length; - char *block_data_begin = block_pos; - const char *blob_pos = (const char *)blob; - while (blob_size > 0) { - unsigned int payload_size = Min(blob_size, max_payload_size); - blob_size -= payload_size; - internal_memcpy(block_data_begin, blob_pos, payload_size); - blob_pos += payload_size; - ((CovHeader *)block.data())->data_length = payload_size; - WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size); - } - } -} - -// If packed = false: .. (name = module name). -// If packed = true and name == 0: ... -// If packed = true and name != 0: .. (name is -// user-supplied). -static fd_t CovOpenFile(InternalScopedString *path, bool packed, - const char *name, const char *extension = "sancov") { - path->clear(); - if (!packed) { - CHECK(name); - path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), - extension); - } else { - if (!name) - path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), - extension); - else - path->append("%s/%s.%s.packed", coverage_dir, name, extension); - } - error_t err; - fd_t fd = OpenFile(path->data(), WrOnly, &err); - if (fd == kInvalidFd) - Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", - path->data(), err); - return fd; -} - -void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym, - InternalMmapVector* offsets) const { - offsets->clear(); - for (uptr i = 0; i < kNumWordsForMagic; i++) - offsets->push_back(0); - CHECK(r.copied_module_name); - CHECK_LE(r.beg, r.end); - CHECK_LE(r.end, size()); - for (uptr i = r.beg; i < r.end; i++) { - uptr pc = UnbundlePc(pc_array[i]); - uptr counter = UnbundleCounter(pc_array[i]); - if (!pc) continue; // Not visited. - uptr offset = 0; - sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset); - offsets->push_back(BundlePcAndCounter(offset, counter)); - } - - CHECK_GE(offsets->size(), kNumWordsForMagic); - SortArray(offsets->data(), offsets->size()); - for (uptr i = 0; i < offsets->size(); i++) - (*offsets)[i] = UnbundlePc((*offsets)[i]); -} - -static void GenerateHtmlReport(const InternalMmapVector &cov_files) { - if (!common_flags()->html_cov_report) { - return; - } - char *sancov_path = FindPathToBinary(common_flags()->sancov_path); - if (sancov_path == nullptr) { - return; - } - - InternalMmapVector sancov_argv(cov_files.size() * 2 + 3); - sancov_argv.push_back(sancov_path); - sancov_argv.push_back(internal_strdup("-html-report")); - auto argv_deleter = at_scope_exit([&] { - for (uptr i = 0; i < sancov_argv.size(); ++i) { - InternalFree(sancov_argv[i]); - } - }); - - for (const auto &cov_file : cov_files) { - sancov_argv.push_back(internal_strdup(cov_file)); - } - - { - ListOfModules modules; - modules.init(); - for (const LoadedModule &module : modules) { - sancov_argv.push_back(internal_strdup(module.full_name())); - } - } - - InternalScopedString report_path(kMaxPathLength); - fd_t report_fd = - CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html"); - int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(), - kInvalidFd /* stdin */, report_fd /* std_out */); - if (pid > 0) { - int result = WaitForProcess(pid); - if (result == 0) - Printf("coverage report generated to %s\n", report_path.data()); - } -} - -void CoverageData::DumpOffsets() { - auto sym = Symbolizer::GetOrInit(); - if (!common_flags()->coverage_pcs) return; - Printf("**\n***\n***\n"); - Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n"); - Printf("**WARNING: and will be removed in future versions\n"); - Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n"); - Printf("**\n***\n***\n"); - - CHECK_NE(sym, nullptr); - InternalMmapVector offsets(0); - InternalScopedString path(kMaxPathLength); - - InternalMmapVector cov_files(module_name_vec.size()); - auto cov_files_deleter = at_scope_exit([&] { - for (uptr i = 0; i < cov_files.size(); ++i) { - InternalFree(cov_files[i]); - } - }); - - for (uptr m = 0; m < module_name_vec.size(); m++) { - auto r = module_name_vec[m]; - GetRangeOffsets(r, sym, &offsets); - - uptr num_offsets = offsets.size() - kNumWordsForMagic; - u64 *magic_p = reinterpret_cast(offsets.data()); - CHECK_EQ(*magic_p, 0ULL); - // FIXME: we may want to write 32-bit offsets even in 64-mode - // if all the offsets are small enough. - *magic_p = kMagic; - - const char *module_name = StripModuleName(r.copied_module_name); - if (cov_sandboxed) { - if (cov_fd != kInvalidFd) { - CovWritePacked(internal_getpid(), module_name, offsets.data(), - offsets.size() * sizeof(offsets[0])); - VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets); - } - } else { - // One file per module per process. - fd_t fd = CovOpenFile(&path, false /* packed */, module_name); - if (fd == kInvalidFd) continue; - WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0])); - CloseFile(fd); - cov_files.push_back(internal_strdup(path.data())); - VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets); - } - } - if (cov_fd != kInvalidFd) - CloseFile(cov_fd); - - GenerateHtmlReport(cov_files); -} - -void CoverageData::DumpAll() { - if (!coverage_enabled || common_flags()->coverage_direct) return; - if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) - return; - DumpOffsets(); -} - -void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - if (!args) return; - if (!coverage_enabled) return; - cov_sandboxed = args->coverage_sandboxed; - if (!cov_sandboxed) return; - cov_max_block_size = args->coverage_max_block_size; - if (args->coverage_fd >= 0) { - cov_fd = (fd_t)args->coverage_fd; - } else { - InternalScopedString path(kMaxPathLength); - // Pre-open the file now. The sandbox won't allow us to do it later. - cov_fd = CovOpenFile(&path, true /* packed */, nullptr); - } -} - -fd_t MaybeOpenCovFile(const char *name) { - CHECK(name); - if (!coverage_enabled) return kInvalidFd; - InternalScopedString path(kMaxPathLength); - return CovOpenFile(&path, true /* packed */, name); -} - -void CovBeforeFork() { - coverage_data.BeforeFork(); -} - -void CovAfterFork(int child_pid) { - coverage_data.AfterFork(child_pid); -} - -static void MaybeDumpCoverage() { - if (common_flags()->coverage) - __sanitizer_cov_dump(); -} - -void InitializeCoverage(bool enabled, const char *dir) { - if (coverage_enabled) - return; // May happen if two sanitizer enable coverage in the same process. - coverage_enabled = enabled; - coverage_dir = dir; - coverage_data.Init(); - if (enabled) coverage_data.Enable(); - if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump); - AddDieCallback(MaybeDumpCoverage); -} - -void ReInitializeCoverage(bool enabled, const char *dir) { - coverage_enabled = enabled; - coverage_dir = dir; - coverage_data.ReInit(); -} - -} // namespace __sanitizer - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { - __sanitizer_dump_trace_pc_guard_coverage(); -} -// Default empty implementations (weak). Users should redefine them. -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index a98dde76e..24433356c 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -146,6 +146,17 @@ static TracePcGuardController pc_guard_controller; } // namespace } // namespace __sancov +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + static bool coverage_enabled = false; + if (coverage_enabled) + return; // May happen if two sanitizer enable coverage in the same process. + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); +} +} // namespace __sanitizer + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT const uptr* pcs, uptr len) { @@ -166,4 +177,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { __sancov::pc_guard_controller.Dump(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 791ff4481..5b1d53698 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -264,7 +264,6 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // Same for /proc/self/exe in the symbolizer. #if !SANITIZER_GO Symbolizer::GetOrInit()->PrepareForSandboxing(); - CovPrepareForSandboxing(args); #endif } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index c912e8fa2..afc3bb0ac 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -400,9 +400,6 @@ void ReExec() { } void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { -#if !SANITIZER_GO - CovPrepareForSandboxing(args); -#endif } bool StackSizeIsUnlimited() { -- cgit v1.2.1 From 66ccf00796296ff1e791e4f385ae487202617b65 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 2 Jun 2017 01:17:04 +0000 Subject: [sanitizer-coverage] nuke more stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304508 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flags.inc | 10 -- lib/sanitizer_common/tests/sanitizer_flags_test.cc | 6 +- test/asan/TestCases/Android/coverage-android.cc | 147 --------------------- 3 files changed, 3 insertions(+), 160 deletions(-) delete mode 100644 test/asan/TestCases/Android/coverage-android.cc diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index f87d8b643..8c486b5b1 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -138,16 +138,6 @@ COMMON_FLAG( bool, coverage, false, "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time).") -COMMON_FLAG(bool, coverage_pcs, true, - "If set (and if 'coverage' is set too), the coverage information " - "will be dumped as a set of PC offsets for every module.") -COMMON_FLAG(bool, coverage_order_pcs, false, - "If true, the PCs will be dumped in the order they've" - " appeared during the execution.") -COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, - "If set, coverage information will be dumped directly to a memory " - "mapped file. This way data is not lost even if the process is " - "suddenly killed.") COMMON_FLAG(const char *, coverage_dir, ".", "Target directory for coverage dumps. Defaults to the current " "directory.") diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc index 0af84a20b..f3fe139e6 100644 --- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -167,13 +167,13 @@ TEST(SanitizerCommon, CommonFlags) { cf.symbolize = false; cf.coverage = true; - cf.coverage_direct = true; + cf.heap_profile = true; cf.log_path = "path/one"; - parser.ParseString("symbolize=1:coverage_direct=false log_path='path/two'"); + parser.ParseString("symbolize=1:heap_profile=false log_path='path/two'"); EXPECT_TRUE(cf.symbolize); EXPECT_TRUE(cf.coverage); - EXPECT_FALSE(cf.coverage_direct); + EXPECT_FALSE(cf.heap_profile); EXPECT_STREQ("path/two", cf.log_path); } diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc deleted file mode 100644 index cf4f33ebd..000000000 --- a/test/asan/TestCases/Android/coverage-android.cc +++ /dev/null @@ -1,147 +0,0 @@ -// Test for direct coverage writing with dlopen. - -// Test normal exit, coverage level 1. -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s - - -// Test sudden death, coverage level 1. -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s - - -// Test normal exit, coverage level 2. -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s - - -// Test sudden death, coverage level 2. -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s - - -// Test normal exit, coverage level 3. -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s - - -// Test sudden death, coverage level 3. -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s - -// PC counts in CHECK lines are platform dependent and match arm32 at the moment. -// sancov tool does not support Android well enough to match function names -// REQUIRES: arm - -#include -#include -#include -#include -#include -#include - -#ifdef SHARED -extern "C" { -void bar() { - printf("bar\n"); -#ifdef KILL - kill(getpid(), SIGKILL); -#endif -} -} -#else - -volatile int sink; - -int main(int argc, char **argv) { - fprintf(stderr, "PID: %d\n", getpid()); - void *handle1 = - dlopen(SO_DIR "/libcoverage_android_test_1.so", RTLD_LAZY); - assert(handle1); - - if (argc == 0) - sink = 0; - - void (*bar1)() = (void (*)())dlsym(handle1, "bar"); - assert(bar1); - bar1(); - - return 0; -} -#endif - -// CHECK1: 2 PCs total -// CHECK2: 4 PCs total -// CHECK3: 5 PCs total -- cgit v1.2.1 From 8c2855d2320ab8a951a09e50195bd94ba19fcfe5 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 2 Jun 2017 21:32:04 +0000 Subject: [asan] fix one more case where stack-use-after-return is not async-signal-safe (during thread startup). beef-up the test to give it a chance to catch regressions. Also relax the lint to make C++11 more usable. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304598 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_thread.cc | 12 +++++++---- lib/sanitizer_common/scripts/check_lint.sh | 2 +- test/asan/TestCases/Linux/uar_signals.cc | 33 ++++++++++++++++++------------ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index f41ee2df2..714496d5c 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -166,16 +166,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, } inline AsanThread::StackBounds AsanThread::GetStackBounds() const { - if (!atomic_load(&stack_switching_, memory_order_acquire)) - return StackBounds{stack_bottom_, stack_top_}; // NOLINT + if (!atomic_load(&stack_switching_, memory_order_acquire)) { + // Make sure the stack bounds are fully initialized. + if (stack_bottom_ >= stack_top_) return {0, 0}; + return {stack_bottom_, stack_top_}; + } char local; const uptr cur_stack = (uptr)&local; // Note: need to check next stack first, because FinishSwitchFiber // may be in process of overwriting stack_top_/bottom_. But in such case // we are already on the next stack. if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) - return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT - return StackBounds{stack_bottom_, stack_top_}; // NOLINT + return {next_stack_bottom_, next_stack_top_}; + return {stack_bottom_, stack_top_}; } uptr AsanThread::stack_top() { @@ -197,6 +200,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. return nullptr; + CHECK_LE(stack_size, 0x10000000); uptr old_val = 0; // fake_stack_ has 3 states: // 0 -- not initialized diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh index 9108a81e2..82e4bc84d 100755 --- a/lib/sanitizer_common/scripts/check_lint.sh +++ b/lib/sanitizer_common/scripts/check_lint.sh @@ -18,7 +18,7 @@ fi # Filters # TODO: remove some of these filters COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\ --build/namespaces +-build/namespaces,-readability/braces ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length diff --git a/test/asan/TestCases/Linux/uar_signals.cc b/test/asan/TestCases/Linux/uar_signals.cc index f42c3f666..f96a2fecb 100644 --- a/test/asan/TestCases/Linux/uar_signals.cc +++ b/test/asan/TestCases/Linux/uar_signals.cc @@ -1,12 +1,13 @@ // This test checks that the implementation of use-after-return // is async-signal-safe. -// RUN: %clangxx_asan -O1 %s -o %t -pthread && %run %t +// RUN: %clangxx_asan -std=c++11 -O1 %s -o %t -pthread && %run %t // REQUIRES: stable-runtime #include #include #include #include #include +#include int *g; int n_signals; @@ -17,7 +18,6 @@ void SignalHandler(int, siginfo_t*, void*) { int local; g = &local; n_signals++; - // printf("s: %p\n", &local); } static void EnableSigprof(Sigaction SignalHandler) { @@ -49,22 +49,29 @@ void RecursiveFunction(int depth) { RecursiveFunction(depth - 1); } -void *Thread(void *) { - RecursiveFunction(18); +void *FastThread(void *) { + RecursiveFunction(1); + return NULL; +} + +void *SlowThread(void *) { + RecursiveFunction(1); return NULL; } int main(int argc, char **argv) { EnableSigprof(SignalHandler); - for (int i = 0; i < 4; i++) { - fprintf(stderr, "."); - const int kNumThread = sizeof(void*) == 8 ? 16 : 8; - pthread_t t[kNumThread]; - for (int i = 0; i < kNumThread; i++) - pthread_create(&t[i], 0, Thread, 0); - for (int i = 0; i < kNumThread; i++) - pthread_join(t[i], 0); + for (auto Thread : {&FastThread, &SlowThread}) { + for (int i = 0; i < 1000; i++) { + fprintf(stderr, "."); + const int kNumThread = sizeof(void*) == 8 ? 32 : 8; + pthread_t t[kNumThread]; + for (int i = 0; i < kNumThread; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThread; i++) + pthread_join(t[i], 0); + } + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); } -- cgit v1.2.1 From b88c71e5c6f79459386e2a3e569f970b17a600ac Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 3 Jun 2017 01:36:53 +0000 Subject: [sanitizer-coverage] test for -fsanitize-coverage=inline-8bit-counters git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304632 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_coverage_inline8bit_counter.cc | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc new file mode 100644 index 000000000..b7246ebf2 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -0,0 +1,23 @@ +// Tests -fsanitize-coverage=inline-8bit-counters +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin +// +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 + +#include +#include + +const char *first_counter; + +extern "C" +void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { + printf("INIT: %p %p\n", start, end); + assert(end - start > 1); + first_counter = start; +} + +int main() { + assert(first_counter); + assert(*first_counter == 1); +} -- cgit v1.2.1 From e82d511eb9a1834d8f108101e7f9cd2955dfdaf9 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Sat, 3 Jun 2017 01:43:44 +0000 Subject: [LSan] Detect dynamic loader by its base address. Summary: Whenever possible (Linux + glibc 2.16+), detect dynamic loader module by its base address, not by the module name matching. The current name matching approach fails on some configurations. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D33859 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304633 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 3 +++ lib/lsan/lsan_common_linux.cc | 23 +++++++++++++++++------ lib/sanitizer_common/sanitizer_linux.cc | 10 ---------- lib/sanitizer_common/sanitizer_platform.h | 9 +++++++++ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a5ffc6835..d4f670681 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -408,6 +408,9 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { // On Linux, handles dynamically allocated TLS blocks by treating all chunks // allocated from ld-linux.so as reachable. +// On Linux, treats all chunks allocated from ld-linux.so as reachable, which +// covers dynamically allocated TLS blocks, internal dynamic loader's loaded +// modules accounting etc. // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. // They are allocated with a __libc_memalign() call in allocate_and_init() // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index c903be42d..2e4095b49 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -23,6 +23,10 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#if SANITIZER_USE_GETAUXVAL +#include +#endif // SANITIZER_USE_GETAUXVAL + namespace __lsan { static const char kLinkerName[] = "ld"; @@ -30,8 +34,12 @@ static const char kLinkerName[] = "ld"; static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; -static bool IsLinker(const char* full_name) { - return LibraryNameIs(full_name, kLinkerName); +static bool IsLinker(const LoadedModule& module) { +#if SANITIZER_USE_GETAUXVAL + return module.base_address() == getauxval(AT_BASE); +#else + return LibraryNameIs(module.full_name(), kLinkerName); +#endif // SANITIZER_USE_GETAUXVAL } __attribute__((tls_model("initial-exec"))) @@ -49,22 +57,25 @@ void InitializePlatformSpecificModules() { ListOfModules modules; modules.init(); for (LoadedModule &module : modules) { - if (!IsLinker(module.full_name())) continue; + if (!IsLinker(module)) + continue; if (linker == nullptr) { linker = reinterpret_cast(linker_placeholder); *linker = module; module = LoadedModule(); } else { VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " - "TLS will not be handled correctly.\n", kLinkerName); + "TLS and other allocations originating from linker might be " + "falsely reported as leaks.\n", kLinkerName); linker->clear(); linker = nullptr; return; } } if (linker == nullptr) { - VReport(1, "LeakSanitizer: Dynamic linker not found. " - "TLS will not be handled correctly.\n"); + VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " + "allocations originating from linker might be falsely reported " + "as leaks.\n"); } } diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 3bda35655..b8aee8022 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -77,16 +77,6 @@ extern char **environ; // provided by crt1 #include #endif -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif - #if SANITIZER_USE_GETAUXVAL #include #endif diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 49732aa32..8fa3f7ab6 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -269,5 +269,14 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif #endif // SANITIZER_PLATFORM_H -- cgit v1.2.1 From 677ecacd29d67d6e7b2ac7d6f27af4188d02dc17 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 3 Jun 2017 11:11:36 +0000 Subject: Adjust sanitizers for FreeBSD 64-bit inode update Summary: Very recently, FreeBSD 12 has been updated to use 64-bit inode numbers: . This entails many user-visible changes, but for the sanitizers the modifications are limited in scope: * The `stat` and `lstat` syscalls were removed, and should be replaced with calls to `fstatat`. * The `getdents` syscall was removed, and should be replaced with calls to `getdirentries`. * The layout of `struct dirent` was changed to accomodate 64-bit inode numbers, and a new `d_off` field was added. * The system header now contains a macro `__INO64` to determine whether the system uses 64-bit inode numbers. I tested these changes on both FreeBSD 12.0-CURRENT (after r318959, which adds the `__INO64` macro), and FreeBSD 11.0-STABLE (which still uses 32-bit inode numbers). Reviewers: emaste, kcc, vitalybuka, kubamracek Reviewed By: vitalybuka Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33600 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304658 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 12 +++++++----- lib/sanitizer_common/sanitizer_platform_limits_posix.h | 8 ++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index b8aee8022..7bc7682dd 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -62,8 +62,6 @@ #if SANITIZER_FREEBSD #include #include -#include -#include #include extern "C" { // must be included after and on @@ -227,7 +225,8 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { uptr internal_stat(const char *path, void *buf) { #if SANITIZER_FREEBSD - return internal_syscall(SYSCALL(stat), path, buf); + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, + (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); @@ -251,7 +250,8 @@ uptr internal_stat(const char *path, void *buf) { uptr internal_lstat(const char *path, void *buf) { #if SANITIZER_FREEBSD - return internal_syscall(SYSCALL(lstat), path, buf); + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, + (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); @@ -594,7 +594,9 @@ uptr internal_getppid() { } uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); #else return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index c6f6a2115..24ffcd7d9 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -23,6 +23,9 @@ // incorporates the map structure. # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544))) +// Get sys/_types.h, because that tells us whether 64-bit inodes are +// used in struct dirent below. +#include #else # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) #endif // !SANITIZER_FREEBSD @@ -485,7 +488,12 @@ namespace __sanitizer { }; #elif SANITIZER_FREEBSD struct __sanitizer_dirent { +#if defined(__INO64) + unsigned long long d_fileno; + unsigned long long d_off; +#else unsigned int d_fileno; +#endif unsigned short d_reclen; // more fields that we don't care about }; -- cgit v1.2.1 From b32da432b3fcfea05728ec42d254f3e5ca109579 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sun, 4 Jun 2017 01:56:44 +0000 Subject: Mark sancov test as unsupported on Darwin This test has been failing on all Darwin bots since it was introduced: http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/32111 fatal error: error in backend: Global variable '__sancov_gen_' has an invalid section specifier '__DATA,__sancov_counters': mach-o section specifier requires a section whose length is between 1 and 16 characters. Target: x86_64-apple-darwin15.6.0 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304673 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc index b7246ebf2..0da81fc38 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -1,7 +1,7 @@ // Tests -fsanitize-coverage=inline-8bit-counters // // REQUIRES: has_sancovcc,stable-runtime -// UNSUPPORTED: i386-darwin +// UNSUPPORTED: i386-darwin, x86_64-darwin // // RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 -- cgit v1.2.1 From a3054203772cb561ce8023508c9005d74b1afe0d Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sun, 4 Jun 2017 02:18:45 +0000 Subject: Mark the atos-symbolizer test as unsupported on i386-darwin atos is apparently not able to resolve symbol addresses properly on i386-darwin reliably any more. This is causing bot flakiness: http://lab.llvm.org:8080/green/job/clang-stage1-cmake-RA-expensive/6841 There have not been any SDK changes on the bot as of late. /Users/buildslave/jenkins/sharedspace/clang-stage1-cmake-RA_workspace/llvm/projects/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer.cc:20:12: error: expected string not found in input // CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-4]] ^ :35:27: note: scanning from here #0 0x112f56 in wrap_free (/Users/buildslave/jenkins/sharedspace/clang-stage1-cmake-RA_workspace/clang-build/lib/clang/5.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:i386+0x56f56) ^ :35:27: note: with expression "@LINE-4" equal to "16" #0 0x112f56 in wrap_free (/Users/buildslave/jenkins/sharedspace/clang-stage1-cmake-RA_workspace/clang-build/lib/clang/5.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:i386+0x56f56) ^ :36:168: note: possible intended match here #1 0xb6f20 in main (/Users/buildslave/jenkins/sharedspace/clang-stage1-cmake-RA_workspace/clang-build/tools/clang/runtime/compiler-rt-bins/test/asan/I386DarwinConfig/TestCases/Darwin/Output/atos-symbolizer.cc.tmp:i386+0x1f20) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304674 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/atos-symbolizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Darwin/atos-symbolizer.cc b/test/asan/TestCases/Darwin/atos-symbolizer.cc index 7b091c4d6..e7d7e7a17 100644 --- a/test/asan/TestCases/Darwin/atos-symbolizer.cc +++ b/test/asan/TestCases/Darwin/atos-symbolizer.cc @@ -4,7 +4,7 @@ // RUN: %env_asan_opts=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) not %run %t 2>&1 | FileCheck %s // Path returned by `which atos` is invalid on iOS. -// UNSUPPORTED: ios +// UNSUPPORTED: ios, i386-darwin #include #include -- cgit v1.2.1 From 9c790e8abc177dee14e192c982c911f37b9653e7 Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Mon, 5 Jun 2017 07:36:02 +0000 Subject: Revert "[sanitizer-coverage] test for -fsanitize-coverage=inline-8bit-counters" Revert "Mark sancov test as unsupported on Darwin" Revert "[LSan] Detect dynamic loader by its base address." This reverts commit r304633. This reverts commit r304673. This reverts commit r304632. Those commit have broken LOTS of ARM/AArch64 bots for two days. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304699 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 3 --- lib/lsan/lsan_common_linux.cc | 23 ++++++---------------- lib/sanitizer_common/sanitizer_linux.cc | 10 ++++++++++ lib/sanitizer_common/sanitizer_platform.h | 9 --------- .../sanitizer_coverage_inline8bit_counter.cc | 23 ---------------------- 5 files changed, 16 insertions(+), 52 deletions(-) delete mode 100644 test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index d4f670681..a5ffc6835 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -408,9 +408,6 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { // On Linux, handles dynamically allocated TLS blocks by treating all chunks // allocated from ld-linux.so as reachable. -// On Linux, treats all chunks allocated from ld-linux.so as reachable, which -// covers dynamically allocated TLS blocks, internal dynamic loader's loaded -// modules accounting etc. // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. // They are allocated with a __libc_memalign() call in allocate_and_init() // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 2e4095b49..c903be42d 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -23,10 +23,6 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#if SANITIZER_USE_GETAUXVAL -#include -#endif // SANITIZER_USE_GETAUXVAL - namespace __lsan { static const char kLinkerName[] = "ld"; @@ -34,12 +30,8 @@ static const char kLinkerName[] = "ld"; static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; -static bool IsLinker(const LoadedModule& module) { -#if SANITIZER_USE_GETAUXVAL - return module.base_address() == getauxval(AT_BASE); -#else - return LibraryNameIs(module.full_name(), kLinkerName); -#endif // SANITIZER_USE_GETAUXVAL +static bool IsLinker(const char* full_name) { + return LibraryNameIs(full_name, kLinkerName); } __attribute__((tls_model("initial-exec"))) @@ -57,25 +49,22 @@ void InitializePlatformSpecificModules() { ListOfModules modules; modules.init(); for (LoadedModule &module : modules) { - if (!IsLinker(module)) - continue; + if (!IsLinker(module.full_name())) continue; if (linker == nullptr) { linker = reinterpret_cast(linker_placeholder); *linker = module; module = LoadedModule(); } else { VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " - "TLS and other allocations originating from linker might be " - "falsely reported as leaks.\n", kLinkerName); + "TLS will not be handled correctly.\n", kLinkerName); linker->clear(); linker = nullptr; return; } } if (linker == nullptr) { - VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " - "allocations originating from linker might be falsely reported " - "as leaks.\n"); + VReport(1, "LeakSanitizer: Dynamic linker not found. " + "TLS will not be handled correctly.\n"); } } diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 7bc7682dd..cec2f264c 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -75,6 +75,16 @@ extern char **environ; // provided by crt1 #include #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif + #if SANITIZER_USE_GETAUXVAL #include #endif diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 8fa3f7ab6..49732aa32 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -269,14 +269,5 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif #endif // SANITIZER_PLATFORM_H diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc deleted file mode 100644 index 0da81fc38..000000000 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Tests -fsanitize-coverage=inline-8bit-counters -// -// REQUIRES: has_sancovcc,stable-runtime -// UNSUPPORTED: i386-darwin, x86_64-darwin -// -// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 - -#include -#include - -const char *first_counter; - -extern "C" -void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { - printf("INIT: %p %p\n", start, end); - assert(end - start > 1); - first_counter = start; -} - -int main() { - assert(first_counter); - assert(*first_counter == 1); -} -- cgit v1.2.1 From b058fd625f568029ac4b2585fe2e507b6a77b653 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 5 Jun 2017 15:10:04 +0000 Subject: CMake: don't try to use lld if we're not building it. Monorepo version! git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304716 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b522c340d..51769088a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,7 +255,7 @@ if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) set(COMPILER_RT_HAS_LLD TRUE) else() set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld) - if(EXISTS ${COMPILER_RT_LLD_PATH}/) + if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) set(COMPILER_RT_HAS_LLD TRUE) else() set(COMPILER_RT_HAS_LLD FALSE) -- cgit v1.2.1 From 9b257cb6116f10e5aa0711fd8cb58730725b74fc Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 5 Jun 2017 20:36:57 +0000 Subject: [asan] Use asan exitcode=0 option to always succeed a test run. Summary: halt_on_error-torture.cc intermittently fails on ppc64be, let's try to collect more info on failures. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D33912 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304731 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 1b26173d7..ec66e0289 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -10,12 +10,12 @@ // // Collisions are unlikely but still possible so we need the ||. // RUN: rm -f 10.txt -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 10 20 >>10.txt 2>&1 || true +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >>10.txt 2>&1 // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt // // Collisions are unlikely but still possible so we need the ||. // RUN: rm -f 20.txt -// RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >>20.txt 2>&1 || true +// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >>20.txt 2>&1 // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt #include -- cgit v1.2.1 From d20e4ba84ed63067ae0989b7c2e9fbfd8e3974b8 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 5 Jun 2017 21:20:55 +0000 Subject: Revert r304285, r304297. r304285 - [sanitizer] Avoid possible deadlock in child process after fork r304297 - [sanitizer] Trying to fix MAC buildbots after r304285 These changes create deadlock when Tcl calls pthread_create from a pthread_atfork child handler. More info in the original review at https://reviews.llvm.org/D33325 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304735 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 4 +- lib/asan/asan_allocator.h | 2 - lib/asan/asan_interceptors.cc | 17 --- lib/lsan/lsan_interceptors.cc | 24 ----- lib/msan/msan_allocator.cc | 96 ++++++++++++++++- lib/msan/msan_allocator.h | 97 ----------------- lib/msan/msan_interceptors.cc | 2 - .../TestCases/Linux/allocator_fork_no_hang.cc | 118 --------------------- 8 files changed, 97 insertions(+), 263 deletions(-) delete mode 100644 test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index db5a683e2..7010b6023 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -47,6 +47,8 @@ static u32 RZSize2Log(u32 rz_size) { return res; } +static AsanAllocator &get_allocator(); + // The memory chunk allocated from the underlying allocator looks like this: // L L L L L L H H U U U U U U R R // L -- left redzone words (0 or more bytes) @@ -717,7 +719,7 @@ struct Allocator { static Allocator instance(LINKER_INITIALIZED); -AsanAllocator &get_allocator() { +static AsanAllocator &get_allocator() { return instance.allocator; } diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index ce3e25dc5..ad1aeb58a 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -213,7 +213,5 @@ void asan_mz_force_unlock(); void PrintInternalAllocatorStats(); void AsanSoftRssLimitExceededCallback(bool exceeded); -AsanAllocator &get_allocator(); - } // namespace __asan #endif // ASAN_ALLOCATOR_H diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 4682fba33..264d5aee8 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -22,7 +22,6 @@ #include "asan_stats.h" #include "asan_suppressions.h" #include "lsan/lsan_common.h" -#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX @@ -705,25 +704,9 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #endif // ASAN_INTERCEPT___CXA_ATEXIT #if ASAN_INTERCEPT_FORK -static void BeforeFork() { - if (SANITIZER_LINUX) { - get_allocator().ForceLock(); - StackDepotLockAll(); - } -} - -static void AfterFork() { - if (SANITIZER_LINUX) { - StackDepotUnlockAll(); - get_allocator().ForceUnlock(); - } -} - INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); - BeforeFork(); int pid = REAL(fork)(); - AfterFork(); return pid; } #endif // ASAN_INTERCEPT_FORK diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index a0a59daa0..9e39a7d19 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -22,7 +22,6 @@ #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_posix.h" -#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" @@ -98,28 +97,6 @@ INTERCEPTOR(void*, valloc, uptr size) { } #endif -static void BeforeFork() { - if (SANITIZER_LINUX) { - LockAllocator(); - StackDepotLockAll(); - } -} - -static void AfterFork() { - if (SANITIZER_LINUX) { - StackDepotUnlockAll(); - UnlockAllocator(); - } -} - -INTERCEPTOR(int, fork, void) { - ENSURE_LSAN_INITED; - BeforeFork(); - int pid = REAL(fork)(); - AfterFork(); - return pid; -} - #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; @@ -359,7 +336,6 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_MALLOPT; INTERCEPT_FUNCTION(pthread_create); INTERCEPT_FUNCTION(pthread_join); - INTERCEPT_FUNCTION(fork); if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index f76b01de0..1be573faa 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -12,6 +12,8 @@ // MemorySanitizer allocator. //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" #include "msan.h" #include "msan_allocator.h" #include "msan_origin.h" @@ -20,12 +22,102 @@ namespace __msan { +struct Metadata { + uptr requested_size; +}; + +struct MsanMapUnmapCallback { + void OnMap(uptr p, uptr size) const {} + void OnUnmap(uptr p, uptr size) const { + __msan_unpoison((void *)p, size); + + // We are about to unmap a chunk of user memory. + // Mark the corresponding shadow memory as not needed. + uptr shadow_p = MEM_TO_SHADOW(p); + ReleaseMemoryPagesToOS(shadow_p, shadow_p + size); + if (__msan_get_track_origins()) { + uptr origin_p = MEM_TO_ORIGIN(p); + ReleaseMemoryPagesToOS(origin_p, origin_p + size); + } + } +}; + +#if defined(__mips64) + static const uptr kMaxAllowedMallocSize = 2UL << 30; + static const uptr kRegionSizeLog = 20; + static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; + typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; + + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; +#elif defined(__x86_64__) +#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) + static const uptr kAllocatorSpace = 0x700000000000ULL; +#else + static const uptr kAllocatorSpace = 0x600000000000ULL; +#endif + static const uptr kMaxAllowedMallocSize = 8UL << 30; + + struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = 0x40000000000; // 4T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + + typedef SizeClassAllocator64 PrimaryAllocator; + +#elif defined(__powerpc64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + + struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x300000000000; + static const uptr kSpaceSize = 0x020000000000; // 2T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + + typedef SizeClassAllocator64 PrimaryAllocator; +#elif defined(__aarch64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + static const uptr kRegionSizeLog = 20; + static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; + typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; + + struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = __msan::kRegionSizeLog; + typedef __msan::ByteMap ByteMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + }; + typedef SizeClassAllocator32 PrimaryAllocator; +#endif +typedef SizeClassAllocatorLocalCache AllocatorCache; +typedef LargeMmapAllocator SecondaryAllocator; +typedef CombinedAllocator Allocator; + static Allocator allocator; static AllocatorCache fallback_allocator_cache; static SpinMutex fallback_mutex; -Allocator &get_allocator() { return allocator; } - void MsanAllocatorInit() { allocator.Init( common_flags()->allocator_may_return_null, diff --git a/lib/msan/msan_allocator.h b/lib/msan/msan_allocator.h index abd4ea678..407942e54 100644 --- a/lib/msan/msan_allocator.h +++ b/lib/msan/msan_allocator.h @@ -15,106 +15,9 @@ #define MSAN_ALLOCATOR_H #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_allocator.h" -#include "sanitizer_common/sanitizer_allocator_interface.h" namespace __msan { -struct Metadata { - uptr requested_size; -}; - -struct MsanMapUnmapCallback { - void OnMap(uptr p, uptr size) const {} - void OnUnmap(uptr p, uptr size) const { - __msan_unpoison((void *)p, size); - - // We are about to unmap a chunk of user memory. - // Mark the corresponding shadow memory as not needed. - uptr shadow_p = MEM_TO_SHADOW(p); - ReleaseMemoryPagesToOS(shadow_p, shadow_p + size); - if (__msan_get_track_origins()) { - uptr origin_p = MEM_TO_ORIGIN(p); - ReleaseMemoryPagesToOS(origin_p, origin_p + size); - } - } -}; - -#if defined(__mips64) - static const uptr kMaxAllowedMallocSize = 2UL << 30; - static const uptr kRegionSizeLog = 20; - static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; - typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - - struct AP32 { - static const uptr kSpaceBeg = 0; - static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; - static const uptr kMetadataSize = sizeof(Metadata); - typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = __msan::kRegionSizeLog; - typedef __msan::ByteMap ByteMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - typedef SizeClassAllocator32 PrimaryAllocator; -#elif defined(__x86_64__) -#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) - static const uptr kAllocatorSpace = 0x700000000000ULL; -#else - static const uptr kAllocatorSpace = 0x600000000000ULL; -#endif - static const uptr kMaxAllowedMallocSize = 8UL << 30; - - struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = kAllocatorSpace; - static const uptr kSpaceSize = 0x40000000000; // 4T. - static const uptr kMetadataSize = sizeof(Metadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - - typedef SizeClassAllocator64 PrimaryAllocator; - -#elif defined(__powerpc64__) - static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G - - struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x300000000000; - static const uptr kSpaceSize = 0x020000000000; // 2T. - static const uptr kMetadataSize = sizeof(Metadata); - typedef DefaultSizeClassMap SizeClassMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - - typedef SizeClassAllocator64 PrimaryAllocator; -#elif defined(__aarch64__) - static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G - static const uptr kRegionSizeLog = 20; - static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; - typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; - - struct AP32 { - static const uptr kSpaceBeg = 0; - static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; - static const uptr kMetadataSize = sizeof(Metadata); - typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = __msan::kRegionSizeLog; - typedef __msan::ByteMap ByteMap; - typedef MsanMapUnmapCallback MapUnmapCallback; - static const uptr kFlags = 0; - }; - typedef SizeClassAllocator32 PrimaryAllocator; -#endif -typedef SizeClassAllocatorLocalCache AllocatorCache; -typedef LargeMmapAllocator SecondaryAllocator; -typedef CombinedAllocator Allocator; - - -Allocator &get_allocator(); - struct MsanThreadLocalMallocStorage { uptr quarantine_cache[16]; // Allocator cache contains atomic_uint64_t which must be 8-byte aligned. diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index fbc2ea4fe..0f5069344 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -1201,7 +1201,6 @@ INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) { } static void BeforeFork() { - get_allocator().ForceLock(); StackDepotLockAll(); ChainedOriginDepotLockAll(); } @@ -1209,7 +1208,6 @@ static void BeforeFork() { static void AfterFork() { ChainedOriginDepotUnlockAll(); StackDepotUnlockAll(); - get_allocator().ForceUnlock(); } INTERCEPTOR(int, fork, void) { diff --git a/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc b/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc deleted file mode 100644 index d159d85ee..000000000 --- a/test/sanitizer_common/TestCases/Linux/allocator_fork_no_hang.cc +++ /dev/null @@ -1,118 +0,0 @@ -// https://github.com/google/sanitizers/issues/774 -// Test that sanitizer allocator is fork-safe. -// Run a number of threads that perform memory allocation/deallocation, then fork -// and verify that malloc/free do not deadlock in the child process. - -// RUN: %clangxx -std=c++11 -O0 %s -o %t -// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t 2>&1 | FileCheck %s - -// Fun fact: if test output is redirected to a file (as opposed to -// being piped directly to FileCheck), we may lose some "done"s due to -// a kernel bug: -// https://lkml.org/lkml/2014/2/17/324 - -// UNSUPPORTED: tsan - -// Flaky on PPC64. -// UNSUPPORTED: powerpc64-target-arch -// UNSUPPORTED: powerpc64le-target-arch - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int done; - -void *worker(void *arg) { - while (true) { - void *p = malloc(4); - if (__atomic_load_n(&done, __ATOMIC_RELAXED)) - return 0; - } - return 0; -} - -// Run through malloc/free in the child process. -// This can deadlock on allocator cache refilling. -void child() { - for (int i = 0; i < 10000; ++i) { - void *p = malloc(4); - } - write(2, "done\n", 5); -} - -void test() { - const int kThreads = 10; - pthread_t t[kThreads]; - for (int i = 0; i < kThreads; ++i) - pthread_create(&t[i], NULL, worker, (void*)(long)i); - usleep(100000); - pid_t pid = fork(); - if (pid) { - // parent - __atomic_store_n(&done, 1, __ATOMIC_RELAXED); - pid_t p; - while ((p = wait(NULL)) == -1) { } - } else { - // child - child(); - } -} - -int main() { - const int kChildren = 30; - for (int i = 0; i < kChildren; ++i) { - pid_t pid = fork(); - if (pid) { - // parent - } else { - test(); - exit(0); - } - } - - for (int i = 0; i < kChildren; ++i) { - pid_t p; - while ((p = wait(NULL)) == -1) { } - } - - return 0; -} - -// Expect 30 (== kChildren) "done" messages. -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -// CHECK: done -- cgit v1.2.1 From b36ffc36dc75bbb701525be82ebe47e8879d1d45 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 5 Jun 2017 22:23:15 +0000 Subject: [ASan] A speculative attempt to fix a flaky test on ppc64be. Summary: As mentioned in test/msan/fork.cc, if test output is redirected to a file (as opposed to being piped directly to FileCheck), we may lose some "done"s due to a kernel bug: https://lkml.org/lkml/2014/2/17/324, so let's pipe the output of the test. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D33915 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304744 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index ec66e0289..829568e26 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -10,12 +10,12 @@ // // Collisions are unlikely but still possible so we need the ||. // RUN: rm -f 10.txt -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >>10.txt 2>&1 +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 2>&1 | cat > 10.txt // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt // // Collisions are unlikely but still possible so we need the ||. // RUN: rm -f 20.txt -// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >>20.txt 2>&1 +// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 2>&1 | cat > 20.txt // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt #include @@ -38,7 +38,7 @@ void *run(void *arg) { unsigned seed = (unsigned)(size_t)arg; volatile char tmp[2]; - __asan_poison_memory_region(&tmp, sizeof(tmp)); + __asan_poison_memory_region(&tmp, sizeof(tmp)); for (size_t i = 0; i < niter; ++i) { random_delay(&seed); -- cgit v1.2.1 From 35f212efc287a7b582afcb41d86bdff7a29e7367 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 7 Jun 2017 01:53:38 +0000 Subject: [tsan]: Fix GNU version of strerror_r interceptor GNU version of strerror_r returns a result pointer that doesn't match the input buffer. The result pointer is in fact a pointer to some internal storage. TSAN was recording a write to this location, which was incorrect. Fixed https://github.com/google/sanitizers/issues/696 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304858 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 5 +++- lib/tsan/rtl/tsan_rtl_thread.cc | 1 + test/msan/Linux/strerror_r.cc | 18 ++++++++++++++ test/tsan/strerror_r.cc | 28 ++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/msan/Linux/strerror_r.cc create mode 100644 test/tsan/strerror_r.cc diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index c0c08a031..6ca431d8a 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3395,7 +3395,10 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { // its metadata. See // https://github.com/google/sanitizers/issues/321. char *res = REAL(strerror_r)(errnum, buf, buflen); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + if (res == buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); + else + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); return res; } #endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE || diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index edb60980c..67eebf5d0 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -345,6 +345,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, StatInc(thr, StatMopRange); if (*shadow_mem == kShadowRodata) { + DCHECK(!is_write); // Access to .rodata section, no races here. // Measurements show that it can be 10-20% of all memory accesses. StatInc(thr, StatMopRangeRodata); diff --git a/test/msan/Linux/strerror_r.cc b/test/msan/Linux/strerror_r.cc new file mode 100644 index 000000000..aec653f9c --- /dev/null +++ b/test/msan/Linux/strerror_r.cc @@ -0,0 +1,18 @@ +// RUN: %clang_msan -O0 -g %s -o %t && %run %t + +#include +#include +#include + +int main() { + char buf[1000]; + char *res = strerror_r(EINVAL, buf, sizeof(buf)); + assert(res); + volatile int z = strlen(res); + + res = strerror_r(-1, buf, sizeof(buf)); + assert(res); + z = strlen(res); + + return 0; +} diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc new file mode 100644 index 000000000..f8570b67f --- /dev/null +++ b/test/tsan/strerror_r.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_tsan -O1 -DTEST_ERROR=ERANGE %s -o %t && %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-SYS %s +// RUN: %clangxx_tsan -O1 -DTEST_ERROR=-1 %s -o %t && not %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-USER %s + +#include +#include +#include +#include +#include + +char buffer[1000]; + +void *Thread(void *p) { + return strerror_r(TEST_ERROR, buffer, sizeof(buffer)); +} + +int main() { + pthread_t th[2]; + pthread_create(&th[0], 0, Thread, 0); + pthread_create(&th[1], 0, Thread, 0); + pthread_join(th[0], 0); + pthread_join(th[1], 0); + fprintf(stderr, "DONE\n"); +} + +// CHECK-USER: WARNING: ThreadSanitizer: data race +// CHECK-SYS-NOT: WARNING: ThreadSanitizer: data race + +// CHECK: DONE -- cgit v1.2.1 From 439e42a0184069cdbc31d106052e3f6ce01cd8e0 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 7 Jun 2017 17:24:58 +0000 Subject: [sanitizer] Fix symbolizer build after r304864. r304864 moved code into a new BinaryFormat library. Update the symbolizer build script. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304930 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh index 4a0fb03c4..c5865ecfe 100755 --- a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +++ b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh @@ -129,7 +129,7 @@ if [[ ! -d ${LLVM_BUILD} ]]; then $LLVM_SRC fi cd ${LLVM_BUILD} -ninja LLVMSymbolize LLVMObject LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC +ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC cd ${BUILD_DIR} rm -rf ${SYMBOLIZER_BUILD} @@ -148,6 +148,7 @@ $SCRIPT_DIR/ar_to_bc.sh $LIBCXX_BUILD/lib/libc++.a \ $LIBCXX_BUILD/lib/libc++abi.a \ $LLVM_BUILD/lib/libLLVMSymbolize.a \ $LLVM_BUILD/lib/libLLVMObject.a \ + $LLVM_BUILD/lib/libLLVMBinaryFormat.a \ $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \ $LLVM_BUILD/lib/libLLVMSupport.a \ $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ -- cgit v1.2.1 From 63ddb4b32b74ade76730b721ea8553baf39211c5 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 7 Jun 2017 20:43:15 +0000 Subject: Fix tsan test for Darwin. NFCI. On Darwin, strerror_r returns an int, not a char*. I don't think this test really depends on what strerror_r returns, so I've used something else in place of the result of the call to strerror_r. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304941 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/strerror_r.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc index f8570b67f..972d5f4a7 100644 --- a/test/tsan/strerror_r.cc +++ b/test/tsan/strerror_r.cc @@ -10,7 +10,8 @@ char buffer[1000]; void *Thread(void *p) { - return strerror_r(TEST_ERROR, buffer, sizeof(buffer)); + (void)strerror_r(TEST_ERROR, buffer, sizeof(buffer)); + return p; } int main() { -- cgit v1.2.1 From eb68deea368c273d6fb7a986ca717a260146c2a0 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 7 Jun 2017 21:10:33 +0000 Subject: Revert "Fix tsan test for Darwin. NFCI." This reverts commit r304941. Vitaly Buka writes: "Actually it depends on return value. Test is for char* version of function. It will probably fail for int version." git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304943 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/strerror_r.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc index 972d5f4a7..f8570b67f 100644 --- a/test/tsan/strerror_r.cc +++ b/test/tsan/strerror_r.cc @@ -10,8 +10,7 @@ char buffer[1000]; void *Thread(void *p) { - (void)strerror_r(TEST_ERROR, buffer, sizeof(buffer)); - return p; + return strerror_r(TEST_ERROR, buffer, sizeof(buffer)); } int main() { -- cgit v1.2.1 From 4906f471eeabb1ffd1edb2c6cef5b5a5d790ddd7 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 7 Jun 2017 21:10:35 +0000 Subject: Mark the tsan strerror_r test as unsupported on Darwin git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304944 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/strerror_r.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc index f8570b67f..06c92d3bb 100644 --- a/test/tsan/strerror_r.cc +++ b/test/tsan/strerror_r.cc @@ -1,5 +1,6 @@ // RUN: %clangxx_tsan -O1 -DTEST_ERROR=ERANGE %s -o %t && %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-SYS %s // RUN: %clangxx_tsan -O1 -DTEST_ERROR=-1 %s -o %t && not %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-USER %s +// UNSUPPORTED: darwin #include #include -- cgit v1.2.1 From f06499282eb358206ec5bc6e325d8ab5b4073cf0 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 8 Jun 2017 22:58:19 +0000 Subject: [sanitizer-coverage] one more flavor of coverage: -fsanitize-coverage=inline-8bit-counters. Experimental so far, not documenting yet. Reapplying revisions 304630, 304631, 304632, 304673, see PR33308 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305026 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_coverage_inline8bit_counter.cc | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc new file mode 100644 index 000000000..0da81fc38 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -0,0 +1,23 @@ +// Tests -fsanitize-coverage=inline-8bit-counters +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin, x86_64-darwin +// +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 + +#include +#include + +const char *first_counter; + +extern "C" +void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { + printf("INIT: %p %p\n", start, end); + assert(end - start > 1); + first_counter = start; +} + +int main() { + assert(first_counter); + assert(*first_counter == 1); +} -- cgit v1.2.1 From 5f551f74fb007090cc65a2392d38cc080a04abfe Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 9 Jun 2017 07:47:38 +0000 Subject: [asan] Fix ASan internal failure in AllocateFromLocalPool This patch addresses PR 33206. There might be a situation when dynamic ASan runtime initializes later than shared library which has malloc in static constructor (rtld doesn't provide an order of shared libs initialization). In this case ASan hasn't yet initialized interceptors, but already intercepts malloc. If malloc is too big to be handled by static local pool, ASan will die with error: Sanitizer CHECK failed: lib/asan/asan_malloc_linux.cc:40 ((allocated_for_dlsym)) < ((kDlsymAllocPoolSize)) (1036, 1024) Patch by Denis Khalikov. Differential Revision: https://reviews.llvm.org/D33784 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305058 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_linux.cc | 22 ++++++++++------ test/asan/TestCases/Linux/asan_preload_test-3.cc | 33 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 test/asan/TestCases/Linux/asan_preload_test-3.cc diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 8c99d3bc9..fd40f47db 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -60,36 +60,42 @@ INTERCEPTOR(void, cfree, void *ptr) { #endif // SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void*, malloc, uptr size) { - if (UNLIKELY(!asan_inited)) + if (UNLIKELY(asan_init_is_running)) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); + ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(!asan_inited)) + if (UNLIKELY(asan_init_is_running)) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); + ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { - GET_STACK_TRACE_MALLOC; if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); + const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); void *new_ptr; - if (UNLIKELY(!asan_inited)) { + if (UNLIKELY(asan_init_is_running)) { new_ptr = AllocateFromLocalPool(size); } else { - copy_size = size; - new_ptr = asan_malloc(copy_size, &stack); + ENSURE_ASAN_INITED(); + GET_STACK_TRACE_MALLOC; + new_ptr = asan_malloc(size, &stack); } internal_memcpy(new_ptr, ptr, copy_size); return new_ptr; } + if (UNLIKELY(asan_init_is_running)) + return AllocateFromLocalPool(size); + ENSURE_ASAN_INITED(); + GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } diff --git a/test/asan/TestCases/Linux/asan_preload_test-3.cc b/test/asan/TestCases/Linux/asan_preload_test-3.cc new file mode 100644 index 000000000..041669b56 --- /dev/null +++ b/test/asan/TestCases/Linux/asan_preload_test-3.cc @@ -0,0 +1,33 @@ +// Regression test for PR33206 +// +// RUN: %clang -DDYN=1 -DMALLOC=1 -fPIC -shared %s -o %t-dso1.so +// RUN: %clang -DDYN=1 -DMALLOC=1 -fPIC -shared %s -o %t-dso2.so %t-dso1.so +// RUN: %clang %s -o %t-1 %t-dso2.so +// RUN: env LD_PRELOAD=%shared_libasan %run %t-1 2>&1 | FileCheck %s +// RUN: %clang -DDYN=1 -DREALLOC=1 -fPIC -shared %s -o %t-dso3.so +// RUN: %clang -DDYN=1 -DREALLOC=1 -fPIC -shared %s -o %t-dso4.so %t-dso3.so +// RUN: %clang %s -o %t-2 %t-dso4.so +// RUN: env LD_PRELOAD=%shared_libasan %run %t-2 2>&1 | FileCheck %s +// REQUIRES: asan-dynamic-runtime + +#include +#include + +#ifdef DYN +__attribute__((constructor)) void foo() { + void *p; +#ifdef MALLOC + p = malloc(1 << 20); +#endif +#ifdef REALLOC + p = realloc (0, 1 << 20); +#endif + free(p); +} +#else +int main() { + // CHECK: Success + printf("Success\n"); + return 0; +} +#endif -- cgit v1.2.1 From 09cdb957f4edde9e5094f00ab8564a33143f1a13 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Fri, 9 Jun 2017 21:14:19 +0000 Subject: Minor clean up of profile rt tests git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305113 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Linux/instrprof-alloc.test | 4 ++-- test/profile/Linux/instrprof-value-prof-warn.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/profile/Linux/instrprof-alloc.test b/test/profile/Linux/instrprof-alloc.test index 752b10892..4db764704 100644 --- a/test/profile/Linux/instrprof-alloc.test +++ b/test/profile/Linux/instrprof-alloc.test @@ -1,6 +1,6 @@ -// RUN: %clang_profgen -Xclang -fprofile-instrument=llvm -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t -O3 %S/../Inputs/instrprof-alloc.c +// RUN: %clang_pgogen -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t -O3 %S/../Inputs/instrprof-alloc.c // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t -// RUN: %clang_profgen -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t.dyn -O3 %S/../Inputs/instrprof-alloc.c +// RUN: %clang_pgogen -mllvm -vp-static-alloc=false -fuse-ld=gold -Wl,-wrap,malloc -Wl,-wrap,calloc -o %t.dyn -O3 %S/../Inputs/instrprof-alloc.c // RUN: env LLVM_PROFILE_FILE=%t.profraw not %run %t.dyn diff --git a/test/profile/Linux/instrprof-value-prof-warn.test b/test/profile/Linux/instrprof-value-prof-warn.test index 26502cc90..6ca1603fb 100644 --- a/test/profile/Linux/instrprof-value-prof-warn.test +++ b/test/profile/Linux/instrprof-value-prof-warn.test @@ -1,4 +1,4 @@ -RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -DSTRESS=1 -o %t.ir.warn %S/../Inputs/instrprof-value-prof-real.c +RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -DSTRESS=1 -o %t.ir.warn %S/../Inputs/instrprof-value-prof-real.c RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir.warn 2>&1 |FileCheck --check-prefix=WARNING %s # Test that enough static counters have been allocated RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=150 %run %t.ir.warn 2>&1 |FileCheck --check-prefix=NOWARNING --allow-empty %s -- cgit v1.2.1 From a2b9a14ce8ed68ce8678fb20a25a140a011a9198 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 10 Jun 2017 00:12:11 +0000 Subject: Mark a sancov test as unsupported on x86_64h-darwin Failing bot: http://lab.llvm.org:8080/green/job/clang-stage1-cmake-RA-expensive/6891 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305133 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc index 0da81fc38..1a4ad1f06 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -1,7 +1,7 @@ // Tests -fsanitize-coverage=inline-8bit-counters // // REQUIRES: has_sancovcc,stable-runtime -// UNSUPPORTED: i386-darwin, x86_64-darwin +// UNSUPPORTED: i386-darwin, x86_64-darwin, x86_64h-darwin // // RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 -- cgit v1.2.1 From 079b7657767dcc0fb284225c277d2b9ce73e423b Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 12 Jun 2017 18:42:51 +0000 Subject: [ubsan] Detect invalid unsigned pointer index expression (compiler-rt) Compiler-rt part of: https://reviews.llvm.org/D33910 Differential Revision: https://reviews.llvm.org/D33911 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305217 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 10 ++++++++-- test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 80cc8ad25..5dabbd8e0 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -566,8 +566,14 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ScopedReport R(Opts, Loc, ET); - Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1") - << (void *)Base << (void*)Result; + if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) + Diag(Loc, DL_Error, "unsigned pointer index expression result is %0, " + "preceding its base %1") + << (void *)Result << (void *)Base; + else + Diag(Loc, DL_Error, + "pointer index expression with base %0 overflowed to %1") + << (void *)Base << (void *)Result; } void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, diff --git a/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp b/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp new file mode 100644 index 000000000..991374b5a --- /dev/null +++ b/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp @@ -0,0 +1,13 @@ +// RUN: %clangxx -fsanitize=pointer-overflow %s -o %t +// RUN: %t 2>&1 | FileCheck %s + +int main(int argc, char *argv[]) { + char c; + char *p = &c; + unsigned long long offset = -1; + + // CHECK: unsigned-index-expression.cpp:[[@LINE+1]]:15: runtime error: unsigned pointer index expression result is 0x{{.*}}, preceding its base 0x{{.*}} + char *q = p + offset; + + return 0; +} -- cgit v1.2.1 From 247f914543e89003c932df550a91de37ec19ca8a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 13 Jun 2017 07:09:56 +0000 Subject: tsan: fix pedantic warnings ISO C++ does not allow ?: with omitted middle operand git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305273 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_report.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 2de7ffc74..32cc3325f 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -92,7 +92,8 @@ static const char *ReportTypeString(ReportType typ, uptr tag) { if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free (virtual call vs free)"; if (typ == ReportTypeExternalRace) { - return GetReportHeaderFromTag(tag) ?: "race on external object"; + const char *str = GetReportHeaderFromTag(tag); + return str ? str : "race on external object"; } if (typ == ReportTypeThreadLeak) return "thread leak"; @@ -170,8 +171,9 @@ static void PrintMop(const ReportMop *mop, bool first) { MopDesc(first, mop->write, mop->atomic), mop->size, (void *)mop->addr, thread_name(thrbuf, mop->tid)); } else { - const char *object_type = - GetObjectTypeFromTag(mop->external_tag) ?: "external object"; + const char *object_type = GetObjectTypeFromTag(mop->external_tag); + if (object_type == nullptr) + object_type = "external object"; Printf(" %s access of %s at %p by %s", ExternalMopDesc(first, mop->write), object_type, (void *)mop->addr, thread_name(thrbuf, mop->tid)); -- cgit v1.2.1 From 81825ab6eab9b060f549a94c281c7cc3cc4f1b4f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 13 Jun 2017 09:37:51 +0000 Subject: tsan: fix reading of mutex flags SyncVar::IsFlagSet returns true if any flag is set. This is wrong. Check the actual requested flag. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305281 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_sync.h | 2 +- test/tsan/custom_mutex.h | 6 +++--- test/tsan/custom_mutex0.cc | 2 +- test/tsan/custom_mutex1.cc | 2 +- test/tsan/custom_mutex2.cc | 2 +- test/tsan/custom_mutex3.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 test/tsan/custom_mutex3.cc diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h index d24d69762..b83c09ff7 100644 --- a/lib/tsan/rtl/tsan_sync.h +++ b/lib/tsan/rtl/tsan_sync.h @@ -83,7 +83,7 @@ struct SyncVar { } bool IsFlagSet(u32 f) const { - return atomic_load_relaxed(&flags); + return atomic_load_relaxed(&flags) & f; } void SetFlags(u32 f) { diff --git a/test/tsan/custom_mutex.h b/test/tsan/custom_mutex.h index 675ad59b3..e3ac7a9a5 100644 --- a/test/tsan/custom_mutex.h +++ b/test/tsan/custom_mutex.h @@ -6,11 +6,11 @@ // A very primitive mutex annotated with tsan annotations. class Mutex { public: - Mutex(bool prof = true) + Mutex(bool prof, unsigned flags) : prof_(prof) , locked_(false) , seq_(0) { - __tsan_mutex_create(this, 0); + __tsan_mutex_create(this, flags); } ~Mutex() { @@ -87,5 +87,5 @@ class Mutex { } }; -Mutex Mutex::prof_mu_(false); +Mutex Mutex::prof_mu_(false, __tsan_mutex_linker_init); int Mutex::prof_data_; diff --git a/test/tsan/custom_mutex0.cc b/test/tsan/custom_mutex0.cc index 998385ca1..8302fd884 100644 --- a/test/tsan/custom_mutex0.cc +++ b/test/tsan/custom_mutex0.cc @@ -4,7 +4,7 @@ // Test that custom annoations provide normal mutex synchronization // (no race reports for properly protected critical sections). -Mutex mu; +Mutex mu(true, 0); long data; void *thr(void *arg) { diff --git a/test/tsan/custom_mutex1.cc b/test/tsan/custom_mutex1.cc index 06186515f..1c879f502 100644 --- a/test/tsan/custom_mutex1.cc +++ b/test/tsan/custom_mutex1.cc @@ -3,7 +3,7 @@ // Test that failed TryLock does not induce parasitic synchronization. -Mutex mu; +Mutex mu(true, 0); long data; void *thr(void *arg) { diff --git a/test/tsan/custom_mutex2.cc b/test/tsan/custom_mutex2.cc index 9329cbc3f..d4aca7e03 100644 --- a/test/tsan/custom_mutex2.cc +++ b/test/tsan/custom_mutex2.cc @@ -3,7 +3,7 @@ // Test that Broadcast does not induce parasitic synchronization. -Mutex mu; +Mutex mu(true, 0); long data; void *thr(void *arg) { diff --git a/test/tsan/custom_mutex3.cc b/test/tsan/custom_mutex3.cc new file mode 100644 index 000000000..6e99926ad --- /dev/null +++ b/test/tsan/custom_mutex3.cc @@ -0,0 +1,46 @@ +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t +// RUN: %env_tsan_opts=report_destroy_locked=0 %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +// Regression test for a bug. +// Thr1 destroys a locked mutex, previously such mutex was not removed from +// sync map and as the result subsequent uses of a mutex located at the same +// address caused false race reports. + +Mutex mu(false, __tsan_mutex_write_reentrant); +long data; + +void *thr1(void *arg) { + mu.Lock(); + mu.~Mutex(); + new(&mu) Mutex(true, __tsan_mutex_write_reentrant); + return 0; +} + +void *thr2(void *arg) { + barrier_wait(&barrier); + mu.Lock(); + data++; + mu.Unlock(); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t th; + pthread_create(&th, 0, thr1, 0); + pthread_join(th, 0); + + barrier_init(&barrier, 2); + pthread_create(&th, 0, thr2, 0); + mu.Lock(); + data++; + mu.Unlock(); + barrier_wait(&barrier); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE -- cgit v1.2.1 From 5cf6036d46c149520f75ca93289e967277baa930 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 13 Jun 2017 22:29:15 +0000 Subject: [sanitize] Remove stack size limits from secondary threads. If pthread_attr_getstack tell us the stack is 2G, why would we doubt that? Differential Revision: https://reviews.llvm.org/D34169 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305330 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index a15b5858a..894013ddd 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -113,7 +113,6 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_destroy(&attr); - CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check. *stack_top = (uptr)stackaddr + stacksize; *stack_bottom = (uptr)stackaddr; } -- cgit v1.2.1 From 2716b49e6801990c55b0dcbfcfbed120f6a364d8 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 13 Jun 2017 23:57:24 +0000 Subject: [ASan] Move rss_limit_is_exceeded_ flag to ASan. Summary: Move the OOM decision based on RSS limits out of generic allocator to ASan allocator, where it makes more sense at the moment. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34180 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305342 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 21 ++++++++++++++++----- lib/sanitizer_common/sanitizer_allocator_combined.h | 19 +++++-------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 7010b6023..1ded7794c 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -235,6 +235,8 @@ struct Allocator { AllocatorCache fallback_allocator_cache; QuarantineCache fallback_quarantine_cache; + atomic_uint8_t rss_limit_exceeded; + // ------------------- Options -------------------------- atomic_uint16_t min_redzone; atomic_uint16_t max_redzone; @@ -268,6 +270,14 @@ struct Allocator { SharedInitCode(options); } + bool RssLimitExceeded() { + return atomic_load(&rss_limit_exceeded, memory_order_relaxed); + } + + void SetRssLimitExceeded(bool limit_exceeded) { + atomic_store(&rss_limit_exceeded, limit_exceeded, memory_order_relaxed); + } + void RePoisonChunk(uptr chunk) { // This could be a user-facing chunk (with redzones), or some internal // housekeeping chunk, like TransferBatch. Start by assuming the former. @@ -363,6 +373,8 @@ struct Allocator { AllocType alloc_type, bool can_fill) { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); + if (RssLimitExceeded()) + return allocator.ReturnNullOrDieOnOOM(); Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; @@ -400,16 +412,15 @@ struct Allocator { AsanThread *t = GetCurrentThread(); void *allocated; - bool check_rss_limit = true; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); allocated = - allocator.Allocate(cache, needed_size, 8, false, check_rss_limit); + allocator.Allocate(cache, needed_size, 8, false); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; allocated = - allocator.Allocate(cache, needed_size, 8, false, check_rss_limit); + allocator.Allocate(cache, needed_size, 8, false); } if (!allocated) return allocator.ReturnNullOrDieOnOOM(); @@ -866,8 +877,8 @@ void asan_mz_force_unlock() { instance.ForceUnlock(); } -void AsanSoftRssLimitExceededCallback(bool exceeded) { - instance.allocator.SetRssLimitIsExceeded(exceeded); +void AsanSoftRssLimitExceededCallback(bool limit_exceeded) { + instance.SetRssLimitExceeded(limit_exceeded); } } // namespace __asan diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h index 19e1ae9b9..2c2390b3d 100644 --- a/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -43,12 +43,12 @@ class CombinedAllocator { } void *Allocate(AllocatorCache *cache, uptr size, uptr alignment, - bool cleared = false, bool check_rss_limit = false) { + bool cleared = false) { // Returning 0 on malloc(0) may break a lot of code. if (size == 0) size = 1; - if (size + alignment < size) return ReturnNullOrDieOnBadRequest(); - if (check_rss_limit && RssLimitIsExceeded()) return ReturnNullOrDieOnOOM(); + if (size + alignment < size) + return ReturnNullOrDieOnBadRequest(); uptr original_size = size; // If alignment requirements are to be fulfilled by the frontend allocator // rather than by the primary or secondary, passing an alignment lower than @@ -89,7 +89,8 @@ class CombinedAllocator { } void *ReturnNullOrDieOnOOM() { - if (MayReturnNull()) return nullptr; + if (MayReturnNull()) + return nullptr; ReportAllocatorCannotReturnNull(true); } @@ -106,15 +107,6 @@ class CombinedAllocator { primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms); } - bool RssLimitIsExceeded() { - return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire); - } - - void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) { - atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded, - memory_order_release); - } - void Deallocate(AllocatorCache *cache, void *p) { if (!p) return; if (primary_.PointerIsMine(p)) @@ -228,6 +220,5 @@ class CombinedAllocator { SecondaryAllocator secondary_; AllocatorGlobalStats stats_; atomic_uint8_t may_return_null_; - atomic_uint8_t rss_limit_is_exceeded_; }; -- cgit v1.2.1 From fccfd4523bbad39dfaf5e1a9dbf7491abbc80a22 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 14 Jun 2017 15:32:17 +0000 Subject: [sanitizer] MmapAlignedOrDie changes to reduce fragmentation Summary: The reasoning behind this change is explained in D33454, which unfortunately broke the Windows version (due to the platform not supporting partial unmapping of a memory region). This new approach changes `MmapAlignedOrDie` to allow for the specification of a `padding_chunk`. If non-null, and the initial allocation is aligned, this padding chunk will hold the address of the extra memory (of `alignment` bytes). This allows `AllocateRegion` to get 2 regions if the memory is aligned properly, and thus help reduce fragmentation (and saves on unmapping operations). As with the initial D33454, we use a stash in the 32-bit Primary to hold those extra regions and return them on the fast-path. The Windows version of `MmapAlignedOrDie` will always return a 0 `padding_chunk` if one was requested. Reviewers: alekseyshl, dvyukov, kcc Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34152 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305391 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary32.h | 58 +++++++++++++++++++--- lib/sanitizer_common/sanitizer_common.h | 10 +++- lib/sanitizer_common/sanitizer_posix.cc | 23 ++++++--- lib/sanitizer_common/sanitizer_win.cc | 6 ++- .../tests/sanitizer_common_test.cc | 35 ++++++++++++- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index e13510ba3..bfedbc0a7 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,7 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). +// a result of an allocation of kRegionSize bytes aligned on kRegionSize. // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -106,6 +106,7 @@ class SizeClassAllocator32 { void Init(s32 release_to_os_interval_ms) { possible_regions.TestOnlyInit(); internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); + num_stashed_regions = 0; } s32 ReleaseToOSIntervalMs() const { @@ -275,15 +276,49 @@ class SizeClassAllocator32 { return mem & ~(kRegionSize - 1); } + // Allocates a region of kRegionSize bytes, aligned on kRegionSize. If we get + // more than one region back (in the event the allocation is aligned on the + // first try), attempt to store the second region into a stash. If the stash + // is full, just unmap the superfluous memory. + uptr AllocateRegionSlow(AllocatorStats *stat) { + uptr map_size = kRegionSize; + uptr padding_chunk; + uptr region = reinterpret_cast( + MmapAlignedOrDie(kRegionSize, kRegionSize, "SizeClassAllocator32", + &padding_chunk)); + if (padding_chunk) { + // We have an extra region, attempt to stash it. + CHECK_EQ(padding_chunk, region + kRegionSize); + bool trim_extra = true; + { + SpinMutexLock l(®ions_stash_mutex); + if (num_stashed_regions < kMaxStashedRegions) { + regions_stash[num_stashed_regions++] = padding_chunk; + map_size = 2 * kRegionSize; + trim_extra = false; + } + } + if (trim_extra) + UnmapOrDie((void*)padding_chunk, kRegionSize); + } + MapUnmapCallback().OnMap(region, map_size); + stat->Add(AllocatorStatMapped, map_size); + return region; + } + uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, - "SizeClassAllocator32")); - MapUnmapCallback().OnMap(res, kRegionSize); - stat->Add(AllocatorStatMapped, kRegionSize); - CHECK_EQ(0U, (res & (kRegionSize - 1))); - possible_regions.set(ComputeRegionId(res), static_cast(class_id)); - return res; + uptr region = 0; + { + SpinMutexLock l(®ions_stash_mutex); + if (num_stashed_regions > 0) + region = regions_stash[--num_stashed_regions]; + } + if (!region) + region = AllocateRegionSlow(stat); + CHECK(IsAligned(region, kRegionSize)); + possible_regions.set(ComputeRegionId(region), static_cast(class_id)); + return region; } SizeClassInfo *GetSizeClassInfo(uptr class_id) { @@ -316,6 +351,13 @@ class SizeClassAllocator32 { } } + // Unless several threads request regions simultaneously from different size + // classes, the stash rarely contains more than 1 entry. + static const uptr kMaxStashedRegions = 8; + SpinMutex regions_stash_mutex; + uptr num_stashed_regions; + uptr regions_stash[kMaxStashedRegions]; + ByteMap possible_regions; SizeClassInfo size_class_info_array[kNumClasses]; }; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 79ee6873b..ea9a7d342 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -92,7 +92,15 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); +// Since the predominant use case of this function is "size == alignment" and +// the nature of the way the alignment requirement is satisfied (by allocating +// size+alignment bytes of memory), there's a potential of address space +// fragmentation. The padding_chunk parameter provides the opportunity to +// return the contiguous padding of "size" bytes of the allocated chunk if the +// initial allocation happened to be perfectly aligned and the platform supports +// partial unmapping of the mapped region. +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, + uptr *padding_chunk); // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an // unaccessible memory. bool MprotectNoAccess(uptr addr, uptr size); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 9916f4d38..3a6b711db 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -146,22 +146,29 @@ void UnmapOrDie(void *addr, uptr size) { } // We want to map a chunk of address space aligned to 'alignment'. -// We do it by maping a bit more and then unmaping redundant pieces. +// We do it by mapping a bit more and then unmapping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, + uptr* padding_chunk) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; uptr map_res = (uptr)MmapOrDie(map_size, mem_type); uptr map_end = map_res + map_size; + bool is_aligned = IsAligned(map_res, alignment); + if (is_aligned && padding_chunk && size == alignment) { + *padding_chunk = map_res + size; + return (void *)map_res; + } + if (padding_chunk) + *padding_chunk = 0; uptr res = map_res; - if (res & (alignment - 1)) // Not aligned. - res = (map_res + alignment) & ~(alignment - 1); - uptr end = res + size; - if (res != map_res) + if (!is_aligned) { + res = (map_res + alignment - 1) & ~(alignment - 1); UnmapOrDie((void*)map_res, res - map_res); - if (end != map_end) - UnmapOrDie((void*)end, map_end - end); + } + uptr end = res + size; + UnmapOrDie((void*)end, map_end - end); return (void*)res; } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index afc3bb0ac..493167a19 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -132,10 +132,14 @@ void UnmapOrDie(void *addr, uptr size) { } // We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, + uptr *padding_chunk) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); + if (padding_chunk) + *padding_chunk = 0; + // Windows will align our allocations to at least 64K. alignment = Max(alignment, GetMmapGranularity()); diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index ebc885db7..c1077e628 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -77,8 +77,8 @@ TEST(SanitizerCommon, MmapAlignedOrDie) { for (uptr size = 1; size <= 32; size *= 2) { for (uptr alignment = 1; alignment <= 32; alignment *= 2) { for (int iter = 0; iter < 100; iter++) { - uptr res = (uptr)MmapAlignedOrDie( - size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest"); + uptr res = (uptr)MmapAlignedOrDie(size * PageSize, alignment * PageSize, + "MmapAlignedOrDieTest", nullptr); EXPECT_EQ(0U, res % (alignment * PageSize)); internal_memset((void*)res, 1, size * PageSize); UnmapOrDie((void*)res, size * PageSize); @@ -87,6 +87,37 @@ TEST(SanitizerCommon, MmapAlignedOrDie) { } } +TEST(SanitizerCommon, MmapAlignedOrDiePaddingChunk) { + uptr PageSize = GetPageSizeCached(); + for (uptr size = 1; size <= 32; size *= 2) { + for (uptr alignment = 1; alignment <= 32; alignment *= 2) { + for (int iter = 0; iter < 100; iter++) { + uptr padding_chunk; + uptr res = (uptr)MmapAlignedOrDie(size * PageSize, alignment * PageSize, + "MmapAlignedOrDiePaddingChunkTest", &padding_chunk); + EXPECT_EQ(0U, res % (alignment * PageSize)); + internal_memset((void*)res, 1, size * PageSize); + UnmapOrDie((void*)res, size * PageSize); + if (SANITIZER_WINDOWS || (size != alignment)) { + // Not supported on Windows or for different size and alignment. + EXPECT_EQ(0U, padding_chunk); + continue; + } + if (size == 1 && alignment == 1) { + // mmap returns PageSize aligned chunks, so this is a specific case + // where we can check that padding_chunk will never be 0. + EXPECT_NE(0U, padding_chunk); + } + if (padding_chunk) { + EXPECT_EQ(res + size * PageSize, padding_chunk); + internal_memset((void*)padding_chunk, 1, alignment * PageSize); + UnmapOrDie((void*)padding_chunk, alignment * PageSize); + } + } + } + } +} + #if SANITIZER_LINUX TEST(SanitizerCommon, SanitizerSetThreadName) { const char *names[] = { -- cgit v1.2.1 From 6cd1865e1d8bc8fd1cb62fe4ef51c8c908385609 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 14 Jun 2017 17:32:26 +0000 Subject: [sanitizer] Reverting D34152 Summary: This broke thread_local_quarantine_pthread_join.cc on some architectures, due to the overhead of the stashed regions. Reverting while figuring out the best way to deal with it. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34213 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305404 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary32.h | 58 +++------------------- lib/sanitizer_common/sanitizer_common.h | 10 +--- lib/sanitizer_common/sanitizer_posix.cc | 23 +++------ lib/sanitizer_common/sanitizer_win.cc | 6 +-- .../tests/sanitizer_common_test.cc | 35 +------------ 5 files changed, 20 insertions(+), 112 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index bfedbc0a7..e13510ba3 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,7 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of an allocation of kRegionSize bytes aligned on kRegionSize. +// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -106,7 +106,6 @@ class SizeClassAllocator32 { void Init(s32 release_to_os_interval_ms) { possible_regions.TestOnlyInit(); internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); - num_stashed_regions = 0; } s32 ReleaseToOSIntervalMs() const { @@ -276,49 +275,15 @@ class SizeClassAllocator32 { return mem & ~(kRegionSize - 1); } - // Allocates a region of kRegionSize bytes, aligned on kRegionSize. If we get - // more than one region back (in the event the allocation is aligned on the - // first try), attempt to store the second region into a stash. If the stash - // is full, just unmap the superfluous memory. - uptr AllocateRegionSlow(AllocatorStats *stat) { - uptr map_size = kRegionSize; - uptr padding_chunk; - uptr region = reinterpret_cast( - MmapAlignedOrDie(kRegionSize, kRegionSize, "SizeClassAllocator32", - &padding_chunk)); - if (padding_chunk) { - // We have an extra region, attempt to stash it. - CHECK_EQ(padding_chunk, region + kRegionSize); - bool trim_extra = true; - { - SpinMutexLock l(®ions_stash_mutex); - if (num_stashed_regions < kMaxStashedRegions) { - regions_stash[num_stashed_regions++] = padding_chunk; - map_size = 2 * kRegionSize; - trim_extra = false; - } - } - if (trim_extra) - UnmapOrDie((void*)padding_chunk, kRegionSize); - } - MapUnmapCallback().OnMap(region, map_size); - stat->Add(AllocatorStatMapped, map_size); - return region; - } - uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr region = 0; - { - SpinMutexLock l(®ions_stash_mutex); - if (num_stashed_regions > 0) - region = regions_stash[--num_stashed_regions]; - } - if (!region) - region = AllocateRegionSlow(stat); - CHECK(IsAligned(region, kRegionSize)); - possible_regions.set(ComputeRegionId(region), static_cast(class_id)); - return region; + uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, + "SizeClassAllocator32")); + MapUnmapCallback().OnMap(res, kRegionSize); + stat->Add(AllocatorStatMapped, kRegionSize); + CHECK_EQ(0U, (res & (kRegionSize - 1))); + possible_regions.set(ComputeRegionId(res), static_cast(class_id)); + return res; } SizeClassInfo *GetSizeClassInfo(uptr class_id) { @@ -351,13 +316,6 @@ class SizeClassAllocator32 { } } - // Unless several threads request regions simultaneously from different size - // classes, the stash rarely contains more than 1 entry. - static const uptr kMaxStashedRegions = 8; - SpinMutex regions_stash_mutex; - uptr num_stashed_regions; - uptr regions_stash[kMaxStashedRegions]; - ByteMap possible_regions; SizeClassInfo size_class_info_array[kNumClasses]; }; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ea9a7d342..79ee6873b 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -92,15 +92,7 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. -// Since the predominant use case of this function is "size == alignment" and -// the nature of the way the alignment requirement is satisfied (by allocating -// size+alignment bytes of memory), there's a potential of address space -// fragmentation. The padding_chunk parameter provides the opportunity to -// return the contiguous padding of "size" bytes of the allocated chunk if the -// initial allocation happened to be perfectly aligned and the platform supports -// partial unmapping of the mapped region. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, - uptr *padding_chunk); +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an // unaccessible memory. bool MprotectNoAccess(uptr addr, uptr size); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 3a6b711db..9916f4d38 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -146,29 +146,22 @@ void UnmapOrDie(void *addr, uptr size) { } // We want to map a chunk of address space aligned to 'alignment'. -// We do it by mapping a bit more and then unmapping redundant pieces. +// We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, - uptr* padding_chunk) { +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; uptr map_res = (uptr)MmapOrDie(map_size, mem_type); uptr map_end = map_res + map_size; - bool is_aligned = IsAligned(map_res, alignment); - if (is_aligned && padding_chunk && size == alignment) { - *padding_chunk = map_res + size; - return (void *)map_res; - } - if (padding_chunk) - *padding_chunk = 0; uptr res = map_res; - if (!is_aligned) { - res = (map_res + alignment - 1) & ~(alignment - 1); - UnmapOrDie((void*)map_res, res - map_res); - } + if (res & (alignment - 1)) // Not aligned. + res = (map_res + alignment) & ~(alignment - 1); uptr end = res + size; - UnmapOrDie((void*)end, map_end - end); + if (res != map_res) + UnmapOrDie((void*)map_res, res - map_res); + if (end != map_end) + UnmapOrDie((void*)end, map_end - end); return (void*)res; } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 493167a19..afc3bb0ac 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -132,14 +132,10 @@ void UnmapOrDie(void *addr, uptr size) { } // We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type, - uptr *padding_chunk) { +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); - if (padding_chunk) - *padding_chunk = 0; - // Windows will align our allocations to at least 64K. alignment = Max(alignment, GetMmapGranularity()); diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index c1077e628..ebc885db7 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -77,8 +77,8 @@ TEST(SanitizerCommon, MmapAlignedOrDie) { for (uptr size = 1; size <= 32; size *= 2) { for (uptr alignment = 1; alignment <= 32; alignment *= 2) { for (int iter = 0; iter < 100; iter++) { - uptr res = (uptr)MmapAlignedOrDie(size * PageSize, alignment * PageSize, - "MmapAlignedOrDieTest", nullptr); + uptr res = (uptr)MmapAlignedOrDie( + size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest"); EXPECT_EQ(0U, res % (alignment * PageSize)); internal_memset((void*)res, 1, size * PageSize); UnmapOrDie((void*)res, size * PageSize); @@ -87,37 +87,6 @@ TEST(SanitizerCommon, MmapAlignedOrDie) { } } -TEST(SanitizerCommon, MmapAlignedOrDiePaddingChunk) { - uptr PageSize = GetPageSizeCached(); - for (uptr size = 1; size <= 32; size *= 2) { - for (uptr alignment = 1; alignment <= 32; alignment *= 2) { - for (int iter = 0; iter < 100; iter++) { - uptr padding_chunk; - uptr res = (uptr)MmapAlignedOrDie(size * PageSize, alignment * PageSize, - "MmapAlignedOrDiePaddingChunkTest", &padding_chunk); - EXPECT_EQ(0U, res % (alignment * PageSize)); - internal_memset((void*)res, 1, size * PageSize); - UnmapOrDie((void*)res, size * PageSize); - if (SANITIZER_WINDOWS || (size != alignment)) { - // Not supported on Windows or for different size and alignment. - EXPECT_EQ(0U, padding_chunk); - continue; - } - if (size == 1 && alignment == 1) { - // mmap returns PageSize aligned chunks, so this is a specific case - // where we can check that padding_chunk will never be 0. - EXPECT_NE(0U, padding_chunk); - } - if (padding_chunk) { - EXPECT_EQ(res + size * PageSize, padding_chunk); - internal_memset((void*)padding_chunk, 1, alignment * PageSize); - UnmapOrDie((void*)padding_chunk, alignment * PageSize); - } - } - } - } -} - #if SANITIZER_LINUX TEST(SanitizerCommon, SanitizerSetThreadName) { const char *names[] = { -- cgit v1.2.1 From 1d3673a97a3099ae6b00c847095e20a513b0f112 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 15 Jun 2017 00:19:13 +0000 Subject: [asan] Return allow_user_segv_handler=0 to fix compatibility issues. Summary: After r303941 it was not possible to setup ASAN_OPTIONS to have the same behavior for pre r303941 and post r303941 builds. Pre r303941 Asan does not accept handle_sigbus=2. Post r303941 Asan does not accept allow_user_segv_handler. This fix ignores allow_user_segv_handler=1, but for allow_user_segv_handler=0 it will upgrade flags like handle_sigbus=1 to handle_sigbus=2. So user can set ASAN_OPTIONS=allow_user_segv_handler=0 and have same behavior on old and new clang builds (except range from r303941 to this revision). In future users which need to prevent third party handlers should switch to handle_sigbus=2 and remove allow_user_segv_handler as soon as suport of older builds is not needed. Related bugs: https://github.com/google/oss-fuzz/issues/675 https://bugs.chromium.org/p/chromium/issues/detail?id=731130 Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34227 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305433 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flags.inc | 3 +++ lib/sanitizer_common/sanitizer_linux.cc | 9 ++++++++- lib/sanitizer_common/sanitizer_mac.cc | 15 +++++++++++---- test/asan/TestCases/Posix/allow_user_segv.cc | 8 ++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 8c486b5b1..6c42cb495 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -93,6 +93,9 @@ 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, true, + "Deprecated. Thue has no effect, see handle_sigbus. If false, " + "handle_*=1 will be upgraded to handle_*=2.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, false, diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index cec2f264c..d31c49d69 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1396,7 +1396,7 @@ AndroidApiLevel AndroidGetApiLevel() { #endif -HandleSignalMode GetHandleSignalMode(int signum) { +static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: return common_flags()->handle_abort; @@ -1412,6 +1412,13 @@ HandleSignalMode GetHandleSignalMode(int signum) { return kHandleSignalNo; } +HandleSignalMode GetHandleSignalMode(int signum) { + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + #if !SANITIZER_GO void *internal_start_thread(void(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index f1b9e5fda..a788a0915 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -414,10 +414,7 @@ void ListOfModules::init() { memory_mapping.DumpListOfModules(&modules_); } -HandleSignalMode GetHandleSignalMode(int signum) { - // Handling fatal signals on watchOS and tvOS devices is disallowed. - if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) - return kHandleSignalNo; +static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: return common_flags()->handle_abort; @@ -433,6 +430,16 @@ HandleSignalMode GetHandleSignalMode(int signum) { return kHandleSignalNo; } +HandleSignalMode GetHandleSignalMode(int signum) { + // Handling fatal signals on watchOS and tvOS devices is disallowed. + if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) + return kHandleSignalNo; + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; MacosVersion GetMacosVersionInternal() { diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc index 52f4f046d..fee589430 100644 --- a/test/asan/TestCases/Posix/allow_user_segv.cc +++ b/test/asan/TestCases/Posix/allow_user_segv.cc @@ -10,6 +10,14 @@ // 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 +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 + +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 + #include #include #include -- cgit v1.2.1 From 435e37653c947127ede69a90981d1fc609721555 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 15 Jun 2017 00:31:59 +0000 Subject: [asan] Fix typo in doc string. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305436 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flags.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 6c42cb495..9f71861ef 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -94,7 +94,7 @@ 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, true, - "Deprecated. Thue has no effect, see handle_sigbus. If false, " + "Deprecated. True has no effect, use handle_sigbus=1. If false, " "handle_*=1 will be upgraded to handle_*=2.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") -- cgit v1.2.1 From 6f8de12f02063d5900c639d46dd34788e4c0fd82 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 15 Jun 2017 18:23:16 +0000 Subject: [ubsan] Fix a faulty memory accessibility check The dynamic type check needs to inspect vtables, but could crash if it encounters a vtable pointer to inaccessible memory. In the first attempt to fix the issue (r304437), we performed a memory accessibility check on the wrong range of memory. This should *really* fix the problem. Patch by Max Moroz! Differential Revision: https://reviews.llvm.org/D34215 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305489 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_type_hash_itanium.cc | 4 +- test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp | 50 ++++++++++++++++++++++ test/ubsan/TestCases/TypeCheck/Linux/lit.local.cfg | 9 ++++ test/ubsan/TestCases/TypeCheck/PR33221.cpp | 2 +- 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp create mode 100644 test/ubsan/TestCases/TypeCheck/Linux/lit.local.cfg diff --git a/lib/ubsan/ubsan_type_hash_itanium.cc b/lib/ubsan/ubsan_type_hash_itanium.cc index 729c4a0f3..dcce0dd85 100644 --- a/lib/ubsan/ubsan_type_hash_itanium.cc +++ b/lib/ubsan/ubsan_type_hash_itanium.cc @@ -197,9 +197,9 @@ struct VtablePrefix { }; VtablePrefix *getVtablePrefix(void *Vtable) { VtablePrefix *Vptr = reinterpret_cast(Vtable); - if (!IsAccessibleMemoryRange((uptr)Vptr, sizeof(VtablePrefix))) - return nullptr; VtablePrefix *Prefix = Vptr - 1; + if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix))) + return nullptr; if (!Prefix->TypeInfo) // This can't possibly be a valid vtable. return nullptr; diff --git a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp new file mode 100644 index 000000000..e026e8d05 --- /dev/null +++ b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp @@ -0,0 +1,50 @@ +// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr -g %s -O3 -o %t +// RUN: %run %t &> %t.log +// RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0 + +// REQUIRES: cxxabi + +#include +#include + +class Base { +public: + int i; + virtual void print() {} +}; + +class Derived : public Base { +public: + void print() {} +}; + + +int main() { + int page_size = getpagesize(); + + void *non_accessible = mmap(nullptr, page_size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (non_accessible == MAP_FAILED) + return 0; + + void *accessible = mmap((char*)non_accessible + page_size, page_size, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (accessible == MAP_FAILED) + return 0; + + char *c = new char[sizeof(Derived)]; + + // The goal is to trigger a condition when Vptr points to accessible memory, + // but VptrPrefix does not. That has been triggering SIGSEGV in UBSan code. + void **vtable_ptr = reinterpret_cast(c); + *vtable_ptr = (void*)accessible; + + Derived *list = (Derived *)c; + +// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base' +// CHECK-NEXT: invalid vptr + int foo = list->i; + return 0; +} diff --git a/test/ubsan/TestCases/TypeCheck/Linux/lit.local.cfg b/test/ubsan/TestCases/TypeCheck/Linux/lit.local.cfg new file mode 100644 index 000000000..57271b807 --- /dev/null +++ b/test/ubsan/TestCases/TypeCheck/Linux/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Linux']: + config.unsupported = True diff --git a/test/ubsan/TestCases/TypeCheck/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/PR33221.cpp index 09411aa50..c691e5fb2 100644 --- a/test/ubsan/TestCases/TypeCheck/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/PR33221.cpp @@ -18,7 +18,7 @@ public: int main() { char *c = new char[sizeof(Derived)]; - memset((void *)c, 0, sizeof(Derived)); + memset((void *)c, 0xFF, sizeof(Derived)); Derived *list = (Derived *)c; // CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base' -- cgit v1.2.1 From f6b2a077d0f4aef7ac469d3d9b18070b361f7222 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 16 Jun 2017 00:18:35 +0000 Subject: [cfi] Enable icall tests with thinlto. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305534 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/cross-dso/icall/lit.local.cfg | 3 --- test/cfi/cross-dso/stats.cpp | 1 - test/cfi/icall/lit.local.cfg | 3 --- test/cfi/icall/wrong-signature-mixed-lto.c | 41 ++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 test/cfi/icall/wrong-signature-mixed-lto.c diff --git a/test/cfi/cross-dso/icall/lit.local.cfg b/test/cfi/cross-dso/icall/lit.local.cfg index 322b287a6..db08765a2 100644 --- a/test/cfi/cross-dso/icall/lit.local.cfg +++ b/test/cfi/cross-dso/icall/lit.local.cfg @@ -1,6 +1,3 @@ # The cfi-icall checker is only supported on x86 and x86_64 for now. if config.root.host_arch not in ['x86', 'x86_64']: config.unsupported = True - -if config.root.use_thinlto: - config.unsupported = True diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp index fb98a50a3..975a1ff9f 100644 --- a/test/cfi/cross-dso/stats.cpp +++ b/test/cfi/cross-dso/stats.cpp @@ -5,7 +5,6 @@ // CFI-icall is not implemented in thinlto mode => ".cfi" suffixes are missing // in sanstats output. -// XFAIL: thinlto struct ABase {}; diff --git a/test/cfi/icall/lit.local.cfg b/test/cfi/icall/lit.local.cfg index 44891c5e2..db08765a2 100644 --- a/test/cfi/icall/lit.local.cfg +++ b/test/cfi/icall/lit.local.cfg @@ -1,6 +1,3 @@ # The cfi-icall checker is only supported on x86 and x86_64 for now. if config.root.host_arch not in ['x86', 'x86_64']: config.unsupported = True - -if config.use_thinlto: - config.unsupported = True diff --git a/test/cfi/icall/wrong-signature-mixed-lto.c b/test/cfi/icall/wrong-signature-mixed-lto.c new file mode 100644 index 000000000..0e5fb8508 --- /dev/null +++ b/test/cfi/icall/wrong-signature-mixed-lto.c @@ -0,0 +1,41 @@ +// Test that the checking is done with the actual type of f() even when the +// calling module has an incorrect declaration. Test a mix of lto types. +// +// -flto below overrides -flto=thin in %clang_cfi +// RUN: %clang_cfi %s -DMODULE_A -c -o %t1_a.o +// RUN: %clang_cfi %s -DMODULE_B -c -o %t1_b.o -flto +// RUN: %clang_cfi %t1_a.o %t1_b.o -o %t1 +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// +// RUN: %clang_cfi %s -DMODULE_A -c -o %t2_a.o -flto +// RUN: %clang_cfi %s -DMODULE_B -c -o %t2_b.o +// RUN: %clang_cfi %t2_a.o %t2_b.o -o %t2 +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// +// RUN: %clang_cfi %s -DMODULE_A -c -o %t3_a.o +// RUN: %clang_cfi %s -DMODULE_B -c -o %t3_b.o +// RUN: %clang_cfi %t3_a.o %t3_b.o -o %t3 +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// +// REQUIRES: thinlto + +#include + +#if defined(MODULE_B) +int f() { + return 42; +} +#elif defined(MODULE_A) +void f(); + +int main() { + // CFI: 1 + fprintf(stderr, "1\n"); + + void (*volatile p)() = &f; + p(); + + // CFI-NOT: 2 + fprintf(stderr, "2\n"); +} +#endif -- cgit v1.2.1 From ca24bb081b5fc6f885bec6f1a0c2db05f1184900 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 16 Jun 2017 03:24:07 +0000 Subject: Add test for logging the implicit "this" argument for C++ member functions. Summary: This allows us to do more interesting things with the data available to C++ methods, to log the `this` pointer. Depends on D34050. Reviewers: pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34051 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305545 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/arg1-logging-implicit-this.cc | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/xray/TestCases/Linux/arg1-logging-implicit-this.cc diff --git a/test/xray/TestCases/Linux/arg1-logging-implicit-this.cc b/test/xray/TestCases/Linux/arg1-logging-implicit-this.cc new file mode 100644 index 000000000..66dfce9a3 --- /dev/null +++ b/test/xray/TestCases/Linux/arg1-logging-implicit-this.cc @@ -0,0 +1,31 @@ +// Intercept the implicit 'this' argument of class member functions. +// +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm log-args-this-* || true +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=log-args-this-" %run %t +// +// XFAIL: arm || aarch64 || mips +// UNSUPPORTED: powerpc64le +#include "xray/xray_interface.h" +#include + +class A { + public: + [[clang::xray_always_instrument, clang::xray_log_args(1)]] void f() { + // does nothing. + } +}; + +volatile uint64_t captured = 0; + +void handler(int32_t, XRayEntryType, uint64_t arg1) { + captured = arg1; +} + +int main() { + __xray_set_handler_arg1(handler); + A instance; + instance.f(); + __xray_remove_handler_arg1(); + assert(captured == (uint64_t)&instance); +} -- cgit v1.2.1 From 03a96b718d30e9b878100923745658c370916a40 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 16 Jun 2017 18:48:08 +0000 Subject: [Sanitizers] Secondary allocator respects allocator_may_return_null=1. Summary: Context: https://github.com/google/sanitizers/issues/740. Making secondary allocator to respect allocator_may_return_null=1 flag and return nullptr when "out of memory" happens. More changes in primary allocator and operator new will follow. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34243 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305569 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_secondary.h | 7 +- lib/sanitizer_common/sanitizer_common.h | 3 + lib/sanitizer_common/sanitizer_posix.cc | 16 +++++ lib/sanitizer_common/sanitizer_win.cc | 10 +++ test/asan/TestCases/Linux/allocator_oom_test.cc | 82 ++++++++++++++++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 test/asan/TestCases/Linux/allocator_oom_test.cc diff --git a/lib/sanitizer_common/sanitizer_allocator_secondary.h b/lib/sanitizer_common/sanitizer_allocator_secondary.h index 2e98e591b..2c69f47ec 100644 --- a/lib/sanitizer_common/sanitizer_allocator_secondary.h +++ b/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -36,9 +36,12 @@ class LargeMmapAllocator { if (alignment > page_size_) map_size += alignment; // Overflow. - if (map_size < size) return ReturnNullOrDieOnBadRequest(); + if (map_size < size) + return ReturnNullOrDieOnBadRequest(); uptr map_beg = reinterpret_cast( - MmapOrDie(map_size, "LargeMmapAllocator")); + MmapOrDieOnFatalError(map_size, "LargeMmapAllocator")); + if (!map_beg) + return ReturnNullOrDieOnOOM(); CHECK(IsAligned(map_beg, page_size_)); MapUnmapCallback().OnMap(map_beg, map_size); uptr map_end = map_beg + map_size; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 79ee6873b..875a46009 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -85,6 +85,9 @@ INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type, /*raw_report*/ true); } void UnmapOrDie(void *addr, uptr size); +// Behaves just like MmapOrDie, but tolerates out of memory condition, in that +// case returns nullptr. +void *MmapOrDieOnFatalError(uptr size, const char *mem_type); void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 9916f4d38..4184a84c7 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -22,6 +22,7 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include #include #include #include @@ -145,6 +146,21 @@ void UnmapOrDie(void *addr, uptr size) { DecreaseTotalMmap(size); } +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = internal_mmap(nullptr, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + int reserrno; + if (internal_iserror(res, &reserrno)) { + if (reserrno == ENOMEM) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)res; +} + // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index afc3bb0ac..506e7374a 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -131,6 +131,16 @@ void UnmapOrDie(void *addr, uptr size) { } } +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) { + error_t last_error = GetLastError(); + if (last_error != ERROR_NOT_ENOUGH_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "allocate", last_error); + } + return rv; +} + // We want to map a chunk of address space aligned to 'alignment'. void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { CHECK(IsPowerOfTwo(size)); diff --git a/test/asan/TestCases/Linux/allocator_oom_test.cc b/test/asan/TestCases/Linux/allocator_oom_test.cc new file mode 100644 index 000000000..c93e9fe21 --- /dev/null +++ b/test/asan/TestCases/Linux/allocator_oom_test.cc @@ -0,0 +1,82 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ulimit -v 22024290304 +// RUN: not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC,CHECK-CRASH +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC,CHECK-CRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC,CHECK-NULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-CALLOC,CHECK-CRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-CALLOC,CHECK-NULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-REALLOC,CHECK-CRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-REALLOC,CHECK-NULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC-REALLOC,CHECK-CRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC-REALLOC,CHECK-NULL + +#include +#include +#include +#include + +int main(int argc, char **argv) { + assert(argc == 2); + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + + // Allocate just a bit less than max allocation size enforced by ASan's + // allocator (currently 1T and 3G). + const size_t size = +#if __LP64__ + (1ULL << 40) - (1ULL << 30); +#else + (3ULL << 30) - (1ULL << 20); +#endif + + void *x = 0; + + if (!strcmp(action, "malloc")) { + x = malloc(size); + } else if (!strcmp(action, "calloc")) { + x = calloc(size / 4, 4); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, size); + } else if (!strcmp(action, "realloc-after-malloc")) { + char *t = (char*)malloc(100); + *t = 42; + x = realloc(t, size); + assert(*t == 42); + free(t); + } else { + assert(0); + } + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %lx\n", (long)x); + free(x); + + return x != 0; +} + +// CHECK-MALLOC: malloc: +// CHECK-CALLOC: calloc: +// CHECK-REALLOC: realloc: +// CHECK-MALLOC-REALLOC: realloc-after-malloc: + +// CHECK-CRASH: AddressSanitizer's allocator is terminating the process +// CHECK-NULL: x: 0 -- cgit v1.2.1 From f91b4c62913375ae7f6c0a16e7edd9f0f2b2a443 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 16 Jun 2017 20:36:39 +0000 Subject: [Sanitizers] Fix allocator OOM test on Windows. Summary: Point of failure is different after D34243, hence the change of the message. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34292 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305580 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/oom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Windows/oom.cc b/test/asan/TestCases/Windows/oom.cc index 59cc7ed0e..71a9c2a75 100644 --- a/test/asan/TestCases/Windows/oom.cc +++ b/test/asan/TestCases/Windows/oom.cc @@ -8,5 +8,5 @@ int main() { while (true) { void *ptr = malloc(200 * 1024 * 1024); // 200MB } -// CHECK: failed to allocate +// CHECK: allocator is terminating the process instead of returning 0 } -- cgit v1.2.1 From b0ee5a9393c30d2db2c6527492dfce94cefabc91 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 16 Jun 2017 20:44:00 +0000 Subject: [WinASan] Fix hotpatching new Win 10 build 1703 x64 strnlen prologue The first instruction of the new ucrtbase!strnlen implementation loads a global, presumably to dispatch between SSE and non-SSE optimized strnlen implementations. Fixes PR32895 and probably https://github.com/google/sanitizers/issues/818 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305581 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception_win.cc | 7 ++++++- lib/interception/tests/interception_win_test.cc | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index e4f3d358f..b2902d57f 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -477,7 +477,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { switch (*(u8*)address) { case 0xA1: // A1 XX XX XX XX XX XX XX XX : // movabs eax, dword ptr ds:[XXXXXXXX] - return 8; + return 9; } switch (*(u16*)address) { @@ -495,6 +495,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x5741: // push r15 case 0x9066: // Two-byte NOP return 2; + + case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX] + if (rel_offset) + *rel_offset = 2; + return 6; } switch (0x00FFFFFF & *(u32*)address) { diff --git a/lib/interception/tests/interception_win_test.cc b/lib/interception/tests/interception_win_test.cc index a705768d6..37ef994f8 100644 --- a/lib/interception/tests/interception_win_test.cc +++ b/lib/interception/tests/interception_win_test.cc @@ -170,6 +170,13 @@ const u8 kPatchableCode5[] = { 0x54, // push esp }; +#if SANITIZER_WINDOWS64 +u8 kLoadGlobalCode[] = { + 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global] + 0xC3, // ret +}; +#endif + const u8 kUnpatchableCode1[] = { 0xC3, // ret }; @@ -502,6 +509,10 @@ TEST(Interception, PatchableFunction) { EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override)); +#if SANITIZER_WINDOWS64 + EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override)); +#endif + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); -- cgit v1.2.1 From 802ac1eb4fa6188c824ea8c49fd303626aba59de Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 16 Jun 2017 21:00:03 +0000 Subject: [Sanitizer] Remove CombinedAllocator::Allocate's 'cleared' parameter Summary: CombinedAllocator::Allocate cleared parameter is not used anywhere and seem to be obsolete. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34289 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305590 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 8 +++----- lib/lsan/lsan_allocator.cc | 2 +- lib/msan/msan_allocator.cc | 4 ++-- lib/sanitizer_common/sanitizer_allocator.cc | 4 ++-- lib/sanitizer_common/sanitizer_allocator_combined.h | 8 +------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 1ded7794c..a93a196cb 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -160,7 +160,7 @@ struct QuarantineCallback { } void *Allocate(uptr size) { - return get_allocator().Allocate(cache_, size, 1, false); + return get_allocator().Allocate(cache_, size, 1); } void Deallocate(void *p) { @@ -414,13 +414,11 @@ struct Allocator { void *allocated; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); - allocated = - allocator.Allocate(cache, needed_size, 8, false); + allocated = allocator.Allocate(cache, needed_size, 8); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; - allocated = - allocator.Allocate(cache, needed_size, 8, false); + allocated = allocator.Allocate(cache, needed_size, 8); } if (!allocated) return allocator.ReturnNullOrDieOnOOM(); diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 011979eee..acff1f5ae 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -76,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); + void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 1be573faa..8d6cc69a4 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -145,11 +145,11 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, void *allocated; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); - allocated = allocator.Allocate(cache, size, alignment, false); + allocated = allocator.Allocate(cache, size, alignment); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; - allocated = allocator.Allocate(cache, size, alignment, false); + allocated = allocator.Allocate(cache, size, alignment); } Metadata *meta = reinterpret_cast(allocator.GetMetaData(allocated)); diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index d47b5b414..15d01de86 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -108,9 +108,9 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, if (cache == 0) { SpinMutexLock l(&internal_allocator_cache_mu); return internal_allocator()->Allocate(&internal_allocator_cache, size, - alignment, false); + alignment); } - return internal_allocator()->Allocate(cache, size, alignment, false); + return internal_allocator()->Allocate(cache, size, alignment); } static void *RawInternalRealloc(void *ptr, uptr size, diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h index 2c2390b3d..90ccb1771 100644 --- a/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -42,8 +42,7 @@ class CombinedAllocator { InitCommon(may_return_null, release_to_os_interval_ms); } - void *Allocate(AllocatorCache *cache, uptr size, uptr alignment, - bool cleared = false) { + void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) { // Returning 0 on malloc(0) may break a lot of code. if (size == 0) size = 1; @@ -70,11 +69,6 @@ class CombinedAllocator { res = secondary_.Allocate(&stats_, original_size, alignment); if (alignment > 8) CHECK_EQ(reinterpret_cast(res) & (alignment - 1), 0); - // When serviced by the secondary, the chunk comes from a mmap allocation - // and will be zero'd out anyway. We only need to clear our the chunk if - // it was serviced by the primary, hence using the rounded up 'size'. - if (cleared && res && from_primary) - internal_bzero_aligned16(res, RoundUpTo(size, 16)); return res; } -- cgit v1.2.1 From f0d7258f4a2f5e6443011f7be011b5e9999c33f2 Mon Sep 17 00:00:00 2001 From: Pirama Arumuga Nainar Date: Fri, 16 Jun 2017 21:14:45 +0000 Subject: Call cmake_minimum_required at the top of CMakeLists.txt Summary: Since r298413, the NEW behavior of the CMake policy CMP0056 is followed. However, it is only effective after the call to cmake_minimum_required. This causes CMAKE_EXE_LINKER_FLAGS etc. to be unused when CMake tries to check compilers for languages specified in the 'project' declaration. Set cmake_minimum_required(VERSION) at the top of the file and ahead of the project declaration. Reviewers: beanz Subscribers: mgorny, srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D34282 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305593 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51769088a..315223358 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,14 +7,14 @@ # An important constraint of the build is that it only produces libraries # based on the ability of the host toolchain to target various platforms. +cmake_minimum_required(VERSION 3.4.3) + # Check if compiler-rt is built as a standalone project. if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD) project(CompilerRT C CXX ASM) set(COMPILER_RT_STANDALONE_BUILD TRUE) endif() -cmake_minimum_required(VERSION 3.4.3) - # Add path for custom compiler-rt modules. list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake" -- cgit v1.2.1 From 028649d48d70b36ab6226c81cba4e76936ca9bd1 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 19 Jun 2017 01:30:04 +0000 Subject: [XRay][compiler-rt][NFC] Add a name for argument to __xray_set_handler_arg1(...) Just makes the interface consistent with the other functions in include/xray/xray_interface.h. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305658 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_interface.h | 3 ++- lib/xray/xray_interface.cc | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index dc0c277aa..564613417 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -60,7 +60,8 @@ extern int __xray_remove_handler(); /// start logging their subsequent affected function calls (if patched). /// /// Returns 1 on success, 0 on error. -extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); +extern int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, + uint64_t)); /// Disables the XRay handler used to log first arguments of function calls. /// Returns 1 on success, 0 on error. diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index e912b6e47..694d34c01 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -312,7 +312,7 @@ __xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { return patchFunction(FuncId, false); } -int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { +int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) { if (!__sanitizer::atomic_load(&XRayInitialized, __sanitizer::memory_order_acquire)) return 0; @@ -320,7 +320,7 @@ int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { // A relaxed write might not be visible even if the current thread gets // scheduled on a different CPU/NUMA node. We need to wait for everyone to // have this handler installed for consistency of collected data across CPUs. - __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast(Handler), + __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast(entry), __sanitizer::memory_order_release); return 1; } -- cgit v1.2.1 From 366176ff1bf74e8fe330cdc5b712845b94650078 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 19 Jun 2017 03:52:25 +0000 Subject: [XRay][compiler-rt][NFC] Add a test for both arg1 and arg0 handling in the same binary This test makes sure we can handle both arg0 and arg1 handling in the same binary, and making sure that the XRay runtime calls the correct trampoline when handlers for both of these cases are installed. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305660 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/arg1-arg0-logging.cc | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/xray/TestCases/Linux/arg1-arg0-logging.cc diff --git a/test/xray/TestCases/Linux/arg1-arg0-logging.cc b/test/xray/TestCases/Linux/arg1-arg0-logging.cc new file mode 100644 index 000000000..e7730bfa6 --- /dev/null +++ b/test/xray/TestCases/Linux/arg1-arg0-logging.cc @@ -0,0 +1,39 @@ +// Allow having both the no-arg and arg1 logging implementation live together, +// and be called in the correct cases. +// +// RUN: rm arg0-arg1-logging-* || true +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=arg0-arg1-logging-" %run %t +// +// TODO: Support these in ARM and PPC +// XFAIL: arm || aarch64 || mips +// UNSUPPORTED: powerpc64le + +#include "xray/xray_interface.h" +#include +#include + +using namespace std; + +bool arg0loggercalled = false; +void arg0logger(int32_t, XRayEntryType) { arg0loggercalled = true; } + +[[clang::xray_always_instrument]] void arg0fn() { printf("hello, arg0!\n"); } + +bool arg1loggercalled = false; +void arg1logger(int32_t, XRayEntryType, uint64_t) { arg1loggercalled = true; } + +[[ clang::xray_always_instrument, clang::xray_log_args(1) ]] void +arg1fn(uint64_t arg1) { + printf("hello, arg1!\n"); +} + +int main(int argc, char *argv[]) { + __xray_set_handler(arg0logger); + __xray_set_handler_arg1(arg1logger); + arg0fn(); + arg1fn(0xcafef00d); + __xray_remove_handler_arg1(); + __xray_remove_handler(); + assert(arg0loggercalled && arg1loggercalled); +} -- cgit v1.2.1 From 80ed4944ba672f0f7a2143f149b59e833b94d2f6 Mon Sep 17 00:00:00 2001 From: Sagar Thakur Date: Mon, 19 Jun 2017 11:28:59 +0000 Subject: [scudo] Enabling MIPS support for Scudo Adding MIPS 32-bit and 64-bit support for Scudo. Reviewed by cryptoad, sdardis. Differential: D31803 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305682 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/sanitizer_common/sanitizer_atomic_clang.h | 22 ++++++-- .../sanitizer_atomic_clang_other.h | 65 ++++++++++++++++++++++ test/scudo/random_shuffle.cpp | 2 +- 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index ae2a262a1..0da98b9a4 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -179,7 +179,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64}) set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) -set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}) +set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le) if(APPLE) diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h index 38363e875..47581282a 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -71,16 +71,26 @@ INLINE typename T::Type atomic_exchange(volatile T *a, return v; } -template -INLINE bool atomic_compare_exchange_strong(volatile T *a, - typename T::Type *cmp, +template +INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { typedef typename T::Type Type; Type cmpv = *cmp; - Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); - if (prev == cmpv) - return true; + Type prev; +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + if (sizeof(*a) == 8) { + Type volatile *val_ptr = const_cast(&a->val_dont_use); + prev = __mips_sync_val_compare_and_swap( + reinterpret_cast(val_ptr), reinterpret_cast cmpv, + reinterpret_cast xchg); + } else { + prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); + } +#else + prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); +#endif + if (prev == cmpv) return true; *cmp = prev; return false; } diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h index 099b9f7ec..2825c7400 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -17,6 +17,56 @@ namespace __sanitizer { +// MIPS32 does not support atomic > 4 bytes. To address this lack of +// functionality, the sanitizer library provides helper methods which use an +// internal spin lock mechanism to emulate atomic oprations when the size is +// 8 bytes. +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 +static void __spin_lock(volatile int *lock) { + while (__sync_lock_test_and_set(lock, 1)) + while (*lock) { + } +} + +static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } + + +// Make sure the lock is on its own cache line to prevent false sharing. +// Put it inside a struct that is aligned and padded to the typical MIPS +// cacheline which is 32 bytes. +static struct { + int lock; + char pad[32 - sizeof(int)]; +} __attribute__((aligned(32))) lock = {0}; + +template +T __mips_sync_fetch_and_add(volatile T *ptr, T val) { + T ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret + val; + + __spin_unlock(&lock.lock); + + return ret; +} + +template +T __mips_sync_val_compare_and_swap(volatile T *ptr, T oldval, T newval) { + T ret; + __spin_lock(&lock.lock); + + ret = *ptr; + if (ret == oldval) *ptr = newval; + + __spin_unlock(&lock.lock); + + return ret; +} +#endif + INLINE void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); } @@ -53,8 +103,15 @@ INLINE typename T::Type atomic_load( // 64-bit load on 32-bit platform. // Gross, but simple and reliable. // Assume that it is not in read-only memory. +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + typename T::Type volatile *val_ptr = + const_cast(&a->val_dont_use); + v = __mips_sync_fetch_and_add( + reinterpret_cast(val_ptr), 0); +#else v = __sync_fetch_and_add( const_cast(&a->val_dont_use), 0); +#endif } return v; } @@ -84,7 +141,15 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { typename T::Type cmp = a->val_dont_use; typename T::Type cur; for (;;) { +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + typename T::Type volatile *val_ptr = + const_cast(&a->val_dont_use); + cur = __mips_sync_val_compare_and_swap( + reinterpret_cast(val_ptr), reinterpret_cast cmp, + reinterpret_cast v); +#else cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); +#endif if (cmp == v) break; cmp = cur; diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 41e67ded6..05a432615 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From a3d787dff9cc28412a3df4035e23edba6ddf5357 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 19 Jun 2017 14:09:10 +0000 Subject: Add lsan interceptors for libdispatch functions on darwin Summary: This is required for standalone LSan to work with libdispatch worker threads, and is a slimmed down version of the functionality provided for ASan in asan_mac.cc. Reviewers: alekseyshl, kubamracek, glider, kcc Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D34247 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305695 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/CMakeLists.txt | 1 + lib/lsan/lsan.h | 2 + lib/lsan/lsan_common_mac.cc | 3 +- lib/lsan/lsan_mac.cc | 192 +++++++++++++++++++++++++++++++ lib/lsan/lsan_thread.cc | 4 +- lib/lsan/lsan_thread.h | 2 +- test/lsan/TestCases/Darwin/dispatch.mm | 59 ++++++++++ test/lsan/TestCases/Darwin/lit.local.cfg | 9 ++ test/lsan/lit.common.cfg | 2 +- 9 files changed, 268 insertions(+), 6 deletions(-) create mode 100644 lib/lsan/lsan_mac.cc create mode 100644 test/lsan/TestCases/Darwin/dispatch.mm create mode 100644 test/lsan/TestCases/Darwin/lit.local.cfg diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index 55c825f5c..bd3a96f32 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -13,6 +13,7 @@ set(LSAN_SOURCES lsan_allocator.cc lsan_linux.cc lsan_interceptors.cc + lsan_mac.cc lsan_malloc_mac.cc lsan_preinit.cc lsan_thread.cc) diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h index 1061d2fcf..7446e9507 100644 --- a/lib/lsan/lsan.h +++ b/lib/lsan/lsan.h @@ -38,6 +38,8 @@ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ common_flags()->fast_unwind_on_malloc) +#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true) + namespace __lsan { void InitializeInterceptors(); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 114dd8c90..adde3a1b4 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -79,8 +79,7 @@ void EnableInThisThread() { u32 GetCurrentThread() { thread_local_data_t *data = get_tls_val(false); - CHECK(data); - return data->current_thread_id; + return data ? data->current_thread_id : kInvalidTid; } void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } diff --git a/lib/lsan/lsan_mac.cc b/lib/lsan/lsan_mac.cc new file mode 100644 index 000000000..1a6f5f489 --- /dev/null +++ b/lib/lsan/lsan_mac.cc @@ -0,0 +1,192 @@ +//===-- lsan_mac.cc -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer, a memory leak checker. +// +// Mac-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_MAC + +#include "interception/interception.h" +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_thread.h" + +#include + +namespace __lsan { +// Support for the following functions from libdispatch on Mac OS: +// dispatch_async_f() +// dispatch_async() +// dispatch_sync_f() +// dispatch_sync() +// dispatch_after_f() +// dispatch_after() +// dispatch_group_async_f() +// dispatch_group_async() +// TODO(glider): libdispatch API contains other functions that we don't support +// yet. +// +// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are +// they can cause jobs to run on a thread different from the current one. +// TODO(glider): if so, we need a test for this (otherwise we should remove +// them). +// +// The following functions use dispatch_barrier_async_f() (which isn't a library +// function but is exported) and are thus supported: +// dispatch_source_set_cancel_handler_f() +// dispatch_source_set_cancel_handler() +// dispatch_source_set_event_handler_f() +// dispatch_source_set_event_handler() +// +// The reference manual for Grand Central Dispatch is available at +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// The implementation details are at +// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c + +typedef void *dispatch_group_t; +typedef void *dispatch_queue_t; +typedef void *dispatch_source_t; +typedef u64 dispatch_time_t; +typedef void (*dispatch_function_t)(void *block); +typedef void *(*worker_t)(void *block); + +// A wrapper for the ObjC blocks used to support libdispatch. +typedef struct { + void *block; + dispatch_function_t func; + u32 parent_tid; +} lsan_block_context_t; + +ALWAYS_INLINE +void lsan_register_worker_thread(int parent_tid) { + if (GetCurrentThread() == kInvalidTid) { + u32 tid = ThreadCreate(parent_tid, 0, true); + ThreadStart(tid, GetTid()); + SetCurrentThread(tid); + } +} + +// For use by only those functions that allocated the context via +// alloc_lsan_context(). +extern "C" void lsan_dispatch_call_block_and_release(void *block) { + lsan_block_context_t *context = (lsan_block_context_t *)block; + VReport(2, + "lsan_dispatch_call_block_and_release(): " + "context: %p, pthread_self: %p\n", + block, pthread_self()); + lsan_register_worker_thread(context->parent_tid); + // Call the original dispatcher for the block. + context->func(context->block); + lsan_free(context); +} + +} // namespace __lsan + +using namespace __lsan; // NOLINT + +// Wrap |ctxt| and |func| into an lsan_block_context_t. +// The caller retains control of the allocated context. +extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt, + dispatch_function_t func) { + GET_STACK_TRACE_THREAD; + lsan_block_context_t *lsan_ctxt = + (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack); + lsan_ctxt->block = ctxt; + lsan_ctxt->func = func; + lsan_ctxt->parent_tid = GetCurrentThread(); + return lsan_ctxt; +} + +// Define interceptor for dispatch_*_f function with the three most common +// parameters: dispatch_queue_t, context, dispatch_function_t. +#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ + INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ + dispatch_function_t func) { \ + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \ + return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt, \ + lsan_dispatch_call_block_and_release); \ + } + +INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) + +INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, + void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt, + lsan_dispatch_call_block_and_release); +} + +INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, + dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + REAL(dispatch_group_async_f) + (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release); +} + +#if !defined(MISSING_BLOCKS_SUPPORT) +extern "C" { +void dispatch_async(dispatch_queue_t dq, void (^work)(void)); +void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, + void (^work)(void)); +void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)); +void dispatch_source_set_cancel_handler(dispatch_source_t ds, + void (^work)(void)); +void dispatch_source_set_event_handler(dispatch_source_t ds, + void (^work)(void)); +} + +#define GET_LSAN_BLOCK(work) \ + void (^lsan_block)(void); \ + int parent_tid = GetCurrentThread(); \ + lsan_block = ^(void) { \ + lsan_register_worker_thread(parent_tid); \ + work(); \ + } + +INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_async)(dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, + dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_group_async)(dg, dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_after)(when, queue, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, + void (^work)(void)) { + if (!work) { + REAL(dispatch_source_set_cancel_handler)(ds, work); + return; + } + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_cancel_handler)(ds, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_event_handler)(ds, lsan_block); +} +#endif + +#endif // SANITIZER_MAC diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index 0ea7a6e97..4404c8cc5 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { /* arg */ nullptr); } -void ThreadStart(u32 tid, tid_t os_id) { +void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { OnStartedArgs args; uptr stack_size = 0; uptr tls_size = 0; @@ -87,7 +87,7 @@ void ThreadStart(u32 tid, tid_t os_id) { args.tls_end = args.tls_begin + tls_size; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args); + thread_registry->StartThread(tid, os_id, workerthread, &args); } void ThreadFinish() { diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h index 73e080e26..b16d3d915 100644 --- a/lib/lsan/lsan_thread.h +++ b/lib/lsan/lsan_thread.h @@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase { void InitializeThreadRegistry(); -void ThreadStart(u32 tid, tid_t os_id); +void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false); void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); diff --git a/test/lsan/TestCases/Darwin/dispatch.mm b/test/lsan/TestCases/Darwin/dispatch.mm new file mode 100644 index 000000000..2472230d7 --- /dev/null +++ b/test/lsan/TestCases/Darwin/dispatch.mm @@ -0,0 +1,59 @@ +// Test for threads spawned with wqthread_start +// RUN: LSAN_BASE="report_objects=1" +// RUN: %clangxx_lsan %s -DDISPATCH_ASYNC -o %t-async -framework Foundation +// RUN: %clangxx_lsan %s -DDISPATCH_SYNC -o %t-sync -framework Foundation +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-async 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-sync 2>&1 | FileCheck %s + +#include +#include +#include + +#include "sanitizer_common/print_address.h" + +bool done = false; + +void worker_do_leak(int size) { + void *p = malloc(size); + print_address("Test alloc: ", 1, p); + done = true; +} + +#if DISPATCH_ASYNC +// Tests for the Grand Central Dispatch. See +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// for the reference. +void TestGCDDispatch() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block = ^{ + worker_do_leak(1337); + }; + // dispatch_async() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that LeakSanitizer notices that the + // thread has started. + dispatch_async(queue, block); + while (!done) + pthread_yield_np(); +} +#elif DISPATCH_SYNC +void TestGCDDispatch() { + dispatch_queue_t queue = dispatch_get_global_queue(2, 0); + dispatch_block_t block = ^{ + worker_do_leak(1337); + }; + // dispatch_sync() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that LeakSanitizer notices that the + // thread has started. + dispatch_sync(queue, block); +} +#endif + +int main() { + TestGCDDispatch(); + return 0; +} + +// CHECK: Test alloc: [[addr:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[addr]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Darwin/lit.local.cfg b/test/lsan/TestCases/Darwin/lit.local.cfg new file mode 100644 index 000000000..a85dfcd24 --- /dev/null +++ b/test/lsan/TestCases/Darwin/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Darwin']: + config.unsupported = True diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 309e8f27b..610b1b1ad 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -77,4 +77,4 @@ if not (supported_linux or supported_darwin): if re.search('mthumb', config.target_cflags) is not None: config.unsupported = True -config.suffixes = ['.c', '.cc', '.cpp'] +config.suffixes = ['.c', '.cc', '.cpp', '.mm'] -- cgit v1.2.1 From ebb8e45a1520095da9b8b778b801dab9550d6f63 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 19 Jun 2017 17:08:55 +0000 Subject: Revert "Add lsan interceptors for libdispatch functions on darwin" This reverts r305695 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305712 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/CMakeLists.txt | 1 - lib/lsan/lsan.h | 2 - lib/lsan/lsan_common_mac.cc | 3 +- lib/lsan/lsan_mac.cc | 192 ------------------------------- lib/lsan/lsan_thread.cc | 4 +- lib/lsan/lsan_thread.h | 2 +- test/lsan/TestCases/Darwin/dispatch.mm | 59 ---------- test/lsan/TestCases/Darwin/lit.local.cfg | 9 -- test/lsan/lit.common.cfg | 2 +- 9 files changed, 6 insertions(+), 268 deletions(-) delete mode 100644 lib/lsan/lsan_mac.cc delete mode 100644 test/lsan/TestCases/Darwin/dispatch.mm delete mode 100644 test/lsan/TestCases/Darwin/lit.local.cfg diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index bd3a96f32..55c825f5c 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -13,7 +13,6 @@ set(LSAN_SOURCES lsan_allocator.cc lsan_linux.cc lsan_interceptors.cc - lsan_mac.cc lsan_malloc_mac.cc lsan_preinit.cc lsan_thread.cc) diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h index 7446e9507..1061d2fcf 100644 --- a/lib/lsan/lsan.h +++ b/lib/lsan/lsan.h @@ -38,8 +38,6 @@ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ common_flags()->fast_unwind_on_malloc) -#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true) - namespace __lsan { void InitializeInterceptors(); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index adde3a1b4..114dd8c90 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -79,7 +79,8 @@ void EnableInThisThread() { u32 GetCurrentThread() { thread_local_data_t *data = get_tls_val(false); - return data ? data->current_thread_id : kInvalidTid; + CHECK(data); + return data->current_thread_id; } void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } diff --git a/lib/lsan/lsan_mac.cc b/lib/lsan/lsan_mac.cc deleted file mode 100644 index 1a6f5f489..000000000 --- a/lib/lsan/lsan_mac.cc +++ /dev/null @@ -1,192 +0,0 @@ -//===-- lsan_mac.cc -------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of LeakSanitizer, a memory leak checker. -// -// Mac-specific details. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_MAC - -#include "interception/interception.h" -#include "lsan.h" -#include "lsan_allocator.h" -#include "lsan_thread.h" - -#include - -namespace __lsan { -// Support for the following functions from libdispatch on Mac OS: -// dispatch_async_f() -// dispatch_async() -// dispatch_sync_f() -// dispatch_sync() -// dispatch_after_f() -// dispatch_after() -// dispatch_group_async_f() -// dispatch_group_async() -// TODO(glider): libdispatch API contains other functions that we don't support -// yet. -// -// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are -// they can cause jobs to run on a thread different from the current one. -// TODO(glider): if so, we need a test for this (otherwise we should remove -// them). -// -// The following functions use dispatch_barrier_async_f() (which isn't a library -// function but is exported) and are thus supported: -// dispatch_source_set_cancel_handler_f() -// dispatch_source_set_cancel_handler() -// dispatch_source_set_event_handler_f() -// dispatch_source_set_event_handler() -// -// The reference manual for Grand Central Dispatch is available at -// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html -// The implementation details are at -// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c - -typedef void *dispatch_group_t; -typedef void *dispatch_queue_t; -typedef void *dispatch_source_t; -typedef u64 dispatch_time_t; -typedef void (*dispatch_function_t)(void *block); -typedef void *(*worker_t)(void *block); - -// A wrapper for the ObjC blocks used to support libdispatch. -typedef struct { - void *block; - dispatch_function_t func; - u32 parent_tid; -} lsan_block_context_t; - -ALWAYS_INLINE -void lsan_register_worker_thread(int parent_tid) { - if (GetCurrentThread() == kInvalidTid) { - u32 tid = ThreadCreate(parent_tid, 0, true); - ThreadStart(tid, GetTid()); - SetCurrentThread(tid); - } -} - -// For use by only those functions that allocated the context via -// alloc_lsan_context(). -extern "C" void lsan_dispatch_call_block_and_release(void *block) { - lsan_block_context_t *context = (lsan_block_context_t *)block; - VReport(2, - "lsan_dispatch_call_block_and_release(): " - "context: %p, pthread_self: %p\n", - block, pthread_self()); - lsan_register_worker_thread(context->parent_tid); - // Call the original dispatcher for the block. - context->func(context->block); - lsan_free(context); -} - -} // namespace __lsan - -using namespace __lsan; // NOLINT - -// Wrap |ctxt| and |func| into an lsan_block_context_t. -// The caller retains control of the allocated context. -extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt, - dispatch_function_t func) { - GET_STACK_TRACE_THREAD; - lsan_block_context_t *lsan_ctxt = - (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack); - lsan_ctxt->block = ctxt; - lsan_ctxt->func = func; - lsan_ctxt->parent_tid = GetCurrentThread(); - return lsan_ctxt; -} - -// Define interceptor for dispatch_*_f function with the three most common -// parameters: dispatch_queue_t, context, dispatch_function_t. -#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ - INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ - dispatch_function_t func) { \ - lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \ - return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt, \ - lsan_dispatch_call_block_and_release); \ - } - -INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) -INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) -INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) - -INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, - void *ctxt, dispatch_function_t func) { - lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); - return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt, - lsan_dispatch_call_block_and_release); -} - -INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, - dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { - lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); - REAL(dispatch_group_async_f) - (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release); -} - -#if !defined(MISSING_BLOCKS_SUPPORT) -extern "C" { -void dispatch_async(dispatch_queue_t dq, void (^work)(void)); -void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, - void (^work)(void)); -void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, - void (^work)(void)); -void dispatch_source_set_cancel_handler(dispatch_source_t ds, - void (^work)(void)); -void dispatch_source_set_event_handler(dispatch_source_t ds, - void (^work)(void)); -} - -#define GET_LSAN_BLOCK(work) \ - void (^lsan_block)(void); \ - int parent_tid = GetCurrentThread(); \ - lsan_block = ^(void) { \ - lsan_register_worker_thread(parent_tid); \ - work(); \ - } - -INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) { - GET_LSAN_BLOCK(work); - REAL(dispatch_async)(dq, lsan_block); -} - -INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, - dispatch_queue_t dq, void (^work)(void)) { - GET_LSAN_BLOCK(work); - REAL(dispatch_group_async)(dg, dq, lsan_block); -} - -INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, - void (^work)(void)) { - GET_LSAN_BLOCK(work); - REAL(dispatch_after)(when, queue, lsan_block); -} - -INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, - void (^work)(void)) { - if (!work) { - REAL(dispatch_source_set_cancel_handler)(ds, work); - return; - } - GET_LSAN_BLOCK(work); - REAL(dispatch_source_set_cancel_handler)(ds, lsan_block); -} - -INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, - void (^work)(void)) { - GET_LSAN_BLOCK(work); - REAL(dispatch_source_set_event_handler)(ds, lsan_block); -} -#endif - -#endif // SANITIZER_MAC diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index 4404c8cc5..0ea7a6e97 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { /* arg */ nullptr); } -void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { +void ThreadStart(u32 tid, tid_t os_id) { OnStartedArgs args; uptr stack_size = 0; uptr tls_size = 0; @@ -87,7 +87,7 @@ void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { args.tls_end = args.tls_begin + tls_size; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, workerthread, &args); + thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args); } void ThreadFinish() { diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h index b16d3d915..73e080e26 100644 --- a/lib/lsan/lsan_thread.h +++ b/lib/lsan/lsan_thread.h @@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase { void InitializeThreadRegistry(); -void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false); +void ThreadStart(u32 tid, tid_t os_id); void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); diff --git a/test/lsan/TestCases/Darwin/dispatch.mm b/test/lsan/TestCases/Darwin/dispatch.mm deleted file mode 100644 index 2472230d7..000000000 --- a/test/lsan/TestCases/Darwin/dispatch.mm +++ /dev/null @@ -1,59 +0,0 @@ -// Test for threads spawned with wqthread_start -// RUN: LSAN_BASE="report_objects=1" -// RUN: %clangxx_lsan %s -DDISPATCH_ASYNC -o %t-async -framework Foundation -// RUN: %clangxx_lsan %s -DDISPATCH_SYNC -o %t-sync -framework Foundation -// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-async 2>&1 | FileCheck %s -// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-sync 2>&1 | FileCheck %s - -#include -#include -#include - -#include "sanitizer_common/print_address.h" - -bool done = false; - -void worker_do_leak(int size) { - void *p = malloc(size); - print_address("Test alloc: ", 1, p); - done = true; -} - -#if DISPATCH_ASYNC -// Tests for the Grand Central Dispatch. See -// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html -// for the reference. -void TestGCDDispatch() { - dispatch_queue_t queue = dispatch_get_global_queue(0, 0); - dispatch_block_t block = ^{ - worker_do_leak(1337); - }; - // dispatch_async() runs the task on a worker thread that does not go through - // pthread_create(). We need to verify that LeakSanitizer notices that the - // thread has started. - dispatch_async(queue, block); - while (!done) - pthread_yield_np(); -} -#elif DISPATCH_SYNC -void TestGCDDispatch() { - dispatch_queue_t queue = dispatch_get_global_queue(2, 0); - dispatch_block_t block = ^{ - worker_do_leak(1337); - }; - // dispatch_sync() runs the task on a worker thread that does not go through - // pthread_create(). We need to verify that LeakSanitizer notices that the - // thread has started. - dispatch_sync(queue, block); -} -#endif - -int main() { - TestGCDDispatch(); - return 0; -} - -// CHECK: Test alloc: [[addr:0x[0-9,a-f]+]] -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: [[addr]] (1337 bytes) -// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Darwin/lit.local.cfg b/test/lsan/TestCases/Darwin/lit.local.cfg deleted file mode 100644 index a85dfcd24..000000000 --- a/test/lsan/TestCases/Darwin/lit.local.cfg +++ /dev/null @@ -1,9 +0,0 @@ -def getRoot(config): - if not config.parent: - return config - return getRoot(config.parent) - -root = getRoot(config) - -if root.host_os not in ['Darwin']: - config.unsupported = True diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 610b1b1ad..309e8f27b 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -77,4 +77,4 @@ if not (supported_linux or supported_darwin): if re.search('mthumb', config.target_cflags) is not None: config.unsupported = True -config.suffixes = ['.c', '.cc', '.cpp', '.mm'] +config.suffixes = ['.c', '.cc', '.cpp'] -- cgit v1.2.1 From e9f87b734244609f83ee0d66cb34688acae9d643 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 19 Jun 2017 19:21:31 +0000 Subject: Add lsan interceptors for libdispatch functions on darwin Summary: This is required for standalone LSan to work with libdispatch worker threads, and is a slimmed down version of the functionality provided for ASan in asan_mac.cc. Re-commit of r305695 with use_stacks=0 to get around a racy lingering pointer. Reviewers: alekseyshl, kubamracek, glider, kcc Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D34247 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305732 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/weak_symbols.txt | 9 ++ lib/lsan/CMakeLists.txt | 1 + lib/lsan/lsan.h | 2 + lib/lsan/lsan_common_mac.cc | 3 +- lib/lsan/lsan_mac.cc | 192 +++++++++++++++++++++++++++++++ lib/lsan/lsan_thread.cc | 4 +- lib/lsan/lsan_thread.h | 2 +- test/lsan/TestCases/Darwin/dispatch.mm | 59 ++++++++++ test/lsan/TestCases/Darwin/lit.local.cfg | 9 ++ test/lsan/lit.common.cfg | 2 +- 10 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 lib/lsan/lsan_mac.cc create mode 100644 test/lsan/TestCases/Darwin/dispatch.mm create mode 100644 test/lsan/TestCases/Darwin/lit.local.cfg diff --git a/lib/asan/weak_symbols.txt b/lib/asan/weak_symbols.txt index ba7b0272c..fe680f8a9 100644 --- a/lib/asan/weak_symbols.txt +++ b/lib/asan/weak_symbols.txt @@ -1,3 +1,12 @@ ___asan_default_options ___asan_default_suppressions ___asan_on_error +___asan_set_shadow_00 +___asan_set_shadow_f1 +___asan_set_shadow_f2 +___asan_set_shadow_f3 +___asan_set_shadow_f4 +___asan_set_shadow_f5 +___asan_set_shadow_f6 +___asan_set_shadow_f7 +___asan_set_shadow_f8 diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index 55c825f5c..bd3a96f32 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -13,6 +13,7 @@ set(LSAN_SOURCES lsan_allocator.cc lsan_linux.cc lsan_interceptors.cc + lsan_mac.cc lsan_malloc_mac.cc lsan_preinit.cc lsan_thread.cc) diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h index 1061d2fcf..7446e9507 100644 --- a/lib/lsan/lsan.h +++ b/lib/lsan/lsan.h @@ -38,6 +38,8 @@ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ common_flags()->fast_unwind_on_malloc) +#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true) + namespace __lsan { void InitializeInterceptors(); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 114dd8c90..adde3a1b4 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -79,8 +79,7 @@ void EnableInThisThread() { u32 GetCurrentThread() { thread_local_data_t *data = get_tls_val(false); - CHECK(data); - return data->current_thread_id; + return data ? data->current_thread_id : kInvalidTid; } void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } diff --git a/lib/lsan/lsan_mac.cc b/lib/lsan/lsan_mac.cc new file mode 100644 index 000000000..1a6f5f489 --- /dev/null +++ b/lib/lsan/lsan_mac.cc @@ -0,0 +1,192 @@ +//===-- lsan_mac.cc -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer, a memory leak checker. +// +// Mac-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_MAC + +#include "interception/interception.h" +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_thread.h" + +#include + +namespace __lsan { +// Support for the following functions from libdispatch on Mac OS: +// dispatch_async_f() +// dispatch_async() +// dispatch_sync_f() +// dispatch_sync() +// dispatch_after_f() +// dispatch_after() +// dispatch_group_async_f() +// dispatch_group_async() +// TODO(glider): libdispatch API contains other functions that we don't support +// yet. +// +// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are +// they can cause jobs to run on a thread different from the current one. +// TODO(glider): if so, we need a test for this (otherwise we should remove +// them). +// +// The following functions use dispatch_barrier_async_f() (which isn't a library +// function but is exported) and are thus supported: +// dispatch_source_set_cancel_handler_f() +// dispatch_source_set_cancel_handler() +// dispatch_source_set_event_handler_f() +// dispatch_source_set_event_handler() +// +// The reference manual for Grand Central Dispatch is available at +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// The implementation details are at +// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c + +typedef void *dispatch_group_t; +typedef void *dispatch_queue_t; +typedef void *dispatch_source_t; +typedef u64 dispatch_time_t; +typedef void (*dispatch_function_t)(void *block); +typedef void *(*worker_t)(void *block); + +// A wrapper for the ObjC blocks used to support libdispatch. +typedef struct { + void *block; + dispatch_function_t func; + u32 parent_tid; +} lsan_block_context_t; + +ALWAYS_INLINE +void lsan_register_worker_thread(int parent_tid) { + if (GetCurrentThread() == kInvalidTid) { + u32 tid = ThreadCreate(parent_tid, 0, true); + ThreadStart(tid, GetTid()); + SetCurrentThread(tid); + } +} + +// For use by only those functions that allocated the context via +// alloc_lsan_context(). +extern "C" void lsan_dispatch_call_block_and_release(void *block) { + lsan_block_context_t *context = (lsan_block_context_t *)block; + VReport(2, + "lsan_dispatch_call_block_and_release(): " + "context: %p, pthread_self: %p\n", + block, pthread_self()); + lsan_register_worker_thread(context->parent_tid); + // Call the original dispatcher for the block. + context->func(context->block); + lsan_free(context); +} + +} // namespace __lsan + +using namespace __lsan; // NOLINT + +// Wrap |ctxt| and |func| into an lsan_block_context_t. +// The caller retains control of the allocated context. +extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt, + dispatch_function_t func) { + GET_STACK_TRACE_THREAD; + lsan_block_context_t *lsan_ctxt = + (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack); + lsan_ctxt->block = ctxt; + lsan_ctxt->func = func; + lsan_ctxt->parent_tid = GetCurrentThread(); + return lsan_ctxt; +} + +// Define interceptor for dispatch_*_f function with the three most common +// parameters: dispatch_queue_t, context, dispatch_function_t. +#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ + INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ + dispatch_function_t func) { \ + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \ + return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt, \ + lsan_dispatch_call_block_and_release); \ + } + +INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) + +INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, + void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt, + lsan_dispatch_call_block_and_release); +} + +INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, + dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + REAL(dispatch_group_async_f) + (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release); +} + +#if !defined(MISSING_BLOCKS_SUPPORT) +extern "C" { +void dispatch_async(dispatch_queue_t dq, void (^work)(void)); +void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, + void (^work)(void)); +void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)); +void dispatch_source_set_cancel_handler(dispatch_source_t ds, + void (^work)(void)); +void dispatch_source_set_event_handler(dispatch_source_t ds, + void (^work)(void)); +} + +#define GET_LSAN_BLOCK(work) \ + void (^lsan_block)(void); \ + int parent_tid = GetCurrentThread(); \ + lsan_block = ^(void) { \ + lsan_register_worker_thread(parent_tid); \ + work(); \ + } + +INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_async)(dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, + dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_group_async)(dg, dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_after)(when, queue, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, + void (^work)(void)) { + if (!work) { + REAL(dispatch_source_set_cancel_handler)(ds, work); + return; + } + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_cancel_handler)(ds, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_event_handler)(ds, lsan_block); +} +#endif + +#endif // SANITIZER_MAC diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc index 0ea7a6e97..4404c8cc5 100644 --- a/lib/lsan/lsan_thread.cc +++ b/lib/lsan/lsan_thread.cc @@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { /* arg */ nullptr); } -void ThreadStart(u32 tid, tid_t os_id) { +void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { OnStartedArgs args; uptr stack_size = 0; uptr tls_size = 0; @@ -87,7 +87,7 @@ void ThreadStart(u32 tid, tid_t os_id) { args.tls_end = args.tls_begin + tls_size; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args); + thread_registry->StartThread(tid, os_id, workerthread, &args); } void ThreadFinish() { diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h index 73e080e26..b16d3d915 100644 --- a/lib/lsan/lsan_thread.h +++ b/lib/lsan/lsan_thread.h @@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase { void InitializeThreadRegistry(); -void ThreadStart(u32 tid, tid_t os_id); +void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false); void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); diff --git a/test/lsan/TestCases/Darwin/dispatch.mm b/test/lsan/TestCases/Darwin/dispatch.mm new file mode 100644 index 000000000..606cc9e1c --- /dev/null +++ b/test/lsan/TestCases/Darwin/dispatch.mm @@ -0,0 +1,59 @@ +// Test for threads spawned with wqthread_start +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -DDISPATCH_ASYNC -o %t-async -framework Foundation +// RUN: %clangxx_lsan %s -DDISPATCH_SYNC -o %t-sync -framework Foundation +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-async 2>&1 | FileCheck %s +// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-sync 2>&1 | FileCheck %s + +#include +#include +#include + +#include "sanitizer_common/print_address.h" + +bool done = false; + +void worker_do_leak(int size) { + void *p = malloc(size); + print_address("Test alloc: ", 1, p); + done = true; +} + +#if DISPATCH_ASYNC +// Tests for the Grand Central Dispatch. See +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// for the reference. +void TestGCDDispatch() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block = ^{ + worker_do_leak(1337); + }; + // dispatch_async() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that LeakSanitizer notices that the + // thread has started. + dispatch_async(queue, block); + while (!done) + pthread_yield_np(); +} +#elif DISPATCH_SYNC +void TestGCDDispatch() { + dispatch_queue_t queue = dispatch_get_global_queue(2, 0); + dispatch_block_t block = ^{ + worker_do_leak(1337); + }; + // dispatch_sync() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that LeakSanitizer notices that the + // thread has started. + dispatch_sync(queue, block); +} +#endif + +int main() { + TestGCDDispatch(); + return 0; +} + +// CHECK: Test alloc: [[addr:0x[0-9,a-f]+]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[addr]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/Darwin/lit.local.cfg b/test/lsan/TestCases/Darwin/lit.local.cfg new file mode 100644 index 000000000..a85dfcd24 --- /dev/null +++ b/test/lsan/TestCases/Darwin/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os not in ['Darwin']: + config.unsupported = True diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 309e8f27b..610b1b1ad 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -77,4 +77,4 @@ if not (supported_linux or supported_darwin): if re.search('mthumb', config.target_cflags) is not None: config.unsupported = True -config.suffixes = ['.c', '.cc', '.cpp'] +config.suffixes = ['.c', '.cc', '.cpp', '.mm'] -- cgit v1.2.1 From 9cbbe014c4d99e31fce00f40cfbecf3799872d2e Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 19 Jun 2017 21:42:44 +0000 Subject: [asan] Fix android setup script to overwrite the symlink. This fixes asan_device_setup failing to update an existing asan installation. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305746 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index c807df3cd..79ac2f916 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -410,15 +410,15 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then install "$TMPDIR/asanwrapper" /system/bin 755 install "$TMPDIR/asanwrapper64" /system/bin 755 - adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK - adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK + adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK + adb_shell ln -sf $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK else install "$TMPDIR/$ASAN_RT" /system/lib 644 install "$TMPDIR/app_process32" /system/bin 755 $CTX install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX install "$TMPDIR/asanwrapper" /system/bin 755 $CTX - adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK + adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK adb_shell rm /system/bin/app_process adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process -- cgit v1.2.1 From 4f2195f82b6124970cefd89e4ae0e179e7b99381 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 20 Jun 2017 19:16:41 +0000 Subject: [ASan] Disable allocator_oom_test.cc on s390 Summary: ASan shadow memory on s390 is larger than other configurations, let's disable this test for now (will revisit it later). Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34414 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305822 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/allocator_oom_test.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/asan/TestCases/Linux/allocator_oom_test.cc b/test/asan/TestCases/Linux/allocator_oom_test.cc index c93e9fe21..4c696f325 100644 --- a/test/asan/TestCases/Linux/allocator_oom_test.cc +++ b/test/asan/TestCases/Linux/allocator_oom_test.cc @@ -28,6 +28,9 @@ // RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC-REALLOC,CHECK-NULL +// ASan shadow memory on s390 is too large for this test. +// UNSUPPORTED: s390 + #include #include #include -- cgit v1.2.1 From c13d2469d55325c30566bff7db800053e1bca2ca Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 20 Jun 2017 21:23:02 +0000 Subject: [Sanitizers] Move cached allocator_may_return_null flag to sanitizer_allocator Summary: Move cached allocator_may_return_null flag to sanitizer_allocator.cc and provide API to consolidate and unify the behavior of all specific allocators. Make all sanitizers using CombinedAllocator to follow AllocatorReturnNullOrDieOnOOM() rules to behave the same way when OOM happens. When OOM happens, turn allocator_out_of_memory flag on regardless of allocator_may_return_null flag value (it used to not to be set when allocator_may_return_null == true). release_to_os_interval_ms and rss_limit_exceeded will likely be moved to sanitizer_allocator.cc too (later). Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34310 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305858 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 17 ++++---- lib/lsan/lsan_allocator.cc | 2 +- lib/msan/msan_allocator.cc | 9 ++-- lib/sanitizer_common/sanitizer_allocator.cc | 47 +++++++++++++++++---- lib/sanitizer_common/sanitizer_allocator.h | 26 +++++++++--- .../sanitizer_allocator_combined.h | 49 ++++++---------------- .../sanitizer_allocator_internal.h | 3 +- .../sanitizer_allocator_secondary.h | 35 ++++------------ .../sanitizer_symbolizer_posix_libcdep.cc | 2 +- .../tests/sanitizer_allocator_test.cc | 21 +++++----- lib/scudo/scudo_allocator.cpp | 15 ++++--- lib/scudo/scudo_allocator_combined.h | 18 +------- lib/scudo/scudo_allocator_secondary.h | 12 +----- lib/tsan/rtl/tsan_mman.cc | 9 ++-- 14 files changed, 127 insertions(+), 138 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index a93a196cb..57651f49c 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -266,7 +266,8 @@ struct Allocator { } void Initialize(const AllocatorOptions &options) { - allocator.Init(options.may_return_null, options.release_to_os_interval_ms); + SetAllocatorMayReturnNull(options.may_return_null); + allocator.Init(options.release_to_os_interval_ms); SharedInitCode(options); } @@ -302,7 +303,7 @@ struct Allocator { } void ReInitialize(const AllocatorOptions &options) { - allocator.SetMayReturnNull(options.may_return_null); + SetAllocatorMayReturnNull(options.may_return_null); allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms); SharedInitCode(options); @@ -323,7 +324,7 @@ struct Allocator { options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10; options->min_redzone = atomic_load(&min_redzone, memory_order_acquire); options->max_redzone = atomic_load(&max_redzone, memory_order_acquire); - options->may_return_null = allocator.MayReturnNull(); + options->may_return_null = AllocatorMayReturnNull(); options->alloc_dealloc_mismatch = atomic_load(&alloc_dealloc_mismatch, memory_order_acquire); options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs(); @@ -374,7 +375,7 @@ struct Allocator { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); if (RssLimitExceeded()) - return allocator.ReturnNullOrDieOnOOM(); + return AsanAllocator::FailureHandler::OnOOM(); Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; @@ -407,7 +408,7 @@ struct Allocator { if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", (void*)size); - return allocator.ReturnNullOrDieOnBadRequest(); + return AsanAllocator::FailureHandler::OnBadRequest(); } AsanThread *t = GetCurrentThread(); @@ -420,8 +421,8 @@ struct Allocator { AllocatorCache *cache = &fallback_allocator_cache; allocated = allocator.Allocate(cache, needed_size, 8); } - - if (!allocated) return allocator.ReturnNullOrDieOnOOM(); + if (!allocated) + return nullptr; if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) { // Heap poisoning is enabled, but the allocator provides an unpoisoned @@ -632,7 +633,7 @@ struct Allocator { void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return allocator.ReturnNullOrDieOnBadRequest(); + return AsanAllocator::FailureHandler::OnBadRequest(); void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); // If the memory comes from the secondary allocator no need to clear it // as it comes directly from mmap. diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index acff1f5ae..f54e95373 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -38,8 +38,8 @@ typedef CombinedAllocatorallocator_may_return_null); allocator.InitLinkerInitialized( - common_flags()->allocator_may_return_null, common_flags()->allocator_release_to_os_interval_ms); } diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 8d6cc69a4..d0f478afc 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -119,9 +119,8 @@ static AllocatorCache fallback_allocator_cache; static SpinMutex fallback_mutex; void MsanAllocatorInit() { - allocator.Init( - common_flags()->allocator_may_return_null, - common_flags()->allocator_release_to_os_interval_ms); + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); + allocator.Init(common_flags()->allocator_release_to_os_interval_ms); } AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) { @@ -139,7 +138,7 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, if (size > kMaxAllowedMallocSize) { Report("WARNING: MemorySanitizer failed to allocate %p bytes\n", (void *)size); - return allocator.ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); } MsanThread *t = GetCurrentThread(); void *allocated; @@ -197,7 +196,7 @@ void MsanDeallocate(StackTrace *stack, void *p) { void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return allocator.ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true); } diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index 15d01de86..db3ebb033 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -94,8 +94,7 @@ InternalAllocator *internal_allocator() { SpinMutexLock l(&internal_alloc_init_mu); if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == 0) { - internal_allocator_instance->Init( - /* may_return_null */ false, kReleaseToOSIntervalNever); + internal_allocator_instance->Init(kReleaseToOSIntervalNever); atomic_store(&internal_allocator_initialized, 1, memory_order_release); } } @@ -162,7 +161,7 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { if (CallocShouldReturnNullDueToOverflow(count, size)) - return internal_allocator()->ReturnNullOrDieOnBadRequest(); + return InternalAllocator::FailureHandler::OnBadRequest(); void *p = InternalAlloc(count * size, cache); if (p) internal_memset(p, 0, count * size); return p; @@ -209,12 +208,15 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) { return (max / size) < n; } -static atomic_uint8_t reporting_out_of_memory = {0}; +static atomic_uint8_t allocator_out_of_memory = {0}; +static atomic_uint8_t allocator_may_return_null = {0}; -bool IsReportingOOM() { return atomic_load_relaxed(&reporting_out_of_memory); } +bool IsAllocatorOutOfMemory() { + return atomic_load_relaxed(&allocator_out_of_memory); +} -void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) { - if (out_of_memory) atomic_store_relaxed(&reporting_out_of_memory, 1); +// Prints error message and kills the program. +void NORETURN ReportAllocatorCannotReturnNull() { Report("%s's allocator is terminating the process instead of returning 0\n", SanitizerToolName); Report("If you don't like this behavior set allocator_may_return_null=1\n"); @@ -222,4 +224,35 @@ void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) { Die(); } +bool AllocatorMayReturnNull() { + return atomic_load(&allocator_may_return_null, memory_order_relaxed); +} + +void SetAllocatorMayReturnNull(bool may_return_null) { + atomic_store(&allocator_may_return_null, may_return_null, + memory_order_relaxed); +} + +void *ReturnNullOrDieOnFailure::OnBadRequest() { + if (AllocatorMayReturnNull()) + return nullptr; + ReportAllocatorCannotReturnNull(); +} + +void *ReturnNullOrDieOnFailure::OnOOM() { + atomic_store_relaxed(&allocator_out_of_memory, 1); + if (AllocatorMayReturnNull()) + return nullptr; + ReportAllocatorCannotReturnNull(); +} + +void *DieOnFailure::OnBadRequest() { + ReportAllocatorCannotReturnNull(); +} + +void *DieOnFailure::OnOOM() { + atomic_store_relaxed(&allocator_out_of_memory, 1); + ReportAllocatorCannotReturnNull(); +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index 9a37a2f21..f59c13d1c 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -24,12 +24,28 @@ namespace __sanitizer { -// Returns true if ReportAllocatorCannotReturnNull(true) was called. -// Can be use to avoid memory hungry operations. -bool IsReportingOOM(); +// Since flags are immutable and allocator behavior can be changed at runtime +// (unit tests or ASan on Android are some examples), allocator_may_return_null +// flag value is cached here and can be altered later. +bool AllocatorMayReturnNull(); +void SetAllocatorMayReturnNull(bool may_return_null); -// Prints error message and kills the program. -void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory); +// Allocator failure handling policies: +// Implements AllocatorMayReturnNull policy, returns null when the flag is set, +// dies otherwise. +struct ReturnNullOrDieOnFailure { + static void *OnBadRequest(); + static void *OnOOM(); +}; +// Always dies on the failure. +struct DieOnFailure { + static void *OnBadRequest(); + static void *OnOOM(); +}; + +// Returns true if allocator detected OOM condition. Can be used to avoid memory +// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called. +bool IsAllocatorOutOfMemory(); // Allocators call these callbacks on mmap/munmap. struct NoOpMapUnmapCallback { diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h index 90ccb1771..efd25cadf 100644 --- a/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -24,22 +24,18 @@ template // NOLINT class CombinedAllocator { public: - void InitCommon(bool may_return_null, s32 release_to_os_interval_ms) { - primary_.Init(release_to_os_interval_ms); - atomic_store(&may_return_null_, may_return_null, memory_order_relaxed); - } + typedef typename SecondaryAllocator::FailureHandler FailureHandler; - void InitLinkerInitialized( - bool may_return_null, s32 release_to_os_interval_ms) { - secondary_.InitLinkerInitialized(may_return_null); + void InitLinkerInitialized(s32 release_to_os_interval_ms) { + primary_.Init(release_to_os_interval_ms); + secondary_.InitLinkerInitialized(); stats_.InitLinkerInitialized(); - InitCommon(may_return_null, release_to_os_interval_ms); } - void Init(bool may_return_null, s32 release_to_os_interval_ms) { - secondary_.Init(may_return_null); + void Init(s32 release_to_os_interval_ms) { + primary_.Init(release_to_os_interval_ms); + secondary_.Init(); stats_.Init(); - InitCommon(may_return_null, release_to_os_interval_ms); } void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) { @@ -47,7 +43,7 @@ class CombinedAllocator { if (size == 0) size = 1; if (size + alignment < size) - return ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); uptr original_size = size; // If alignment requirements are to be fulfilled by the frontend allocator // rather than by the primary or secondary, passing an alignment lower than @@ -55,44 +51,24 @@ class CombinedAllocator { // alignment check. if (alignment > 8) size = RoundUpTo(size, alignment); - void *res; - bool from_primary = primary_.CanAllocate(size, alignment); // The primary allocator should return a 2^x aligned allocation when // requested 2^x bytes, hence using the rounded up 'size' when being // serviced by the primary (this is no longer true when the primary is // using a non-fixed base address). The secondary takes care of the // alignment without such requirement, and allocating 'size' would use // extraneous memory, so we employ 'original_size'. - if (from_primary) + void *res; + if (primary_.CanAllocate(size, alignment)) res = cache->Allocate(&primary_, primary_.ClassID(size)); else res = secondary_.Allocate(&stats_, original_size, alignment); + if (!res) + return FailureHandler::OnOOM(); if (alignment > 8) CHECK_EQ(reinterpret_cast(res) & (alignment - 1), 0); return res; } - bool MayReturnNull() const { - return atomic_load(&may_return_null_, memory_order_acquire); - } - - void *ReturnNullOrDieOnBadRequest() { - if (MayReturnNull()) - return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (MayReturnNull()) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - - void SetMayReturnNull(bool may_return_null) { - secondary_.SetMayReturnNull(may_return_null); - atomic_store(&may_return_null_, may_return_null, memory_order_release); - } - s32 ReleaseToOSIntervalMs() const { return primary_.ReleaseToOSIntervalMs(); } @@ -213,6 +189,5 @@ class CombinedAllocator { PrimaryAllocator primary_; SecondaryAllocator secondary_; AllocatorGlobalStats stats_; - atomic_uint8_t may_return_null_; }; diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h index d1890f20f..a791d0d94 100644 --- a/lib/sanitizer_common/sanitizer_allocator_internal.h +++ b/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -47,7 +47,8 @@ typedef SizeClassAllocatorLocalCache InternalAllocatorCache; typedef CombinedAllocator > InternalAllocator; + LargeMmapAllocator + > InternalAllocator; void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr, uptr alignment = 0); diff --git a/lib/sanitizer_common/sanitizer_allocator_secondary.h b/lib/sanitizer_common/sanitizer_allocator_secondary.h index 2c69f47ec..261dfb5e1 100644 --- a/lib/sanitizer_common/sanitizer_allocator_secondary.h +++ b/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -17,17 +17,19 @@ // This class can (de)allocate only large chunks of memory using mmap/unmap. // The main purpose of this allocator is to cover large and rare allocation // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64). -template +template class LargeMmapAllocator { public: - void InitLinkerInitialized(bool may_return_null) { + typedef FailureHandlerT FailureHandler; + + void InitLinkerInitialized() { page_size_ = GetPageSizeCached(); - atomic_store(&may_return_null_, may_return_null, memory_order_relaxed); } - void Init(bool may_return_null) { + void Init() { internal_memset(this, 0, sizeof(*this)); - InitLinkerInitialized(may_return_null); + InitLinkerInitialized(); } void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) { @@ -37,11 +39,11 @@ class LargeMmapAllocator { map_size += alignment; // Overflow. if (map_size < size) - return ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); uptr map_beg = reinterpret_cast( MmapOrDieOnFatalError(map_size, "LargeMmapAllocator")); if (!map_beg) - return ReturnNullOrDieOnOOM(); + return FailureHandler::OnOOM(); CHECK(IsAligned(map_beg, page_size_)); MapUnmapCallback().OnMap(map_beg, map_size); uptr map_end = map_beg + map_size; @@ -75,24 +77,6 @@ class LargeMmapAllocator { return reinterpret_cast(res); } - bool MayReturnNull() const { - return atomic_load(&may_return_null_, memory_order_acquire); - } - - void *ReturnNullOrDieOnBadRequest() { - if (MayReturnNull()) return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (MayReturnNull()) return nullptr; - ReportAllocatorCannotReturnNull(true); - } - - void SetMayReturnNull(bool may_return_null) { - atomic_store(&may_return_null_, may_return_null, memory_order_release); - } - void Deallocate(AllocatorStats *stat, void *p) { Header *h = GetHeader(p); { @@ -278,7 +262,6 @@ class LargeMmapAllocator { struct Stats { uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64]; } stats; - atomic_uint8_t may_return_null_; SpinMutex mutex_; }; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index d3c77b510..60ec7506c 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -495,7 +495,7 @@ static void ChooseSymbolizerTools(IntrusiveList *list, VReport(2, "Symbolizer is disabled.\n"); return; } - if (IsReportingOOM()) { + if (IsAllocatorOutOfMemory()) { VReport(2, "Cannot use internal symbolizer: out of memory\n"); } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { VReport(2, "Using internal symbolizer.\n"); diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index b28159a2a..f256d8776 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -426,8 +426,8 @@ TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) { TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) { TestMapUnmapCallback::map_count = 0; TestMapUnmapCallback::unmap_count = 0; - LargeMmapAllocator a; - a.Init(/* may_return_null */ false); + LargeMmapAllocator a; + a.Init(); AllocatorStats stats; stats.Init(); void *x = a.Allocate(&stats, 1 << 20, 1); @@ -463,8 +463,8 @@ TEST(SanitizerCommon, SizeClassAllocator64Overflow) { #endif TEST(SanitizerCommon, LargeMmapAllocator) { - LargeMmapAllocator<> a; - a.Init(/* may_return_null */ false); + LargeMmapAllocator a; + a.Init(); AllocatorStats stats; stats.Init(); @@ -546,8 +546,9 @@ void TestCombinedAllocator() { typedef CombinedAllocator Allocator; + SetAllocatorMayReturnNull(true); Allocator *a = new Allocator; - a->Init(/* may_return_null */ true, kReleaseToOSIntervalNever); + a->Init(kReleaseToOSIntervalNever); std::mt19937 r; AllocatorCache cache; @@ -561,7 +562,7 @@ void TestCombinedAllocator() { EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0); // Set to false - a->SetMayReturnNull(false); + SetAllocatorMayReturnNull(false); EXPECT_DEATH(a->Allocate(&cache, -1, 1), "allocator is terminating the process"); @@ -873,8 +874,8 @@ TEST(SanitizerCommon, SizeClassAllocator32Iteration) { } TEST(SanitizerCommon, LargeMmapAllocatorIteration) { - LargeMmapAllocator<> a; - a.Init(/* may_return_null */ false); + LargeMmapAllocator a; + a.Init(); AllocatorStats stats; stats.Init(); @@ -900,8 +901,8 @@ TEST(SanitizerCommon, LargeMmapAllocatorIteration) { } TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) { - LargeMmapAllocator<> a; - a.Init(/* may_return_null */ false); + LargeMmapAllocator a; + a.Init(); AllocatorStats stats; stats.Init(); diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index ce69ddf55..1d0db84a5 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -273,6 +273,8 @@ struct ScudoAllocator { static const uptr MaxAllowedMallocSize = FIRST_32_SECOND_64(2UL << 30, 1ULL << 40); + typedef ReturnNullOrDieOnFailure FailureHandler; + ScudoBackendAllocator BackendAllocator; ScudoQuarantine AllocatorQuarantine; @@ -326,7 +328,8 @@ struct ScudoAllocator { DeallocationTypeMismatch = Options.DeallocationTypeMismatch; DeleteSizeMismatch = Options.DeleteSizeMismatch; ZeroContents = Options.ZeroContents; - BackendAllocator.Init(Options.MayReturnNull, Options.ReleaseToOSIntervalMs); + SetAllocatorMayReturnNull(Options.MayReturnNull); + BackendAllocator.Init(Options.ReleaseToOSIntervalMs); AllocatorQuarantine.Init( static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); @@ -354,11 +357,11 @@ struct ScudoAllocator { dieWithMessage("ERROR: alignment is not a power of 2\n"); } if (Alignment > MaxAlignment) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); if (Alignment < MinAlignment) Alignment = MinAlignment; if (Size >= MaxAllowedMallocSize) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); if (Size == 0) Size = 1; @@ -366,7 +369,7 @@ struct ScudoAllocator { uptr AlignedSize = (Alignment > MinAlignment) ? NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; if (AlignedSize >= MaxAllowedMallocSize) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); // Primary and Secondary backed allocations have a different treatment. We // deal with alignment requirements of Primary serviced allocations here, @@ -391,7 +394,7 @@ struct ScudoAllocator { AllocationAlignment, FromPrimary); } if (!Ptr) - return BackendAllocator.ReturnNullOrDieOnOOM(); + return FailureHandler::OnOOM(); // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && FromPrimary) @@ -583,7 +586,7 @@ struct ScudoAllocator { initThreadMaybe(); uptr Total = NMemB * Size; if (Size != 0 && Total / Size != NMemB) // Overflow check - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); return allocate(Total, MinAlignment, FromMalloc, true); } diff --git a/lib/scudo/scudo_allocator_combined.h b/lib/scudo/scudo_allocator_combined.h index c978db55a..21c45897b 100644 --- a/lib/scudo/scudo_allocator_combined.h +++ b/lib/scudo/scudo_allocator_combined.h @@ -23,11 +23,10 @@ template class ScudoCombinedAllocator { public: - void Init(bool AllocatorMayReturnNull, s32 ReleaseToOSIntervalMs) { + void Init(s32 ReleaseToOSIntervalMs) { Primary.Init(ReleaseToOSIntervalMs); - Secondary.Init(AllocatorMayReturnNull); + Secondary.Init(); Stats.Init(); - atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); } void *Allocate(AllocatorCache *Cache, uptr Size, uptr Alignment, @@ -37,18 +36,6 @@ class ScudoCombinedAllocator { return Secondary.Allocate(&Stats, Size, Alignment); } - void *ReturnNullOrDieOnBadRequest() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - void Deallocate(AllocatorCache *Cache, void *Ptr, bool FromPrimary) { if (FromPrimary) Cache->Deallocate(&Primary, Primary.GetSizeClass(Ptr), Ptr); @@ -78,7 +65,6 @@ class ScudoCombinedAllocator { PrimaryAllocator Primary; SecondaryAllocator Secondary; AllocatorGlobalStats Stats; - atomic_uint8_t MayReturnNull; }; #endif // SCUDO_ALLOCATOR_COMBINED_H_ diff --git a/lib/scudo/scudo_allocator_secondary.h b/lib/scudo/scudo_allocator_secondary.h index 2950909b5..dbfb22565 100644 --- a/lib/scudo/scudo_allocator_secondary.h +++ b/lib/scudo/scudo_allocator_secondary.h @@ -24,9 +24,8 @@ class ScudoLargeMmapAllocator { public: - void Init(bool AllocatorMayReturnNull) { + void Init() { PageSize = GetPageSizeCached(); - atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); } void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) { @@ -42,7 +41,7 @@ class ScudoLargeMmapAllocator { uptr MapBeg = reinterpret_cast(MmapNoAccess(MapSize)); if (MapBeg == ~static_cast(0)) - return ReturnNullOrDieOnOOM(); + return ReturnNullOrDieOnFailure::OnOOM(); // A page-aligned pointer is assumed after that, so check it now. CHECK(IsAligned(MapBeg, PageSize)); uptr MapEnd = MapBeg + MapSize; @@ -96,12 +95,6 @@ class ScudoLargeMmapAllocator { return reinterpret_cast(Ptr); } - void *ReturnNullOrDieOnOOM() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - void Deallocate(AllocatorStats *Stats, void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); { @@ -140,7 +133,6 @@ class ScudoLargeMmapAllocator { const uptr HeadersSize = SecondaryHeaderSize + AlignedChunkHeaderSize; uptr PageSize; SpinMutex StatsMutex; - atomic_uint8_t MayReturnNull; }; #endif // SCUDO_ALLOCATOR_SECONDARY_H_ diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 2dea24915..fa0d0cafe 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -112,9 +112,8 @@ ScopedGlobalProcessor::~ScopedGlobalProcessor() { } void InitializeAllocator() { - allocator()->Init( - common_flags()->allocator_may_return_null, - common_flags()->allocator_release_to_os_interval_ms); + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); + allocator()->Init(common_flags()->allocator_release_to_os_interval_ms); } void InitializeAllocatorLate() { @@ -151,7 +150,7 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) - return allocator()->ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); if (p == 0) return 0; @@ -164,7 +163,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { if (CallocShouldReturnNullDueToOverflow(size, n)) - return allocator()->ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); void *p = user_alloc(thr, pc, n * size); if (p) internal_memset(p, 0, n * size); -- cgit v1.2.1 From f7b4c29b512605bb3e57e9e59c8825eccab30562 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 21 Jun 2017 00:56:31 +0000 Subject: [asan] Fix android compiler wrapper lost in r301617. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305870 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 063c33b02..e25dd297a 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -114,6 +114,7 @@ asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir") if config.android == "1": config.available_features.add('android') compile_wrapper = os.path.join(asan_lit_source_dir, "android_commands", "android_compile.py") + " " + config.compile_wrapper = compile_wrapper else: config.available_features.add('not-android') -- cgit v1.2.1 From 5866aaba94362547a6a9c0d7f8f8eb2e52ecc9c8 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 21 Jun 2017 01:10:23 +0000 Subject: Revert "[compiler-rt] Don't reset non-default user handler if allow_user_segv_handler is true." Summary: On Android we still need to reset preinstalled handlers and allow use handlers later. This reverts commit r304039. Reviewers: eugenis Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D34434 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305871 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 20 +---------- test/asan/TestCases/Linux/preinstalled_signal.cc | 44 +++++++++++++----------- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 5b1d53698..e113fb109 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -189,25 +189,7 @@ void UnsetAlternateSignalStack() { static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { - 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; - } + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc index 40dadf43d..4d466c21f 100644 --- a/test/asan/TestCases/Linux/preinstalled_signal.cc +++ b/test/asan/TestCases/Linux/preinstalled_signal.cc @@ -4,11 +4,13 @@ // 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=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HANDLER +// 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_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=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ACTION +// 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 // REQUIRES: asan-dynamic-runtime @@ -51,22 +53,22 @@ int InternalSigaction(int sig, KernelSigaction *act, KernelSigaction *oact) { return syscall(__NR_rt_sigaction, sig, act, oact, NSIG / 8); } -struct KernelSigaction sigact = {}; +struct KernelSigaction pre_asan = {}; static void Init() { - int res = InternalSigaction(SIGSEGV, nullptr, &sigact); + int res = InternalSigaction(SIGSEGV, nullptr, &pre_asan); assert(res >= 0); - assert(sigact.handler == SIG_DFL || sigact.handler == SIG_IGN); + assert(pre_asan.handler == SIG_DFL || pre_asan.handler == SIG_IGN); #if defined(TEST_INSTALL_SIG_HANDLER) - sigact = {}; - sigact.handler = &SigHandler; - res = InternalSigaction(SIGSEGV, &sigact, nullptr); + pre_asan = {}; + pre_asan.handler = &SigHandler; + res = InternalSigaction(SIGSEGV, &pre_asan, 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); + pre_asan = {}; + pre_asan.flags = SA_SIGINFO | SA_NODEFER; + pre_asan.handler = (__sighandler_t)&SigAction; + res = InternalSigaction(SIGSEGV, &pre_asan, nullptr); assert(res >= 0); #endif } @@ -74,21 +76,21 @@ static void Init() { __attribute__((section(".preinit_array"), used)) void (*__local_test_preinit)(void) = Init; -bool ShouldAsanInstallHandlers() { +bool ExpectUserHandler() { #if defined(TEST_INSTALL_SIG_HANDLER) || defined(TEST_INSTALL_SIG_ACTION) - return !strcmp(getenv("ASAN_OPTIONS"), "handle_segv=2"); + return !strcmp(getenv("ASAN_OPTIONS"), "handle_segv=0"); #endif - return true; + return false; } int main(int argc, char *argv[]) { - KernelSigaction sigact_asan = {}; - InternalSigaction(SIGSEGV, nullptr, &sigact_asan); + KernelSigaction post_asan = {}; + InternalSigaction(SIGSEGV, nullptr, &post_asan); - assert(sigact_asan.handler != SIG_DFL); - assert(sigact_asan.handler != SIG_IGN); - assert(ShouldAsanInstallHandlers() == - (sigact_asan.handler != sigact.handler)); + assert(post_asan.handler != SIG_DFL); + assert(post_asan.handler != SIG_IGN); + assert(ExpectUserHandler() == + (post_asan.handler == pre_asan.handler)); raise(SIGSEGV); printf("%s\n", handler); -- cgit v1.2.1 From d75d4f58e625a84ca1961e51cbc02276b7ebdc65 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Wed, 21 Jun 2017 11:29:15 +0000 Subject: [mips][compiler-rt] Fix build breakage. Change some reinterpret_casts to c-style casts due to template instantiation restrictions and build breakage due to missing paranthesises. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305899 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_atomic_clang.h | 3 +-- lib/sanitizer_common/sanitizer_atomic_clang_other.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h index 47581282a..65b3a38f0 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -82,8 +82,7 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, if (sizeof(*a) == 8) { Type volatile *val_ptr = const_cast(&a->val_dont_use); prev = __mips_sync_val_compare_and_swap( - reinterpret_cast(val_ptr), reinterpret_cast cmpv, - reinterpret_cast xchg); + reinterpret_cast(val_ptr), (u64)cmpv, (u64)xchg); } else { prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); } diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h index 2825c7400..d2acc311b 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -145,8 +145,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { typename T::Type volatile *val_ptr = const_cast(&a->val_dont_use); cur = __mips_sync_val_compare_and_swap( - reinterpret_cast(val_ptr), reinterpret_cast cmp, - reinterpret_cast v); + reinterpret_cast(val_ptr), (u64)cmp, (u64)v); #else cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); #endif -- cgit v1.2.1 From a7d94d30c9484f514213292f9e6f8b8bb9ef0908 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 21 Jun 2017 15:56:03 +0000 Subject: [sanitizer] Add a function to gather random bytes Summary: AFAICT compiler-rt doesn't have a function that would return 'good' random bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses returned by `mmap` to seed its PRNG, which is not ideal, and `SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit counterpart address space, so right now it has nothing. This function aims at solving this, allowing to implement good 32-bit chunk randomization. Scudo also has a function that does this for Cookie purposes, which would go away in a later CL once this lands. This function will try the `getrandom` syscall if available, and fallback to `/dev/urandom` if not. Unfortunately, I do not have a way to implement and test a Mac and Windows version, so those are unimplemented as of now. Note that `kRandomShuffleChunks` is only used on Linux for now. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: zturner, rnk, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34412 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 4 ++++ lib/sanitizer_common/sanitizer_linux.cc | 26 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_mac.cc | 5 +++++ lib/sanitizer_common/sanitizer_win.cc | 5 +++++ .../tests/sanitizer_common_test.cc | 17 ++++++++++++++ 5 files changed, 57 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 875a46009..46678b4ad 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -919,6 +919,10 @@ const s32 kReleaseToOSIntervalNever = -1; void CheckNoDeepBind(const char *filename, int flag); +// Returns the requested amount of random data (up to 256 bytes) that can then +// be used to seed a PRNG. +bool GetRandom(void *buffer, uptr length); + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index d31c49d69..a94a63c7f 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1604,6 +1604,32 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { return 0; } +bool GetRandom(void *buffer, uptr length) { + if (!buffer || !length || length > 256) + return false; +#if defined(__NR_getrandom) + static atomic_uint8_t skip_getrandom_syscall; + if (!atomic_load_relaxed(&skip_getrandom_syscall)) { + // Up to 256 bytes, getrandom will not be interrupted. + uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, 0); + int rverrno = 0; + if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) + atomic_store_relaxed(&skip_getrandom_syscall, 1); + else if (res == length) + return true; + } +#endif + uptr fd = internal_open("/dev/urandom", O_RDONLY); + if (internal_iserror(fd)) + return false; + // internal_read deals with EINTR. + uptr res = internal_read(fd, buffer, length); + if (internal_iserror(res)) + return false; + internal_close(fd); + return true; +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index a788a0915..b48238106 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -923,6 +923,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 506e7374a..40800c158 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -1002,6 +1002,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index ebc885db7..ebadef3e2 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -300,4 +300,21 @@ TEST(SanitizerCommon, InternalScopedString) { EXPECT_STREQ("012345678", str.data()); } +#if SANITIZER_LINUX +TEST(SanitizerCommon, GetRandom) { + u8 buffer_1[32], buffer_2[32]; + EXPECT_FALSE(GetRandom(nullptr, 32)); + EXPECT_FALSE(GetRandom(buffer_1, 0)); + EXPECT_FALSE(GetRandom(buffer_1, 512)); + EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2)); + for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) { + for (uptr i = 0; i < 100; i++) { + EXPECT_TRUE(GetRandom(buffer_1, size)); + EXPECT_TRUE(GetRandom(buffer_2, size)); + EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0); + } + } +} +#endif + } // namespace __sanitizer -- cgit v1.2.1 From ef55de50c1c83559a70bccfe6439c7b8284e2b75 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Wed, 21 Jun 2017 19:04:59 +0000 Subject: [sanitizer-coverage] Stop marking this test as unsupported on Darwin The bug that was causing this to fail was fixed in r305429. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305942 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc index 1a4ad1f06..b7246ebf2 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -1,7 +1,7 @@ // Tests -fsanitize-coverage=inline-8bit-counters // // REQUIRES: has_sancovcc,stable-runtime -// UNSUPPORTED: i386-darwin, x86_64-darwin, x86_64h-darwin +// UNSUPPORTED: i386-darwin // // RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 -- cgit v1.2.1 From 712a9e568d79c2d7e424a60e8cdadf4d6b58e5fc Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 22 Jun 2017 00:02:37 +0000 Subject: [Sanitizers] 32 bit allocator respects allocator_may_return_null flag Summary: Make SizeClassAllocator32 return nullptr when it encounters OOM, which allows the entire sanitizer's allocator to follow allocator_may_return_null=1 policy, even for small allocations (LargeMmapAllocator is already fixed by D34243). Will add a test for OOM in primary allocator later, when SizeClassAllocator64 can gracefully handle OOM too. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34433 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305972 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 15 ++++++++++--- .../sanitizer_allocator_primary32.h | 21 ++++++++++++------ lib/sanitizer_common/sanitizer_common.h | 4 +++- lib/sanitizer_common/sanitizer_posix.cc | 7 ++++-- lib/sanitizer_common/sanitizer_win.cc | 25 +++++++++++++--------- .../tests/sanitizer_common_test.cc | 4 ++-- 6 files changed, 52 insertions(+), 24 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index b3729bf55..8fa62a3bf 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -144,8 +144,10 @@ struct SizeClassAllocator32LocalCache { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); PerClass *c = &per_class_[class_id]; - if (UNLIKELY(c->count == 0)) - Refill(allocator, class_id); + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(allocator, class_id))) + return nullptr; + } stats_.Add(AllocatorStatAllocated, c->class_size); void *res = c->batch[--c->count]; PREFETCH(c->batch[c->count - 1]); @@ -227,14 +229,17 @@ struct SizeClassAllocator32LocalCache { Deallocate(allocator, batch_class_id, b); } - NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) { + NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) { InitCache(); PerClass *c = &per_class_[class_id]; TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); + if (UNLIKELY(!b)) + return false; CHECK_GT(b->Count(), 0); b->CopyToArray(c->batch); c->count = b->Count(); DestroyBatch(class_id, allocator, b); + return true; } NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) { @@ -244,6 +249,10 @@ struct SizeClassAllocator32LocalCache { uptr first_idx_to_drain = c->count - cnt; TransferBatch *b = CreateBatch( class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]); + // Failure to allocate a batch while releasing memory is non recoverable. + // TODO(alekseys): Figure out how to do it without allocating a new batch. + if (UNLIKELY(!b)) + DieOnFailure::OnOOM(); b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id), &c->batch[first_idx_to_drain], cnt); c->count -= cnt; diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index e13510ba3..d3949cc05 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,8 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). +// a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize, +// kRegionSize). // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -149,8 +150,9 @@ class SizeClassAllocator32 { CHECK_LT(class_id, kNumClasses); SizeClassInfo *sci = GetSizeClassInfo(class_id); SpinMutexLock l(&sci->mutex); - if (sci->free_list.empty()) - PopulateFreeList(stat, c, sci, class_id); + if (sci->free_list.empty() && + UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) + return nullptr; CHECK(!sci->free_list.empty()); TransferBatch *b = sci->free_list.front(); sci->free_list.pop_front(); @@ -277,8 +279,10 @@ class SizeClassAllocator32 { uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, - "SizeClassAllocator32")); + uptr res = reinterpret_cast(MmapAlignedOrDieOnFatalError( + kRegionSize, kRegionSize, "SizeClassAllocator32")); + if (UNLIKELY(!res)) + return 0; MapUnmapCallback().OnMap(res, kRegionSize); stat->Add(AllocatorStatMapped, kRegionSize); CHECK_EQ(0U, (res & (kRegionSize - 1))); @@ -291,16 +295,20 @@ class SizeClassAllocator32 { return &size_class_info_array[class_id]; } - void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, + bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, SizeClassInfo *sci, uptr class_id) { uptr size = ClassIdToSize(class_id); uptr reg = AllocateRegion(stat, class_id); + if (UNLIKELY(!reg)) + return false; uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = TransferBatch::MaxCached(class_id); TransferBatch *b = nullptr; for (uptr i = reg; i < reg + n_chunks * size; i += size) { if (!b) { b = c->CreateBatch(class_id, this, (TransferBatch*)i); + if (!b) + return false; b->Clear(); } b->Add((void*)i); @@ -314,6 +322,7 @@ class SizeClassAllocator32 { CHECK_GT(b->Count(), 0); sci->free_list.push_back(b); } + return true; } ByteMap possible_regions; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 46678b4ad..3c6f9fcee 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -95,7 +95,9 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); +// Dies on all but out of memory errors, in the latter case returns nullptr. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type); // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an // unaccessible memory. bool MprotectNoAccess(uptr addr, uptr size); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 4184a84c7..87c5b9add 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -164,11 +164,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; - uptr map_res = (uptr)MmapOrDie(map_size, mem_type); + uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); + if (!map_res) + return nullptr; uptr map_end = map_res + map_size; uptr res = map_res; if (res & (alignment - 1)) // Not aligned. diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 40800c158..c6a146553 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -131,18 +131,24 @@ void UnmapOrDie(void *addr, uptr size) { } } +static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); + if (last_error == ERROR_NOT_ENOUGH_MEMORY) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); +} + void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) { - error_t last_error = GetLastError(); - if (last_error != ERROR_NOT_ENOUGH_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "allocate", last_error); - } + if (rv == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); return rv; } // We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); @@ -152,7 +158,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { uptr mapped_addr = (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // If we got it right on the first try, return. Otherwise, unmap it and go to // the slow path. @@ -172,8 +178,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { mapped_addr = (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", - GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // Find the aligned address. uptr aligned_addr = RoundUpTo(mapped_addr, alignment); @@ -191,7 +196,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { // Fail if we can't make this work quickly. if (retries == kMaxRetries && mapped_addr == 0) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); return (void *)mapped_addr; } diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index ebadef3e2..93a8794ee 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -72,12 +72,12 @@ TEST(SanitizerCommon, SortTest) { EXPECT_TRUE(IsSorted(array, 2)); } -TEST(SanitizerCommon, MmapAlignedOrDie) { +TEST(SanitizerCommon, MmapAlignedOrDieOnFatalError) { uptr PageSize = GetPageSizeCached(); for (uptr size = 1; size <= 32; size *= 2) { for (uptr alignment = 1; alignment <= 32; alignment *= 2) { for (int iter = 0; iter < 100; iter++) { - uptr res = (uptr)MmapAlignedOrDie( + uptr res = (uptr)MmapAlignedOrDieOnFatalError( size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest"); EXPECT_EQ(0U, res % (alignment * PageSize)); internal_memset((void*)res, 1, size * PageSize); -- cgit v1.2.1 From d23b5ace10c240e8773dabf6f606534c46405b83 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 23 Jun 2017 21:32:48 +0000 Subject: [ubsan] Improve diagnostics for return value checks (compiler-rt) Differential Revision: https://reviews.llvm.org/D34298 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306164 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 29 ++++++++++++++++---------- lib/ubsan/ubsan_handlers.h | 5 ++--- lib/ubsan/ubsan_interface.inc | 8 +++---- test/ubsan/TestCases/Misc/nonnull.cpp | 37 ++++++++++++++++++++++++++++----- test/ubsan/TestCases/Misc/nullability.c | 2 +- 5 files changed, 57 insertions(+), 24 deletions(-) diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 5dabbd8e0..185752719 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -473,9 +473,12 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort( Die(); } -static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts, - bool IsAttr) { - SourceLocation Loc = Data->Loc.acquire(); +static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, + ReportOptions Opts, bool IsAttr) { + if (!LocPtr) + UNREACHABLE("source location pointer is null!"); + + SourceLocation Loc = LocPtr->acquire(); ErrorType ET = ErrorType::InvalidNullReturn; if (ignoreReport(Loc, Opts, ET)) @@ -491,25 +494,29 @@ static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts, : "_Nonnull return type annotation"); } -void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(false); - handleNonNullReturn(Data, Opts, true); + handleNonNullReturn(Data, LocPtr, Opts, true); } -void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(true); - handleNonNullReturn(Data, Opts, true); + handleNonNullReturn(Data, LocPtr, Opts, true); Die(); } -void __ubsan::__ubsan_handle_nullability_return(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(false); - handleNonNullReturn(Data, Opts, false); + handleNonNullReturn(Data, LocPtr, Opts, false); } -void __ubsan::__ubsan_handle_nullability_return_abort(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nullability_return_v1_abort( + NonNullReturnData *Data, SourceLocation *LocPtr) { GET_REPORT_OPTIONS(true); - handleNonNullReturn(Data, Opts, false); + handleNonNullReturn(Data, LocPtr, Opts, false); Die(); } diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 483c18ced..796321b81 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -132,14 +132,13 @@ RECOVERABLE(function_type_mismatch, ValueHandle Val) struct NonNullReturnData { - SourceLocation Loc; SourceLocation AttrLoc; }; /// \brief Handle returning null from function with the returns_nonnull /// attribute, or a return type annotated with _Nonnull. -RECOVERABLE(nonnull_return, NonNullReturnData *Data) -RECOVERABLE(nullability_return, NonNullReturnData *Data) +RECOVERABLE(nonnull_return_v1, NonNullReturnData *Data, SourceLocation *Loc) +RECOVERABLE(nullability_return_v1, NonNullReturnData *Data, SourceLocation *Loc) struct NonNullArgData { SourceLocation Loc; diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 681476b3c..a69ca57cd 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -28,12 +28,12 @@ INTERFACE_FUNCTION(__ubsan_handle_negate_overflow) INTERFACE_FUNCTION(__ubsan_handle_negate_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg) INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg_abort) -INTERFACE_FUNCTION(__ubsan_handle_nonnull_return) -INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_abort) +INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1) +INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1_abort) INTERFACE_FUNCTION(__ubsan_handle_nullability_arg) INTERFACE_FUNCTION(__ubsan_handle_nullability_arg_abort) -INTERFACE_FUNCTION(__ubsan_handle_nullability_return) -INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow) diff --git a/test/ubsan/TestCases/Misc/nonnull.cpp b/test/ubsan/TestCases/Misc/nonnull.cpp index c3ab49c11..d5cd2bf76 100644 --- a/test/ubsan/TestCases/Misc/nonnull.cpp +++ b/test/ubsan/TestCases/Misc/nonnull.cpp @@ -1,15 +1,42 @@ -// RUN: %clangxx -fsanitize=returns-nonnull-attribute %s -O3 -o %t -// RUN: %run %t foo +// RUN: %clangxx -fsanitize=returns-nonnull-attribute -w %s -O3 -o %t +// RUN: %run %t foo 2>&1 | count 0 // RUN: %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=returns-nonnull-attribute -fno-sanitize-recover=returns-nonnull-attribute -w %s -O3 -o %t.abort +// RUN: not %run %t.abort &> /dev/null __attribute__((returns_nonnull)) char *foo(char *a); char *foo(char *a) { + // CHECK: nonnull.cpp:[[@LINE+2]]:3: runtime error: null pointer returned from function declared to never return null + // CHECK-NEXT: nonnull.cpp:[[@LINE-4]]:16: note: returns_nonnull attribute specified here return a; - // CHECK: nonnull.cpp:[[@LINE+2]]:1: runtime error: null pointer returned from function declared to never return null - // CHECK-NEXT: nonnull.cpp:[[@LINE-5]]:16: note: returns_nonnull attribute specified here +} + +__attribute__((returns_nonnull)) char *bar(int x, char *a) { + if (x > 10) { + // CHECK: nonnull.cpp:[[@LINE+2]]:5: runtime error: null pointer returned from function declared to never return null + // CHECK-NEXT: nonnull.cpp:[[@LINE-3]]:16: note: returns_nonnull attribute specified here + return a; + } else { + // CHECK: nonnull.cpp:[[@LINE+2]]:5: runtime error: null pointer returned from function declared to never return null + // CHECK-NEXT: nonnull.cpp:[[@LINE-7]]:16: note: returns_nonnull attribute specified here + return a; + } } int main(int argc, char **argv) { - return foo(argv[1]) == 0; + char *a = argv[1]; + + foo(a); + + bar(20, a); + + // We expect to see a runtime error the first time we cover the "else"... + bar(5, a); + + // ... but not a second time. + // CHECK-NOT: runtime error + bar(5, a); + + return 0; } diff --git a/test/ubsan/TestCases/Misc/nullability.c b/test/ubsan/TestCases/Misc/nullability.c index 583b8ec12..a6ddf0e23 100644 --- a/test/ubsan/TestCases/Misc/nullability.c +++ b/test/ubsan/TestCases/Misc/nullability.c @@ -2,7 +2,7 @@ // RUN: %run %t foo 2>&1 | count 0 // RUN: %run %t 2>&1 | FileCheck %s -// CHECK: nullability.c:[[@LINE+2]]:51: runtime error: null pointer returned from function declared to never return null +// CHECK: nullability.c:[[@LINE+2]]:41: runtime error: null pointer returned from function declared to never return null // CHECK-NEXT: nullability.c:[[@LINE+1]]:6: note: _Nonnull return type annotation specified here int *_Nonnull nonnull_retval1(int *p) { return p; } -- cgit v1.2.1 From 37a2e2e98baf49fd965bebb2c9c9b1a7b0428109 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 23 Jun 2017 23:38:20 +0000 Subject: [asan] Add support for Android debug message. Add ASan report to the "debug message" field in Android tombstones. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306184 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 8 ++++++++ lib/sanitizer_common/sanitizer_common.h | 3 +++ lib/sanitizer_common/sanitizer_linux_libcdep.cc | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index f751b6184..2e477f258 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -204,6 +204,14 @@ class ScopedInErrorReport { error_report_callback(buffer_copy.data()); } + if (halt_on_error_ && common_flags()->abort_on_error) { + // On Android the message is truncated to 512 characters. + // FIXME: implement "compact" error format, possibly without, or with + // highly compressed stack traces? + // FIXME: or just use the summary line as abort message? + SetAbortMessage(buffer_copy.data()); + } + // In halt_on_error = false mode, reset the current error object (before // unlocking). if (!halt_on_error_) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 3c6f9fcee..560c53b64 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -810,8 +810,11 @@ INLINE void LogMessageOnPrintf(const char *str) {} #if SANITIZER_LINUX // Initialize Android logging. Any writes before this are silently lost. void AndroidLogInit(); +void SetAbortMessage(const char *); #else INLINE void AndroidLogInit() {} +// FIXME: MacOS implementation could use CRSetCrashLogMessage. +INLINE void SetAbortMessage(const char *) {} #endif #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 894013ddd..b9a48a1e4 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -551,6 +551,13 @@ void LogMessageOnPrintf(const char *str) { WriteToSyslog(str); } +#if SANITIZER_ANDROID && __ANDROID_API__ >= 21 +extern "C" void android_set_abort_message(const char *msg); +void SetAbortMessage(const char *str) { android_set_abort_message(str); } +#else +void SetAbortMessage(const char *str) {} +#endif + #endif // SANITIZER_LINUX } // namespace __sanitizer -- cgit v1.2.1 From bc311bbb04f823ee9d58261111a4455a0354c358 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 24 Jun 2017 01:40:41 +0000 Subject: [asan] Regression test for PR33372 Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34315 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306195 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/pr33372.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/asan/TestCases/pr33372.cc diff --git a/test/asan/TestCases/pr33372.cc b/test/asan/TestCases/pr33372.cc new file mode 100644 index 000000000..a4b606e02 --- /dev/null +++ b/test/asan/TestCases/pr33372.cc @@ -0,0 +1,39 @@ +// RUN: %clangxx_asan -O0 -std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 -std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 -std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s + +// Test that we do not detect false buffer overflows cased by optimization when +// when local variable replaced by a smaller global constant. +// https://bugs.llvm.org/show_bug.cgi?id=33372 + +#include +#include + +struct A { int x, y, z; }; +struct B { A a; /*gap*/ long b; }; +B *bb; + +void test1() { + A a1 = {1, 1, 2}; + B b1 = {a1, 6}; + bb = new B(b1); +} + +const char KKK[] = {1, 1, 2}; +char bbb[100000]; + +void test2() { + char cc[sizeof(bbb)]; + memcpy(cc, KKK , sizeof(KKK)); + memcpy(bbb, cc, sizeof(bbb)); +} + +int main(int argc, char *argv[]) { + test1(); + test2(); + printf("PASSED"); + return 0; +} + +// CHECK-NOT: ERROR: AddressSanitizer +// CHECK: PASSED -- cgit v1.2.1 From 0f531abec8e46ddc4416c04523cdab96194d30fe Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Sun, 25 Jun 2017 00:27:09 +0000 Subject: [PGO] Implementate profile counter regiser promotion (test case) Differential Revision: http://reviews.llvm.org/D34085 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306232 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Linux/counter_promo_for.c | 59 ++++++++++++++++++++++++++++++++ test/profile/Linux/counter_promo_while.c | 55 +++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 test/profile/Linux/counter_promo_for.c create mode 100644 test/profile/Linux/counter_promo_while.c diff --git a/test/profile/Linux/counter_promo_for.c b/test/profile/Linux/counter_promo_for.c new file mode 100644 index 000000000..313964669 --- /dev/null +++ b/test/profile/Linux/counter_promo_for.c @@ -0,0 +1,59 @@ +// RUN: rm -fr %t.promo.prof +// RUN: rm -fr %t.nopromo.prof +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen -O2 %s +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen.ll -emit-llvm -S -O2 %s +// RUN: cat %t.promo.gen.ll | FileCheck --check-prefix=PROMO %s +// RUN: %run %t.promo.gen +// RUN: llvm-profdata merge -o %t.promo.profdata %t.promo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.promo.profdata > %t.promo.dump +// RUN: %clang_pgogen=%t.nopromo.prof/ -mllvm -do-counter-promotion=false -o %t.nopromo.gen -O2 %s +// RUN: %clang_pgogen=%t.nopromo.prof/ -mllvm -do-counter-promotion=false -o %t.nopromo.gen.ll -emit-llvm -S -O2 %s +// RUN: cat %t.nopromo.gen.ll | FileCheck --check-prefix=NOPROMO %s +// RUN: %run %t.nopromo.gen +// RUN: llvm-profdata merge -o %t.nopromo.profdata %t.nopromo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.nopromo.profdata > %t.nopromo.dump +// RUN: diff %t.promo.profdata %t.nopromo.profdata + +int g; +__attribute__((noinline)) void bar(int i) { g += i; } + +__attribute__((noinline)) void foo(int n, int N) { +// PROMO-LABEL: @foo +// PROMO: load{{.*}}@__profc_foo{{.*}} 0){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 0){{.*}} +// PROMO-NEXT: load{{.*}}@__profc_foo{{.*}} 1){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 1){{.*}} +// PROMO-NEXT: load{{.*}}@__profc_foo{{.*}} 2){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 2){{.*}} +// PROMO: load{{.*}}@__profc_foo{{.*}} 3){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 3){{.*}} +// +// NOPROMO-LABEL: @foo +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 0){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 0){{.*}} +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 1){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 1){{.*}} +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 2){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 2){{.*}} + int i; + for (i = 0; i < N; i++) { + if (i < n + 1) + bar(1); + else if (i < n - 1) + bar(2); + else + bar(3); + } +} + +int main() { + foo(10, 20); + return 0; +} diff --git a/test/profile/Linux/counter_promo_while.c b/test/profile/Linux/counter_promo_while.c new file mode 100644 index 000000000..b4d4e7aa2 --- /dev/null +++ b/test/profile/Linux/counter_promo_while.c @@ -0,0 +1,55 @@ +// RUN: rm -fr %t.promo.prof +// RUN: rm -fr %t.nopromo.prof +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen -O2 %s +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen.ll -emit-llvm -S -O2 %s +// RUN: cat %t.promo.gen.ll | FileCheck --check-prefix=PROMO %s +// RUN: %run %t.promo.gen +// RUN: llvm-profdata merge -o %t.promo.profdata %t.promo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.promo.profdata > %t.promo.dump +// RUN: %clang_pgogen=%t.nopromo.prof/ -mllvm -do-counter-promotion=false -o %t.nopromo.gen -O2 %s +// RUN: %clang_pgogen=%t.nopromo.prof/ -mllvm -do-counter-promotion=false -o %t.nopromo.gen.ll -emit-llvm -S -O2 %s +// RUN: cat %t.nopromo.gen.ll | FileCheck --check-prefix=NOPROMO %s +// RUN: %run %t.nopromo.gen +// RUN: llvm-profdata merge -o %t.nopromo.profdata %t.nopromo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.nopromo.profdata > %t.nopromo.dump +// RUN: diff %t.promo.profdata %t.nopromo.profdata +int g; +__attribute__((noinline)) void bar(int i) { g += i; } +__attribute__((noinline)) void foo(int n, int N) { +// PROMO-LABEL: @foo +// PROMO: load{{.*}}@__profc_foo{{.*}} 0){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 0){{.*}} +// PROMO-NEXT: load{{.*}}@__profc_foo{{.*}} 1){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 1){{.*}} +// PROMO-NEXT: load{{.*}}@__profc_foo{{.*}} 2){{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 2){{.*}} +// +// NOPROMO-LABEL: @foo +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 0){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 0){{.*}} +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 1){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 1){{.*}} +// NOPROMO: load{{.*}}@__profc_foo{{.*}} 2){{.*}} +// NOPROMO-NEXT: add +// NOPROMO-NEXT: store{{.*}}@__profc_foo{{.*}} 2){{.*}} + int i = 0; + while (i < N) { + if (i < n + 1) + bar(1); + else if (i < n - 1) + bar(2); + else + bar(3); + i++; + } +} + +int main() { + foo(10, 20); + return 0; +} -- cgit v1.2.1 From 9461bb47aac9c74935cca95ca8e1821eb9ae1258 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Mon, 26 Jun 2017 01:02:54 +0000 Subject: [esan] Disable flaky tests for PR33590 Disables 3 esan workingset tests until their underlying failures are determined and resolved. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306259 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/esan/TestCases/workingset-midreport.cpp | 3 +++ test/esan/TestCases/workingset-samples.cpp | 3 +++ test/esan/TestCases/workingset-simple.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/test/esan/TestCases/workingset-midreport.cpp b/test/esan/TestCases/workingset-midreport.cpp index 2c29cf48c..38c376554 100644 --- a/test/esan/TestCases/workingset-midreport.cpp +++ b/test/esan/TestCases/workingset-midreport.cpp @@ -4,6 +4,9 @@ // RUN: %clang -O0 %s -o %t 2>&1 // RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ESAN +// FIXME: Re-enable once PR33590 is fixed. +// UNSUPPORTED: x86_64 + #include #include #include diff --git a/test/esan/TestCases/workingset-samples.cpp b/test/esan/TestCases/workingset-samples.cpp index 7db2110b9..d97b62ba4 100644 --- a/test/esan/TestCases/workingset-samples.cpp +++ b/test/esan/TestCases/workingset-samples.cpp @@ -1,6 +1,9 @@ // RUN: %clang_esan_wset -O0 %s -o %t 2>&1 // RUN: %run %t 2>&1 | FileCheck %s +// FIXME: Re-enable once PR33590 is fixed. +// UNSUPPORTED: x86_64 + #include #include #include diff --git a/test/esan/TestCases/workingset-simple.cpp b/test/esan/TestCases/workingset-simple.cpp index c8a2d52e7..f1ac2ecfe 100644 --- a/test/esan/TestCases/workingset-simple.cpp +++ b/test/esan/TestCases/workingset-simple.cpp @@ -1,6 +1,9 @@ // RUN: %clang_esan_wset -O0 %s -o %t 2>&1 // RUN: %run %t 2>&1 | FileCheck %s +// FIXME: Re-enable once PR33590 is fixed. +// UNSUPPORTED: x86_64 + #include #include #include -- cgit v1.2.1 From f3180f887ff3b17f3c5dc654d3c1726e90bb64e4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 26 Jun 2017 21:37:40 +0000 Subject: [asan] Flag 'asan_gen_prefixes.cc' as unsupported on iOS. The ARM and ARM64 assemblers can use different label prefixes than the expected. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306335 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/asan_gen_prefixes.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/asan/TestCases/Darwin/asan_gen_prefixes.cc b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc index 13363ac47..9f3a66a7a 100644 --- a/test/asan/TestCases/Darwin/asan_gen_prefixes.cc +++ b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc @@ -4,6 +4,8 @@ // RUN: %clang_asan %s -S -o %t.s // RUN: cat %t.s | FileCheck %s || exit 1 +// UNSUPPORTED: ios + int x, y, z; int main() { return 0; } // CHECK: .section{{.*}}__TEXT,__const -- cgit v1.2.1 From 9d35abce5aacd116a1f2a5ac5541934f88dbfa54 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 26 Jun 2017 22:54:10 +0000 Subject: [Sanitizers] 64 bit allocator respects allocator_may_return_null flag Summary: Make SizeClassAllocator64 return nullptr when it encounters OOM, which allows the entire sanitizer's allocator to follow allocator_may_return_null=1 policy (LargeMmapAllocator: D34243, SizeClassAllocator64: D34433). Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34540 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306342 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 14 +- .../sanitizer_allocator_primary64.h | 191 +++++++++++++-------- lib/sanitizer_common/sanitizer_common.h | 3 + lib/sanitizer_common/sanitizer_posix.cc | 12 +- lib/sanitizer_common/sanitizer_win.cc | 12 ++ .../tests/sanitizer_allocator_test.cc | 34 ++-- 6 files changed, 168 insertions(+), 98 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index 8fa62a3bf..ec0742c20 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -46,8 +46,10 @@ struct SizeClassAllocator64LocalCache { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); PerClass *c = &per_class_[class_id]; - if (UNLIKELY(c->count == 0)) - Refill(c, allocator, class_id); + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(c, allocator, class_id))) + return nullptr; + } stats_.Add(AllocatorStatAllocated, c->class_size); CHECK_GT(c->count, 0); CompactPtrT chunk = c->chunks[--c->count]; @@ -101,13 +103,15 @@ struct SizeClassAllocator64LocalCache { } } - NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator, + NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, uptr class_id) { InitCache(); uptr num_requested_chunks = c->max_count / 2; - allocator->GetFromAllocator(&stats_, class_id, c->chunks, - num_requested_chunks); + if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks, + num_requested_chunks))) + return false; c->count = num_requested_chunks; + return true; } NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id, diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 035d92b98..efa2258dd 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -80,7 +80,7 @@ class SizeClassAllocator64 { CHECK_NE(NonConstSpaceBeg, ~(uptr)0); } SetReleaseToOSIntervalMs(release_to_os_interval_ms); - MapWithCallback(SpaceEnd(), AdditionalSize()); + MapWithCallbackOrDie(SpaceEnd(), AdditionalSize()); } s32 ReleaseToOSIntervalMs() const { @@ -92,16 +92,6 @@ class SizeClassAllocator64 { memory_order_relaxed); } - void MapWithCallback(uptr beg, uptr size) { - CHECK_EQ(beg, reinterpret_cast(MmapFixedOrDie(beg, size))); - MapUnmapCallback().OnMap(beg, size); - } - - void UnmapWithCallback(uptr beg, uptr size) { - MapUnmapCallback().OnUnmap(beg, size); - UnmapOrDie(reinterpret_cast(beg), size); - } - static bool CanAllocate(uptr size, uptr alignment) { return size <= SizeClassMap::kMaxSize && alignment <= SizeClassMap::kMaxSize; @@ -116,16 +106,20 @@ class SizeClassAllocator64 { BlockingMutexLock l(®ion->mutex); uptr old_num_chunks = region->num_freed_chunks; uptr new_num_freed_chunks = old_num_chunks + n_chunks; - EnsureFreeArraySpace(region, region_beg, new_num_freed_chunks); + // Failure to allocate free array space while releasing memory is non + // recoverable. + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, + new_num_freed_chunks))) + DieOnFailure::OnOOM(); for (uptr i = 0; i < n_chunks; i++) free_array[old_num_chunks + i] = chunks[i]; region->num_freed_chunks = new_num_freed_chunks; - region->n_freed += n_chunks; + region->stats.n_freed += n_chunks; MaybeReleaseToOS(class_id); } - NOINLINE void GetFromAllocator(AllocatorStats *stat, uptr class_id, + NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id, CompactPtrT *chunks, uptr n_chunks) { RegionInfo *region = GetRegionInfo(class_id); uptr region_beg = GetRegionBeginBySizeClass(class_id); @@ -133,18 +127,19 @@ class SizeClassAllocator64 { BlockingMutexLock l(®ion->mutex); if (UNLIKELY(region->num_freed_chunks < n_chunks)) { - PopulateFreeArray(stat, class_id, region, - n_chunks - region->num_freed_chunks); + if (UNLIKELY(!PopulateFreeArray(stat, class_id, region, + n_chunks - region->num_freed_chunks))) + return false; CHECK_GE(region->num_freed_chunks, n_chunks); } region->num_freed_chunks -= n_chunks; uptr base_idx = region->num_freed_chunks; for (uptr i = 0; i < n_chunks; i++) chunks[i] = free_array[base_idx + i]; - region->n_allocated += n_chunks; + region->stats.n_allocated += n_chunks; + return true; } - bool PointerIsMine(const void *p) { uptr P = reinterpret_cast(p); if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0) @@ -211,7 +206,7 @@ class SizeClassAllocator64 { // Test-only. void TestOnlyUnmap() { - UnmapWithCallback(SpaceBeg(), kSpaceSize + AdditionalSize()); + UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize()); } static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, @@ -224,15 +219,15 @@ class SizeClassAllocator64 { void PrintStats(uptr class_id, uptr rss) { RegionInfo *region = GetRegionInfo(class_id); if (region->mapped_user == 0) return; - uptr in_use = region->n_allocated - region->n_freed; + uptr in_use = region->stats.n_allocated - region->stats.n_freed; uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id); Printf( - " %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " + "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd\n", - class_id, ClassIdToSize(class_id), region->mapped_user >> 10, - region->n_allocated, region->n_freed, in_use, - region->num_freed_chunks, avail_chunks, rss >> 10, - region->rtoi.num_releases); + region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), + region->mapped_user >> 10, region->stats.n_allocated, + region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, + rss >> 10, region->rtoi.num_releases); } void PrintStats() { @@ -242,8 +237,8 @@ class SizeClassAllocator64 { for (uptr class_id = 1; class_id < kNumClasses; class_id++) { RegionInfo *region = GetRegionInfo(class_id); total_mapped += region->mapped_user; - n_allocated += region->n_allocated; - n_freed += region->n_freed; + n_allocated += region->stats.n_allocated; + n_freed += region->stats.n_freed; } Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; " "remains %zd\n", @@ -326,6 +321,11 @@ class SizeClassAllocator64 { atomic_sint32_t release_to_os_interval_ms_; + struct Stats { + uptr n_allocated; + uptr n_freed; + }; + struct ReleaseToOsInfo { uptr n_freed_at_last_release; uptr num_releases; @@ -340,8 +340,9 @@ class SizeClassAllocator64 { uptr allocated_meta; // Bytes allocated for metadata. uptr mapped_user; // Bytes mapped for user memory. uptr mapped_meta; // Bytes mapped for metadata. - u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. - uptr n_allocated, n_freed; // Just stats. + u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. + bool exhausted; // Whether region is out of space for new chunks. + Stats stats; ReleaseToOsInfo rtoi; }; COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); @@ -386,7 +387,26 @@ class SizeClassAllocator64 { kFreeArraySize); } - void EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, + bool MapWithCallback(uptr beg, uptr size) { + uptr mapped = reinterpret_cast(MmapFixedOrDieOnFatalError(beg, size)); + if (!mapped) + return false; + CHECK_EQ(beg, mapped); + MapUnmapCallback().OnMap(beg, size); + return true; + } + + void MapWithCallbackOrDie(uptr beg, uptr size) { + CHECK_EQ(beg, reinterpret_cast(MmapFixedOrDie(beg, size))); + MapUnmapCallback().OnMap(beg, size); + } + + void UnmapWithCallbackOrDie(uptr beg, uptr size) { + MapUnmapCallback().OnUnmap(beg, size); + UnmapOrDie(reinterpret_cast(beg), size); + } + + bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, uptr num_freed_chunks) { uptr needed_space = num_freed_chunks * sizeof(CompactPtrT); if (region->mapped_free_array < needed_space) { @@ -395,66 +415,87 @@ class SizeClassAllocator64 { uptr current_map_end = reinterpret_cast(GetFreeArray(region_beg)) + region->mapped_free_array; uptr new_map_size = new_mapped_free_array - region->mapped_free_array; - MapWithCallback(current_map_end, new_map_size); + if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size))) + return false; region->mapped_free_array = new_mapped_free_array; } + return true; } - - NOINLINE void PopulateFreeArray(AllocatorStats *stat, uptr class_id, + NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id, RegionInfo *region, uptr requested_count) { // region->mutex is held. - uptr size = ClassIdToSize(class_id); - uptr beg_idx = region->allocated_user; - uptr end_idx = beg_idx + requested_count * size; - uptr region_beg = GetRegionBeginBySizeClass(class_id); - if (end_idx > region->mapped_user) { + const uptr size = ClassIdToSize(class_id); + const uptr new_space_beg = region->allocated_user; + const uptr new_space_end = new_space_beg + requested_count * size; + const uptr region_beg = GetRegionBeginBySizeClass(class_id); + + // Map more space for chunks, if necessary. + if (new_space_end > region->mapped_user) { if (!kUsingConstantSpaceBeg && region->mapped_user == 0) region->rand_state = static_cast(region_beg >> 12); // From ASLR. // Do the mmap for the user memory. uptr map_size = kUserMapSize; - while (end_idx > region->mapped_user + map_size) + while (new_space_end > region->mapped_user + map_size) map_size += kUserMapSize; - CHECK_GE(region->mapped_user + map_size, end_idx); - MapWithCallback(region_beg + region->mapped_user, map_size); + CHECK_GE(region->mapped_user + map_size, new_space_end); + if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user, + map_size))) + return false; stat->Add(AllocatorStatMapped, map_size); region->mapped_user += map_size; } - CompactPtrT *free_array = GetFreeArray(region_beg); - uptr total_count = (region->mapped_user - beg_idx) / size; - uptr num_freed_chunks = region->num_freed_chunks; - EnsureFreeArraySpace(region, region_beg, num_freed_chunks + total_count); - for (uptr i = 0; i < total_count; i++) { - uptr chunk = beg_idx + i * size; - free_array[num_freed_chunks + total_count - 1 - i] = - PointerToCompactPtr(0, chunk); + const uptr new_chunks_count = (region->mapped_user - new_space_beg) / size; + + // Calculate the required space for metadata. + const uptr requested_allocated_meta = + region->allocated_meta + new_chunks_count * kMetadataSize; + uptr requested_mapped_meta = region->mapped_meta; + while (requested_allocated_meta > requested_mapped_meta) + requested_mapped_meta += kMetaMapSize; + // Check whether this size class is exhausted. + if (region->mapped_user + requested_mapped_meta > + kRegionSize - kFreeArraySize) { + if (!region->exhausted) { + region->exhausted = true; + Printf("%s: Out of memory. ", SanitizerToolName); + Printf("The process has exhausted %zuMB for size class %zu.\n", + kRegionSize >> 20, size); + } + return false; + } + // Map more space for metadata, if necessary. + if (requested_mapped_meta > region->mapped_meta) { + if (UNLIKELY(!MapWithCallback( + GetMetadataEnd(region_beg) - requested_mapped_meta, + requested_mapped_meta - region->mapped_meta))) + return false; + region->mapped_meta = requested_mapped_meta; } + + // If necessary, allocate more space for the free array and populate it with + // newly allocated chunks. + const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count; + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks))) + return false; + CompactPtrT *free_array = GetFreeArray(region_beg); + for (uptr i = 0, chunk = new_space_beg; i < new_chunks_count; + i++, chunk += size) + free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk); if (kRandomShuffleChunks) - RandomShuffle(&free_array[num_freed_chunks], total_count, + RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count, ®ion->rand_state); - region->num_freed_chunks += total_count; - region->allocated_user += total_count * size; - CHECK_LE(region->allocated_user, region->mapped_user); - region->allocated_meta += total_count * kMetadataSize; - if (region->allocated_meta > region->mapped_meta) { - uptr map_size = kMetaMapSize; - while (region->allocated_meta > region->mapped_meta + map_size) - map_size += kMetaMapSize; - // Do the mmap for the metadata. - CHECK_GE(region->mapped_meta + map_size, region->allocated_meta); - MapWithCallback(GetMetadataEnd(region_beg) - - region->mapped_meta - map_size, map_size); - region->mapped_meta += map_size; - } + // All necessary memory is mapped and now it is safe to advance all + // 'allocated_*' counters. + region->num_freed_chunks += new_chunks_count; + region->allocated_user += new_chunks_count * size; + CHECK_LE(region->allocated_user, region->mapped_user); + region->allocated_meta = requested_allocated_meta; CHECK_LE(region->allocated_meta, region->mapped_meta); - if (region->mapped_user + region->mapped_meta > - kRegionSize - kFreeArraySize) { - Printf("%s: Out of memory. Dying. ", SanitizerToolName); - Printf("The process has exhausted %zuMB for size class %zu.\n", - kRegionSize / 1024 / 1024, size); - Die(); - } + region->exhausted = false; + + return true; } void MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size, @@ -478,8 +519,8 @@ class SizeClassAllocator64 { uptr n = region->num_freed_chunks; if (n * chunk_size < page_size) return; // No chance to release anything. - if ((region->n_freed - region->rtoi.n_freed_at_last_release) * chunk_size < - page_size) { + if ((region->stats.n_freed - + region->rtoi.n_freed_at_last_release) * chunk_size < page_size) { return; // Nothing new to release. } @@ -508,7 +549,7 @@ class SizeClassAllocator64 { CHECK_GT(chunk - prev, scaled_chunk_size); if (prev + scaled_chunk_size - range_beg >= kScaledGranularity) { MaybeReleaseChunkRange(region_beg, chunk_size, range_beg, prev); - region->rtoi.n_freed_at_last_release = region->n_freed; + region->rtoi.n_freed_at_last_release = region->stats.n_freed; region->rtoi.num_releases++; } range_beg = chunk; @@ -517,5 +558,3 @@ class SizeClassAllocator64 { } } }; - - diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 560c53b64..d44c71513 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -92,6 +92,9 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size); +// Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in +// that case returns nullptr. +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 87c5b9add..fd2822edb 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -198,7 +198,7 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return (void *)p; } -void *MmapFixedOrDie(uptr fixed_addr, uptr size) { +void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) { uptr PageSize = GetPageSizeCached(); uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), RoundUpTo(size, PageSize), @@ -207,6 +207,8 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { -1, 0); int reserrno; if (internal_iserror(p, &reserrno)) { + if (tolerate_enomem && reserrno == ENOMEM) + return nullptr; char mem_type[30]; internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", fixed_addr); @@ -216,6 +218,14 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return (void *)p; } +void *MmapFixedOrDie(uptr fixed_addr, uptr size) { + return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { + return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/); +} + bool MprotectNoAccess(uptr addr, uptr size) { return 0 == internal_mprotect((void*)addr, size, PROT_NONE); } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index c6a146553..89d9cf61c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,6 +235,18 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + } + return p; +} + void *MmapNoReserveOrDie(uptr size, const char *mem_type) { // FIXME: make this really NoReserve? return MmapOrDie(size, mem_type); diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index f256d8776..0def8ee0f 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -436,30 +436,31 @@ TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) { EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); } -template -void FailInAssertionOnOOM() { - Allocator a; +// Don't test OOM conditions on Win64 because it causes other tests on the same +// machine to OOM. +#if SANITIZER_CAN_USE_ALLOCATOR64 && !SANITIZER_WINDOWS64 && !SANITIZER_ANDROID +TEST(SanitizerCommon, SizeClassAllocator64Overflow) { + Allocator64 a; a.Init(kReleaseToOSIntervalNever); - SizeClassAllocatorLocalCache cache; + SizeClassAllocatorLocalCache cache; memset(&cache, 0, sizeof(cache)); cache.Init(0); AllocatorStats stats; stats.Init(); + const size_t kNumChunks = 128; uint32_t chunks[kNumChunks]; + bool allocation_failed = false; for (int i = 0; i < 1000000; i++) { - a.GetFromAllocator(&stats, 52, chunks, kNumChunks); + if (!a.GetFromAllocator(&stats, 52, chunks, kNumChunks)) { + allocation_failed = true; + break; + } } + EXPECT_EQ(allocation_failed, true); a.TestOnlyUnmap(); } - -// Don't test OOM conditions on Win64 because it causes other tests on the same -// machine to OOM. -#if SANITIZER_CAN_USE_ALLOCATOR64 && !SANITIZER_WINDOWS64 && !SANITIZER_ANDROID -TEST(SanitizerCommon, SizeClassAllocator64Overflow) { - EXPECT_DEATH(FailInAssertionOnOOM(), "Out of memory"); -} #endif TEST(SanitizerCommon, LargeMmapAllocator) { @@ -970,9 +971,9 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) { const uptr kAllocationSize = SpecialSizeClassMap::Size(kClassID); ASSERT_LT(2 * kAllocationSize, kRegionSize); ASSERT_GT(3 * kAllocationSize, kRegionSize); - cache.Allocate(a, kClassID); - EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID), - "The process has exhausted"); + EXPECT_NE(cache.Allocate(a, kClassID), nullptr); + EXPECT_NE(cache.Allocate(a, kClassID), nullptr); + EXPECT_EQ(cache.Allocate(a, kClassID), nullptr); const uptr Class2 = 100; const uptr Size2 = SpecialSizeClassMap::Size(Class2); @@ -980,11 +981,12 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) { char *p[7]; for (int i = 0; i < 7; i++) { p[i] = (char*)cache.Allocate(a, Class2); + EXPECT_NE(p[i], nullptr); fprintf(stderr, "p[%d] %p s = %lx\n", i, (void*)p[i], Size2); p[i][Size2 - 1] = 42; if (i) ASSERT_LT(p[i - 1], p[i]); } - EXPECT_DEATH(cache.Allocate(a, Class2), "The process has exhausted"); + EXPECT_EQ(cache.Allocate(a, Class2), nullptr); cache.Deallocate(a, Class2, p[0]); cache.Drain(a); ASSERT_EQ(p[6][Size2 - 1], 42); -- cgit v1.2.1 From aa207c1685fec72a06a8a51b0518ed9ad87b0c03 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 14:56:59 +0000 Subject: [tsan] Add missing include directory for test unittests Summary: Required to fix standalone builds in some configurations Reviewers: kubamracek, zaks.anna Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D34631 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306411 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index 87e14174a..ca43a928d 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -8,6 +8,7 @@ set(TSAN_UNITTEST_CFLAGS ${TSAN_CFLAGS} ${COMPILER_RT_UNITTEST_CFLAGS} ${COMPILER_RT_GTEST_CFLAGS} + -I${COMPILER_RT_SOURCE_DIR}/include -I${COMPILER_RT_SOURCE_DIR}/lib -I${COMPILER_RT_SOURCE_DIR}/lib/tsan/rtl -DGTEST_HAS_RTTI=0) -- cgit v1.2.1 From 1c6a7b07545f0c9ce68e8b226f5397694ce48af7 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 15:22:56 +0000 Subject: Only test sanitizers that are built when COMPILER_RT_SANITIZERS_TO_BUILD is used Summary: This allows check-all to be used when only a subset of the sanitizers are built. Reviewers: beanz, compnerd Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D34644 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306415 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 1 - test/CMakeLists.txt | 75 +++++++++++++++++++++++------------------------------ 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4ab1e933a..7000efb6b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -28,7 +28,6 @@ function(compiler_rt_build_runtime runtime) endfunction() function(compiler_rt_build_sanitizer sanitizer) - string(TOUPPER ${sanitizer} sanitizer_uppercase) string(TOLOWER ${sanitizer} sanitizer_lowercase) list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) if(NOT ${result} EQUAL -1) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7685fb3f4..8ef66c3c0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,21 @@ if(NOT ANDROID) endif() endif() +function(compiler_rt_test_runtime runtime) + string(TOUPPER ${runtime} runtime_uppercase) + if(COMPILER_RT_HAS_${runtime_uppercase}) + add_subdirectory(${runtime}) + endif() +endfunction() + +function(compiler_rt_test_sanitizer sanitizer) + string(TOLOWER ${sanitizer} sanitizer_lowercase) + list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) + if(NOT ${result} EQUAL -1) + compiler_rt_test_runtime(${sanitizer}) + endif() +endfunction() + # Run sanitizer tests only if we're sure that clang would produce # working binaries. if(COMPILER_RT_CAN_EXECUTE_TESTS) @@ -42,49 +57,25 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) add_subdirectory(builtins) endif() if(COMPILER_RT_BUILD_SANITIZERS) - if(COMPILER_RT_HAS_ASAN) - add_subdirectory(asan) - endif() - if(COMPILER_RT_HAS_DFSAN) - add_subdirectory(dfsan) - endif() - if (COMPILER_RT_HAS_INTERCEPTION) - add_subdirectory(interception) - endif() - if(COMPILER_RT_HAS_LSAN) - add_subdirectory(lsan) - endif() - if(COMPILER_RT_HAS_MSAN) - add_subdirectory(msan) - endif() - if(COMPILER_RT_HAS_PROFILE) - add_subdirectory(profile) - endif() - if(COMPILER_RT_HAS_SANITIZER_COMMON) - add_subdirectory(sanitizer_common) - endif() - if(COMPILER_RT_HAS_TSAN) - add_subdirectory(tsan) - endif() - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(ubsan) - endif() - # CFI tests require diagnostic mode, which is implemented in UBSan. - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(cfi) - endif() - if(COMPILER_RT_HAS_SAFESTACK) - add_subdirectory(safestack) - endif() - if(COMPILER_RT_HAS_ESAN) - add_subdirectory(esan) - endif() - if(COMPILER_RT_HAS_SCUDO) - add_subdirectory(scudo) - endif() + compiler_rt_test_runtime(interception) + + compiler_rt_test_runtime(lsan) + compiler_rt_test_runtime(ubsan) + compiler_rt_test_runtime(sanitizer_common) + + compiler_rt_test_sanitizer(asan) + compiler_rt_test_sanitizer(dfsan) + compiler_rt_test_sanitizer(msan) + compiler_rt_test_sanitizer(tsan) + compiler_rt_test_sanitizer(safestack) + compiler_rt_test_sanitizer(cfi) + compiler_rt_test_sanitizer(esan) + compiler_rt_test_sanitizer(scudo) + + compiler_rt_test_runtime(profile) endif() - if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY) - add_subdirectory(xray) + if(COMPILER_RT_BUILD_XRAY) + compiler_rt_test_runtime(xray) endif() endif() -- cgit v1.2.1 From f2a5e92a674199b5c1138b916f406afa05eb5eba Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 17:24:26 +0000 Subject: Revert "Only test sanitizers that are built when COMPILER_RT_SANITIZERS_TO_BUILD is used" This breaks cfi testing in cases when the cfi runtime isn't built. This reverts commit 1c6a7b07545f0c9ce68e8b226f5397694ce48af7. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306431 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 1 + test/CMakeLists.txt | 75 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7000efb6b..4ab1e933a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -28,6 +28,7 @@ function(compiler_rt_build_runtime runtime) endfunction() function(compiler_rt_build_sanitizer sanitizer) + string(TOUPPER ${sanitizer} sanitizer_uppercase) string(TOLOWER ${sanitizer} sanitizer_lowercase) list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) if(NOT ${result} EQUAL -1) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8ef66c3c0..7685fb3f4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,21 +35,6 @@ if(NOT ANDROID) endif() endif() -function(compiler_rt_test_runtime runtime) - string(TOUPPER ${runtime} runtime_uppercase) - if(COMPILER_RT_HAS_${runtime_uppercase}) - add_subdirectory(${runtime}) - endif() -endfunction() - -function(compiler_rt_test_sanitizer sanitizer) - string(TOLOWER ${sanitizer} sanitizer_lowercase) - list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) - if(NOT ${result} EQUAL -1) - compiler_rt_test_runtime(${sanitizer}) - endif() -endfunction() - # Run sanitizer tests only if we're sure that clang would produce # working binaries. if(COMPILER_RT_CAN_EXECUTE_TESTS) @@ -57,25 +42,49 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) add_subdirectory(builtins) endif() if(COMPILER_RT_BUILD_SANITIZERS) - compiler_rt_test_runtime(interception) - - compiler_rt_test_runtime(lsan) - compiler_rt_test_runtime(ubsan) - compiler_rt_test_runtime(sanitizer_common) - - compiler_rt_test_sanitizer(asan) - compiler_rt_test_sanitizer(dfsan) - compiler_rt_test_sanitizer(msan) - compiler_rt_test_sanitizer(tsan) - compiler_rt_test_sanitizer(safestack) - compiler_rt_test_sanitizer(cfi) - compiler_rt_test_sanitizer(esan) - compiler_rt_test_sanitizer(scudo) - - compiler_rt_test_runtime(profile) + if(COMPILER_RT_HAS_ASAN) + add_subdirectory(asan) + endif() + if(COMPILER_RT_HAS_DFSAN) + add_subdirectory(dfsan) + endif() + if (COMPILER_RT_HAS_INTERCEPTION) + add_subdirectory(interception) + endif() + if(COMPILER_RT_HAS_LSAN) + add_subdirectory(lsan) + endif() + if(COMPILER_RT_HAS_MSAN) + add_subdirectory(msan) + endif() + if(COMPILER_RT_HAS_PROFILE) + add_subdirectory(profile) + endif() + if(COMPILER_RT_HAS_SANITIZER_COMMON) + add_subdirectory(sanitizer_common) + endif() + if(COMPILER_RT_HAS_TSAN) + add_subdirectory(tsan) + endif() + if(COMPILER_RT_HAS_UBSAN) + add_subdirectory(ubsan) + endif() + # CFI tests require diagnostic mode, which is implemented in UBSan. + if(COMPILER_RT_HAS_UBSAN) + add_subdirectory(cfi) + endif() + if(COMPILER_RT_HAS_SAFESTACK) + add_subdirectory(safestack) + endif() + if(COMPILER_RT_HAS_ESAN) + add_subdirectory(esan) + endif() + if(COMPILER_RT_HAS_SCUDO) + add_subdirectory(scudo) + endif() endif() - if(COMPILER_RT_BUILD_XRAY) - compiler_rt_test_runtime(xray) + if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY) + add_subdirectory(xray) endif() endif() -- cgit v1.2.1 From ad281e0a30af6db87b4019a958b7ebc3f68d8a99 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 27 Jun 2017 17:28:01 +0000 Subject: [PGO] Refactor file/buffer writer callback interfaces /NFC Introduces a 'owner' struct to include the overridable write method and the write context in C. This allows easy introdution of new member API to help reduce profile merge time in the follow up patch. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306432 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingBuffer.c | 17 +++++++++--- lib/profile/InstrProfilingFile.c | 23 ++++++++++++---- lib/profile/InstrProfilingInternal.h | 29 +++++++++++--------- lib/profile/InstrProfilingWriter.c | 51 ++++++++++++++++++------------------ 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c index ac259e83c..548f92205 100644 --- a/lib/profile/InstrProfilingBuffer.c +++ b/lib/profile/InstrProfilingBuffer.c @@ -45,15 +45,24 @@ uint64_t __llvm_profile_get_size_for_buffer_internal( (CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding; } +COMPILER_RT_VISIBILITY +void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) { + BufferWriter->Write = lprofBufferWriter; + BufferWriter->WriterCtx = Buffer; +} + COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { - return lprofWriteData(lprofBufferWriter, Buffer, 0); + ProfDataWriter BufferWriter; + initBufferWriter(&BufferWriter, Buffer); + return lprofWriteData(&BufferWriter, 0); } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { - return lprofWriteDataImpl(lprofBufferWriter, Buffer, DataBegin, DataEnd, - CountersBegin, CountersEnd, 0, NamesBegin, - NamesEnd); + ProfDataWriter BufferWriter; + initBufferWriter(&BufferWriter, Buffer); + return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin, + CountersEnd, 0, NamesBegin, NamesEnd); } diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index dfcbe52d7..75262109c 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -91,10 +91,11 @@ static const char *getCurFilename(char *FilenameBuf); static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } /* Return 1 if there is an error, otherwise return 0. */ -static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, - void **WriterCtx) { +static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, + uint32_t NumIOVecs) { + uint32_t I; - FILE *File = (FILE *)*WriterCtx; + FILE *File = (FILE *)This->WriterCtx; for (I = 0; I < NumIOVecs; I++) { if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != IOVecs[I].NumElm) @@ -103,12 +104,22 @@ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, return 0; } +static void initFileWriter(ProfDataWriter *This, FILE *File) { + This->Write = fileWriter; + This->WriterCtx = File; +} + COMPILER_RT_VISIBILITY ProfBufferIO * lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { FreeHook = &free; DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); VPBufferSize = BufferSz; - return lprofCreateBufferIO(fileWriter, File); + ProfDataWriter *fileWriter = + (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1); + initFileWriter(fileWriter, File); + ProfBufferIO *IO = lprofCreateBufferIO(fileWriter); + IO->OwnFileWriter = 1; + return IO; } static void setupIOBuffer() { @@ -226,7 +237,9 @@ static int writeFile(const char *OutputName) { FreeHook = &free; setupIOBuffer(); - RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); + ProfDataWriter fileWriter; + initFileWriter(&fileWriter, OutputFile); + RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader()); fclose(OutputFile); return RetVal; diff --git a/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h index c73b29101..ee710722a 100644 --- a/lib/profile/InstrProfilingInternal.h +++ b/lib/profile/InstrProfilingInternal.h @@ -48,17 +48,21 @@ typedef struct ProfDataIOVec { size_t NumElm; } ProfDataIOVec; -typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs, - void **WriterCtx); +struct ProfDataWriter; +typedef uint32_t (*WriterCallback)(struct ProfDataWriter *This, ProfDataIOVec *, + uint32_t NumIOVecs); + +typedef struct ProfDataWriter { + WriterCallback Write; + void *WriterCtx; +} ProfDataWriter; /*! * The data structure for buffered IO of profile data. */ typedef struct ProfBufferIO { - /* File handle. */ - void *File; - /* Low level IO callback. */ - WriterCallback FileWriter; + ProfDataWriter *FileWriter; + uint32_t OwnFileWriter; /* The start of the buffer. */ uint8_t *BufferStart; /* Total size of the buffer. */ @@ -73,7 +77,7 @@ ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz); /*! * This is the interface to create a handle for buffered IO. */ -ProfBufferIO *lprofCreateBufferIO(WriterCallback FileWriter, void *File); +ProfBufferIO *lprofCreateBufferIO(ProfDataWriter *FileWriter); /*! * The interface to destroy the bufferIO handle and reclaim @@ -96,8 +100,10 @@ int lprofBufferIOFlush(ProfBufferIO *BufferIO); /* The low level interface to write data into a buffer. It is used as the * callback by other high level writer methods such as buffered IO writer * and profile data writer. */ -uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, - void **WriterCtx); +uint32_t lprofBufferWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, + uint32_t NumIOVecs); + +void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer); struct ValueProfData; struct ValueProfRecord; @@ -133,9 +139,8 @@ typedef struct VPDataReaderType { uint32_t N); } VPDataReaderType; -int lprofWriteData(WriterCallback Writer, void *WriterCtx, - VPDataReaderType *VPDataReader); -int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, +int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader); +int lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, diff --git a/lib/profile/InstrProfilingWriter.c b/lib/profile/InstrProfilingWriter.c index 95f37e8e9..b6cefe049 100644 --- a/lib/profile/InstrProfilingWriter.c +++ b/lib/profile/InstrProfilingWriter.c @@ -31,11 +31,11 @@ COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0; /* The buffer writer is reponsponsible in keeping writer state * across the call. */ -COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, - uint32_t NumIOVecs, - void **WriterCtx) { +COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This, + ProfDataIOVec *IOVecs, + uint32_t NumIOVecs) { uint32_t I; - char **Buffer = (char **)WriterCtx; + char **Buffer = (char **)&This->WriterCtx; for (I = 0; I < NumIOVecs; I++) { size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; memcpy(*Buffer, IOVecs[I].Data, Length); @@ -44,28 +44,30 @@ COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, return 0; } -static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, - void *File, uint8_t *Buffer, uint32_t BufferSz) { - BufferIO->File = File; +static void llvmInitBufferIO(ProfBufferIO *BufferIO, ProfDataWriter *FileWriter, + uint8_t *Buffer, uint32_t BufferSz) { BufferIO->FileWriter = FileWriter; + BufferIO->OwnFileWriter = 0; BufferIO->BufferStart = Buffer; BufferIO->BufferSz = BufferSz; BufferIO->CurOffset = 0; } COMPILER_RT_VISIBILITY ProfBufferIO * -lprofCreateBufferIO(WriterCallback FileWriter, void *File) { +lprofCreateBufferIO(ProfDataWriter *FileWriter) { uint8_t *Buffer = DynamicBufferIOBuffer; uint32_t BufferSize = VPBufferSize; if (!Buffer) { Buffer = &BufferIOBuffer[0]; BufferSize = sizeof(BufferIOBuffer); } - llvmInitBufferIO(&TheBufferIO, FileWriter, File, Buffer, BufferSize); + llvmInitBufferIO(&TheBufferIO, FileWriter, Buffer, BufferSize); return &TheBufferIO; } COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) { + if (BufferIO->OwnFileWriter) + FreeHook(BufferIO->FileWriter); if (DynamicBufferIOBuffer) { FreeHook(DynamicBufferIOBuffer); DynamicBufferIOBuffer = 0; @@ -83,13 +85,16 @@ lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { /* Special case, bypass the buffer completely. */ ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; if (Size > BufferIO->BufferSz) { - if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) + if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1)) return -1; } else { /* Write the data to buffer */ uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; - lprofBufferWriter(IO, 1, (void **)&Buffer); - BufferIO->CurOffset = Buffer - BufferIO->BufferStart; + ProfDataWriter BufferWriter; + initBufferWriter(&BufferWriter, (char *)Buffer); + lprofBufferWriter(&BufferWriter, IO, 1); + BufferIO->CurOffset = + (uint8_t *)BufferWriter.WriterCtx - BufferIO->BufferStart; } return 0; } @@ -98,7 +103,7 @@ COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) { if (BufferIO->CurOffset) { ProfDataIOVec IO[] = { {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; - if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) + if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1)) return -1; BufferIO->CurOffset = 0; } @@ -201,7 +206,7 @@ static int writeOneValueProfData(ProfBufferIO *BufferIO, return 0; } -static int writeValueProfData(WriterCallback Writer, void *WriterCtx, +static int writeValueProfData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd) { @@ -211,7 +216,7 @@ static int writeValueProfData(WriterCallback Writer, void *WriterCtx, if (!VPDataReader) return 0; - BufferIO = lprofCreateBufferIO(Writer, WriterCtx); + BufferIO = lprofCreateBufferIO(Writer); for (DI = DataBegin; DI < DataEnd; DI++) { if (writeOneValueProfData(BufferIO, VPDataReader, DI)) @@ -225,8 +230,7 @@ static int writeValueProfData(WriterCallback Writer, void *WriterCtx, return 0; } -COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer, - void *WriterCtx, +COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); @@ -235,14 +239,12 @@ COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer, const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); - return lprofWriteDataImpl(Writer, WriterCtx, DataBegin, DataEnd, - CountersBegin, CountersEnd, VPDataReader, - NamesBegin, NamesEnd); + return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin, + CountersEnd, VPDataReader, NamesBegin, NamesEnd); } COMPILER_RT_VISIBILITY int -lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, - const __llvm_profile_data *DataBegin, +lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, @@ -273,9 +275,8 @@ lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, {CountersBegin, sizeof(uint64_t), CountersSize}, {NamesBegin, sizeof(uint8_t), NamesSize}, {Zeroes, sizeof(uint8_t), Padding}}; - if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx)) + if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec))) return -1; - return writeValueProfData(Writer, WriterCtx, VPDataReader, DataBegin, - DataEnd); + return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd); } -- cgit v1.2.1 From 4b54038e0f9f79ad910f8add82770c761f32b173 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 19:18:01 +0000 Subject: Only test sanitizers that are built when COMPILER_RT_SANITIZERS_TO_BUILD is used Summary: This allows check-all to be used when only a subset of the sanitizers are built. Reviewers: beanz, compnerd, rnk, pcc Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D34644 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306450 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 1 - test/CMakeLists.txt | 76 ++++++++++++++++++++++++----------------------------- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4ab1e933a..7000efb6b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -28,7 +28,6 @@ function(compiler_rt_build_runtime runtime) endfunction() function(compiler_rt_build_sanitizer sanitizer) - string(TOUPPER ${sanitizer} sanitizer_uppercase) string(TOLOWER ${sanitizer} sanitizer_lowercase) list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) if(NOT ${result} EQUAL -1) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7685fb3f4..040d19bcc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,24 @@ if(NOT ANDROID) endif() endif() +function(compiler_rt_test_runtime runtime) + string(TOUPPER ${runtime} runtime_uppercase) + if(COMPILER_RT_HAS_${runtime_uppercase}) + add_subdirectory(${runtime}) + foreach(directory ${ARGN}) + add_subdirectory(${directory}) + endforeach() + endif() +endfunction() + +function(compiler_rt_test_sanitizer sanitizer) + string(TOLOWER ${sanitizer} sanitizer_lowercase) + list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) + if(NOT ${result} EQUAL -1) + compiler_rt_test_runtime(${sanitizer} ${ARGN}) + endif() +endfunction() + # Run sanitizer tests only if we're sure that clang would produce # working binaries. if(COMPILER_RT_CAN_EXECUTE_TESTS) @@ -42,49 +60,25 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) add_subdirectory(builtins) endif() if(COMPILER_RT_BUILD_SANITIZERS) - if(COMPILER_RT_HAS_ASAN) - add_subdirectory(asan) - endif() - if(COMPILER_RT_HAS_DFSAN) - add_subdirectory(dfsan) - endif() - if (COMPILER_RT_HAS_INTERCEPTION) - add_subdirectory(interception) - endif() - if(COMPILER_RT_HAS_LSAN) - add_subdirectory(lsan) - endif() - if(COMPILER_RT_HAS_MSAN) - add_subdirectory(msan) - endif() - if(COMPILER_RT_HAS_PROFILE) - add_subdirectory(profile) - endif() - if(COMPILER_RT_HAS_SANITIZER_COMMON) - add_subdirectory(sanitizer_common) - endif() - if(COMPILER_RT_HAS_TSAN) - add_subdirectory(tsan) - endif() - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(ubsan) - endif() + compiler_rt_test_runtime(interception) + + compiler_rt_test_runtime(lsan) # CFI tests require diagnostic mode, which is implemented in UBSan. - if(COMPILER_RT_HAS_UBSAN) - add_subdirectory(cfi) - endif() - if(COMPILER_RT_HAS_SAFESTACK) - add_subdirectory(safestack) - endif() - if(COMPILER_RT_HAS_ESAN) - add_subdirectory(esan) - endif() - if(COMPILER_RT_HAS_SCUDO) - add_subdirectory(scudo) - endif() + compiler_rt_test_runtime(ubsan cfi) + compiler_rt_test_runtime(sanitizer_common) + + compiler_rt_test_sanitizer(asan) + compiler_rt_test_sanitizer(dfsan) + compiler_rt_test_sanitizer(msan) + compiler_rt_test_sanitizer(tsan) + compiler_rt_test_sanitizer(safestack) + compiler_rt_test_sanitizer(esan) + compiler_rt_test_sanitizer(scudo) + + compiler_rt_test_runtime(profile) endif() - if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY) - add_subdirectory(xray) + if(COMPILER_RT_BUILD_XRAY) + compiler_rt_test_runtime(xray) endif() endif() -- cgit v1.2.1 From 2dcc25721dcf6329b8a0cb0f526996a8e841f8bb Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 19:32:39 +0000 Subject: Loop directly over sanitizers to build in cmake Summary: Cleaner than computing the intersection for each possible sanitizer Reviewers: compnerd, beanz Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D34693 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306453 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 25 ++++++------------------- test/CMakeLists.txt | 18 +++--------------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7000efb6b..83a5acde7 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -21,17 +21,6 @@ function(compiler_rt_build_runtime runtime) string(TOUPPER ${runtime} runtime_uppercase) if(COMPILER_RT_HAS_${runtime_uppercase}) add_subdirectory(${runtime}) - foreach(directory ${ARGN}) - add_subdirectory(${directory}) - endforeach() - endif() -endfunction() - -function(compiler_rt_build_sanitizer sanitizer) - string(TOLOWER ${sanitizer} sanitizer_lowercase) - list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) - if(NOT ${result} EQUAL -1) - compiler_rt_build_runtime(${sanitizer} ${ARGN}) endif() endfunction() @@ -44,14 +33,12 @@ if(COMPILER_RT_BUILD_SANITIZERS) add_subdirectory(ubsan) endif() - compiler_rt_build_sanitizer(asan) - compiler_rt_build_sanitizer(dfsan) - compiler_rt_build_sanitizer(msan) - compiler_rt_build_sanitizer(tsan tsan/dd) - compiler_rt_build_sanitizer(safestack) - compiler_rt_build_sanitizer(cfi) - compiler_rt_build_sanitizer(esan) - compiler_rt_build_sanitizer(scudo) + foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) + compiler_rt_build_runtime(${sanitizer}) + if(${sanitizer} STREQUAL tsan) + add_subdirectory(tsan/dd) + endif() + endforeach() compiler_rt_build_runtime(profile) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 040d19bcc..0a6c11c34 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,14 +45,6 @@ function(compiler_rt_test_runtime runtime) endif() endfunction() -function(compiler_rt_test_sanitizer sanitizer) - string(TOLOWER ${sanitizer} sanitizer_lowercase) - list(FIND COMPILER_RT_SANITIZERS_TO_BUILD ${sanitizer_lowercase} result) - if(NOT ${result} EQUAL -1) - compiler_rt_test_runtime(${sanitizer} ${ARGN}) - endif() -endfunction() - # Run sanitizer tests only if we're sure that clang would produce # working binaries. if(COMPILER_RT_CAN_EXECUTE_TESTS) @@ -67,13 +59,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) compiler_rt_test_runtime(ubsan cfi) compiler_rt_test_runtime(sanitizer_common) - compiler_rt_test_sanitizer(asan) - compiler_rt_test_sanitizer(dfsan) - compiler_rt_test_sanitizer(msan) - compiler_rt_test_sanitizer(tsan) - compiler_rt_test_sanitizer(safestack) - compiler_rt_test_sanitizer(esan) - compiler_rt_test_sanitizer(scudo) + foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) + compiler_rt_test_runtime(${sanitizer}) + endforeach() compiler_rt_test_runtime(profile) endif() -- cgit v1.2.1 From 1a427fa56cbea4e65c1f01e25b3cf91da78eadad Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 19:52:35 +0000 Subject: Don't double-include cfi tests on linux git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306455 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0a6c11c34..9b4759dfb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,7 +60,10 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) compiler_rt_test_runtime(sanitizer_common) foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) - compiler_rt_test_runtime(${sanitizer}) + # cfi testing is gated on ubsan + if(NOT ${sanitizer} STREQUAL cfi) + compiler_rt_test_runtime(${sanitizer}) + endif() endforeach() compiler_rt_test_runtime(profile) -- cgit v1.2.1 From b24f89116ba057e006bcfa9307544f70fd23af26 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 27 Jun 2017 21:10:46 +0000 Subject: Don't build tsan/dd when COMPILER_RT_HAS_TSAN is false git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306463 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 83a5acde7..90f72d02a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -21,6 +21,9 @@ function(compiler_rt_build_runtime runtime) string(TOUPPER ${runtime} runtime_uppercase) if(COMPILER_RT_HAS_${runtime_uppercase}) add_subdirectory(${runtime}) + if(${runtime} STREQUAL tsan) + add_subdirectory(tsan/dd) + endif() endif() endfunction() @@ -35,9 +38,6 @@ if(COMPILER_RT_BUILD_SANITIZERS) foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) compiler_rt_build_runtime(${sanitizer}) - if(${sanitizer} STREQUAL tsan) - add_subdirectory(tsan/dd) - endif() endforeach() compiler_rt_build_runtime(profile) -- cgit v1.2.1 From a8a922c4f3636a58856848406755786e69c6d7a5 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 27 Jun 2017 22:42:24 +0000 Subject: [Profile] Remove redundant call git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306480 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingFile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index 75262109c..f99f86d89 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -218,7 +218,6 @@ static FILE *openFileForMerging(const char *ProfileFileName) { fclose(ProfileFile); return NULL; } - fseek(ProfileFile, 0L, SEEK_SET); return ProfileFile; } -- cgit v1.2.1 From 054ff981e8e285ba623c9255f2ecc52263f0e03a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 27 Jun 2017 22:52:38 +0000 Subject: [msan] Intercept wcscat, wcsncat. Also move wcslen, wscnlen to common interceptors. Reviewers: vitalybuka Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34656 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306482 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 11 --- lib/msan/msan_interceptors.cc | 82 +++++++++------------- lib/msan/tests/msan_test.cc | 42 +++++++++++ .../sanitizer_common_interceptors.inc | 77 +++++++++++++++++--- .../sanitizer_platform_interceptors.h | 2 + 5 files changed, 145 insertions(+), 69 deletions(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 264d5aee8..e03c0f94c 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -579,17 +579,6 @@ INTERCEPTOR(char*, __strdup, const char *s) { } #endif // ASAN_INTERCEPT___STRDUP -INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, wcslen); - SIZE_T length = internal_wcslen(s); - if (!asan_init_is_running) { - ENSURE_ASAN_INITED(); - ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t)); - } - return length; -} - INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncpy); diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 0f5069344..ce8444a3b 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -538,49 +538,6 @@ INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) { return res; } -INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { - ENSURE_MSAN_INITED(); - SIZE_T res = REAL(wcslen)(s); - CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1)); - return res; -} - -INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { - ENSURE_MSAN_INITED(); - SIZE_T res = REAL(wcsnlen)(s, n); - CHECK_UNPOISONED(s, sizeof(wchar_t) * Min(res + 1, n)); - return res; -} - -// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); -INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { - ENSURE_MSAN_INITED(); - wchar_t *res = REAL(wcschr)(s, wc, ps); - return res; -} - -// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); -INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - wchar_t *res = REAL(wcscpy)(dest, src); - CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), - &stack); - return res; -} - -INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, - SIZE_T n) { // NOLINT - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - SIZE_T copy_size = REAL(wcsnlen)(src, n); - if (copy_size < n) copy_size++; // trailing \0 - wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT - CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack); - __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t)); - return res; -} - // wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n); INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { ENSURE_MSAN_INITED(); @@ -1344,11 +1301,11 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } -#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ - do { \ - GET_STORE_STACK_TRACE; \ - CopyShadowAndOrigin(to, from, size, &stack); \ - __msan_unpoison(to + size, 1); \ +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ } while (false) #include "sanitizer_common/sanitizer_platform_interceptors.h" @@ -1424,6 +1381,35 @@ INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) { return res; } +// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); +INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { + ENSURE_MSAN_INITED(); + wchar_t *res = REAL(wcschr)(s, wc, ps); + return res; +} + +// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); +INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + wchar_t *res = REAL(wcscpy)(dest, src); + CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1), + &stack); + return res; +} + +INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, + SIZE_T n) { // NOLINT + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = REAL(wcsnlen)(src, n); + if (copy_size < n) copy_size++; // trailing \0 + wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT + CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack); + __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t)); + return res; +} + // These interface functions reside here so that they can use // REAL(memset), etc. void __msan_unpoison(const void *a, uptr size) { diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 543a7eb98..b2d5f7c60 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1707,6 +1707,48 @@ TEST(MemorySanitizer, strncat_overflow) { // NOLINT EXPECT_POISONED(a[7]); } +TEST(MemorySanitizer, wcscat) { + wchar_t a[10]; + wchar_t b[] = L"def"; + wcscpy(a, L"abc"); + + wcscat(a, b); + EXPECT_EQ(6U, wcslen(a)); + EXPECT_POISONED(a[7]); + + a[3] = 0; + __msan_poison(b + 1, sizeof(wchar_t)); + EXPECT_UMR(wcscat(a, b)); + + __msan_unpoison(b + 1, sizeof(wchar_t)); + __msan_poison(a + 2, sizeof(wchar_t)); + EXPECT_UMR(wcscat(a, b)); +} + +TEST(MemorySanitizer, wcsncat) { + wchar_t a[10]; + wchar_t b[] = L"def"; + wcscpy(a, L"abc"); + + wcsncat(a, b, 5); + EXPECT_EQ(6U, wcslen(a)); + EXPECT_POISONED(a[7]); + + a[3] = 0; + __msan_poison(a + 4, sizeof(wchar_t) * 6); + wcsncat(a, b, 2); + EXPECT_EQ(5U, wcslen(a)); + EXPECT_POISONED(a[6]); + + a[3] = 0; + __msan_poison(b + 1, sizeof(wchar_t)); + EXPECT_UMR(wcsncat(a, b, 2)); + + __msan_unpoison(b + 1, sizeof(wchar_t)); + __msan_poison(a + 2, sizeof(wchar_t)); + EXPECT_UMR(wcsncat(a, b, 2)); +} + #define TEST_STRTO_INT(func_name, char_type, str_prefix) \ TEST(MemorySanitizer, func_name) { \ char_type *e; \ diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 6ca431d8a..af7de6759 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -224,16 +224,16 @@ bool PlatformHasDifferentMemcpyAndMemmove(); #endif #ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL -#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ - COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ - uptr copy_length = internal_strnlen(s, size); \ - char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ - if (common_flags()->intercept_strndup) { \ - COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ - } \ - COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ - internal_memcpy(new_mem, s, copy_length); \ - new_mem[copy_length] = '\0'; \ +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr copy_length = internal_strnlen(s, size); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ return new_mem; #endif @@ -6199,6 +6199,61 @@ INTERCEPTOR(int, mprobe, void *ptr) { } #endif +#if SANITIZER_INTERCEPT_WCSLEN +INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s); + SIZE_T res = REAL(wcslen)(s); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (res + 1)); + return res; +} + +INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsnlen, s, n); + SIZE_T res = REAL(wcsnlen)(s, n); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * Min(res + 1, n)); + return res; +} +#define INIT_WCSLEN \ + COMMON_INTERCEPT_FUNCTION(wcslen); \ + COMMON_INTERCEPT_FUNCTION(wcsnlen); +#else +#define INIT_WCSLEN +#endif + +#if SANITIZER_INTERCEPT_WCSCAT +INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcscat, dst, src); + SIZE_T src_size = REAL(wcslen)(src); + SIZE_T dst_size = REAL(wcslen)(dst); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, (src_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, + (src_size + 1) * sizeof(wchar_t)); + return REAL(wcscat)(dst, src); // NOLINT +} + +INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsncat, dst, src, n); + SIZE_T src_size = REAL(wcsnlen)(src, n); + SIZE_T dst_size = REAL(wcslen)(dst); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, + Min(src_size + 1, n) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, + (src_size + 1) * sizeof(wchar_t)); + return REAL(wcsncat)(dst, src, n); // NOLINT +} +#define INIT_WCSCAT \ + COMMON_INTERCEPT_FUNCTION(wcscat); \ + COMMON_INTERCEPT_FUNCTION(wcsncat); +#else +#define INIT_WCSCAT +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -6403,4 +6458,6 @@ static void InitializeCommonInterceptors() { INIT_UTMP; INIT_UTMPX; INIT_GETLOADAVG; + INIT_WCSLEN; + INIT_WCSCAT; } diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a95497467..da683c62f 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -354,5 +354,7 @@ #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_WCSLEN SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_WCSCAT SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H -- cgit v1.2.1 From 30e44dc9287437438ef90d5acc7340061ce12111 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 28 Jun 2017 00:37:29 +0000 Subject: [asan] Fix windows build. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306493 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index e03c0f94c..ed12a9ac9 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -711,7 +711,6 @@ void InitializeAsanInterceptors() { // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT ASAN_INTERCEPT_FUNC(strcpy); // NOLINT - ASAN_INTERCEPT_FUNC(wcslen); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); -- cgit v1.2.1 From 659b039b43cb9b15099676159633e27a60765104 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 28 Jun 2017 04:44:36 +0000 Subject: [XRay][compiler-rt][NFC] Add example always/never instrument files. Summary: This change introduces two files that show exaples of the always/never instrument files that can be provided to clang. We don't add these as defaults yet in clang, which we can do later on (in a separate change). We also add a test that makes sure that these apply in the compiler-rt project tests, and that changes in clang don't break the expectations in compiler-rt. Reviewers: pelikan, kpw Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34669 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306502 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_always_instrument.txt | 6 ++++++ lib/xray/xray_never_instrument.txt | 6 ++++++ test/xray/TestCases/always-never-instrument.cc | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 lib/xray/xray_always_instrument.txt create mode 100644 lib/xray/xray_never_instrument.txt create mode 100644 test/xray/TestCases/always-never-instrument.cc diff --git a/lib/xray/xray_always_instrument.txt b/lib/xray/xray_always_instrument.txt new file mode 100644 index 000000000..151ed703d --- /dev/null +++ b/lib/xray/xray_always_instrument.txt @@ -0,0 +1,6 @@ +# List of function matchers common to C/C++ applications that make sense to +# always instrument. You can use this as an argument to +# -fxray-always-instrument= along with your project-specific lists. + +# Always instrument the main function. +fun:main diff --git a/lib/xray/xray_never_instrument.txt b/lib/xray/xray_never_instrument.txt new file mode 100644 index 000000000..7fa48dda7 --- /dev/null +++ b/lib/xray/xray_never_instrument.txt @@ -0,0 +1,6 @@ +# List of function matchers common to C/C++ applications that make sense to +# never instrument. You can use this as an argument to +# -fxray-never-instrument= along with your project-specific lists. + +# Never instrument any function whose symbol starts with __xray. +fun:__xray* diff --git a/test/xray/TestCases/always-never-instrument.cc b/test/xray/TestCases/always-never-instrument.cc new file mode 100644 index 000000000..990ee3eff --- /dev/null +++ b/test/xray/TestCases/always-never-instrument.cc @@ -0,0 +1,21 @@ +// Test that the always/never instrument lists apply. +// RUN: echo "fun:main" > %tmp-always.txt +// RUN: echo "fun:__xray*" > %tmp-never.txt +// RUN: %clangxx_xray \ +// RUN: -fxray-never-instrument=%tmp-never.txt \ +// RUN: -fxray-always-instrument=%tmp-always.txt \ +// RUN: %s -o %t +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix NOINSTR +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix ALWAYSINSTR + +// NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} +int __xray_NeverInstrumented() { + return 0; +} + +// ALWAYSINSTR: {{.*function-name:.*main.*}} +int main(int argc, char *argv[]) { + return __xray_NeverInstrumented(); +} -- cgit v1.2.1 From 0371dabce2ccba52d1ba89f93e45fb164048ab06 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 28 Jun 2017 05:03:28 +0000 Subject: Re-enable wait.cc, wait4.cc, waitid.cc tests on Darwin. They used to be flaky, something to do with LeakSanitizer now being enabled on Darwin. Let's re-enable them and see if they are still flaky or not. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306504 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/wait.cc | 2 -- test/asan/TestCases/Posix/wait4.cc | 1 - test/asan/TestCases/Posix/waitid.cc | 2 -- 3 files changed, 5 deletions(-) diff --git a/test/asan/TestCases/Posix/wait.cc b/test/asan/TestCases/Posix/wait.cc index 85e819369..9fe9651bb 100644 --- a/test/asan/TestCases/Posix/wait.cc +++ b/test/asan/TestCases/Posix/wait.cc @@ -4,8 +4,6 @@ // 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 #include #include diff --git a/test/asan/TestCases/Posix/wait4.cc b/test/asan/TestCases/Posix/wait4.cc index aee5570b8..b95246efa 100644 --- a/test/asan/TestCases/Posix/wait4.cc +++ b/test/asan/TestCases/Posix/wait4.cc @@ -5,7 +5,6 @@ // RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s // XFAIL: android -// UNSUPPORTED: darwin #include #include diff --git a/test/asan/TestCases/Posix/waitid.cc b/test/asan/TestCases/Posix/waitid.cc index 20fb0c694..8b516dca9 100644 --- a/test/asan/TestCases/Posix/waitid.cc +++ b/test/asan/TestCases/Posix/waitid.cc @@ -1,8 +1,6 @@ // 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 #include #include -- cgit v1.2.1 From 7ed3d6d5aa1774a76cee7c3405b23dfc5dfbc30b Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 28 Jun 2017 05:19:59 +0000 Subject: [XRay][compiler-rt] Only run test in x86_64 linux. Followup to D34669. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306505 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/always-never-instrument.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/xray/TestCases/always-never-instrument.cc b/test/xray/TestCases/always-never-instrument.cc index 990ee3eff..4e196859b 100644 --- a/test/xray/TestCases/always-never-instrument.cc +++ b/test/xray/TestCases/always-never-instrument.cc @@ -9,6 +9,8 @@ // RUN: FileCheck %s --check-prefix NOINSTR // RUN: %llvm_xray extract -symbolize %t | \ // RUN: FileCheck %s --check-prefix ALWAYSINSTR +// REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree // NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} int __xray_NeverInstrumented() { -- cgit v1.2.1 From 4cd87c537385b5d17231e0619968fa5cd0818a1d Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 28 Jun 2017 05:21:15 +0000 Subject: [XRay][compiler-rt][NFC] Move test case into correct directory. Followup to D34669. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306506 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/always-never-instrument.cc | 23 ++++++++++++++++++++++ test/xray/TestCases/always-never-instrument.cc | 23 ---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 test/xray/TestCases/Linux/always-never-instrument.cc delete mode 100644 test/xray/TestCases/always-never-instrument.cc diff --git a/test/xray/TestCases/Linux/always-never-instrument.cc b/test/xray/TestCases/Linux/always-never-instrument.cc new file mode 100644 index 000000000..4e196859b --- /dev/null +++ b/test/xray/TestCases/Linux/always-never-instrument.cc @@ -0,0 +1,23 @@ +// Test that the always/never instrument lists apply. +// RUN: echo "fun:main" > %tmp-always.txt +// RUN: echo "fun:__xray*" > %tmp-never.txt +// RUN: %clangxx_xray \ +// RUN: -fxray-never-instrument=%tmp-never.txt \ +// RUN: -fxray-always-instrument=%tmp-always.txt \ +// RUN: %s -o %t +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix NOINSTR +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix ALWAYSINSTR +// REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree + +// NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} +int __xray_NeverInstrumented() { + return 0; +} + +// ALWAYSINSTR: {{.*function-name:.*main.*}} +int main(int argc, char *argv[]) { + return __xray_NeverInstrumented(); +} diff --git a/test/xray/TestCases/always-never-instrument.cc b/test/xray/TestCases/always-never-instrument.cc deleted file mode 100644 index 4e196859b..000000000 --- a/test/xray/TestCases/always-never-instrument.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Test that the always/never instrument lists apply. -// RUN: echo "fun:main" > %tmp-always.txt -// RUN: echo "fun:__xray*" > %tmp-never.txt -// RUN: %clangxx_xray \ -// RUN: -fxray-never-instrument=%tmp-never.txt \ -// RUN: -fxray-always-instrument=%tmp-always.txt \ -// RUN: %s -o %t -// RUN: %llvm_xray extract -symbolize %t | \ -// RUN: FileCheck %s --check-prefix NOINSTR -// RUN: %llvm_xray extract -symbolize %t | \ -// RUN: FileCheck %s --check-prefix ALWAYSINSTR -// REQUIRES: x86_64-linux -// REQUIRES: built-in-llvm-tree - -// NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} -int __xray_NeverInstrumented() { - return 0; -} - -// ALWAYSINSTR: {{.*function-name:.*main.*}} -int main(int argc, char *argv[]) { - return __xray_NeverInstrumented(); -} -- cgit v1.2.1 From 8ec8c48d6b22265de20c6d0d5f2e047946c7fd58 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 28 Jun 2017 15:13:09 +0000 Subject: Revert r306504: Re-enable wait.cc, wait4.cc, waitid.cc tests on Darwin. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306551 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/wait.cc | 2 ++ test/asan/TestCases/Posix/wait4.cc | 1 + test/asan/TestCases/Posix/waitid.cc | 2 ++ 3 files changed, 5 insertions(+) diff --git a/test/asan/TestCases/Posix/wait.cc b/test/asan/TestCases/Posix/wait.cc index 9fe9651bb..85e819369 100644 --- a/test/asan/TestCases/Posix/wait.cc +++ b/test/asan/TestCases/Posix/wait.cc @@ -4,6 +4,8 @@ // 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 #include #include diff --git a/test/asan/TestCases/Posix/wait4.cc b/test/asan/TestCases/Posix/wait4.cc index b95246efa..aee5570b8 100644 --- a/test/asan/TestCases/Posix/wait4.cc +++ b/test/asan/TestCases/Posix/wait4.cc @@ -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 #include diff --git a/test/asan/TestCases/Posix/waitid.cc b/test/asan/TestCases/Posix/waitid.cc index 8b516dca9..20fb0c694 100644 --- a/test/asan/TestCases/Posix/waitid.cc +++ b/test/asan/TestCases/Posix/waitid.cc @@ -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 #include #include -- cgit v1.2.1 From 59b78d964b68f9e8c4fe540e759ead35dc35e240 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Wed, 28 Jun 2017 16:46:06 +0000 Subject: [PGO] Reduce IO in profile dumping with merging Differential Revision: http://reviews.llvm.org/D34709 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306561 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingBuffer.c | 4 ++-- lib/profile/InstrProfilingFile.c | 30 +++++++++++++++++++----------- lib/profile/InstrProfilingInternal.h | 8 +++++--- lib/profile/InstrProfilingWriter.c | 22 +++++++++++++--------- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c index 548f92205..a7e852f53 100644 --- a/lib/profile/InstrProfilingBuffer.c +++ b/lib/profile/InstrProfilingBuffer.c @@ -54,7 +54,7 @@ void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) { COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { ProfDataWriter BufferWriter; initBufferWriter(&BufferWriter, Buffer); - return lprofWriteData(&BufferWriter, 0); + return lprofWriteData(&BufferWriter, 0, 0); } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( @@ -64,5 +64,5 @@ COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( ProfDataWriter BufferWriter; initBufferWriter(&BufferWriter, Buffer); return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin, - CountersEnd, 0, NamesBegin, NamesEnd); + CountersEnd, 0, NamesBegin, NamesEnd, 0); } diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index f99f86d89..d038bb9cb 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -93,13 +93,17 @@ static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } /* Return 1 if there is an error, otherwise return 0. */ static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, uint32_t NumIOVecs) { - uint32_t I; FILE *File = (FILE *)This->WriterCtx; for (I = 0; I < NumIOVecs; I++) { - if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != - IOVecs[I].NumElm) - return 1; + if (IOVecs[I].Data) { + if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != + IOVecs[I].NumElm) + return 1; + } else { + if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1) + return 1; + } } return 0; } @@ -133,9 +137,10 @@ static void setupIOBuffer() { /* Read profile data in \c ProfileFile and merge with in-memory profile counters. Returns -1 if there is fatal error, otheriwse - 0 is returned. + 0 is returned. Returning 0 does not mean merge is actually + performed. If merge is actually done, *MergeDone is set to 1. */ -static int doProfileMerging(FILE *ProfileFile) { +static int doProfileMerging(FILE *ProfileFile, int *MergeDone) { uint64_t ProfileFileSize; char *ProfileBuffer; @@ -180,6 +185,8 @@ static int doProfileMerging(FILE *ProfileFile) { __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); (void)munmap(ProfileBuffer, ProfileFileSize); + *MergeDone = 1; + return 0; } @@ -201,7 +208,7 @@ static void createProfileDir(const char *Filename) { * dumper. With profile merging enabled, each executable as well as any of * its instrumented shared libraries dump profile data into their own data file. */ -static FILE *openFileForMerging(const char *ProfileFileName) { +static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { FILE *ProfileFile; int rc; @@ -210,8 +217,8 @@ static FILE *openFileForMerging(const char *ProfileFileName) { if (!ProfileFile) return NULL; - rc = doProfileMerging(ProfileFile); - if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || + rc = doProfileMerging(ProfileFile, MergeDone); + if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) || fseek(ProfileFile, 0L, SEEK_SET) == -1) { PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, strerror(errno)); @@ -226,10 +233,11 @@ static int writeFile(const char *OutputName) { int RetVal; FILE *OutputFile; + int MergeDone = 0; if (!doMerging()) OutputFile = fopen(OutputName, "ab"); else - OutputFile = openFileForMerging(OutputName); + OutputFile = openFileForMerging(OutputName, &MergeDone); if (!OutputFile) return -1; @@ -238,7 +246,7 @@ static int writeFile(const char *OutputName) { setupIOBuffer(); ProfDataWriter fileWriter; initFileWriter(&fileWriter, OutputFile); - RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader()); + RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone); fclose(OutputFile); return RetVal; diff --git a/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h index ee710722a..36490ef7d 100644 --- a/lib/profile/InstrProfilingInternal.h +++ b/lib/profile/InstrProfilingInternal.h @@ -102,7 +102,6 @@ int lprofBufferIOFlush(ProfBufferIO *BufferIO); * and profile data writer. */ uint32_t lprofBufferWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, uint32_t NumIOVecs); - void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer); struct ValueProfData; @@ -139,14 +138,17 @@ typedef struct VPDataReaderType { uint32_t N); } VPDataReaderType; -int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader); +/* Write profile data to destinitation. If SkipNameDataWrite is set to 1, + the name data is already in destintation, we just skip over it. */ +int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader, + int SkipNameDataWrite); int lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, - const char *NamesEnd); + const char *NamesEnd, int SkipNameDataWrite); /* Merge value profile data pointed to by SrcValueProfData into * in-memory profile counters pointed by to DstData. */ diff --git a/lib/profile/InstrProfilingWriter.c b/lib/profile/InstrProfilingWriter.c index b6cefe049..d4c9b9bd6 100644 --- a/lib/profile/InstrProfilingWriter.c +++ b/lib/profile/InstrProfilingWriter.c @@ -38,7 +38,8 @@ COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This, char **Buffer = (char **)&This->WriterCtx; for (I = 0; I < NumIOVecs; I++) { size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; - memcpy(*Buffer, IOVecs[I].Data, Length); + if (IOVecs[I].Data) + memcpy(*Buffer, IOVecs[I].Data, Length); *Buffer += Length; } return 0; @@ -231,7 +232,8 @@ static int writeValueProfData(ProfDataWriter *Writer, } COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer, - VPDataReaderType *VPDataReader) { + VPDataReaderType *VPDataReader, + int SkipNameDataWrite) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); @@ -240,7 +242,8 @@ COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer, const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin, - CountersEnd, VPDataReader, NamesBegin, NamesEnd); + CountersEnd, VPDataReader, NamesBegin, NamesEnd, + SkipNameDataWrite); } COMPILER_RT_VISIBILITY int @@ -248,7 +251,7 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, - const char *NamesEnd) { + const char *NamesEnd, int SkipNameDataWrite) { /* Calculate size of sections. */ const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); @@ -270,11 +273,12 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin, #include "InstrProfData.inc" /* Write the data. */ - ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1}, - {DataBegin, sizeof(__llvm_profile_data), DataSize}, - {CountersBegin, sizeof(uint64_t), CountersSize}, - {NamesBegin, sizeof(uint8_t), NamesSize}, - {Zeroes, sizeof(uint8_t), Padding}}; + ProfDataIOVec IOVec[] = { + {&Header, sizeof(__llvm_profile_header), 1}, + {DataBegin, sizeof(__llvm_profile_data), DataSize}, + {CountersBegin, sizeof(uint64_t), CountersSize}, + {SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize}, + {Zeroes, sizeof(uint8_t), Padding}}; if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec))) return -1; -- cgit v1.2.1 From 7ea9c79f1e0f9c588e61a638e5354a45b239876c Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 28 Jun 2017 21:58:57 +0000 Subject: [Sanitizers] Operator new() interceptors always die on allocation error Summary: Operator new interceptors behavior is now controlled by their nothrow property as well as by allocator_may_return_null flag value: - allocator_may_return_null=* + new() - die on allocation error - allocator_may_return_null=0 + new(nothrow) - die on allocation error - allocator_may_return_null=1 + new(nothrow) - return null Ideally new() should throw std::bad_alloc exception, but that is not trivial to achieve, hence TODO. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34731 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306604 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 11 ++- lib/asan/asan_new_delete.cc | 39 +++++---- lib/lsan/lsan_interceptors.cc | 23 +++-- lib/msan/msan_new_delete.cc | 20 +++-- lib/sanitizer_common/sanitizer_allocator.cc | 4 +- lib/sanitizer_common/sanitizer_allocator.h | 4 +- lib/scudo/scudo_new_delete.cpp | 9 +- lib/tsan/rtl/tsan_new_delete.cc | 13 +-- test/asan/TestCases/allocator_returns_null.cc | 107 ++++++++++++++++-------- test/msan/allocator_returns_null.cc | 115 +++++++++++++++++-------- test/scudo/sizes.cpp | 45 +++++++--- test/tsan/allocator_returns_null.cc | 116 ++++++++++++++++++-------- 12 files changed, 342 insertions(+), 164 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 57651f49c..36348834e 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -160,7 +160,11 @@ struct QuarantineCallback { } void *Allocate(uptr size) { - return get_allocator().Allocate(cache_, size, 1); + void *res = get_allocator().Allocate(cache_, size, 1); + // TODO(alekseys): Consider making quarantine OOM-friendly. + if (UNLIKELY(!res)) + return DieOnFailure::OnOOM(); + return res; } void Deallocate(void *p) { @@ -524,8 +528,7 @@ struct Allocator { // Expects the chunk to already be marked as quarantined by using // AtomicallySetQuarantineFlagIfAllocated. - void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack, - AllocType alloc_type) { + void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); CHECK_GE(m->alloc_tid, 0); if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area. @@ -603,7 +606,7 @@ struct Allocator { ReportNewDeleteSizeMismatch(p, delete_size, stack); } - QuarantineChunk(m, ptr, stack, alloc_type); + QuarantineChunk(m, ptr, stack); } void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) { diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index 3283fb394..a64fe583b 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -63,12 +63,17 @@ struct nothrow_t {}; enum class align_val_t: size_t {}; } // namespace std -#define OPERATOR_NEW_BODY(type) \ +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(type, nothrow) \ GET_STACK_TRACE_MALLOC;\ - return asan_memalign(0, size, &stack, type); -#define OPERATOR_NEW_BODY_ALIGN(type) \ + void *res = asan_memalign(0, size, &stack, type);\ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + return res; +#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ GET_STACK_TRACE_MALLOC;\ - return asan_memalign((uptr)align, size, &stack, type); + void *res = asan_memalign((uptr)align, size, &stack, type);\ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + return res; // On OS X it's not enough to just provide our own 'operator new' and // 'operator delete' implementations, because they're going to be in the @@ -79,40 +84,42 @@ enum class align_val_t: size_t {}; // OS X we need to intercept them using their mangled names. #if !SANITIZER_MAC CXX_OPERATOR_ATTRIBUTE -void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); } +void *operator new(size_t size) +{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE -void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); } +void *operator new[](size_t size) +{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::nothrow_t const&) -{ OPERATOR_NEW_BODY(FROM_NEW); } +{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) -{ OPERATOR_NEW_BODY(FROM_NEW_BR); } +{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::align_val_t align) -{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size, std::align_val_t align) -{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) -{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) -{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); } #else // SANITIZER_MAC INTERCEPTOR(void *, _Znwm, size_t size) { - OPERATOR_NEW_BODY(FROM_NEW); + OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); } INTERCEPTOR(void *, _Znam, size_t size) { - OPERATOR_NEW_BODY(FROM_NEW_BR); + OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); } INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(FROM_NEW); + OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); } INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(FROM_NEW_BR); + OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); } #endif diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 9e39a7d19..b6ac7b77c 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -199,19 +199,26 @@ INTERCEPTOR(int, mprobe, void *ptr) { } #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE -#define OPERATOR_NEW_BODY \ - ENSURE_LSAN_INITED; \ - GET_STACK_TRACE_MALLOC; \ - return Allocate(stack, size, 1, kAlwaysClearMemory); +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(nothrow) \ + ENSURE_LSAN_INITED; \ + GET_STACK_TRACE_MALLOC; \ + void *res = Allocate(stack, size, 1, kAlwaysClearMemory);\ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + return res; INTERCEPTOR_ATTRIBUTE -void *operator new(size_t size) { OPERATOR_NEW_BODY; } +void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new[](size_t size) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } +void *operator new(size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} INTERCEPTOR_ATTRIBUTE -void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} #define OPERATOR_DELETE_BODY \ ENSURE_LSAN_INITED; \ diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc index 540100316..c7295feeb 100644 --- a/lib/msan/msan_new_delete.cc +++ b/lib/msan/msan_new_delete.cc @@ -14,6 +14,7 @@ #include "msan.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator.h" #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE @@ -27,18 +28,25 @@ namespace std { } // namespace std -#define OPERATOR_NEW_BODY \ +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(nothrow) \ GET_MALLOC_STACK_TRACE; \ - return MsanReallocate(&stack, 0, size, sizeof(u64), false) + void *res = MsanReallocate(&stack, 0, size, sizeof(u64), false);\ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + return res INTERCEPTOR_ATTRIBUTE -void *operator new(size_t size) { OPERATOR_NEW_BODY; } +void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new[](size_t size) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } +void *operator new(size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} INTERCEPTOR_ATTRIBUTE -void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } +void *operator new[](size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} #define OPERATOR_DELETE_BODY \ GET_MALLOC_STACK_TRACE; \ diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index db3ebb033..e081cc576 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -246,11 +246,11 @@ void *ReturnNullOrDieOnFailure::OnOOM() { ReportAllocatorCannotReturnNull(); } -void *DieOnFailure::OnBadRequest() { +void NORETURN *DieOnFailure::OnBadRequest() { ReportAllocatorCannotReturnNull(); } -void *DieOnFailure::OnOOM() { +void NORETURN *DieOnFailure::OnOOM() { atomic_store_relaxed(&allocator_out_of_memory, 1); ReportAllocatorCannotReturnNull(); } diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index f59c13d1c..06f82d3a2 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -39,8 +39,8 @@ struct ReturnNullOrDieOnFailure { }; // Always dies on the failure. struct DieOnFailure { - static void *OnBadRequest(); - static void *OnOOM(); + static void NORETURN *OnBadRequest(); + static void NORETURN *OnOOM(); }; // Returns true if allocator detected OOM condition. Can be used to avoid memory diff --git a/lib/scudo/scudo_new_delete.cpp b/lib/scudo/scudo_new_delete.cpp index c022bd0ac..cdefb127b 100644 --- a/lib/scudo/scudo_new_delete.cpp +++ b/lib/scudo/scudo_new_delete.cpp @@ -26,13 +26,18 @@ namespace std { struct nothrow_t {}; } // namespace std +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size) { - return scudoMalloc(size, FromNew); + void *res = scudoMalloc(size, FromNew); + if (UNLIKELY(!res)) DieOnFailure::OnOOM(); + return res; } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size) { - return scudoMalloc(size, FromNewArray); + void *res = scudoMalloc(size, FromNewArray); + if (UNLIKELY(!res)) DieOnFailure::OnOOM(); + return res; } CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::nothrow_t const&) { diff --git a/lib/tsan/rtl/tsan_new_delete.cc b/lib/tsan/rtl/tsan_new_delete.cc index b6478bb08..4d03145c1 100644 --- a/lib/tsan/rtl/tsan_new_delete.cc +++ b/lib/tsan/rtl/tsan_new_delete.cc @@ -12,6 +12,7 @@ // Interceptors for operators new and delete. //===----------------------------------------------------------------------===// #include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "tsan_interceptors.h" @@ -24,13 +25,15 @@ struct nothrow_t {}; DECLARE_REAL(void *, malloc, uptr size) DECLARE_REAL(void, free, void *ptr) -#define OPERATOR_NEW_BODY(mangled_name) \ +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(mangled_name, nothrow) \ if (cur_thread()->in_symbolizer) \ return InternalAlloc(size); \ void *p = 0; \ { \ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ p = user_alloc(thr, pc, size); \ + if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ } \ invoke_malloc_hook(p, size); \ return p; @@ -38,25 +41,25 @@ DECLARE_REAL(void, free, void *ptr) SANITIZER_INTERFACE_ATTRIBUTE void *operator new(__sanitizer::uptr size); void *operator new(__sanitizer::uptr size) { - OPERATOR_NEW_BODY(_Znwm); + OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new[](__sanitizer::uptr size); void *operator new[](__sanitizer::uptr size) { - OPERATOR_NEW_BODY(_Znam); + OPERATOR_NEW_BODY(_Znam, false /*nothrow*/); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new(__sanitizer::uptr size, std::nothrow_t const&); void *operator new(__sanitizer::uptr size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t); + OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new[](__sanitizer::uptr size, std::nothrow_t const&); void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t); + OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/); } #define OPERATOR_DELETE_BODY(mangled_name) \ diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc index cdfcd90c9..90e25b55e 100644 --- a/test/asan/TestCases/allocator_returns_null.cc +++ b/test/asan/TestCases/allocator_returns_null.cc @@ -1,68 +1,97 @@ -// Test the behavior of malloc/calloc/realloc when the allocation size is huge. +// Test the behavior of malloc/calloc/realloc/new when the allocation size is +// more than ASan allocator's max allowed one. // By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0. +// With allocator_may_return_null=1 the allocator should return 0, except the +// operator new(), which should crash anyway (operator new(std::nothrow) should +// return nullptr, indeed). // // RUN: %clangxx_asan -O0 %s -o %t // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL -#include -#include +#include #include #include -#include +#include #include +#include + int main(int argc, char **argv) { // Disable stderr buffering. Needed on Windows. setvbuf(stderr, NULL, _IONBF, 0); - volatile size_t size = std::numeric_limits::max() - 10000; assert(argc == 2); - void *x = 0; - if (!strcmp(argv[1], "malloc")) { - fprintf(stderr, "malloc:\n"); - x = malloc(size); - } - if (!strcmp(argv[1], "calloc")) { - fprintf(stderr, "calloc:\n"); - x = calloc(size / 4, 4); - } + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); - if (!strcmp(argv[1], "calloc-overflow")) { - fprintf(stderr, "calloc-overflow:\n"); + static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) + (1ULL << 40) + 1; +#else + (3UL << 30) + 1; +#endif + + void *x = 0; + if (!strcmp(action, "malloc")) { + x = malloc(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "calloc")) { + x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); + } else if (!strcmp(action, "calloc-overflow")) { volatile size_t kMaxSizeT = std::numeric_limits::max(); size_t kArraySize = 4096; volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; x = calloc(kArraySize, kArraySize2); - } - - if (!strcmp(argv[1], "realloc")) { - fprintf(stderr, "realloc:\n"); - x = realloc(0, size); - } - if (!strcmp(argv[1], "realloc-after-malloc")) { - fprintf(stderr, "realloc-after-malloc:\n"); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "realloc-after-malloc")) { char *t = (char*)malloc(100); *t = 42; - x = realloc(t, size); + x = realloc(t, kMaxAllowedMallocSizePlusOne); assert(*t == 42); free(t); + } else if (!strcmp(action, "new")) { + x = operator new(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "new-nothrow")) { + x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); + } else { + assert(0); } + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %lx\n", (long)x); free(x); + return x != 0; } + // CHECK-mCRASH: malloc: // CHECK-mCRASH: AddressSanitizer's allocator is terminating the process // CHECK-cCRASH: calloc: @@ -73,6 +102,10 @@ int main(int argc, char **argv) { // CHECK-rCRASH: AddressSanitizer's allocator is terminating the process // CHECK-mrCRASH: realloc-after-malloc: // CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-nCRASH: new: +// CHECK-nCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process // CHECK-mNULL: malloc: // CHECK-mNULL: x: 0 @@ -84,3 +117,5 @@ int main(int argc, char **argv) { // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: // CHECK-mrNULL: x: 0 +// CHECK-nnNULL: new-nothrow: +// CHECK-nnNULL: x: 0 diff --git a/test/msan/allocator_returns_null.cc b/test/msan/allocator_returns_null.cc index f4ea51d58..2c7c32d40 100644 --- a/test/msan/allocator_returns_null.cc +++ b/test/msan/allocator_returns_null.cc @@ -1,63 +1,98 @@ -// Test the behavior of malloc/calloc/realloc when the allocation size is huge. +// Test the behavior of malloc/calloc/realloc/new when the allocation size is +// more than MSan allocator's max allowed one. // By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0. +// With allocator_may_return_null=1 the allocator should return 0, except the +// operator new(), which should crash anyway (operator new(std::nothrow) should +// return nullptr, indeed). // // RUN: %clangxx_msan -O0 %s -o %t // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL -#include -#include + +#include #include #include -#include +#include #include +#include + int main(int argc, char **argv) { - volatile size_t size = std::numeric_limits::max() - 10000; + // Disable stderr buffering. Needed on Windows. + setvbuf(stderr, NULL, _IONBF, 0); + assert(argc == 2); - char *x = 0; - if (!strcmp(argv[1], "malloc")) { - fprintf(stderr, "malloc:\n"); - x = (char*)malloc(size); - } - if (!strcmp(argv[1], "calloc")) { - fprintf(stderr, "calloc:\n"); - x = (char*)calloc(size / 4, 4); - } + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + + static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) + (8UL << 30) + 1; +#else + (2UL << 30) + 1; +#endif - if (!strcmp(argv[1], "calloc-overflow")) { - fprintf(stderr, "calloc-overflow:\n"); + void *x = 0; + if (!strcmp(action, "malloc")) { + x = malloc(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "calloc")) { + x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); + } else if (!strcmp(action, "calloc-overflow")) { volatile size_t kMaxSizeT = std::numeric_limits::max(); size_t kArraySize = 4096; volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - x = (char*)calloc(kArraySize, kArraySize2); - } - - if (!strcmp(argv[1], "realloc")) { - fprintf(stderr, "realloc:\n"); - x = (char*)realloc(0, size); - } - if (!strcmp(argv[1], "realloc-after-malloc")) { - fprintf(stderr, "realloc-after-malloc:\n"); + x = calloc(kArraySize, kArraySize2); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "realloc-after-malloc")) { char *t = (char*)malloc(100); *t = 42; - x = (char*)realloc(t, size); + x = realloc(t, kMaxAllowedMallocSizePlusOne); assert(*t == 42); + free(t); + } else if (!strcmp(action, "new")) { + x = operator new(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "new-nothrow")) { + x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); + } else { + assert(0); } + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %lx\n", (long)x); + free(x); + return x != 0; } + // CHECK-mCRASH: malloc: // CHECK-mCRASH: MemorySanitizer's allocator is terminating the process // CHECK-cCRASH: calloc: @@ -68,6 +103,10 @@ int main(int argc, char **argv) { // CHECK-rCRASH: MemorySanitizer's allocator is terminating the process // CHECK-mrCRASH: realloc-after-malloc: // CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nCRASH: new: +// CHECK-nCRASH: MemorySanitizer's allocator is terminating the process +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process // CHECK-mNULL: malloc: // CHECK-mNULL: x: 0 @@ -79,3 +118,5 @@ int main(int argc, char **argv) { // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: // CHECK-mrNULL: x: 0 +// CHECK-nnNULL: new-nothrow: +// CHECK-nnNULL: x: 0 diff --git a/test/scudo/sizes.cpp b/test/scudo/sizes.cpp index 981b859a8..a0994c251 100644 --- a/test/scudo/sizes.cpp +++ b/test/scudo/sizes.cpp @@ -1,8 +1,12 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clang_scudo %s -lstdc++ -o %t // RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s // RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 // RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s // RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 +// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s +// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s +// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s +// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1 // RUN: %run %t usable 2>&1 // Tests for various edge cases related to sizes, notably the maximum size the @@ -15,26 +19,38 @@ #include #include +#include -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { assert(argc == 2); - if (!strcmp(argv[1], "malloc")) { - // Currently the maximum size the allocator can allocate is 1ULL<<40 bytes. - size_t size = std::numeric_limits::max(); - void *p = malloc(size); + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + +#if __LP64__ || defined(_WIN64) + static const size_t kMaxAllowedMallocSize = 1ULL << 40; + static const size_t kChunkHeaderSize = 16; +#else + static const size_t kMaxAllowedMallocSize = 2UL << 30; + static const size_t kChunkHeaderSize = 8; +#endif + + if (!strcmp(action, "malloc")) { + void *p = malloc(kMaxAllowedMallocSize); assert(!p); - size = (1ULL << 40) - 16; - p = malloc(size); + p = malloc(kMaxAllowedMallocSize - kChunkHeaderSize); assert(!p); - } - if (!strcmp(argv[1], "calloc")) { + } else if (!strcmp(action, "calloc")) { // Trigger an overflow in calloc. size_t size = std::numeric_limits::max(); void *p = calloc((size / 0x1000) + 1, 0x1000); assert(!p); - } - if (!strcmp(argv[1], "usable")) { + } else if (!strcmp(action, "new")) { + void *p = operator new(kMaxAllowedMallocSize); + assert(!p); + } else if (!strcmp(action, "new-nothrow")) { + void *p = operator new(kMaxAllowedMallocSize, std::nothrow); + assert(!p); + } else if (!strcmp(action, "usable")) { // Playing with the actual usable size of a chunk. void *p = malloc(1007); assert(p); @@ -47,7 +63,10 @@ int main(int argc, char **argv) assert(size >= 2014); memset(p, 'B', size); free(p); + } else { + assert(0); } + return 0; } diff --git a/test/tsan/allocator_returns_null.cc b/test/tsan/allocator_returns_null.cc index 66930076a..852dda035 100644 --- a/test/tsan/allocator_returns_null.cc +++ b/test/tsan/allocator_returns_null.cc @@ -1,56 +1,90 @@ -// Test the behavior of malloc/calloc/realloc when the allocation size is huge. +// Test the behavior of malloc/calloc/realloc/new when the allocation size is +// more than TSan allocator's max allowed one. // By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0. +// With allocator_may_return_null=1 the allocator should return 0, except the +// operator new(), which should crash anyway (operator new(std::nothrow) should +// return nullptr, indeed). // // RUN: %clangxx_tsan -O0 %s -o %t // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: %env_tsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL -#include -#include +#include #include #include -#include +#include #include +#include + int main(int argc, char **argv) { - volatile size_t size = std::numeric_limits::max() - 10000; + // Disable stderr buffering. Needed on Windows. + setvbuf(stderr, NULL, _IONBF, 0); + assert(argc == 2); - char *x = 0; - if (!strcmp(argv[1], "malloc")) { - fprintf(stderr, "malloc:\n"); - x = (char*)malloc(size); - } - if (!strcmp(argv[1], "calloc")) { - fprintf(stderr, "calloc:\n"); - x = (char*)calloc(size / 4, 4); - } + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + + static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1; - if (!strcmp(argv[1], "calloc-overflow")) { - fprintf(stderr, "calloc-overflow:\n"); + void *x = 0; + if (!strcmp(action, "malloc")) { + x = malloc(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "calloc")) { + x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); + } else if (!strcmp(action, "calloc-overflow")) { volatile size_t kMaxSizeT = std::numeric_limits::max(); size_t kArraySize = 4096; volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - x = (char*)calloc(kArraySize, kArraySize2); - } - - if (!strcmp(argv[1], "realloc")) { - fprintf(stderr, "realloc:\n"); - x = (char*)realloc(0, size); - } - if (!strcmp(argv[1], "realloc-after-malloc")) { - fprintf(stderr, "realloc-after-malloc:\n"); + x = calloc(kArraySize, kArraySize2); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "realloc-after-malloc")) { char *t = (char*)malloc(100); *t = 42; - x = (char*)realloc(t, size); + x = realloc(t, kMaxAllowedMallocSizePlusOne); assert(*t == 42); + } else if (!strcmp(action, "new")) { + x = operator new(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "new-nothrow")) { + x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); + } else { + assert(0); } - fprintf(stderr, "x: %p\n", x); + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %lx\n", (long)x); + free(x); return x != 0; } + // CHECK-mCRASH: malloc: // CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process // CHECK-cCRASH: calloc: @@ -61,4 +95,20 @@ int main(int argc, char **argv) { // CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process // CHECK-mrCRASH: realloc-after-malloc: // CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process +// CHECK-nCRASH: new: +// CHECK-nCRASH: ThreadSanitizer's allocator is terminating the process +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process +// CHECK-mNULL: malloc: +// CHECK-mNULL: x: 0 +// CHECK-cNULL: calloc: +// CHECK-cNULL: x: 0 +// CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: x: 0 +// CHECK-rNULL: realloc: +// CHECK-rNULL: x: 0 +// CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: x: 0 +// CHECK-nnNULL: new-nothrow: +// CHECK-nnNULL: x: 0 -- cgit v1.2.1 From e8dc229260bbbe4a9cc7852d0d8fb621a69fe5cb Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 29 Jun 2017 00:19:27 +0000 Subject: [asan] This test now passes git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306619 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/throw_call_test.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/asan/TestCases/throw_call_test.cc b/test/asan/TestCases/throw_call_test.cc index 5a8204a04..20a7c0b76 100644 --- a/test/asan/TestCases/throw_call_test.cc +++ b/test/asan/TestCases/throw_call_test.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_asan %s -o %t && %run %t // http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed). // BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %run %t -// -// Android builds with static libstdc++ by default. -// XFAIL: android #include static volatile int zero = 0; -- cgit v1.2.1 From aaa18ba4dad3d4e33ad30a34fd9661defc164bb4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 29 Jun 2017 00:19:28 +0000 Subject: [asan] Disable tests which do no work on Android git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306620 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/asan_preload_test-3.cc | 3 +++ test/asan/TestCases/Linux/textdomain.c | 3 +++ test/asan/TestCases/malloc-no-intercept.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/test/asan/TestCases/Linux/asan_preload_test-3.cc b/test/asan/TestCases/Linux/asan_preload_test-3.cc index 041669b56..e998ff647 100644 --- a/test/asan/TestCases/Linux/asan_preload_test-3.cc +++ b/test/asan/TestCases/Linux/asan_preload_test-3.cc @@ -10,6 +10,9 @@ // RUN: env LD_PRELOAD=%shared_libasan %run %t-2 2>&1 | FileCheck %s // REQUIRES: asan-dynamic-runtime +// FIXME: Test regressed while android bot was disabled. Needs investigation. +// UNSUPPORTED: android + #include #include diff --git a/test/asan/TestCases/Linux/textdomain.c b/test/asan/TestCases/Linux/textdomain.c index 31e5139c9..9e249d95c 100644 --- a/test/asan/TestCases/Linux/textdomain.c +++ b/test/asan/TestCases/Linux/textdomain.c @@ -1,6 +1,9 @@ // RUN: %clang_asan -O0 -g %s -o %t // RUN: %env_asan_opts=strict_string_checks=1 %run %t +// Android NDK does not have libintl.h +// UNSUPPORTED: android + #include #include diff --git a/test/asan/TestCases/malloc-no-intercept.c b/test/asan/TestCases/malloc-no-intercept.c index 563f2ab15..c1442e6cf 100644 --- a/test/asan/TestCases/malloc-no-intercept.c +++ b/test/asan/TestCases/malloc-no-intercept.c @@ -7,6 +7,9 @@ // RUN: not %clang_asan -Dtestfunc=pvalloc %s -o %t // RUN: not %clang_asan -Dtestfunc=cfree %s -o %t +// Conflicts with BIONIC declarations. +// UNSUPPORTED: android + #include // For glibc, cause link failures by referencing a nonexistent function. -- cgit v1.2.1 From 628643aeb3b82d4bc074e7ecc0a4de13f654a01a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 29 Jun 2017 00:19:29 +0000 Subject: [asan] Fix try to fix test on Android %T is dir on host system, device does not have it git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306621 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/asan-sigbus.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/asan/TestCases/Posix/asan-sigbus.cpp b/test/asan/TestCases/Posix/asan-sigbus.cpp index d02ebbd9d..c91ecbd75 100644 --- a/test/asan/TestCases/Posix/asan-sigbus.cpp +++ b/test/asan/TestCases/Posix/asan-sigbus.cpp @@ -1,8 +1,8 @@ // Check handle_bus flag // Defaults to true // RUN: %clangxx_asan -std=c++11 %s -o %t -// RUN: not %run %t %T/file 2>&1 | FileCheck %s -check-prefix=CHECK-BUS -// RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t %T/file 2>&1 | FileCheck %s +// RUN: not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-BUS +// RUN: %env_asan_opts=handle_sigbus=0 not --crash %run %t 2>&1 | FileCheck %s // UNSUPPORTED: ios @@ -12,11 +12,11 @@ #include #include #include +#include char array[4096]; int main(int argc, char **argv) { - assert(argc > 1); - int fd = open(argv[1], O_RDWR | O_CREAT, 0700); + int fd = open((std::string(argv[0]) + ".m").c_str(), O_RDWR | O_CREAT, 0700); if (fd < 0) { perror("open"); exit(1); -- cgit v1.2.1 From 81300751ef926596153f5d8db0b3057b6d169a03 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 29 Jun 2017 01:02:40 +0000 Subject: [LSan] Make LSan allocator allocator_may_return_null compliant Summary: LSan allocator used to always return nullptr on too big allocation requests (the definition of "too big" depends on platform and bitness), now it follows policy configured by allocator_may_return_null flag. Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34786 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306624 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 6 +- lib/lsan/lsan_interceptors.cc | 1 - test/lsan/TestCases/allocator_returns_null.cc | 123 ++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 test/lsan/TestCases/allocator_returns_null.cc diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index f54e95373..134a95bfd 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -74,7 +74,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, size = 1; if (size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); - return nullptr; + return Allocator::FailureHandler::OnBadRequest(); } void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); // Do not rely on the allocator to clear the memory (it's slow). @@ -99,7 +99,7 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); allocator.Deallocate(GetAllocatorCache(), p); - return nullptr; + return Allocator::FailureHandler::OnBadRequest(); } p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); @@ -134,6 +134,8 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { } void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { + if (CallocShouldReturnNullDueToOverflow(size, nmemb)) + return Allocator::FailureHandler::OnBadRequest(); size *= nmemb; return Allocate(stack, size, 1, true); } diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index b6ac7b77c..30709787f 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -70,7 +70,6 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr; ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); diff --git a/test/lsan/TestCases/allocator_returns_null.cc b/test/lsan/TestCases/allocator_returns_null.cc new file mode 100644 index 000000000..ab2c734e1 --- /dev/null +++ b/test/lsan/TestCases/allocator_returns_null.cc @@ -0,0 +1,123 @@ +// Test the behavior of malloc/calloc/realloc/new when the allocation size is +// more than LSan allocator's max allowed one. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0, except the +// operator new(), which should crash anyway (operator new(std::nothrow) should +// return nullptr, indeed). +// +// RUN: %clangxx_lsan -O0 %s -o %t +// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + // Disable stderr buffering. Needed on Windows. + setvbuf(stderr, NULL, _IONBF, 0); + + assert(argc == 2); + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + + // Use max of ASan and LSan allocator limits to cover both "lsan" and + // "lsan + asan" configs. + static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) + (1ULL << 40) + 1; +#else + (3UL << 30) + 1; +#endif + + void *x = 0; + if (!strcmp(action, "malloc")) { + x = malloc(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "calloc")) { + x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); + } else if (!strcmp(action, "calloc-overflow")) { + volatile size_t kMaxSizeT = std::numeric_limits::max(); + size_t kArraySize = 4096; + volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + x = calloc(kArraySize, kArraySize2); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "realloc-after-malloc")) { + char *t = (char*)malloc(100); + *t = 42; + x = realloc(t, kMaxAllowedMallocSizePlusOne); + assert(*t == 42); + free(t); + } else if (!strcmp(action, "new")) { + x = operator new(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "new-nothrow")) { + x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); + } else { + assert(0); + } + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %zu\n", (size_t)x); + free(x); + + return x != 0; +} + +// CHECK-mCRASH: malloc: +// CHECK-mCRASH: Sanitizer's allocator is terminating the process +// CHECK-cCRASH: calloc: +// CHECK-cCRASH: Sanitizer's allocator is terminating the process +// CHECK-coCRASH: calloc-overflow: +// CHECK-coCRASH: Sanitizer's allocator is terminating the process +// CHECK-rCRASH: realloc: +// CHECK-rCRASH: Sanitizer's allocator is terminating the process +// CHECK-mrCRASH: realloc-after-malloc: +// CHECK-mrCRASH: Sanitizer's allocator is terminating the process +// CHECK-nCRASH: new: +// CHECK-nCRASH: Sanitizer's allocator is terminating the process +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: Sanitizer's allocator is terminating the process + +// CHECK-mNULL: malloc: +// CHECK-mNULL: x: 0 +// CHECK-cNULL: calloc: +// CHECK-cNULL: x: 0 +// CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: x: 0 +// CHECK-rNULL: realloc: +// CHECK-rNULL: x: 0 +// CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: x: 0 +// CHECK-nnNULL: new-nothrow: +// CHECK-nnNULL: x: 0 -- cgit v1.2.1 From 02c4d3f8b403a2bc2e20a8d95e1c6fc533209ab4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 29 Jun 2017 01:04:32 +0000 Subject: [asan] Control location of symbolizer on device using ANDROID_SYMBOLIZER_PATH git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306627 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/android_commands/android_run.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py index 7e599453d..fc020f793 100755 --- a/test/asan/android_commands/android_run.py +++ b/test/asan/android_commands/android_run.py @@ -4,6 +4,7 @@ import os, signal, sys, subprocess, tempfile from android_common import * ANDROID_TMPDIR = '/data/local/tmp/Output' +ANDROID_SYMBOLIZER_PATH = os.environ.get('ANDROID_SYMBOLIZER_PATH', None) here = os.path.abspath(os.path.dirname(sys.argv[0])) device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) @@ -12,6 +13,8 @@ def build_env(): args = [] # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) + if ANDROID_SYMBOLIZER_PATH: + args.append('ASAN_SYMBOLIZER_PATH=%s' % (ANDROID_SYMBOLIZER_PATH)) for (key, value) in os.environ.items(): if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: args.append('%s="%s"' % (key, value)) -- cgit v1.2.1 From 90d0de4a6069bdfe7669b23e2d5a8eba55ea5198 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 29 Jun 2017 02:48:06 +0000 Subject: Revert "[asan] Control location of symbolizer on device using ANDROID_SYMBOLIZER_PATH" Not needed, I am going to put symbolizer into tests dir. This reverts commit r306627. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306630 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/android_commands/android_run.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py index fc020f793..7e599453d 100755 --- a/test/asan/android_commands/android_run.py +++ b/test/asan/android_commands/android_run.py @@ -4,7 +4,6 @@ import os, signal, sys, subprocess, tempfile from android_common import * ANDROID_TMPDIR = '/data/local/tmp/Output' -ANDROID_SYMBOLIZER_PATH = os.environ.get('ANDROID_SYMBOLIZER_PATH', None) here = os.path.abspath(os.path.dirname(sys.argv[0])) device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) @@ -13,8 +12,6 @@ def build_env(): args = [] # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) - if ANDROID_SYMBOLIZER_PATH: - args.append('ASAN_SYMBOLIZER_PATH=%s' % (ANDROID_SYMBOLIZER_PATH)) for (key, value) in os.environ.items(): if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: args.append('%s="%s"' % (key, value)) -- cgit v1.2.1 From a05e4630f35a14d8db97417cdb6b959f2781b4f9 Mon Sep 17 00:00:00 2001 From: Michael Zolotukhin Date: Thu, 29 Jun 2017 04:39:17 +0000 Subject: Revert "[LSan] Make LSan allocator allocator_may_return_null compliant" This reverts commit r306624. The committed test failed on various bots (e.g. on green dragon). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306644 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 6 +- lib/lsan/lsan_interceptors.cc | 1 + test/lsan/TestCases/allocator_returns_null.cc | 123 -------------------------- 3 files changed, 3 insertions(+), 127 deletions(-) delete mode 100644 test/lsan/TestCases/allocator_returns_null.cc diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 134a95bfd..f54e95373 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -74,7 +74,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, size = 1; if (size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); - return Allocator::FailureHandler::OnBadRequest(); + return nullptr; } void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); // Do not rely on the allocator to clear the memory (it's slow). @@ -99,7 +99,7 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); allocator.Deallocate(GetAllocatorCache(), p); - return Allocator::FailureHandler::OnBadRequest(); + return nullptr; } p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); @@ -134,8 +134,6 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { } void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return Allocator::FailureHandler::OnBadRequest(); size *= nmemb; return Allocate(stack, size, 1, true); } diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 30709787f..b6ac7b77c 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -70,6 +70,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } + if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr; ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); diff --git a/test/lsan/TestCases/allocator_returns_null.cc b/test/lsan/TestCases/allocator_returns_null.cc deleted file mode 100644 index ab2c734e1..000000000 --- a/test/lsan/TestCases/allocator_returns_null.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Test the behavior of malloc/calloc/realloc/new when the allocation size is -// more than LSan allocator's max allowed one. -// By default (allocator_may_return_null=0) the process should crash. -// With allocator_may_return_null=1 the allocator should return 0, except the -// operator new(), which should crash anyway (operator new(std::nothrow) should -// return nullptr, indeed). -// -// RUN: %clangxx_lsan -O0 %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-mNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-cNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-coNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-rNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH -// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL - -#include -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - // Disable stderr buffering. Needed on Windows. - setvbuf(stderr, NULL, _IONBF, 0); - - assert(argc == 2); - const char *action = argv[1]; - fprintf(stderr, "%s:\n", action); - - // Use max of ASan and LSan allocator limits to cover both "lsan" and - // "lsan + asan" configs. - static const size_t kMaxAllowedMallocSizePlusOne = -#if __LP64__ || defined(_WIN64) - (1ULL << 40) + 1; -#else - (3UL << 30) + 1; -#endif - - void *x = 0; - if (!strcmp(action, "malloc")) { - x = malloc(kMaxAllowedMallocSizePlusOne); - } else if (!strcmp(action, "calloc")) { - x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); - } else if (!strcmp(action, "calloc-overflow")) { - volatile size_t kMaxSizeT = std::numeric_limits::max(); - size_t kArraySize = 4096; - volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - x = calloc(kArraySize, kArraySize2); - } else if (!strcmp(action, "realloc")) { - x = realloc(0, kMaxAllowedMallocSizePlusOne); - } else if (!strcmp(action, "realloc-after-malloc")) { - char *t = (char*)malloc(100); - *t = 42; - x = realloc(t, kMaxAllowedMallocSizePlusOne); - assert(*t == 42); - free(t); - } else if (!strcmp(action, "new")) { - x = operator new(kMaxAllowedMallocSizePlusOne); - } else if (!strcmp(action, "new-nothrow")) { - x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); - } else { - assert(0); - } - - // The NULL pointer is printed differently on different systems, while (long)0 - // is always the same. - fprintf(stderr, "x: %zu\n", (size_t)x); - free(x); - - return x != 0; -} - -// CHECK-mCRASH: malloc: -// CHECK-mCRASH: Sanitizer's allocator is terminating the process -// CHECK-cCRASH: calloc: -// CHECK-cCRASH: Sanitizer's allocator is terminating the process -// CHECK-coCRASH: calloc-overflow: -// CHECK-coCRASH: Sanitizer's allocator is terminating the process -// CHECK-rCRASH: realloc: -// CHECK-rCRASH: Sanitizer's allocator is terminating the process -// CHECK-mrCRASH: realloc-after-malloc: -// CHECK-mrCRASH: Sanitizer's allocator is terminating the process -// CHECK-nCRASH: new: -// CHECK-nCRASH: Sanitizer's allocator is terminating the process -// CHECK-nnCRASH: new-nothrow: -// CHECK-nnCRASH: Sanitizer's allocator is terminating the process - -// CHECK-mNULL: malloc: -// CHECK-mNULL: x: 0 -// CHECK-cNULL: calloc: -// CHECK-cNULL: x: 0 -// CHECK-coNULL: calloc-overflow: -// CHECK-coNULL: x: 0 -// CHECK-rNULL: realloc: -// CHECK-rNULL: x: 0 -// CHECK-mrNULL: realloc-after-malloc: -// CHECK-mrNULL: x: 0 -// CHECK-nnNULL: new-nothrow: -// CHECK-nnNULL: x: 0 -- cgit v1.2.1 From 5d77c239d28020aa3c2e243e009e20e35c98f86e Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 29 Jun 2017 16:45:20 +0000 Subject: [scudo] Change aligned alloc functions to be more compliant & perf changes Summary: We were not following the `man` documented behaviors for invalid arguments to `memalign` and associated functions. Using `CHECK` for those was a bit extreme, so we relax the behavior to return null pointers as expected when this happens. Adapt the associated test. I am using this change also to change a few more minor performance improvements: - mark as `UNLIKELY` a bunch of unlikely conditions; - the current `CHECK` in `__sanitizer::RoundUpTo` is redundant for us in *all* calls. So I am introducing our own version without said `CHECK`. - change our combined allocator `GetActuallyAllocatedSize`. We already know if the pointer is from the Primary or Secondary, so the `PointerIsMine` check is redundant as well, and costly for the 32-bit Primary. So we get the size by directly using the available Primary functions. Finally, change a `int` to `uptr` to avoid a warning/error when compiling on Android. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34782 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306698 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 55 +++++++++++++++++++----------------- lib/scudo/scudo_allocator.h | 5 ++++ lib/scudo/scudo_allocator_combined.h | 2 +- lib/scudo/scudo_tls_android.cpp | 2 +- test/scudo/memalign.cpp | 24 ++++++++++++---- 5 files changed, 55 insertions(+), 33 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 1d0db84a5..a2a3c8ba3 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -22,8 +22,7 @@ #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_quarantine.h" -#include -#include +#include #include namespace __scudo { @@ -341,7 +340,7 @@ struct ScudoAllocator { // Helper function that checks for a valid Scudo chunk. nullptr isn't. bool isValidPointer(const void *UserPtr) { initThreadMaybe(); - if (!UserPtr) + if (UNLIKELY(!UserPtr)) return false; uptr UserBeg = reinterpret_cast(UserPtr); if (!IsAligned(UserBeg, MinAlignment)) @@ -353,22 +352,19 @@ struct ScudoAllocator { void *allocate(uptr Size, uptr Alignment, AllocType Type, bool ForceZeroContents = false) { initThreadMaybe(); - if (UNLIKELY(!IsPowerOfTwo(Alignment))) { - dieWithMessage("ERROR: alignment is not a power of 2\n"); - } - if (Alignment > MaxAlignment) + if (UNLIKELY(Alignment > MaxAlignment)) return FailureHandler::OnBadRequest(); - if (Alignment < MinAlignment) + if (UNLIKELY(Alignment < MinAlignment)) Alignment = MinAlignment; - if (Size >= MaxAllowedMallocSize) + if (UNLIKELY(Size >= MaxAllowedMallocSize)) return FailureHandler::OnBadRequest(); - if (Size == 0) + if (UNLIKELY(Size == 0)) Size = 1; uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize; uptr AlignedSize = (Alignment > MinAlignment) ? NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; - if (AlignedSize >= MaxAllowedMallocSize) + if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize)) return FailureHandler::OnBadRequest(); // Primary and Secondary backed allocations have a different treatment. We @@ -393,7 +389,7 @@ struct ScudoAllocator { Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize, AllocationAlignment, FromPrimary); } - if (!Ptr) + if (UNLIKELY(!Ptr)) return FailureHandler::OnOOM(); // If requested, we will zero out the entire contents of the returned chunk. @@ -404,7 +400,7 @@ struct ScudoAllocator { UnpackedHeader Header = {}; uptr AllocBeg = reinterpret_cast(Ptr); uptr UserBeg = AllocBeg + AlignedChunkHeaderSize; - if (!IsAligned(UserBeg, Alignment)) { + if (UNLIKELY(!IsAligned(UserBeg, Alignment))) { // Since the Secondary takes care of alignment, a non-aligned pointer // means it is from the Primary. It is also the only case where the offset // field of the header would be non-zero. @@ -481,7 +477,7 @@ struct ScudoAllocator { void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { initThreadMaybe(); // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr); - if (!UserPtr) + if (UNLIKELY(!UserPtr)) return; uptr UserBeg = reinterpret_cast(UserPtr); if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) { @@ -568,7 +564,7 @@ struct ScudoAllocator { // Helper function that returns the actual usable size of a chunk. uptr getUsableSize(const void *Ptr) { initThreadMaybe(); - if (!Ptr) + if (UNLIKELY(!Ptr)) return 0; uptr UserBeg = reinterpret_cast(Ptr); ScudoChunk *Chunk = getScudoChunk(UserBeg); @@ -584,10 +580,10 @@ struct ScudoAllocator { void *calloc(uptr NMemB, uptr Size) { initThreadMaybe(); - uptr Total = NMemB * Size; - if (Size != 0 && Total / Size != NMemB) // Overflow check + // TODO(kostyak): switch to CheckForCallocOverflow once D34799 lands. + if (CallocShouldReturnNullDueToOverflow(NMemB, Size)) return FailureHandler::OnBadRequest(); - return allocate(Total, MinAlignment, FromMalloc, true); + return allocate(NMemB * Size, MinAlignment, FromMalloc, true); } void commitBack(ScudoThreadContext *ThreadContext) { @@ -655,10 +651,6 @@ void *scudoValloc(uptr Size) { return Instance.allocate(Size, GetPageSizeCached(), FromMemalign); } -void *scudoMemalign(uptr Alignment, uptr Size) { - return Instance.allocate(Size, Alignment, FromMemalign); -} - void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); Size = RoundUpTo(Size, PageSize); @@ -669,16 +661,27 @@ void *scudoPvalloc(uptr Size) { return Instance.allocate(Size, PageSize, FromMemalign); } +void *scudoMemalign(uptr Alignment, uptr Size) { + if (UNLIKELY(!IsPowerOfTwo(Alignment))) + return ScudoAllocator::FailureHandler::OnBadRequest(); + return Instance.allocate(Size, Alignment, FromMemalign); +} + int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { + if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Alignment % sizeof(void *)) != 0)) { + *MemPtr = ScudoAllocator::FailureHandler::OnBadRequest(); + return EINVAL; + } *MemPtr = Instance.allocate(Size, Alignment, FromMemalign); + if (!*MemPtr) + return ENOMEM; return 0; } void *scudoAlignedAlloc(uptr Alignment, uptr Size) { - // size must be a multiple of the alignment. To avoid a division, we first - // make sure that alignment is a power of 2. - CHECK(IsPowerOfTwo(Alignment)); - CHECK_EQ((Size & (Alignment - 1)), 0); + // Alignment must be a power of 2, Size must be a multiple of Alignment. + if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0)) + return ScudoAllocator::FailureHandler::OnBadRequest(); return Instance.allocate(Size, Alignment, FromMalloc); } diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 523808750..29d85995a 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -116,6 +116,11 @@ struct AP32 { typedef SizeClassAllocator32 PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 +// __sanitizer::RoundUp has a CHECK that is extraneous for us. Use our own. +INLINE uptr RoundUpTo(uptr Size, uptr Boundary) { + return (Size + Boundary - 1) & ~(Boundary - 1); +} + #include "scudo_allocator_secondary.h" #include "scudo_allocator_combined.h" diff --git a/lib/scudo/scudo_allocator_combined.h b/lib/scudo/scudo_allocator_combined.h index 21c45897b..818272868 100644 --- a/lib/scudo/scudo_allocator_combined.h +++ b/lib/scudo/scudo_allocator_combined.h @@ -45,7 +45,7 @@ class ScudoCombinedAllocator { uptr GetActuallyAllocatedSize(void *Ptr, bool FromPrimary) { if (FromPrimary) - return Primary.GetActuallyAllocatedSize(Ptr); + return PrimaryAllocator::ClassIdToSize(Primary.GetSizeClass(Ptr)); return Secondary.GetActuallyAllocatedSize(Ptr); } diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp index 0e3602b2f..ec74e37c8 100644 --- a/lib/scudo/scudo_tls_android.cpp +++ b/lib/scudo/scudo_tls_android.cpp @@ -45,7 +45,7 @@ static void initOnce() { NumberOfContexts = getNumberOfCPUs(); ThreadContexts = reinterpret_cast( MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__)); - for (int i = 0; i < NumberOfContexts; i++) + for (uptr i = 0; i < NumberOfContexts; i++) ThreadContexts[i].init(); } diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index c263da75e..856128f24 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -1,11 +1,12 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 | FileCheck %s +// RUN: %run %t valid 2>&1 +// RUN: %run %t invalid 2>&1 // Tests that the various aligned allocation functions work as intended. Also // tests for the condition where the alignment is not a power of 2. #include +#include #include #include #include @@ -24,6 +25,7 @@ int main(int argc, char **argv) void *p = nullptr; size_t alignment = 1U << 12; size_t size = 1U << 12; + int err; assert(argc == 2); @@ -57,10 +59,22 @@ int main(int argc, char **argv) } } if (!strcmp(argv[1], "invalid")) { + // Alignment is not a power of 2. p = memalign(alignment - 1, size); - free(p); + assert(!p); + // Size is not a multiple of alignment. + p = aligned_alloc(alignment, size >> 1); + assert(!p); + p = (void *)0x42UL; + // Alignment is not a power of 2. + err = posix_memalign(&p, 3, size); + assert(!p); + assert(err == EINVAL); + p = (void *)0x42UL; + // Alignment is a power of 2, but not a multiple of size(void *). + err = posix_memalign(&p, 2, size); + assert(!p); + assert(err == EINVAL); } return 0; } - -// CHECK: ERROR: alignment is not a power of 2 -- cgit v1.2.1 From 5349b6c7c4b4a137f1a7ac2e163045a6c54d565b Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 29 Jun 2017 17:15:53 +0000 Subject: Fix WinASan after moving wcslen interceptor to sanitizer_common Do this by removing SANITIZER_INTERCEPT_WCSLEN and intercept wcslen everywhere. Before this change, we were already intercepting wcslen on Windows, but the interceptor was in asan, not sanitizer_common. After this change, we stopped intercepting wcslen on Windows, which broke asan_dll_thunk.c, which attempts to thunk to __asan_wcslen in the ASan runtime. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306706 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_win_dll_thunk.cc | 1 + lib/sanitizer_common/sanitizer_common_interceptors.inc | 4 ---- lib/sanitizer_common/sanitizer_platform_interceptors.h | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index 189b4b141..c67116c42 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -85,6 +85,7 @@ INTERCEPT_LIBRARY_FUNCTION(strstr); INTERCEPT_LIBRARY_FUNCTION(strtok); INTERCEPT_LIBRARY_FUNCTION(strtol); INTERCEPT_LIBRARY_FUNCTION(wcslen); +INTERCEPT_LIBRARY_FUNCTION(wcsnlen); #ifdef _WIN64 INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index af7de6759..459530aa9 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6199,7 +6199,6 @@ INTERCEPTOR(int, mprobe, void *ptr) { } #endif -#if SANITIZER_INTERCEPT_WCSLEN INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s); @@ -6218,9 +6217,6 @@ INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { #define INIT_WCSLEN \ COMMON_INTERCEPT_FUNCTION(wcslen); \ COMMON_INTERCEPT_FUNCTION(wcsnlen); -#else -#define INIT_WCSLEN -#endif #if SANITIZER_INTERCEPT_WCSCAT INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index da683c62f..1bc43e817 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -354,7 +354,6 @@ #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_WCSLEN SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSCAT SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H -- cgit v1.2.1 From ac3a01da8065bc2245131f7e53359d3b84c3924d Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 29 Jun 2017 17:39:53 +0000 Subject: Export the nothrow overload of operator new This missing export was causing allocator_returns_null.cc to fail on Windows with a dynamic ASan runtime. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306707 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_new_delete.cc | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index a64fe583b..942b169d9 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -25,22 +25,26 @@ // dllexport would normally do. We need to export them in order to make the // VS2015 dynamic CRT (MD) work. #if SANITIZER_WINDOWS -# define CXX_OPERATOR_ATTRIBUTE -# ifdef _WIN64 -# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new -# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete -# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete -# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[] -# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[] -# else -# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new -# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete -# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete -# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[] -# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[] -# endif +#define CXX_OPERATOR_ATTRIBUTE +#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:"##sym)) +#ifdef _WIN64 +COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new +COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow +COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete +COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete +COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[] +COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[] #else -# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE +COMMENT_EXPORT("??2@YAPAXI@Z") // operator new +COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow +COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete +COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete +COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[] +COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] +#endif +#undef COMMENT_EXPORT +#else +#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE #endif using namespace __asan; // NOLINT -- cgit v1.2.1 From 9bf4394e71e00bc967ee620b51ba17ead8d23dbc Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 29 Jun 2017 17:42:24 +0000 Subject: [profile] Move __llvm_profile_filename into a separate object Users can specify the path a raw profile is written to by passing -fprofile-instr-generate=, but this functionality broke on Darwin after __llvm_profile_filename was made weak [1], resulting in profiles being written to "default.profraw" even when is specified. The situation is that instrumented programs provide a weak definition of __llvm_profile_filename, which conflicts with a weak redefinition provided by the profiling runtime. The linker appears to pick the 'winning' definition arbitrarily: on Darwin, it usually prefers the larger definition, which is probably why the instrprof-override-filename.c test has been passing. The fix is to move the runtime's definition into a separate object file within the archive. This means that the linker won't "see" the runtime's definition unless the user program has not provided one. I couldn't think of a great way to test this other than to mimic the Darwin failure: use -fprofile-instr-generate=. Testing: check-{clang,profile}, modified instrprof-override-filename.c. [1] [Profile] deprecate __llvm_profile_override_default_filename https://reviews.llvm.org/D22613 https://reviews.llvm.org/D22614 Differential Revision: https://reviews.llvm.org/D34797 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306710 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/CMakeLists.txt | 1 + lib/profile/InstrProfiling.c | 2 -- lib/profile/InstrProfilingNameVar.c | 18 ++++++++++++++++++ test/profile/instrprof-override-filename.c | 22 ++++++++++++++++------ 4 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 lib/profile/InstrProfilingNameVar.c diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt index 006285b34..342f8ee7e 100644 --- a/lib/profile/CMakeLists.txt +++ b/lib/profile/CMakeLists.txt @@ -48,6 +48,7 @@ set(PROFILE_SOURCES InstrProfilingFile.c InstrProfilingMerge.c InstrProfilingMergeFile.c + InstrProfilingNameVar.c InstrProfilingWriter.c InstrProfilingPlatformDarwin.c InstrProfilingPlatformLinux.c diff --git a/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c index 6828a3d27..fe66fec50 100644 --- a/lib/profile/InstrProfiling.c +++ b/lib/profile/InstrProfiling.c @@ -19,8 +19,6 @@ COMPILER_RT_WEAK uint64_t INSTR_PROF_RAW_VERSION_VAR = INSTR_PROF_RAW_VERSION; -COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0}; - COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) { return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64) : (INSTR_PROF_RAW_MAGIC_32); diff --git a/lib/profile/InstrProfilingNameVar.c b/lib/profile/InstrProfilingNameVar.c new file mode 100644 index 000000000..a0c448c67 --- /dev/null +++ b/lib/profile/InstrProfilingNameVar.c @@ -0,0 +1,18 @@ +//===- InstrProfilingNameVar.c - profile name variable setup --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InstrProfiling.h" + +/* char __llvm_profile_filename[1] + * + * The runtime should only provide its own definition of this symbol when the + * user has not specified one. Set this up by moving the runtime's copy of this + * symbol to an object file within the archive. + */ +COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0}; diff --git a/test/profile/instrprof-override-filename.c b/test/profile/instrprof-override-filename.c index a67c7076a..d2b6b69a7 100644 --- a/test/profile/instrprof-override-filename.c +++ b/test/profile/instrprof-override-filename.c @@ -1,14 +1,24 @@ -// RUN: %clang_profgen=%t.profraw -o %t -O3 %s -// RUN: %run %t %t.profraw -// RUN: llvm-profdata merge -o %t.profdata %t.profraw -// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s +// RUN: rm -rf %t.dir && mkdir -p %t.dir +// RUN: cd %t.dir +// +// RUN: %clang_profgen=P_RAW -o %t -O3 %s +// RUN: %run %t P_RAW +// RUN: llvm-profdata merge -o %t.profdata P_RAW +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=FE +// +// RUN: %clang_pgogen=I_RAW -o %t.2 %s +// RUN: %run %t.2 I_RAW +// RUN: llvm-profdata merge -o %t2.profdata I_RAW +// RUN: %clang_profuse=%t2.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=IR void bar() {} int main(int argc, const char *argv[]) { - // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + // FE: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + // IR: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] if (argc < 2) return 1; bar(); return 0; } -// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} +// FE: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} +// IR: ![[PD1]] = !{!"branch_weights", i32 0, i32 1} -- cgit v1.2.1 From db318dfe3724c49f4a628715745799bc7e63e6f5 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 29 Jun 2017 21:54:36 +0000 Subject: Merge git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306746 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 2 +- lib/msan/msan_allocator.cc | 2 +- lib/sanitizer_common/sanitizer_allocator.cc | 4 ++-- lib/sanitizer_common/sanitizer_allocator.h | 6 ++++-- lib/tsan/rtl/tsan_mman.cc | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 36348834e..de6613f56 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -635,7 +635,7 @@ struct Allocator { } void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) + if (CheckForCallocOverflow(size, nmemb)) return AsanAllocator::FailureHandler::OnBadRequest(); void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); // If the memory comes from the secondary allocator no need to clear it diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index d0f478afc..a92b7fd12 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -195,7 +195,7 @@ void MsanDeallocate(StackTrace *stack, void *p) { } void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) + if (CheckForCallocOverflow(size, nmemb)) return Allocator::FailureHandler::OnBadRequest(); return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true); } diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index e081cc576..2f8f6e3f9 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -160,7 +160,7 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { } void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { - if (CallocShouldReturnNullDueToOverflow(count, size)) + if (CheckForCallocOverflow(count, size)) return InternalAllocator::FailureHandler::OnBadRequest(); void *p = InternalAlloc(count * size, cache); if (p) internal_memset(p, 0, count * size); @@ -202,7 +202,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { low_level_alloc_callback = callback; } -bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) { +bool CheckForCallocOverflow(uptr size, uptr n) { if (!size) return false; uptr max = (uptr)-1L; return (max / size) < n; diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index 06f82d3a2..0fb8a087e 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -56,8 +56,10 @@ struct NoOpMapUnmapCallback { // Callback type for iterating over chunks. typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); -// Returns true if calloc(size, n) should return 0 due to overflow in size*n. -bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n); +// Returns true if calloc(size, n) call overflows on size*n calculation. +// The caller should "return POLICY::OnBadRequest();" where POLICY is the +// current allocator failure handling policy. +bool CheckForCallocOverflow(uptr size, uptr n); #include "sanitizer_allocator_size_class_map.h" #include "sanitizer_allocator_stats.h" diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index fa0d0cafe..7169d5b02 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -162,7 +162,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { } void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { - if (CallocShouldReturnNullDueToOverflow(size, n)) + if (CheckForCallocOverflow(size, n)) return Allocator::FailureHandler::OnBadRequest(); void *p = user_alloc(thr, pc, n * size); if (p) -- cgit v1.2.1 From 2cd50a16aec00d8d739ff8a8f669027fef286c1d Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 29 Jun 2017 21:54:37 +0000 Subject: [Sanitizers] Rename CallocShouldReturnNullDueToOverflow to CheckForCallocOverflow Summary: Due to changes in semantics, CheckForCallocOverflow makes much more sense now. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34799 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306747 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index f54e95373..b867643b6 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -135,7 +135,7 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { size *= nmemb; - return Allocate(stack, size, 1, true); + return Allocate(stack, size, 1, true /**/); } void *lsan_valloc(uptr size, const StackTrace &stack) { -- cgit v1.2.1 From 28b9d0a32fb203911935a6f723cd46843f381b14 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 29 Jun 2017 21:54:38 +0000 Subject: Merge git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306748 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 2 +- lib/lsan/lsan_interceptors.cc | 2 +- lib/scudo/scudo_allocator.cpp | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index b867643b6..f54e95373 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -135,7 +135,7 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { size *= nmemb; - return Allocate(stack, size, 1, true /**/); + return Allocate(stack, size, 1, true); } void *lsan_valloc(uptr size, const StackTrace &stack) { diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index b6ac7b77c..49ccb33e2 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -70,7 +70,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr; + if (CheckForCallocOverflow(size, nmemb)) return nullptr; ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index a2a3c8ba3..00fa19218 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -580,8 +580,7 @@ struct ScudoAllocator { void *calloc(uptr NMemB, uptr Size) { initThreadMaybe(); - // TODO(kostyak): switch to CheckForCallocOverflow once D34799 lands. - if (CallocShouldReturnNullDueToOverflow(NMemB, Size)) + if (CheckForCallocOverflow(NMemB, Size)) return FailureHandler::OnBadRequest(); return allocate(NMemB * Size, MinAlignment, FromMalloc, true); } -- cgit v1.2.1 From cf40d9536af9ddc8da4f8d0a919cacc1a57888a5 Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Fri, 30 Jun 2017 08:28:50 +0000 Subject: fix trivial typos, NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306807 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/fp_test.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/builtins/Unit/fp_test.h b/test/builtins/Unit/fp_test.h index 1f0e7be6d..781b7e2c7 100644 --- a/test/builtins/Unit/fp_test.h +++ b/test/builtins/Unit/fp_test.h @@ -85,7 +85,7 @@ static inline int compareResultH(uint16_t result, if (rep == expected){ return 0; } - // test other posible NaN representation(signal NaN) + // test other possible NaN representation(signal NaN) else if (expected == 0x7e00U){ if ((rep & 0x7c00U) == 0x7c00U && (rep & 0x3ffU) > 0){ @@ -103,7 +103,7 @@ static inline int compareResultF(float result, if (rep == expected){ return 0; } - // test other posible NaN representation(signal NaN) + // test other possible NaN representation(signal NaN) else if (expected == 0x7fc00000U){ if ((rep & 0x7f800000U) == 0x7f800000U && (rep & 0x7fffffU) > 0){ @@ -121,7 +121,7 @@ static inline int compareResultD(double result, if (rep == expected){ return 0; } - // test other posible NaN representation(signal NaN) + // test other possible NaN representation(signal NaN) else if (expected == 0x7ff8000000000000UL){ if ((rep & 0x7ff0000000000000UL) == 0x7ff0000000000000UL && (rep & 0xfffffffffffffUL) > 0){ @@ -146,7 +146,7 @@ static inline int compareResultLD(long double result, if (hi == expectedHi && lo == expectedLo){ return 0; } - // test other posible NaN representation(signal NaN) + // test other possible NaN representation(signal NaN) else if (expectedHi == 0x7fff800000000000UL && expectedLo == 0x0UL){ if ((hi & 0x7fff000000000000UL) == 0x7fff000000000000UL && ((hi & 0xffffffffffffUL) > 0 || lo > 0)){ -- cgit v1.2.1 From 63de5fcd7287d033a1667de42831c293137e00e4 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 30 Jun 2017 16:05:40 +0000 Subject: [sanitizer] Small tweaks and fixes to allocator related functions Summary: In `sanitizer_allocator_primary32.h`: - rounding up in `MapWithCallback` is not needed as `MmapOrDie` does it. Note that the 64-bit counterpart doesn't round up, this keeps the behavior consistent; - since `IsAligned` exists, use it in `AllocateRegion`; - in `PopulateFreeList`: - checking `b->Count` to be greater than 0 when `b->Count() == max_count` is redundant when done more than once. Just check that `max_count` is greater than 0 out of the loop; the compiler (at least on ARM) didn't optimize it; - mark the batch creation failure as `UNLIKELY`; In `sanitizer_allocator_primary64.h`: - in `MapWithCallback`, mark the failure condition as `UNLIKELY`; In `sanitizer_posix.h`: - mark a bunch of Mmap related failure conditions as `UNLIKELY`; - in `MmapAlignedOrDieOnFatalError`, we have `IsAligned`, so use it; rearrange the conditions as one test was redudant; - in `MmapFixedImpl`, 30 chars was not large enough to hold the message and a full 64-bit address (or at least a 48-bit usermode address), increase to 40. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: aemerson, kubamracek, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D34840 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306834 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary32.h | 7 +++---- .../sanitizer_allocator_primary64.h | 2 +- lib/sanitizer_common/sanitizer_posix.cc | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index d3949cc05..e85821543 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -118,7 +118,6 @@ class SizeClassAllocator32 { } void *MapWithCallback(uptr size) { - size = RoundUpTo(size, GetPageSizeCached()); void *res = MmapOrDie(size, "SizeClassAllocator32"); MapUnmapCallback().OnMap((uptr)res, size); return res; @@ -285,7 +284,7 @@ class SizeClassAllocator32 { return 0; MapUnmapCallback().OnMap(res, kRegionSize); stat->Add(AllocatorStatMapped, kRegionSize); - CHECK_EQ(0U, (res & (kRegionSize - 1))); + CHECK(IsAligned(res, kRegionSize)); possible_regions.set(ComputeRegionId(res), static_cast(class_id)); return res; } @@ -303,17 +302,17 @@ class SizeClassAllocator32 { return false; uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = TransferBatch::MaxCached(class_id); + CHECK_GT(max_count, 0); TransferBatch *b = nullptr; for (uptr i = reg; i < reg + n_chunks * size; i += size) { if (!b) { b = c->CreateBatch(class_id, this, (TransferBatch*)i); - if (!b) + if (UNLIKELY(!b)) return false; b->Clear(); } b->Add((void*)i); if (b->Count() == max_count) { - CHECK_GT(b->Count(), 0); sci->free_list.push_back(b); b = nullptr; } diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index efa2258dd..0c2e72ce7 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -389,7 +389,7 @@ class SizeClassAllocator64 { bool MapWithCallback(uptr beg, uptr size) { uptr mapped = reinterpret_cast(MmapFixedOrDieOnFatalError(beg, size)); - if (!mapped) + if (UNLIKELY(!mapped)) return false; CHECK_EQ(beg, mapped); MapUnmapCallback().OnMap(beg, size); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index fd2822edb..63f1bf713 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -129,7 +129,7 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); int reserrno; - if (internal_iserror(res, &reserrno)) + if (UNLIKELY(internal_iserror(res, &reserrno))) ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); IncreaseTotalMmap(size); return (void *)res; @@ -138,7 +138,7 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { void UnmapOrDie(void *addr, uptr size) { if (!addr || !size) return; uptr res = internal_munmap(addr, size); - if (internal_iserror(res)) { + if (UNLIKELY(internal_iserror(res))) { Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", SanitizerToolName, size, size, addr); CHECK("unable to unmap" && 0); @@ -152,7 +152,7 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); int reserrno; - if (internal_iserror(res, &reserrno)) { + if (UNLIKELY(internal_iserror(res, &reserrno))) { if (reserrno == ENOMEM) return nullptr; ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); @@ -170,15 +170,15 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); - if (!map_res) + if (UNLIKELY(!map_res)) return nullptr; uptr map_end = map_res + map_size; uptr res = map_res; - if (res & (alignment - 1)) // Not aligned. - res = (map_res + alignment) & ~(alignment - 1); - uptr end = res + size; - if (res != map_res) + if (!IsAligned(res, alignment)) { + res = (map_res + alignment - 1) & ~(alignment - 1); UnmapOrDie((void*)map_res, res - map_res); + } + uptr end = res + size; if (end != map_end) UnmapOrDie((void*)end, map_end - end); return (void*)res; @@ -192,7 +192,7 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); int reserrno; - if (internal_iserror(p, &reserrno)) + if (UNLIKELY(internal_iserror(p, &reserrno))) ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); IncreaseTotalMmap(size); return (void *)p; @@ -206,10 +206,10 @@ void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) { MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); int reserrno; - if (internal_iserror(p, &reserrno)) { + if (UNLIKELY(internal_iserror(p, &reserrno))) { if (tolerate_enomem && reserrno == ENOMEM) return nullptr; - char mem_type[30]; + char mem_type[40]; internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", fixed_addr); ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); -- cgit v1.2.1 From f0fdf665b4d351c308557383fadae7828660f499 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 30 Jun 2017 16:29:43 +0000 Subject: [objc] Don't require null-check and don't emit memset when result is ignored for struct-returning method calls [compiler-rt part] This fixes an issue with the emission of lifetime markers for struct-returning Obj-C msgSend calls. When the result of a struct-returning call is ignored, the temporary storage is only marked with lifetime markers in one of the two branches of the nil-receiver-check. The check is, however, not required when the result is unused. If we still need to emit the check (due to consumer arguments), let's not emit the memset to zero out the result if it's unused. This fixes a use-after-scope false positive with AddressSanitizer. Differential Revision: https://reviews.llvm.org/D34834 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306838 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/nil-return-struct.mm | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/asan/TestCases/Darwin/nil-return-struct.mm diff --git a/test/asan/TestCases/Darwin/nil-return-struct.mm b/test/asan/TestCases/Darwin/nil-return-struct.mm new file mode 100644 index 000000000..9fb77e746 --- /dev/null +++ b/test/asan/TestCases/Darwin/nil-return-struct.mm @@ -0,0 +1,31 @@ +// RUN: %clang_asan %s -o %t -framework Foundation +// RUN: %run %t 2>&1 | FileCheck %s + +#import + +struct MyStruct { + long a, b, c, d; +}; + +@interface MyClass: NSObject +- (MyStruct)methodWhichReturnsARect; +@end +@implementation MyClass +- (MyStruct)methodWhichReturnsARect { + MyStruct s; + s.a = 10; + s.b = 20; + s.c = 30; + s.d = 40; + return s; +} +@end + +int main() { + MyClass *myNil = nil; // intentionally nil + [myNil methodWhichReturnsARect]; + fprintf(stderr, "Hello world"); +} + +// CHECK-NOT: AddressSanitizer: stack-use-after-scope +// CHECK: Hello world -- cgit v1.2.1 From 598fa11c9960fa8f548554601b79cfab4b6a1d08 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 30 Jun 2017 17:21:34 +0000 Subject: [LSan] Make LSan allocator allocator_may_return_null compliant Summary: An attempt to reland D34786 (which caused bot failres on Mac), now with properly intercepted operators new() and delete(). LSan allocator used to always return nullptr on too big allocation requests (the definition of "too big" depends on platform and bitness), now it follows policy configured by allocator_may_return_null flag Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34845 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306845 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 6 +- lib/lsan/lsan_interceptors.cc | 56 +++++++++--- test/lsan/TestCases/allocator_returns_null.cc | 123 ++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 16 deletions(-) create mode 100644 test/lsan/TestCases/allocator_returns_null.cc diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index f54e95373..6514aea6f 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -74,7 +74,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, size = 1; if (size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); - return nullptr; + return Allocator::FailureHandler::OnBadRequest(); } void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); // Do not rely on the allocator to clear the memory (it's slow). @@ -99,7 +99,7 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); allocator.Deallocate(GetAllocatorCache(), p); - return nullptr; + return Allocator::FailureHandler::OnBadRequest(); } p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); RegisterAllocation(stack, p, new_size); @@ -134,6 +134,8 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { } void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { + if (CheckForCallocOverflow(size, nmemb)) + return Allocator::FailureHandler::OnBadRequest(); size *= nmemb; return Allocate(stack, size, 1, true); } diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 49ccb33e2..7d514402a 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -70,7 +70,6 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } - if (CheckForCallocOverflow(size, nmemb)) return nullptr; ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); @@ -199,6 +198,7 @@ INTERCEPTOR(int, mprobe, void *ptr) { } #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE + // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. #define OPERATOR_NEW_BODY(nothrow) \ ENSURE_LSAN_INITED; \ @@ -207,22 +207,28 @@ INTERCEPTOR(int, mprobe, void *ptr) { if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ return res; +#define OPERATOR_DELETE_BODY \ + ENSURE_LSAN_INITED; \ + Deallocate(ptr); + +// On OS X it's not enough to just provide our own 'operator new' and +// 'operator delete' implementations, because they're going to be in the runtime +// dylib, and the main executable will depend on both the runtime dylib and +// libstdc++, each of has its implementation of new and delete. +// To make sure that C++ allocation/deallocation operators are overridden on +// OS X we need to intercept them using their mangled names. +#if !SANITIZER_MAC + INTERCEPTOR_ATTRIBUTE void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new(size_t size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(true /*nothrow*/); -} +void *operator new(size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(true /*nothrow*/); } INTERCEPTOR_ATTRIBUTE -void *operator new[](size_t size, std::nothrow_t const&) { - OPERATOR_NEW_BODY(true /*nothrow*/); -} - -#define OPERATOR_DELETE_BODY \ - ENSURE_LSAN_INITED; \ - Deallocate(ptr); +void *operator new[](size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(true /*nothrow*/); } INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } @@ -231,9 +237,31 @@ void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE -void operator delete[](void *ptr, std::nothrow_t const &) { - OPERATOR_DELETE_BODY; -} +void operator delete[](void *ptr, std::nothrow_t const &) +{ OPERATOR_DELETE_BODY; } + +#else // SANITIZER_MAC + +INTERCEPTOR(void *, _Znwm, size_t size) +{ OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR(void *, _Znam, size_t size) +{ OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(true /*nothrow*/); } +INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) +{ OPERATOR_NEW_BODY(true /*nothrow*/); } + +INTERCEPTOR(void, _ZdlPv, void *ptr) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR(void, _ZdaPv, void *ptr) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } + +#endif // !SANITIZER_MAC + ///// Thread initialization and finalization. ///// diff --git a/test/lsan/TestCases/allocator_returns_null.cc b/test/lsan/TestCases/allocator_returns_null.cc new file mode 100644 index 000000000..ab2c734e1 --- /dev/null +++ b/test/lsan/TestCases/allocator_returns_null.cc @@ -0,0 +1,123 @@ +// Test the behavior of malloc/calloc/realloc/new when the allocation size is +// more than LSan allocator's max allowed one. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0, except the +// operator new(), which should crash anyway (operator new(std::nothrow) should +// return nullptr, indeed). +// +// RUN: %clangxx_lsan -O0 %s -o %t +// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH +// RUN: %env_lsan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + // Disable stderr buffering. Needed on Windows. + setvbuf(stderr, NULL, _IONBF, 0); + + assert(argc == 2); + const char *action = argv[1]; + fprintf(stderr, "%s:\n", action); + + // Use max of ASan and LSan allocator limits to cover both "lsan" and + // "lsan + asan" configs. + static const size_t kMaxAllowedMallocSizePlusOne = +#if __LP64__ || defined(_WIN64) + (1ULL << 40) + 1; +#else + (3UL << 30) + 1; +#endif + + void *x = 0; + if (!strcmp(action, "malloc")) { + x = malloc(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "calloc")) { + x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4); + } else if (!strcmp(action, "calloc-overflow")) { + volatile size_t kMaxSizeT = std::numeric_limits::max(); + size_t kArraySize = 4096; + volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + x = calloc(kArraySize, kArraySize2); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "realloc-after-malloc")) { + char *t = (char*)malloc(100); + *t = 42; + x = realloc(t, kMaxAllowedMallocSizePlusOne); + assert(*t == 42); + free(t); + } else if (!strcmp(action, "new")) { + x = operator new(kMaxAllowedMallocSizePlusOne); + } else if (!strcmp(action, "new-nothrow")) { + x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow); + } else { + assert(0); + } + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %zu\n", (size_t)x); + free(x); + + return x != 0; +} + +// CHECK-mCRASH: malloc: +// CHECK-mCRASH: Sanitizer's allocator is terminating the process +// CHECK-cCRASH: calloc: +// CHECK-cCRASH: Sanitizer's allocator is terminating the process +// CHECK-coCRASH: calloc-overflow: +// CHECK-coCRASH: Sanitizer's allocator is terminating the process +// CHECK-rCRASH: realloc: +// CHECK-rCRASH: Sanitizer's allocator is terminating the process +// CHECK-mrCRASH: realloc-after-malloc: +// CHECK-mrCRASH: Sanitizer's allocator is terminating the process +// CHECK-nCRASH: new: +// CHECK-nCRASH: Sanitizer's allocator is terminating the process +// CHECK-nnCRASH: new-nothrow: +// CHECK-nnCRASH: Sanitizer's allocator is terminating the process + +// CHECK-mNULL: malloc: +// CHECK-mNULL: x: 0 +// CHECK-cNULL: calloc: +// CHECK-cNULL: x: 0 +// CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: x: 0 +// CHECK-rNULL: realloc: +// CHECK-rNULL: x: 0 +// CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: x: 0 +// CHECK-nnNULL: new-nothrow: +// CHECK-nnNULL: x: 0 -- cgit v1.2.1 From dfa9d55abc855ea66209238471591265230b0ffe Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 30 Jun 2017 23:47:03 +0000 Subject: [asan] Disable test which fails on Android x86 Other Android CPUs probably pass just by luck as ulimit was not executed. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306914 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/allocator_oom_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Linux/allocator_oom_test.cc b/test/asan/TestCases/Linux/allocator_oom_test.cc index 4c696f325..33b6677de 100644 --- a/test/asan/TestCases/Linux/allocator_oom_test.cc +++ b/test/asan/TestCases/Linux/allocator_oom_test.cc @@ -29,7 +29,8 @@ // RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC-REALLOC,CHECK-NULL // ASan shadow memory on s390 is too large for this test. -// UNSUPPORTED: s390 +// TODO(alekseys): Android lit do not run ulimit on device. +// UNSUPPORTED: s390,android #include #include -- cgit v1.2.1 From 5849df7a0ab8819181f65981db36b26d61ba9b30 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 1 Jul 2017 03:54:19 +0000 Subject: [asan] Fix test on Android i686/fugu printf from .preinit_array may crash. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306940 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/init_fini_sections.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Linux/init_fini_sections.cc b/test/asan/TestCases/Linux/init_fini_sections.cc index c7234eeea..3037b2329 100644 --- a/test/asan/TestCases/Linux/init_fini_sections.cc +++ b/test/asan/TestCases/Linux/init_fini_sections.cc @@ -2,11 +2,18 @@ #include +int c = 0; + static void foo() { - printf("foo\n"); + ++c; +} + +static void fini() { + printf("fini\n"); } int main() { + printf("c=%d\n", c); return 0; } @@ -17,8 +24,7 @@ __attribute__((section(".init_array"))) void (*call_foo_2)(void) = &foo; __attribute__((section(".fini_array"))) -void (*call_foo_3)(void) = &foo; +void (*call_foo_3)(void) = &fini; -// CHECK: foo -// CHECK: foo -// CHECK: foo +// CHECK: c=2 +// CHECK: fini -- cgit v1.2.1 From 457fbcb4ad284308574a5dfd734c7298fd7f95ae Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 1 Jul 2017 04:23:47 +0000 Subject: [asan] This Android lit workaround should not be needed as bug is fixed git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306942 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/android_commands/android_common.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/asan/android_commands/android_common.py b/test/asan/android_commands/android_common.py index 1a295b781..41994bb87 100644 --- a/test/asan/android_commands/android_common.py +++ b/test/asan/android_commands/android_common.py @@ -37,8 +37,5 @@ def pull_from_device(path): return text def push_to_device(path): - # Workaround for https://code.google.com/p/android/issues/detail?id=65857 dst_path = os.path.join(ANDROID_TMPDIR, os.path.basename(path)) - tmp_path = dst_path + '.push' - adb(['push', path, tmp_path], 5) - adb(['shell', 'cp "%s" "%s" 2>&1' % (tmp_path, dst_path)], 5) + adb(['push', path, dst_path], 5) -- cgit v1.2.1 From 6ee59ff2a0b91f2224d38adb3fdb2dd5aefc107b Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sat, 1 Jul 2017 08:58:47 +0000 Subject: fix trivial typo; NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306955 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/sibling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfi/sibling.cpp b/test/cfi/sibling.cpp index 9f32302ed..601359888 100644 --- a/test/cfi/sibling.cpp +++ b/test/cfi/sibling.cpp @@ -15,7 +15,7 @@ // RUN: %clangxx -o %t5 %s // RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// Tests that the CFI enforcement distinguishes betwen non-overriding siblings. +// Tests that the CFI enforcement distinguishes between non-overriding siblings. // XFAILed as not implemented yet. #include -- cgit v1.2.1 From 3919408587ff646c2268da97a24fc3a9caba5910 Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Mon, 3 Jul 2017 06:44:05 +0000 Subject: fix trivial typos in comments; NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307005 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix.cc | 2 +- test/tsan/Darwin/ignore-noninstrumented.mm | 2 +- test/tsan/Darwin/ignored-interceptors.mm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 63f1bf713..ade1da2b1 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -162,7 +162,7 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { } // We want to map a chunk of address space aligned to 'alignment'. -// We do it by maping a bit more and then unmaping redundant pieces. +// We do it by mapping a bit more and then unmapping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, const char *mem_type) { diff --git a/test/tsan/Darwin/ignore-noninstrumented.mm b/test/tsan/Darwin/ignore-noninstrumented.mm index 528e07b9a..668a76a46 100644 --- a/test/tsan/Darwin/ignore-noninstrumented.mm +++ b/test/tsan/Darwin/ignore-noninstrumented.mm @@ -1,4 +1,4 @@ -// Check that ignore_noninstrumented_modules=1 supresses races from system libraries on OS X. +// Check that ignore_noninstrumented_modules=1 suppresses races from system libraries on OS X. // RUN: %clang_tsan %s -o %t -framework Foundation diff --git a/test/tsan/Darwin/ignored-interceptors.mm b/test/tsan/Darwin/ignored-interceptors.mm index 1105132a3..b2e40f07d 100644 --- a/test/tsan/Darwin/ignored-interceptors.mm +++ b/test/tsan/Darwin/ignored-interceptors.mm @@ -1,4 +1,4 @@ -// Check that ignore_interceptors_accesses=1 supresses reporting races from +// Check that ignore_interceptors_accesses=1 suppresses reporting races from // system libraries on OS X. There are currently false positives coming from // libxpc, libdispatch, CoreFoundation and others, because these libraries use // TSan-invisible atomics as synchronization. -- cgit v1.2.1 From b69423cad409c8837d7dbf242b183c9938d0dd2c Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Wed, 5 Jul 2017 05:43:31 +0000 Subject: fix trivial typos in comments; NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307124 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 68fde9139..added746a 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -59,7 +59,7 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { // lis r0,-10000 // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 // If the store faults then sp will not have been updated, so test above - // will not work, becase the fault address will be more than just "slightly" + // will not work, because the fault address will be more than just "slightly" // below sp. if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { u32 inst = *(unsigned *)sig.pc; -- cgit v1.2.1 From f339952e6e43368ab0f4783bc330a4e5240a4024 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Wed, 5 Jul 2017 06:54:43 +0000 Subject: [asan] Remove check for stack size This has been introduced in r304598 and fails for increased stack sizes. Differential Revision: https://reviews.llvm.org/D34876 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307127 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_thread.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index 714496d5c..b1a0d9a3b 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -200,7 +200,6 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. return nullptr; - CHECK_LE(stack_size, 0x10000000); uptr old_val = 0; // fake_stack_ has 3 states: // 0 -- not initialized -- cgit v1.2.1 From f863c64e6e6ec4b46420bd546dea312c0bb3e2f5 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 5 Jul 2017 22:17:44 +0000 Subject: [tsan] Use pthread_sigmask instead of sigprocmask to block signals in a thread on Darwin On Darwin, sigprocmask changes the signal mask for the entire process. This has some unwanted consequences, because e.g. internal_start_thread wants to disable signals only in the current thread (to make the new thread inherit the signal mask), which is currently broken on Darwin. This patch switches to pthread_sigmask. Differential Revision: https://reviews.llvm.org/D35016 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307212 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 3 +- test/tsan/Darwin/signals-blocked.cc | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/tsan/Darwin/signals-blocked.cc diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index b48238106..2a13fee05 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -191,7 +191,8 @@ void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { - return sigprocmask(how, set, oldset); + // Don't use sigprocmask here, because it affects all threads. + return pthread_sigmask(how, set, oldset); } // Doesn't call pthread_atfork() handlers (but not available on 10.6). diff --git a/test/tsan/Darwin/signals-blocked.cc b/test/tsan/Darwin/signals-blocked.cc new file mode 100644 index 000000000..209dc2229 --- /dev/null +++ b/test/tsan/Darwin/signals-blocked.cc @@ -0,0 +1,75 @@ +// RUN: %clangxx_tsan %s -o %t && %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include +#include +#include + +volatile bool signal_delivered; + +static void handler(int sig) { + if (sig == SIGALRM) + signal_delivered = true; +} + +static void* thr(void *p) { + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + int ret = pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); + if (ret) abort(); + + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGALRM, &act, 0)) { + perror("sigaction"); + exit(1); + } + + itimerval t; + t.it_value.tv_sec = 0; + t.it_value.tv_usec = 10000; + t.it_interval = t.it_value; + if (setitimer(ITIMER_REAL, &t, 0)) { + perror("setitimer"); + exit(1); + } + + while (!signal_delivered) { + usleep(1000); + } + + t.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &t, 0)) { + perror("setitimer"); + exit(1); + } + + fprintf(stderr, "SIGNAL DELIVERED\n"); + + return 0; +} + +int main() { + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + int ret = pthread_sigmask(SIG_BLOCK, &sigset, NULL); + if (ret) abort(); + + pthread_t th; + pthread_create(&th, 0, thr, 0); + pthread_join(th, 0); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: SIGNAL DELIVERED +// CHECK: DONE +// CHECK-NOT: WARNING: ThreadSanitizer: -- cgit v1.2.1 From ff641b94674eae2f1a20cebf8a59bfe0f71802c4 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 6 Jul 2017 00:50:57 +0000 Subject: [Sanitizers] Consolidate internal errno definitions. Move internal errno definitions to common to be shared by all sanitizers and to be used by allocators. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307233 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 11 ++----- lib/sanitizer_common/CMakeLists.txt | 3 ++ .../sanitizer_common_interceptors.inc | 1 + lib/sanitizer_common/sanitizer_errno.cc | 35 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_errno.h | 35 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_errno_codes.h | 34 +++++++++++++++++++++ .../sanitizer_platform_limits_posix.cc | 9 ------ .../sanitizer_platform_limits_posix.h | 3 -- lib/tsan/rtl/tsan_interceptors.cc | 19 ++++-------- lib/tsan/rtl/tsan_platform_linux.cc | 1 - 10 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_errno.cc create mode 100644 lib/sanitizer_common/sanitizer_errno.h create mode 100644 lib/sanitizer_common/sanitizer_errno_codes.h diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index ce8444a3b..069777c7f 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -27,6 +27,7 @@ #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" @@ -48,15 +49,9 @@ DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) DECLARE_REAL(void *, memset, void *dest, int c, uptr n) -#if SANITIZER_FREEBSD -#define __errno_location __error -#endif - // True if this is a nested interceptor. static THREADLOCAL int in_interceptor_scope; -extern "C" int *__errno_location(void); - struct InterceptorScope { InterceptorScope() { ++in_interceptor_scope; } ~InterceptorScope() { --in_interceptor_scope; } @@ -915,7 +910,7 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, ENSURE_MSAN_INITED(); if (addr && !MEM_IS_APP(addr)) { if (flags & map_fixed) { - *__errno_location() = errno_EINVAL; + errno = errno_EINVAL; return (void *)-1; } else { addr = nullptr; @@ -933,7 +928,7 @@ INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, ENSURE_MSAN_INITED(); if (addr && !MEM_IS_APP(addr)) { if (flags & map_fixed) { - *__errno_location() = errno_EINVAL; + errno = errno_EINVAL; return (void *)-1; } else { addr = nullptr; diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index bf8459ef5..26ea071ef 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -6,6 +6,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_common.cc sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc + sanitizer_errno.cc sanitizer_flags.cc sanitizer_flag_parser.cc sanitizer_libc.cc @@ -92,6 +93,8 @@ set(SANITIZER_HEADERS sanitizer_common_syscalls.inc sanitizer_deadlock_detector.h sanitizer_deadlock_detector_interface.h + sanitizer_errno.h + sanitizer_errno_codes.h sanitizer_flag_parser.h sanitizer_flags.h sanitizer_flags.inc diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 459530aa9..8607bf449 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -40,6 +40,7 @@ #include "interception/interception.h" #include "sanitizer_addrhashmap.h" +#include "sanitizer_errno.h" #include "sanitizer_placement_new.h" #include "sanitizer_platform_interceptors.h" #include "sanitizer_tls_get_addr.h" diff --git a/lib/sanitizer_common/sanitizer_errno.cc b/lib/sanitizer_common/sanitizer_errno.cc new file mode 100644 index 000000000..a6f9fc612 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_errno.cc @@ -0,0 +1,35 @@ +//===-- sanitizer_errno.cc --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno to avoid including errno.h and its dependencies into other +// files (e.g. interceptors are not supposed to include any system headers). +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno_codes.h" +#include "sanitizer_internal_defs.h" + +#include + +namespace __sanitizer { + +COMPILER_CHECK(errno_ENOMEM == ENOMEM); +COMPILER_CHECK(errno_EBUSY == EBUSY); +COMPILER_CHECK(errno_EINVAL == EINVAL); + +// EOWNERDEAD is not present in some older platforms. +#if defined(EOWNERDEAD) +extern const int errno_EOWNERDEAD = EOWNERDEAD; +#else +extern const int errno_EOWNERDEAD = -1; +#endif + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_errno.h b/lib/sanitizer_common/sanitizer_errno.h new file mode 100644 index 000000000..c405307ba --- /dev/null +++ b/lib/sanitizer_common/sanitizer_errno.h @@ -0,0 +1,35 @@ +//===-- sanitizer_errno.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno to avoid including errno.h and its dependencies into sensitive +// files (e.g. interceptors are not supposed to include any system headers). +// It's ok to use errno.h directly when your file already depend on other system +// includes though. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ERRNO_H +#define SANITIZER_ERRNO_H + +#include "sanitizer_errno_codes.h" +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_MAC +# define __errno_location __error +#elif SANITIZER_ANDROID +# define __errno_location __errno +#endif + +extern "C" int *__errno_location(); + +#define errno (*__errno_location()) + +#endif // SANITIZER_ERRNO_H diff --git a/lib/sanitizer_common/sanitizer_errno_codes.h b/lib/sanitizer_common/sanitizer_errno_codes.h new file mode 100644 index 000000000..dba774c5b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_errno_codes.h @@ -0,0 +1,34 @@ +//===-- sanitizer_errno_codes.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno codes to avoid including errno.h and its dependencies into +// sensitive files (e.g. interceptors are not supposed to include any system +// headers). +// It's ok to use errno.h directly when your file already depend on other system +// includes though. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ERRNO_CODES_H +#define SANITIZER_ERRNO_CODES_H + +namespace __sanitizer { + +#define errno_ENOMEM 12 +#define errno_EBUSY 16 +#define errno_EINVAL 22 + +// Those might not present or their value differ on different platforms. +extern const int errno_EOWNERDEAD; + +} // namespace __sanitizer + +#endif // SANITIZER_ERRNO_CODES_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 683f019d7..83f4fd22f 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -25,7 +25,6 @@ #endif #include #include -#include #include #include #include @@ -931,14 +930,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID - const int errno_EINVAL = EINVAL; -// EOWNERDEAD is not present in some older platforms. -#if defined(EOWNERDEAD) - const int errno_EOWNERDEAD = EOWNERDEAD; -#else - const int errno_EOWNERDEAD = -1; -#endif - const int si_SEGV_MAPERR = SEGV_MAPERR; const int si_SEGV_ACCERR = SEGV_ACCERR; } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 24ffcd7d9..63dcd2a6d 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -1464,9 +1464,6 @@ struct __sanitizer_cookie_io_functions_t { extern unsigned IOCTL_PIO_SCRNMAP; #endif - extern const int errno_EINVAL; - extern const int errno_EOWNERDEAD; - extern const int si_SEGV_MAPERR; extern const int si_SEGV_ACCERR; } // namespace __sanitizer diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 334cc326d..5ae02f3b4 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" @@ -34,13 +35,11 @@ using namespace __tsan; // NOLINT #if SANITIZER_FREEBSD || SANITIZER_MAC -#define __errno_location __error #define stdout __stdoutp #define stderr __stderrp #endif #if SANITIZER_ANDROID -#define __errno_location __errno #define mallopt(a, b) #endif @@ -84,7 +83,6 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) extern "C" void *pthread_self(); extern "C" void _exit(int status); -extern "C" int *__errno_location(); extern "C" int fileno_unlocked(void *stream); extern "C" int dirfd(void *dirp); #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID @@ -98,9 +96,6 @@ const int PTHREAD_MUTEX_RECURSIVE_NP = 1; const int PTHREAD_MUTEX_RECURSIVE = 2; const int PTHREAD_MUTEX_RECURSIVE_NP = 2; #endif -const int EINVAL = 22; -const int EBUSY = 16; -const int EOWNERDEAD = 130; #if !SANITIZER_FREEBSD && !SANITIZER_MAC const int EPOLL_CTL_ADD = 1; #endif @@ -130,8 +125,6 @@ typedef long long_t; // NOLINT # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ # define F_TEST 3 /* Test a region for other processes locks. */ -#define errno (*__errno_location()) - typedef void (*sighandler_t)(int sig); typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); @@ -665,7 +658,7 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) { if (*addr) { if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { if (flags & MAP_FIXED) { - errno = EINVAL; + errno = errno_EINVAL; return false; } else { *addr = 0; @@ -1122,7 +1115,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m); int res = REAL(pthread_mutex_destroy)(m); - if (res == 0 || res == EBUSY) { + if (res == 0 || res == errno_EBUSY) { MutexDestroy(thr, pc, (uptr)m); } return res; @@ -1131,9 +1124,9 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m); int res = REAL(pthread_mutex_trylock)(m); - if (res == EOWNERDEAD) + if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); - if (res == 0 || res == EOWNERDEAD) + if (res == 0 || res == errno_EOWNERDEAD) MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); return res; } @@ -1311,7 +1304,7 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); if (o == 0 || f == 0) - return EINVAL; + return errno_EINVAL; atomic_uint32_t *a; if (!SANITIZER_MAC) a = static_cast(o); diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index d05c0e701..7d9638c09 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #if SANITIZER_LINUX -- cgit v1.2.1 From 10c0350fb5f2dfff4e71db47c92ba89d195e89b4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 17:13:40 +0000 Subject: [sanitizer] Split GetMaxVirtualAddress into separate Linux version and Mac version [NFC] The logic in GetMaxVirtualAddress is already pretty complex, and I want to get rid of the hardcoded value for iOS/AArch64, which would need adding more Darwin-specific code, so let's split the implementation into sanitizer_linux.cc and sanitizer_mac.cc files. NFC. Differential Revision: https://reviews.llvm.org/D35031 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307281 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 31 +++++++++++++++++++++++++++++ lib/sanitizer_common/sanitizer_mac.cc | 14 +++++++++++++ lib/sanitizer_common/sanitizer_posix.cc | 35 --------------------------------- 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index a94a63c7f..355d581f2 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -815,6 +815,37 @@ bool ThreadLister::GetDirectoryEntries() { return true; } +uptr GetMaxVirtualAddress() { +#if SANITIZER_WORDSIZE == 64 +# if defined(__powerpc64__) || defined(__aarch64__) + // On PowerPC64 we have two different address space layouts: 44- and 46-bit. + // We somehow need to figure out which one we are using now and choose + // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. + // Note that with 'ulimit -s unlimited' the stack is moved away from the top + // of the address space, so simply checking the stack address is not enough. + // This should (does) work for both PowerPC64 Endian modes. + // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. + return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; +# elif defined(__mips64) + return (1ULL << 40) - 1; // 0x000000ffffffffffUL; +# elif defined(__s390x__) + return (1ULL << 53) - 1; // 0x001fffffffffffffUL; +# else + return (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# endif +#else // SANITIZER_WORDSIZE == 32 +# if defined(__s390__) + return (1ULL << 31) - 1; // 0x7fffffff; +# else + uptr res = (1ULL << 32) - 1; // 0xffffffff; + if (!common_flags()->full_address_space) + res -= GetKernelAreaSize(); + CHECK_LT(reinterpret_cast(&res), res); + return res; +# endif +#endif // SANITIZER_WORDSIZE +} + uptr GetPageSize() { // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 2a13fee05..7d027130d 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -800,6 +800,20 @@ char **GetArgv() { return *_NSGetArgv(); } +uptr GetMaxVirtualAddress() { +#if SANITIZER_WORDSIZE == 64 +# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM + // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The + // upper bound can change depending on the device. + return 0x200000000 - 1; +# else + return (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# endif +#else // SANITIZER_WORDSIZE == 32 + return (1ULL << 32) - 1; // 0xffffffff; +#endif // SANITIZER_WORDSIZE +} + uptr FindAvailableMemoryRange(uptr shadow_size, uptr alignment, uptr left_padding) { diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index ade1da2b1..d41f16c94 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -88,41 +88,6 @@ static uptr GetKernelAreaSize() { } #endif // SANITIZER_WORDSIZE == 32 -uptr GetMaxVirtualAddress() { -#if SANITIZER_WORDSIZE == 64 -# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM - // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The - // upper bound can change depending on the device. - return 0x200000000 - 1; -# elif defined(__powerpc64__) || defined(__aarch64__) - // On PowerPC64 we have two different address space layouts: 44- and 46-bit. - // We somehow need to figure out which one we are using now and choose - // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. - // Note that with 'ulimit -s unlimited' the stack is moved away from the top - // of the address space, so simply checking the stack address is not enough. - // This should (does) work for both PowerPC64 Endian modes. - // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. - return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; -# elif defined(__mips64) - return (1ULL << 40) - 1; // 0x000000ffffffffffUL; -# elif defined(__s390x__) - return (1ULL << 53) - 1; // 0x001fffffffffffffUL; -# else - return (1ULL << 47) - 1; // 0x00007fffffffffffUL; -# endif -#else // SANITIZER_WORDSIZE == 32 -# if defined(__s390__) - return (1ULL << 31) - 1; // 0x7fffffff; -# else - uptr res = (1ULL << 32) - 1; // 0xffffffff; - if (!common_flags()->full_address_space) - res -= GetKernelAreaSize(); - CHECK_LT(reinterpret_cast(&res), res); - return res; -# endif -#endif // SANITIZER_WORDSIZE -} - void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { size = RoundUpTo(size, GetPageSizeCached()); uptr res = internal_mmap(nullptr, size, -- cgit v1.2.1 From e0fbf555f26e10b69cd789b6e1b5f9913ddc91fc Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 17:17:50 +0000 Subject: Fixup for r307281: Also move GetKernelAreaSize into sanitizer_linux.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307282 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 39 +++++++++++++++++++++++++++++++++ lib/sanitizer_common/sanitizer_posix.cc | 39 --------------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 355d581f2..71bad4663 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -815,6 +815,45 @@ bool ThreadLister::GetDirectoryEntries() { return true; } +#if SANITIZER_WORDSIZE == 32 +// Take care of unusable kernel area in top gigabyte. +static uptr GetKernelAreaSize() { +#if SANITIZER_LINUX && !SANITIZER_X32 + const uptr gbyte = 1UL << 30; + + // Firstly check if there are writable segments + // mapped to top gigabyte (e.g. stack). + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + uptr end, prot; + while (proc_maps.Next(/*start*/nullptr, &end, + /*offset*/nullptr, /*filename*/nullptr, + /*filename_size*/0, &prot)) { + if ((end >= 3 * gbyte) + && (prot & MemoryMappingLayout::kProtectionWrite) != 0) + return 0; + } + +#if !SANITIZER_ANDROID + // Even if nothing is mapped, top Gb may still be accessible + // if we are running on 64-bit kernel. + // Uname may report misleading results if personality type + // is modified (e.g. under schroot) so check this as well. + struct utsname uname_info; + int pers = personality(0xffffffffUL); + if (!(pers & PER_MASK) + && uname(&uname_info) == 0 + && internal_strstr(uname_info.machine, "64")) + return 0; +#endif // SANITIZER_ANDROID + + // Top gigabyte is reserved for kernel. + return gbyte; +#else + return 0; +#endif // SANITIZER_LINUX && !SANITIZER_X32 +} +#endif // SANITIZER_WORDSIZE == 32 + uptr GetMaxVirtualAddress() { #if SANITIZER_WORDSIZE == 64 # if defined(__powerpc64__) || defined(__aarch64__) diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index d41f16c94..7841b246f 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -49,45 +49,6 @@ uptr GetMmapGranularity() { return GetPageSize(); } -#if SANITIZER_WORDSIZE == 32 -// Take care of unusable kernel area in top gigabyte. -static uptr GetKernelAreaSize() { -#if SANITIZER_LINUX && !SANITIZER_X32 - const uptr gbyte = 1UL << 30; - - // Firstly check if there are writable segments - // mapped to top gigabyte (e.g. stack). - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr end, prot; - while (proc_maps.Next(/*start*/nullptr, &end, - /*offset*/nullptr, /*filename*/nullptr, - /*filename_size*/0, &prot)) { - if ((end >= 3 * gbyte) - && (prot & MemoryMappingLayout::kProtectionWrite) != 0) - return 0; - } - -#if !SANITIZER_ANDROID - // Even if nothing is mapped, top Gb may still be accessible - // if we are running on 64-bit kernel. - // Uname may report misleading results if personality type - // is modified (e.g. under schroot) so check this as well. - struct utsname uname_info; - int pers = personality(0xffffffffUL); - if (!(pers & PER_MASK) - && uname(&uname_info) == 0 - && internal_strstr(uname_info.machine, "64")) - return 0; -#endif // SANITIZER_ANDROID - - // Top gigabyte is reserved for kernel. - return gbyte; -#else - return 0; -#endif // SANITIZER_LINUX && !SANITIZER_X32 -} -#endif // SANITIZER_WORDSIZE == 32 - void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { size = RoundUpTo(size, GetPageSizeCached()); uptr res = internal_mmap(nullptr, size, -- cgit v1.2.1 From b3b4445f1acf7a28712a0b36d973265512ca68fc Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 17:45:01 +0000 Subject: More fixup for r307281: Move the #includes to sanitizer_linux.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307284 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 8 ++++++++ lib/sanitizer_common/sanitizer_posix.cc | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 71bad4663..f3994bfd0 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -59,6 +59,14 @@ #include #include +#if SANITIZER_LINUX +#include +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#include +#endif + #if SANITIZER_FREEBSD #include #include diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 7841b246f..4abc9d16d 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -27,14 +27,6 @@ #include #include -#if SANITIZER_LINUX -#include -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -#include -#endif - #if SANITIZER_FREEBSD // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before // that, it was never implemented. So just define it to zero. -- cgit v1.2.1 From 501c0c7048cfaecb5ef02c34a5c38daac73f413c Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 20:30:09 +0000 Subject: [sanitizer] Use TASK_VM_INFO to get the maximum VM address on iOS/AArch64 We currently hardcode the maximum VM address on iOS/AArch64, which is not really correct and this value changes between device configurations. Let's use TASK_VM_INFO to retrieve the maximum VM address dynamically. Differential Revision: https://reviews.llvm.org/D35032 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307307 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 7d027130d..70f6daeee 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -799,13 +799,37 @@ void MaybeReexec() { char **GetArgv() { return *_NSGetArgv(); } + +#if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM +// The task_vm_info struct is normally provided by the macOS SDK, but we need +// fields only available in 10.12+. Declare the struct manually to be able to +// build against older SDKs. +struct __sanitizer_task_vm_info { + uptr _unused[(SANITIZER_WORDSIZE == 32) ? 20 : 19]; + uptr min_address; + uptr max_address; +}; + +uptr GetTaskInfoMaxAddress() { + __sanitizer_task_vm_info vm_info = {{0}, 0, 0}; + mach_msg_type_number_t count = sizeof(vm_info) / sizeof(int); + int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); + if (err == 0) { + return vm_info.max_address; + } else { + // xnu cannot provide vm address limit + return 0x200000000 - 1; + } +} +#endif uptr GetMaxVirtualAddress() { #if SANITIZER_WORDSIZE == 64 # if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM - // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The - // upper bound can change depending on the device. - return 0x200000000 - 1; + // Get the maximum VM address + static uptr max_vm = GetTaskInfoMaxAddress(); + CHECK(max_vm); + return max_vm; # else return (1ULL << 47) - 1; // 0x00007fffffffffffUL; # endif -- cgit v1.2.1 From 10bdcb2d1ae8ae45b6d047428c6f56bb9859c319 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 20:38:33 +0000 Subject: Fix whitespace lint issue (introduced in r307307). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307309 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 70f6daeee..8a8fc9663 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -799,7 +799,7 @@ void MaybeReexec() { char **GetArgv() { return *_NSGetArgv(); } - + #if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM // The task_vm_info struct is normally provided by the macOS SDK, but we need // fields only available in 10.12+. Declare the struct manually to be able to -- cgit v1.2.1 From 656a9d2e240ebab85ebdd6b3f11c95b7f669a3bf Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 6 Jul 2017 21:51:32 +0000 Subject: [asan] Fix -Winvalid-paste error with clang-cl We don't need to paste tokens here. String literal concatenation works just fine here with MSVC and Clang. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307321 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_new_delete.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index 942b169d9..e68c7f3e2 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -26,7 +26,7 @@ // VS2015 dynamic CRT (MD) work. #if SANITIZER_WINDOWS #define CXX_OPERATOR_ATTRIBUTE -#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:"##sym)) +#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym)) #ifdef _WIN64 COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow -- cgit v1.2.1 From 4761fa543cabb540b466b33b0ff8a24c3ef33fcf Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 6 Jul 2017 23:09:16 +0000 Subject: [cmake] Add an option to prefer public SDK in find_darwin_sdk_dir Adds a CMake option DARWIN_PREFER_PUBLIC_SDK, off by default. When on, this prefers to use the public SDK, even when an internal one is present. With this, it's easy to emulate a build that the public buildbots are doing. Differential Revision: https://reviews.llvm.org/D35071 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307330 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTDarwinUtils.cmake | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index baea4a067..18379080c 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -4,14 +4,17 @@ include(CMakeParseArguments) # set the default Xcode to use. This function finds the SDKs that are present in # the current Xcode. function(find_darwin_sdk_dir var sdk_name) - # Let's first try the internal SDK, otherwise use the public SDK. - execute_process( - COMMAND xcodebuild -version -sdk ${sdk_name}.internal Path - RESULT_VARIABLE result_process - OUTPUT_VARIABLE var_internal - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_FILE /dev/null - ) + set(DARWIN_PREFER_PUBLIC_SDK OFF CACHE BOOL "Prefer Darwin public SDK, even when an internal SDK is present.") + if(NOT DARWIN_PREFER_PUBLIC_SDK) + # Let's first try the internal SDK, otherwise use the public SDK. + execute_process( + COMMAND xcodebuild -version -sdk ${sdk_name}.internal Path + RESULT_VARIABLE result_process + OUTPUT_VARIABLE var_internal + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_FILE /dev/null + ) + endif() if((NOT result_process EQUAL 0) OR "" STREQUAL "${var_internal}") execute_process( COMMAND xcodebuild -version -sdk ${sdk_name} Path -- cgit v1.2.1 From 55b271fd886d0140311c28421fae978e0c19de28 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 7 Jul 2017 00:48:38 +0000 Subject: [asan] Add end-to-end tests for overflows of byval arguments. Included is one test for passing structs by value and one test for passing C++ objects by value. Patch by Matt Morehouse. Differential revision: https://reviews.llvm.org/D34827 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307343 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/pass-object-byval.cc | 36 ++++++++++++++++++++++++++++ test/asan/TestCases/pass-struct-byval-uar.cc | 32 +++++++++++++++++++++++++ test/asan/TestCases/pass-struct-byval.cc | 23 ++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 test/asan/TestCases/pass-object-byval.cc create mode 100644 test/asan/TestCases/pass-struct-byval-uar.cc create mode 100644 test/asan/TestCases/pass-struct-byval.cc diff --git a/test/asan/TestCases/pass-object-byval.cc b/test/asan/TestCases/pass-object-byval.cc new file mode 100644 index 000000000..189fcbeb2 --- /dev/null +++ b/test/asan/TestCases/pass-object-byval.cc @@ -0,0 +1,36 @@ +// Verify that objects passed by value get red zones and that the copy +// constructor is called. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ +// RUN: Assertion{{.*}}failed +#include + +class A { + public: + A() : me(this) {} + A(const A &other) : me(this) { + for (int i = 0; i < 8; ++i) a[i] = other.a[i]; + } + + int a[8]; + A *me; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + assert(a.me == &a); + bar(&a); +} + +int main() { + A a; + foo(a); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread diff --git a/test/asan/TestCases/pass-struct-byval-uar.cc b/test/asan/TestCases/pass-struct-byval-uar.cc new file mode 100644 index 000000000..3b5f4449b --- /dev/null +++ b/test/asan/TestCases/pass-struct-byval-uar.cc @@ -0,0 +1,32 @@ +// Test that use-after-return works with arguments passed by value. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-NO-UAR %s +// RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-UAR %s + +#include + +struct A { + int a[8]; +}; + +A *foo(A a) { + return &a; +} + +int main() { + A *a = foo(A()); + a->a[0] = 7; + std::fprintf(stderr, "\n"); // Ensures some output is generated for FileCheck + // to verify in the case where UAR is not + // detected. +} + +// CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-NO-UAR-NOT: WRITE of size 4 at +// CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable +// +// CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-UAR: WRITE of size 4 at +// CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable diff --git a/test/asan/TestCases/pass-struct-byval.cc b/test/asan/TestCases/pass-struct-byval.cc new file mode 100644 index 000000000..ba49eccf4 --- /dev/null +++ b/test/asan/TestCases/pass-struct-byval.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +struct A { + int a[8]; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + bar(&a); +} + +int main() { + foo(A()); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-underflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread -- cgit v1.2.1 From 32840b9046e67dcf45fb0b14b44c0ec226858cc3 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 7 Jul 2017 01:06:20 +0000 Subject: [cmake] Cache results of find_darwin_sdk_dir This improves find_darwin_sdk_dir to cache the results of executing xcodebuild to find the SDK. Should significantly reduce the CMake re-configure time. Differential Revision: https://reviews.llvm.org/D34736 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307344 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTDarwinUtils.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index 18379080c..aaa97e33e 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -4,6 +4,11 @@ include(CMakeParseArguments) # set the default Xcode to use. This function finds the SDKs that are present in # the current Xcode. function(find_darwin_sdk_dir var sdk_name) + set(DARWIN_${sdk_name}_CACHED_SYSROOT "" CACHE STRING "Darwin SDK path for SDK ${sdk_name}.") + if(DARWIN_${sdk_name}_CACHED_SYSROOT) + set(${var} ${DARWIN_${sdk_name}_CACHED_SYSROOT} PARENT_SCOPE) + return() + endif() set(DARWIN_PREFER_PUBLIC_SDK OFF CACHE BOOL "Prefer Darwin public SDK, even when an internal SDK is present.") if(NOT DARWIN_PREFER_PUBLIC_SDK) # Let's first try the internal SDK, otherwise use the public SDK. @@ -29,6 +34,7 @@ function(find_darwin_sdk_dir var sdk_name) if(result_process EQUAL 0) set(${var} ${var_internal} PARENT_SCOPE) endif() + set(DARWIN_${sdk_name}_CACHED_SYSROOT ${var_internal} CACHE STRING "Darwin SDK path for SDK ${sdk_name}." FORCE) endfunction() # There isn't a clear mapping of what architectures are supported with a given -- cgit v1.2.1 From 9e2c69ffc25e56881e2a4805ac765110dec265dc Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 7 Jul 2017 01:31:23 +0000 Subject: Revert r307342, r307343. Revert "Copy arguments passed by value into explicit allocas for ASan." Revert "[asan] Add end-to-end tests for overflows of byval arguments." Build failure on lldb-x86_64-ubuntu-14.04-buildserver. Test failure on clang-cmake-aarch64-42vma and sanitizer-x86_64-linux-android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307345 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/pass-object-byval.cc | 36 ---------------------------- test/asan/TestCases/pass-struct-byval-uar.cc | 32 ------------------------- test/asan/TestCases/pass-struct-byval.cc | 23 ------------------ 3 files changed, 91 deletions(-) delete mode 100644 test/asan/TestCases/pass-object-byval.cc delete mode 100644 test/asan/TestCases/pass-struct-byval-uar.cc delete mode 100644 test/asan/TestCases/pass-struct-byval.cc diff --git a/test/asan/TestCases/pass-object-byval.cc b/test/asan/TestCases/pass-object-byval.cc deleted file mode 100644 index 189fcbeb2..000000000 --- a/test/asan/TestCases/pass-object-byval.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Verify that objects passed by value get red zones and that the copy -// constructor is called. -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ -// RUN: Assertion{{.*}}failed -#include - -class A { - public: - A() : me(this) {} - A(const A &other) : me(this) { - for (int i = 0; i < 8; ++i) a[i] = other.a[i]; - } - - int a[8]; - A *me; -}; - -int bar(A *a) { - int *volatile ptr = &a->a[0]; - return *(ptr - 1); -} - -void foo(A a) { - assert(a.me == &a); - bar(&a); -} - -int main() { - A a; - foo(a); -} - -// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow -// CHECK: READ of size 4 at -// CHECK: is located in stack of thread diff --git a/test/asan/TestCases/pass-struct-byval-uar.cc b/test/asan/TestCases/pass-struct-byval-uar.cc deleted file mode 100644 index 3b5f4449b..000000000 --- a/test/asan/TestCases/pass-struct-byval-uar.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Test that use-after-return works with arguments passed by value. -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK-NO-UAR %s -// RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK-UAR %s - -#include - -struct A { - int a[8]; -}; - -A *foo(A a) { - return &a; -} - -int main() { - A *a = foo(A()); - a->a[0] = 7; - std::fprintf(stderr, "\n"); // Ensures some output is generated for FileCheck - // to verify in the case where UAR is not - // detected. -} - -// CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return -// CHECK-NO-UAR-NOT: WRITE of size 4 at -// CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable -// -// CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return -// CHECK-UAR: WRITE of size 4 at -// CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable diff --git a/test/asan/TestCases/pass-struct-byval.cc b/test/asan/TestCases/pass-struct-byval.cc deleted file mode 100644 index ba49eccf4..000000000 --- a/test/asan/TestCases/pass-struct-byval.cc +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s - -struct A { - int a[8]; -}; - -int bar(A *a) { - int *volatile ptr = &a->a[0]; - return *(ptr - 1); -} - -void foo(A a) { - bar(&a); -} - -int main() { - foo(A()); -} - -// CHECK: ERROR: AddressSanitizer: stack-buffer-underflow -// CHECK: READ of size 4 at -// CHECK: is located in stack of thread -- cgit v1.2.1 From 922a96fd9fec952be515a42b5e3ed608d093fa11 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 7 Jul 2017 15:32:44 +0000 Subject: Fix-up for r307307: vm_info.max_address is the first non-addressable pointer, so we need to subtract one. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307408 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 8a8fc9663..d6e61f207 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -815,7 +815,7 @@ uptr GetTaskInfoMaxAddress() { mach_msg_type_number_t count = sizeof(vm_info) / sizeof(int); int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); if (err == 0) { - return vm_info.max_address; + return vm_info.max_address - 1; } else { // xnu cannot provide vm address limit return 0x200000000 - 1; -- cgit v1.2.1 From 0a9913ccddd8ede214f20c45aaaf702203908588 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 7 Jul 2017 21:17:29 +0000 Subject: Update buildgo.sh to pass -isysroot on Darwin. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307443 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/go/buildgo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 59176809e..617dd9e11 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -69,7 +69,7 @@ elif [ "`uname -a | grep FreeBSD`" != "" ]; then " elif [ "`uname -a | grep Darwin`" != "" ]; then SUFFIX="darwin_amd64" - OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -mmacosx-version-min=10.7" + OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -isysroot $(xcodebuild -version -sdk macosx Path) -mmacosx-version-min=10.7" OSLDFLAGS="-lpthread -fPIC -fpie -mmacosx-version-min=10.7" SRCS=" $SRCS -- cgit v1.2.1 From 671ef704cfa72856adc7c9a3686a21cb3c1c00ab Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 7 Jul 2017 22:40:13 +0000 Subject: Make sure SANITIZER_MIN_OSX_VERSION is defined before using it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307448 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 315223358..3195de1e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,7 @@ pythonize_bool(COMPILER_RT_DEBUG) include(config-ix) -if(APPLE AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") +if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") # Mac OS X prior to 10.9 had problems with exporting symbols from # libc++/libc++abi. set(use_cxxabi_default OFF) -- cgit v1.2.1 From 199c0c91df22a7d749f6910b795d427f84994b42 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:00:55 +0000 Subject: [tsan] Add support for running TSan tests on iOS simulator and devices Differential Revision: https://reviews.llvm.org/D35157 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307537 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 1 + test/sanitizer_common/ios_commands/iossim_run.py | 5 +-- test/tsan/CMakeLists.txt | 45 ++++++++++++++++++++++++ test/tsan/Darwin/dlopen.cc | 2 ++ test/tsan/Darwin/osspinlock-norace.cc | 5 ++- test/tsan/Darwin/xpc-cancel.mm | 2 +- test/tsan/Darwin/xpc-race.mm | 2 +- test/tsan/Darwin/xpc.mm | 2 +- test/tsan/deep_stack1.cc | 9 ++++- test/tsan/ignore_lib0.cc | 2 ++ test/tsan/lit.cfg | 2 +- test/tsan/lit.site.cfg.in | 3 ++ 12 files changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a5ffc6835..5118ae5dd 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -76,6 +76,7 @@ static const char kStdSuppressions[] = #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. + "leak:*_os_trace*\n" "leak:*tls_get_addr*\n"; void InitializeSuppressions() { diff --git a/test/sanitizer_common/ios_commands/iossim_run.py b/test/sanitizer_common/ios_commands/iossim_run.py index 732880f35..47b847f53 100755 --- a/test/sanitizer_common/ios_commands/iossim_run.py +++ b/test/sanitizer_common/ios_commands/iossim_run.py @@ -8,8 +8,9 @@ if not "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" in os.environ: device_id = os.environ["SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER"] -if "ASAN_OPTIONS" in os.environ: - os.environ["SIMCTL_CHILD_ASAN_OPTIONS"] = os.environ["ASAN_OPTIONS"] +for e in ["ASAN_OPTIONS", "TSAN_OPTIONS"]: + if e in os.environ: + os.environ["SIMCTL_CHILD_" + e] = os.environ[e] exitcode = subprocess.call(["xcrun", "simctl", "spawn", device_id] + sys.argv[1:]) if exitcode > 125: diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index 2db6ce0a8..37b309d64 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -1,3 +1,5 @@ +set(TSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "x86_64") list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck) @@ -22,6 +24,11 @@ if(APPLE) endif() foreach(arch ${TSAN_TEST_ARCH}) + set(TSAN_TEST_IOS "0") + pythonize_bool(TSAN_TEST_IOS) + set(TSAN_TEST_IOSSIM "0") + pythonize_bool(TSAN_TEST_IOSSIM) + set(TSAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" TSAN_TEST_CONFIG_SUFFIX) get_test_cc_for_arch(${arch} TSAN_TEST_TARGET_CC TSAN_TEST_TARGET_CFLAGS) @@ -35,6 +42,44 @@ foreach(arch ${TSAN_TEST_ARCH}) list(APPEND TSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) endforeach() +# iOS and iOS simulator test suites +# These are not added into "check-all", in order to run these tests, you have to +# manually call (from the build directory). They also require that an extra env +# variable to select which iOS device or simulator to use, e.g.: +# $ SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER=BBE44C1C-8AAA-4000-8D06-91C89ED58172 +# $ ./bin/llvm-lit ./projects/compiler-rt/test/tsan/IOSSimX86_64Config +if(APPLE) + set(TSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) + set(TSAN_TEST_IOS "1") + pythonize_bool(TSAN_TEST_IOS) + + set(arch "x86_64") + set(TSAN_TEST_IOSSIM "1") + pythonize_bool(TSAN_TEST_IOSSIM) + set(TSAN_TEST_TARGET_ARCH ${arch}) + set(TSAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_iossim_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") + set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-iossim") + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME "IOSSim${ARCH_UPPER_CASE}Config") + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg + ) + + set(arch "arm64") + set(TSAN_TEST_IOSSIM "0") + pythonize_bool(TSAN_TEST_IOSSIM) + set(TSAN_TEST_TARGET_ARCH ${arch}) + set(TSAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}") + set(TSAN_TEST_CONFIG_SUFFIX "-${arch}-ios") + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config") + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg + ) +endif() + if(COMPILER_RT_INCLUDE_TESTS) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in diff --git a/test/tsan/Darwin/dlopen.cc b/test/tsan/Darwin/dlopen.cc index 7382a6de2..3d12b815f 100644 --- a/test/tsan/Darwin/dlopen.cc +++ b/test/tsan/Darwin/dlopen.cc @@ -4,6 +4,8 @@ // REQUIRES: osx-autointerception +// XFAIL: ios + // RUN: %clangxx_tsan %s -o %t.so -shared -DSHARED_LIB // RUN: %clangxx_tsan -fno-sanitize=thread %s -o %t diff --git a/test/tsan/Darwin/osspinlock-norace.cc b/test/tsan/Darwin/osspinlock-norace.cc index 2ac3989c2..837da3b17 100644 --- a/test/tsan/Darwin/osspinlock-norace.cc +++ b/test/tsan/Darwin/osspinlock-norace.cc @@ -1,8 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include #include #include +typedef int32_t OSSpinLock; +extern "C" void OSSpinLockLock(OSSpinLock *); +extern "C" void OSSpinLockUnlock(OSSpinLock *); + int Global; OSSpinLock lock; diff --git a/test/tsan/Darwin/xpc-cancel.mm b/test/tsan/Darwin/xpc-cancel.mm index 91dafc3ea..ac7aed08c 100644 --- a/test/tsan/Darwin/xpc-cancel.mm +++ b/test/tsan/Darwin/xpc-cancel.mm @@ -1,7 +1,7 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %run %t 2>&1 | FileCheck %s -// XFAIL: ios +// UNSUPPORTED: ios #import #import diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm index 2e965e4a0..a1e214c12 100644 --- a/test/tsan/Darwin/xpc-race.mm +++ b/test/tsan/Darwin/xpc-race.mm @@ -1,7 +1,7 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %deflake %run %t 2>&1 | FileCheck %s -// XFAIL: ios +// UNSUPPORTED: ios #import #import diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm index c5e78a577..036841ed7 100644 --- a/test/tsan/Darwin/xpc.mm +++ b/test/tsan/Darwin/xpc.mm @@ -1,7 +1,7 @@ // RUN: %clang_tsan %s -o %t -framework Foundation // RUN: %run %t 2>&1 | FileCheck %s -// XFAIL: ios +// UNSUPPORTED: ios #import #import diff --git a/test/tsan/deep_stack1.cc b/test/tsan/deep_stack1.cc index 39185efee..e56408322 100644 --- a/test/tsan/deep_stack1.cc +++ b/test/tsan/deep_stack1.cc @@ -24,6 +24,10 @@ void *Thread(void *p) { return 0; } +static size_t RoundUp(size_t n, size_t to) { + return ((n + to - 1) / to) * to; +} + int main() { barrier_init(&barrier, 2); N = 50000; @@ -31,7 +35,10 @@ int main() { pthread_t t; pthread_attr_t a; pthread_attr_init(&a); - pthread_attr_setstacksize(&a, N * 256 + (1 << 20)); + size_t stack_size = N * 256 + (1 << 20); + stack_size = RoundUp(stack_size, 0x10000); // round the stack size to 64k + int ret = pthread_attr_setstacksize(&a, stack_size); + if (ret) abort(); pthread_create(&t, &a, Thread, 0); #ifdef ORDER2 barrier_wait(&barrier); diff --git a/test/tsan/ignore_lib0.cc b/test/tsan/ignore_lib0.cc index d6ae72f31..84632019f 100644 --- a/test/tsan/ignore_lib0.cc +++ b/test/tsan/ignore_lib0.cc @@ -11,6 +11,8 @@ // Some aarch64 kernels do not support non executable write pages // REQUIRES: stable-runtime +// UNSUPPORTED: ios + #ifndef LIB extern "C" void libfunc(); diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index 3c98d1fdc..0ab62db09 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -66,7 +66,7 @@ if config.has_libcxx and config.host_os != 'Darwin': "-Wl,-rpath=%s" % libcxx_libdir] def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " config.substitutions.append( ("%clang_tsan ", build_invocation(clang_tsan_cflags)) ) config.substitutions.append( ("%clangxx_tsan ", build_invocation(clang_tsan_cxxflags)) ) diff --git a/test/tsan/lit.site.cfg.in b/test/tsan/lit.site.cfg.in index a87e8d25d..a215e664a 100644 --- a/test/tsan/lit.site.cfg.in +++ b/test/tsan/lit.site.cfg.in @@ -1,7 +1,10 @@ @LIT_SITE_CFG_IN_HEADER@ config.name_suffix = "@TSAN_TEST_CONFIG_SUFFIX@" +config.tsan_lit_source_dir = "@TSAN_LIT_SOURCE_DIR@" config.has_libcxx = @TSAN_HAS_LIBCXX@ +config.ios = @TSAN_TEST_IOS_PYBOOL@ +config.iossim = @TSAN_TEST_IOSSIM_PYBOOL@ config.target_cflags = "@TSAN_TEST_TARGET_CFLAGS@" config.target_arch = "@TSAN_TEST_TARGET_ARCH@" -- cgit v1.2.1 From da8e133600b768cbd12f356c1bca9a1ab17d439c Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:19:14 +0000 Subject: Fixup whitespace. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307538 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/deep_stack1.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tsan/deep_stack1.cc b/test/tsan/deep_stack1.cc index e56408322..44dd0c443 100644 --- a/test/tsan/deep_stack1.cc +++ b/test/tsan/deep_stack1.cc @@ -26,7 +26,7 @@ void *Thread(void *p) { static size_t RoundUp(size_t n, size_t to) { return ((n + to - 1) / to) * to; -} +} int main() { barrier_init(&barrier, 2); -- cgit v1.2.1 From 9a72e30d6a3c9a227c3ee01699056bfab87ac713 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:20:50 +0000 Subject: Reverting an accidentally landed change. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307539 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 5118ae5dd..a5ffc6835 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -76,7 +76,6 @@ static const char kStdSuppressions[] = #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*_os_trace*\n" "leak:*tls_get_addr*\n"; void InitializeSuppressions() { -- cgit v1.2.1 From 7b20e2670faf41e2b94d9b8481b865e7068bf712 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:24:48 +0000 Subject: [tsan] Add a max VM address check for Darwin/AArch64 Differential Revision: https://reviews.llvm.org/D35154 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307540 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform_mac.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index a82bcd01b..e1ae0c02b 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -230,6 +230,14 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread, #endif void InitializePlatformEarly() { +#if defined(__aarch64__) + uptr max_vm = GetMaxVirtualAddress() + 1; + if (max_vm != kHiAppMemEnd) { + Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n", + max_vm, kHiAppMemEnd); + Die(); + } +#endif } void InitializePlatform() { -- cgit v1.2.1 From 56ead522739462f8f7fe936eea9a0efadcb5789c Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:28:16 +0000 Subject: [tsan] Port setjmp/longjmp assembly to Darwin/AArch64 This patch ports the assembly file implementing TSan's setjmp support to AArch64 on Darwin. Differential Revision: https://reviews.llvm.org/D35143 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307541 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/CMakeLists.txt | 2 +- lib/tsan/rtl/tsan_interceptors.cc | 8 ++- lib/tsan/rtl/tsan_rtl_aarch64.S | 127 +++++++++++++++++++++++++++++++------- lib/tsan/rtl/tsan_rtl_amd64.S | 6 ++ 4 files changed, 117 insertions(+), 26 deletions(-) diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 195ecb5df..193158c54 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -100,7 +100,7 @@ set(TSAN_RUNTIME_LIBRARIES) add_compiler_rt_component(tsan) if(APPLE) - set(TSAN_ASM_SOURCES rtl/tsan_rtl_amd64.S) + set(TSAN_ASM_SOURCES rtl/tsan_rtl_amd64.S rtl/tsan_rtl_aarch64.S) # Xcode will try to compile this file as C ('clang -x c'), and that will fail. if (${CMAKE_GENERATOR} STREQUAL "Xcode") enable_language(ASM) diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 5ae02f3b4..f6acb9f9b 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -459,8 +459,14 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { static void LongJmp(ThreadState *thr, uptr *env) { #ifdef __powerpc__ uptr mangled_sp = env[0]; -#elif SANITIZER_FREEBSD || SANITIZER_MAC +#elif SANITIZER_FREEBSD uptr mangled_sp = env[2]; +#elif SANITIZER_MAC +# ifdef __aarch64__ + uptr mangled_sp = env[13]; +# else + uptr mangled_sp = env[2]; +# endif #elif defined(SANITIZER_LINUX) # ifdef __aarch64__ uptr mangled_sp = env[13]; diff --git a/lib/tsan/rtl/tsan_rtl_aarch64.S b/lib/tsan/rtl/tsan_rtl_aarch64.S index ef06f0444..37de84f95 100644 --- a/lib/tsan/rtl/tsan_rtl_aarch64.S +++ b/lib/tsan/rtl/tsan_rtl_aarch64.S @@ -1,13 +1,46 @@ +// The content of this file is AArch64-only: +#if defined(__aarch64__) + #include "sanitizer_common/sanitizer_asm.h" +#if !defined(__APPLE__) .section .bss .type __tsan_pointer_chk_guard, %object -.size __tsan_pointer_chk_guard, 8 +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__tsan_pointer_chk_guard)) __tsan_pointer_chk_guard: .zero 8 +#endif + +#if defined(__APPLE__) +.align 2 + +.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers +.long _setjmp$non_lazy_ptr +_setjmp$non_lazy_ptr: +.indirect_symbol _setjmp +.long 0 + +.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers +.long __setjmp$non_lazy_ptr +__setjmp$non_lazy_ptr: +.indirect_symbol __setjmp +.long 0 + +.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers +.long _sigsetjmp$non_lazy_ptr +_sigsetjmp$non_lazy_ptr: +.indirect_symbol _sigsetjmp +.long 0 +#endif +#if !defined(__APPLE__) .section .text +#else +.section __TEXT,__text +.align 3 +#endif +#if !defined(__APPLE__) // GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp // functions) by XORing them with a random guard pointer. For AArch64 it is a // global variable rather than a TCB one (as for x86_64/powerpc) and althought @@ -16,9 +49,9 @@ __tsan_pointer_chk_guard: // not stable). So InitializeGuardPtr obtains the pointer guard value by // issuing a setjmp and checking the resulting pointers values against the // original ones. -.hidden _Z18InitializeGuardPtrv +ASM_HIDDEN(_Z18InitializeGuardPtrv) .global _Z18InitializeGuardPtrv -.type _Z18InitializeGuardPtrv, @function +.ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) _Z18InitializeGuardPtrv: CFI_STARTPROC // Allocates a jmp_buf for the setjmp call. @@ -55,12 +88,14 @@ _Z18InitializeGuardPtrv: CFI_DEF_CFA (31, 0) ret CFI_ENDPROC -.size _Z18InitializeGuardPtrv, .-_Z18InitializeGuardPtrv +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) +#endif -.hidden __tsan_setjmp +ASM_HIDDEN(__tsan_setjmp) .comm _ZN14__interception11real_setjmpE,8,8 -.type setjmp, @function -setjmp: +.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp) +ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) +ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): CFI_STARTPROC // save env parameters for function call @@ -78,14 +113,19 @@ setjmp: CFI_OFFSET (19, -16) mov x19, x0 +#if !defined(__APPLE__) // SP pointer mangling (see glibc setjmp) adrp x2, __tsan_pointer_chk_guard ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard] add x0, x29, 32 eor x1, x2, x0 +#else + add x0, x29, 32 + mov x1, x0 +#endif // call tsan interceptor - bl __tsan_setjmp + bl ASM_TSAN_SYMBOL(__tsan_setjmp) // restore env parameter mov x0, x19 @@ -96,18 +136,24 @@ setjmp: CFI_DEF_CFA (31, 0) // tail jump to libc setjmp +#if !defined(__APPLE__) adrp x1, :got:_ZN14__interception11real_setjmpE ldr x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE] ldr x1, [x1] +#else + adrp x1, _setjmp$non_lazy_ptr@page + add x1, x1, _setjmp$non_lazy_ptr@pageoff + ldr x1, [x1] +#endif br x1 CFI_ENDPROC -.size setjmp, .-setjmp +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) .comm _ZN14__interception12real__setjmpE,8,8 -.globl _setjmp -.type _setjmp, @function -_setjmp: +.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp) +ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): CFI_STARTPROC // save env parameters for function call @@ -125,14 +171,19 @@ _setjmp: CFI_OFFSET (19, -16) mov x19, x0 +#if !defined(__APPLE__) // SP pointer mangling (see glibc setjmp) adrp x2, __tsan_pointer_chk_guard ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard] add x0, x29, 32 eor x1, x2, x0 +#else + add x0, x29, 32 + mov x1, x0 +#endif // call tsan interceptor - bl __tsan_setjmp + bl ASM_TSAN_SYMBOL(__tsan_setjmp) // Restore jmp_buf parameter mov x0, x19 @@ -143,18 +194,24 @@ _setjmp: CFI_DEF_CFA (31, 0) // tail jump to libc setjmp +#if !defined(__APPLE__) adrp x1, :got:_ZN14__interception12real__setjmpE ldr x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE] ldr x1, [x1] +#else + adrp x1, __setjmp$non_lazy_ptr@page + add x1, x1, __setjmp$non_lazy_ptr@pageoff + ldr x1, [x1] +#endif br x1 CFI_ENDPROC -.size _setjmp, .-_setjmp +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) .comm _ZN14__interception14real_sigsetjmpE,8,8 -.globl sigsetjmp -.type sigsetjmp, @function -sigsetjmp: +.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp) +ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): CFI_STARTPROC // save env parameters for function call @@ -174,14 +231,19 @@ sigsetjmp: mov w20, w1 mov x19, x0 +#if !defined(__APPLE__) // SP pointer mangling (see glibc setjmp) adrp x2, __tsan_pointer_chk_guard ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard] add x0, x29, 32 eor x1, x2, x0 +#else + add x0, x29, 32 + mov x1, x0 +#endif // call tsan interceptor - bl __tsan_setjmp + bl ASM_TSAN_SYMBOL(__tsan_setjmp) // restore env parameter mov w1, w20 @@ -195,17 +257,24 @@ sigsetjmp: CFI_DEF_CFA (31, 0) // tail jump to libc sigsetjmp +#if !defined(__APPLE__) adrp x2, :got:_ZN14__interception14real_sigsetjmpE ldr x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE] ldr x2, [x2] +#else + adrp x2, _sigsetjmp$non_lazy_ptr@page + add x2, x2, _sigsetjmp$non_lazy_ptr@pageoff + ldr x2, [x2] +#endif br x2 CFI_ENDPROC -.size sigsetjmp, .-sigsetjmp +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) +#if !defined(__APPLE__) .comm _ZN14__interception16real___sigsetjmpE,8,8 -.globl __sigsetjmp -.type __sigsetjmp, @function -__sigsetjmp: +.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp) +ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): CFI_STARTPROC // save env parameters for function call @@ -225,14 +294,16 @@ __sigsetjmp: mov w20, w1 mov x19, x0 +#if !defined(__APPLE__) // SP pointer mangling (see glibc setjmp) adrp x2, __tsan_pointer_chk_guard ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard] add x0, x29, 32 eor x1, x2, x0 +#endif // call tsan interceptor - bl __tsan_setjmp + bl ASM_TSAN_SYMBOL(__tsan_setjmp) mov w1, w20 mov x0, x19 @@ -245,14 +316,22 @@ __sigsetjmp: CFI_DEF_CFA (31, 0) // tail jump to libc __sigsetjmp +#if !defined(__APPLE__) adrp x2, :got:_ZN14__interception16real___sigsetjmpE ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE] ldr x2, [x2] +#else + adrp x2, ASM_TSAN_SYMBOL(__sigsetjmp)@page + add x2, x2, ASM_TSAN_SYMBOL(__sigsetjmp)@pageoff +#endif br x2 CFI_ENDPROC -.size __sigsetjmp, .-__sigsetjmp +ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) +#endif #if defined(__linux__) /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif + +#endif diff --git a/lib/tsan/rtl/tsan_rtl_amd64.S b/lib/tsan/rtl/tsan_rtl_amd64.S index caa832375..98947fd2a 100644 --- a/lib/tsan/rtl/tsan_rtl_amd64.S +++ b/lib/tsan/rtl/tsan_rtl_amd64.S @@ -1,4 +1,8 @@ +// The content of this file is x86_64-only: +#if defined(__x86_64__) + #include "sanitizer_common/sanitizer_asm.h" + #if !defined(__APPLE__) .section .text #else @@ -357,3 +361,5 @@ ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif + +#endif -- cgit v1.2.1 From 7a63eabdf0081731324d26290c21c3e99c3b0097 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:35:04 +0000 Subject: [tsan] Add a mapping for Darwin/AArch64 This patch defines the TSan memory map and offsets for Darwin on AArch64. Differential Revision: https://reviews.llvm.org/D35147 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307544 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform.h | 49 ++++++++++++++++++++++++++++++------- lib/tsan/rtl/tsan_platform_posix.cc | 9 +++++++ lib/tsan/tests/CMakeLists.txt | 1 + 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index 60d9b9d8c..bea1daba3 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -100,6 +100,37 @@ struct Mapping { }; #define TSAN_MID_APP_RANGE 1 +#elif defined(__aarch64__) && defined(__APPLE__) +/* +C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM) +0000 0000 00 - 0100 0000 00: - (4 GB) +0100 0000 00 - 0200 0000 00: main binary, modules, thread stacks (4 GB) +0200 0000 00 - 0300 0000 00: heap (4 GB) +0300 0000 00 - 0400 0000 00: - (4 GB) +0400 0000 00 - 0c00 0000 00: shadow memory (32 GB) +0c00 0000 00 - 0d00 0000 00: - (4 GB) +0d00 0000 00 - 0e00 0000 00: metainfo (4 GB) +0e00 0000 00 - 0f00 0000 00: - (4 GB) +0f00 0000 00 - 1000 0000 00: traces (4 GB) +*/ +struct Mapping { + static const uptr kLoAppMemBeg = 0x0100000000ull; + static const uptr kLoAppMemEnd = 0x0200000000ull; + static const uptr kHeapMemBeg = 0x0200000000ull; + static const uptr kHeapMemEnd = 0x0300000000ull; + static const uptr kShadowBeg = 0x0400000000ull; + static const uptr kShadowEnd = 0x0c00000000ull; + static const uptr kMetaShadowBeg = 0x0d00000000ull; + static const uptr kMetaShadowEnd = 0x0e00000000ull; + static const uptr kTraceMemBeg = 0x0f00000000ull; + static const uptr kTraceMemEnd = 0x1000000000ull; + static const uptr kHiAppMemBeg = 0x1000000000ull; + static const uptr kHiAppMemEnd = 0x1000000000ull; + static const uptr kAppMemMsk = 0x0ull; + static const uptr kAppMemXor = 0x0ull; + static const uptr kVdsoBeg = 0x7000000000000000ull; +}; + #elif defined(__aarch64__) // AArch64 supports multiple VMA which leads to multiple address transformation // functions. To support these multiple VMAS transformations and mappings TSAN @@ -389,7 +420,7 @@ uptr MappingImpl(void) { template uptr MappingArchImpl(void) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return MappingImpl(); case 42: return MappingImpl(); @@ -542,7 +573,7 @@ bool IsAppMemImpl(uptr mem) { ALWAYS_INLINE bool IsAppMem(uptr mem) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return IsAppMemImpl(mem); case 42: return IsAppMemImpl(mem); @@ -569,7 +600,7 @@ bool IsShadowMemImpl(uptr mem) { ALWAYS_INLINE bool IsShadowMem(uptr mem) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return IsShadowMemImpl(mem); case 42: return IsShadowMemImpl(mem); @@ -596,7 +627,7 @@ bool IsMetaMemImpl(uptr mem) { ALWAYS_INLINE bool IsMetaMem(uptr mem) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return IsMetaMemImpl(mem); case 42: return IsMetaMemImpl(mem); @@ -633,7 +664,7 @@ uptr MemToShadowImpl(uptr x) { ALWAYS_INLINE uptr MemToShadow(uptr x) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return MemToShadowImpl(x); case 42: return MemToShadowImpl(x); @@ -672,7 +703,7 @@ u32 *MemToMetaImpl(uptr x) { ALWAYS_INLINE u32 *MemToMeta(uptr x) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return MemToMetaImpl(x); case 42: return MemToMetaImpl(x); @@ -724,7 +755,7 @@ uptr ShadowToMemImpl(uptr s) { ALWAYS_INLINE uptr ShadowToMem(uptr s) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return ShadowToMemImpl(s); case 42: return ShadowToMemImpl(s); @@ -759,7 +790,7 @@ uptr GetThreadTraceImpl(int tid) { ALWAYS_INLINE uptr GetThreadTrace(int tid) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return GetThreadTraceImpl(tid); case 42: return GetThreadTraceImpl(tid); @@ -789,7 +820,7 @@ uptr GetThreadTraceHeaderImpl(int tid) { ALWAYS_INLINE uptr GetThreadTraceHeader(int tid) { -#ifdef __aarch64__ +#if defined(__aarch64__) && !defined(__APPLE__) switch (vmaSize) { case 39: return GetThreadTraceHeaderImpl(tid); case 42: return GetThreadTraceHeaderImpl(tid); diff --git a/lib/tsan/rtl/tsan_platform_posix.cc b/lib/tsan/rtl/tsan_platform_posix.cc index 0732c83d6..e89d955fe 100644 --- a/lib/tsan/rtl/tsan_platform_posix.cc +++ b/lib/tsan/rtl/tsan_platform_posix.cc @@ -46,6 +46,9 @@ void InitializeShadowMemory() { #elif defined(__mips64) const uptr kMadviseRangeBeg = 0xff00000000ull; const uptr kMadviseRangeSize = 0x0100000000ull; +#elif defined(__aarch64__) && defined(__APPLE__) + uptr kMadviseRangeBeg = LoAppMemBeg(); + uptr kMadviseRangeSize = LoAppMemEnd() - LoAppMemBeg(); #elif defined(__aarch64__) uptr kMadviseRangeBeg = 0; uptr kMadviseRangeSize = 0; @@ -130,6 +133,11 @@ void CheckAndProtect() { Die(); } +#if defined(__aarch64__) && defined(__APPLE__) + ProtectRange(HeapMemEnd(), ShadowBeg()); + ProtectRange(ShadowEnd(), MetaShadowBeg()); + ProtectRange(MetaShadowEnd(), TraceMemBeg()); +#else ProtectRange(LoAppMemEnd(), ShadowBeg()); ProtectRange(ShadowEnd(), MetaShadowBeg()); #ifdef TSAN_MID_APP_RANGE @@ -143,6 +151,7 @@ void CheckAndProtect() { ProtectRange(TraceMemBeg(), TraceMemEnd()); ProtectRange(TraceMemEnd(), HeapMemBeg()); ProtectRange(HeapEnd(), HiAppMemBeg()); +#endif } #endif diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index ca43a928d..f8aec6854 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -15,6 +15,7 @@ set(TSAN_UNITTEST_CFLAGS if(APPLE) list(APPEND TSAN_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS}) + list(APPEND TSAN_UNITTEST_LINKFLAGS ${DARWIN_osx_LINKFLAGS}) endif() set(TSAN_RTL_HEADERS) -- cgit v1.2.1 From 2f2503a26772e90eaa89d4b71a7011b6660d6cdc Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:37:13 +0000 Subject: [tsan] Add comments for the bool argument of ThreadIgnoreBegin/ThreadIgnoreSyncBegin, NFC. Differential Revision: https://reviews.llvm.org/D35134 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307545 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 2 +- lib/tsan/rtl/tsan_interface_ann.cc | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index f6acb9f9b..001123f49 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -261,7 +261,7 @@ ScopedInterceptor::~ScopedInterceptor() { void ScopedInterceptor::EnableIgnores() { if (ignoring_) { - ThreadIgnoreBegin(thr_, pc_, false); + ThreadIgnoreBegin(thr_, pc_, /*save_stack=*/false); if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; if (in_ignored_lib_) { DCHECK(!thr_->in_ignored_lib); diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc index 45ec45bbd..f68a0468d 100644 --- a/lib/tsan/rtl/tsan_interface_ann.cc +++ b/lib/tsan/rtl/tsan_interface_ann.cc @@ -483,8 +483,8 @@ void __tsan_mutex_pre_lock(void *m, unsigned flagz) { else MutexPreLock(thr, pc, (uptr)m); } - ThreadIgnoreBegin(thr, pc, false); - ThreadIgnoreSyncBegin(thr, pc, false); + ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); + ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); } INTERFACE_ATTRIBUTE @@ -510,8 +510,8 @@ int __tsan_mutex_pre_unlock(void *m, unsigned flagz) { } else { ret = MutexUnlock(thr, pc, (uptr)m, flagz); } - ThreadIgnoreBegin(thr, pc, false); - ThreadIgnoreSyncBegin(thr, pc, false); + ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); + ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); return ret; } @@ -525,8 +525,8 @@ void __tsan_mutex_post_unlock(void *m, unsigned flagz) { INTERFACE_ATTRIBUTE void __tsan_mutex_pre_signal(void *addr, unsigned flagz) { SCOPED_ANNOTATION(__tsan_mutex_pre_signal); - ThreadIgnoreBegin(thr, pc, false); - ThreadIgnoreSyncBegin(thr, pc, false); + ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); + ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); } INTERFACE_ATTRIBUTE @@ -547,7 +547,7 @@ void __tsan_mutex_pre_divert(void *addr, unsigned flagz) { INTERFACE_ATTRIBUTE void __tsan_mutex_post_divert(void *addr, unsigned flagz) { SCOPED_ANNOTATION(__tsan_mutex_post_divert); - ThreadIgnoreBegin(thr, pc, false); - ThreadIgnoreSyncBegin(thr, pc, false); + ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); + ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); } } // extern "C" -- cgit v1.2.1 From 07c6462c744f9d3247f921430d388c4c23f1c3ad Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:52:30 +0000 Subject: Fix-up for r307540. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307547 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform_mac.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index e1ae0c02b..73a656ffc 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -232,9 +232,9 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread, void InitializePlatformEarly() { #if defined(__aarch64__) uptr max_vm = GetMaxVirtualAddress() + 1; - if (max_vm != kHiAppMemEnd) { + if (max_vm != Mapping::kHiAppMemEnd) { Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n", - max_vm, kHiAppMemEnd); + max_vm, Mapping::kHiAppMemEnd); Die(); } #endif -- cgit v1.2.1 From 6dc96e1bb78d359ac266d6b7632cefea006bda2e Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:55:25 +0000 Subject: [lsan] Add _os_trace into LSan's suppression list Differential Revision: https://reviews.llvm.org/D35173 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307548 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a5ffc6835..7f2bc6379 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -76,7 +76,9 @@ static const char kStdSuppressions[] = #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*tls_get_addr*\n"; + "leak:*tls_get_addr*\n" + // For Darwin and os_log/os_trace. + "leak:*_os_trace*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); -- cgit v1.2.1 From 0973c5bae91bd6fca844603a7af736645f7cbe10 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 15:58:22 +0000 Subject: Fix a build failure due to r307541 (tsan_rtl_aarch64.S:54: Error: unknown pseudo-op: `.'). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307549 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_rtl_aarch64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/rtl/tsan_rtl_aarch64.S b/lib/tsan/rtl/tsan_rtl_aarch64.S index 37de84f95..61171d635 100644 --- a/lib/tsan/rtl/tsan_rtl_aarch64.S +++ b/lib/tsan/rtl/tsan_rtl_aarch64.S @@ -51,7 +51,7 @@ _sigsetjmp$non_lazy_ptr: // original ones. ASM_HIDDEN(_Z18InitializeGuardPtrv) .global _Z18InitializeGuardPtrv -.ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) +ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) _Z18InitializeGuardPtrv: CFI_STARTPROC // Allocates a jmp_buf for the setjmp call. -- cgit v1.2.1 From a4df49d1faa1b93af613901e308b1dc49969f824 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 17:11:52 +0000 Subject: Fix-up for r307537: We need to #include stdint.h to get int32_t. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307557 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/osspinlock-norace.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tsan/Darwin/osspinlock-norace.cc b/test/tsan/Darwin/osspinlock-norace.cc index 837da3b17..5de02c225 100644 --- a/test/tsan/Darwin/osspinlock-norace.cc +++ b/test/tsan/Darwin/osspinlock-norace.cc @@ -1,5 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s #include +#include #include typedef int32_t OSSpinLock; -- cgit v1.2.1 From 78dfe1f88796a7c9daf9742baa0f10661452281d Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 10 Jul 2017 17:30:20 +0000 Subject: [X86] Resync cpu_model.c with llvm's Host.cpp in preparation for making it compatible with newer gcc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307558 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 89 ++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 5ff6baf43..0793dea04 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -67,6 +67,7 @@ enum ProcessorTypes { AMDATHLON, AMDFAM14H, AMDFAM16H, + AMDFAM17H, CPU_TYPE_MAX }; @@ -105,6 +106,7 @@ enum ProcessorSubtypes { AMD_BTVER2, AMDFAM15H_BDVER3, AMDFAM15H_BDVER4, + AMDFAM17H_ZNVER1, CPU_SUBTYPE_MAX }; @@ -164,11 +166,12 @@ static bool isCpuIdSupported() { /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in /// the specified arguments. If we can't run cpuid on the host, return true. -static void getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, +static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) #if defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. __asm__("movq\t%%rbx, %%rsi\n\t" "cpuid\n\t" "xchgq\t%%rbx, %%rsi\n\t" @@ -193,17 +196,20 @@ static void getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; +#endif + return false; #else - assert(0 && "This method is defined only for GNUC, Clang or MSVC."); + return true; #endif } /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return /// the 4 values in the specified arguments. If we can't run cpuid on the host, /// return true. -static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, +static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) #if defined(__x86_64__) || defined(_M_X64) #if defined(__GNUC__) || defined(__clang__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. @@ -220,8 +226,6 @@ static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; -#else - assert(0 && "This method is defined only for GNUC, Clang or MSVC."); #endif #elif defined(__i386__) || defined(_M_IX86) #if defined(__GNUC__) || defined(__clang__) @@ -244,11 +248,13 @@ static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, mov esi,rEDX mov dword ptr [esi],edx } -#else - assert(0 && "This method is defined only for GNUC, Clang or MSVC."); #endif #else assert(0 && "This method is defined only for x86."); +#endif + return false; +#else + return true; #endif } @@ -283,10 +289,10 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family, } } -static void getIntelProcessorTypeAndSubtype(unsigned int Family, - unsigned int Model, - unsigned int Brand_id, - unsigned int Features, +static void getIntelProcessorTypeAndSubtype(unsigned Family, + unsigned Model, + unsigned Brand_id, + unsigned Features, unsigned *Type, unsigned *Subtype) { if (Brand_id != 0) return; @@ -427,15 +433,20 @@ static void getIntelProcessorTypeAndSubtype(unsigned int Family, break; // Skylake: - case 0x4e: - *Type = INTEL_COREI7; // "skylake-avx512" - *Subtype = INTEL_COREI7_SKYLAKE_AVX512; - break; - case 0x5e: + case 0x4e: // Skylake mobile + case 0x5e: // Skylake desktop + case 0x8e: // Kaby Lake mobile + case 0x9e: // Kaby Lake desktop *Type = INTEL_COREI7; // "skylake" *Subtype = INTEL_COREI7_SKYLAKE; break; + // Skylake Xeon: + case 0x55: + *Type = INTEL_COREI7; // "skylake" + *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" + break; + case 0x1c: // Most 45 nm Intel Atom processors case 0x26: // 45 nm Atom Lincroft case 0x27: // 32 nm Atom Medfield @@ -567,9 +578,8 @@ static void getIntelProcessorTypeAndSubtype(unsigned int Family, } } -static void getAMDProcessorTypeAndSubtype(unsigned int Family, - unsigned int Model, - unsigned int Features, unsigned *Type, +static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, + unsigned Features, unsigned *Type, unsigned *Subtype) { // FIXME: this poorly matches the generated SubtargetFeatureKV table. There // appears to be no way to generate the wide variety of AMD-specific targets @@ -683,15 +693,23 @@ static void getAMDProcessorTypeAndSubtype(unsigned int Family, } *Subtype = AMD_BTVER2; break; // "btver2" + case 23: + *Type = AMDFAM17H; + if (Features & (1 << FEATURE_ADX)) { + *Subtype = AMDFAM17H_ZNVER1; + break; // "znver1" + } + *Subtype = AMD_BTVER1; + break; default: break; // "generic" } } -static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, +static unsigned getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf) { unsigned Features = 0; - unsigned int EAX, EBX; + unsigned EAX, EBX; Features |= (((EDX >> 23) & 1) << FEATURE_MMX); Features |= (((EDX >> 25) & 1) << FEATURE_SSE); Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); @@ -708,8 +726,7 @@ static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); - bool HasLeaf7 = MaxLeaf >= 0x7; - getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); @@ -719,8 +736,14 @@ static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, Features |= (HasAVX512Save << FEATURE_AVX512SAVE); Features |= (HasADX << FEATURE_ADX); - getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); + unsigned MaxExtLevel; + getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + + bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && + !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + if (HasExtLeaf1) + Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); + return Features; } @@ -751,11 +774,11 @@ struct __processor_model { int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { - unsigned int EAX, EBX, ECX, EDX; - unsigned int MaxLeaf = 5; - unsigned int Vendor; - unsigned int Model, Family, Brand_id; - unsigned int Features = 0; + unsigned EAX, EBX, ECX, EDX; + unsigned MaxLeaf = 5; + unsigned Vendor; + unsigned Model, Family, Brand_id; + unsigned Features = 0; /* This function needs to run just once. */ if (__cpu_model.__cpu_vendor) @@ -765,9 +788,7 @@ __cpu_indicator_init(void) { return -1; /* Assume cpuid insn present. Run in level 0 to get vendor id. */ - getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX); - - if (MaxLeaf < 1) { + if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { __cpu_model.__cpu_vendor = VENDOR_OTHER; return -1; } -- cgit v1.2.1 From bd3d53bd67d799aa8ba66abf0b305e0d077dba0f Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 10 Jul 2017 17:47:23 +0000 Subject: [X86] Sync a few more things from llvm's Host.cpp to cpu_model. This syncs the cpuid functions and adds breaks to the appropriate spots in the CPU decoding switches. Also a few formatting tweaks. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307561 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 74 +++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 0793dea04..1b03f0f78 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -168,25 +168,25 @@ static bool isCpuIdSupported() { /// the specified arguments. If we can't run cpuid on the host, return true. static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) #if defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. + // FIXME: should we save this for Clang? __asm__("movq\t%%rbx, %%rsi\n\t" "cpuid\n\t" "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); + return false; #elif defined(__i386__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); -// pedantic #else returns to appease -Wunreachable-code (so we don't generate -// postprocessed code that looks like "return true; return false;") + return false; #else - assert(0 && "This method is defined only for x86."); + return true; #endif #elif defined(_MSC_VER) // The MSVC intrinsic is portable across x86 and x64. @@ -196,7 +196,6 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; -#endif return false; #else return true; @@ -209,7 +208,6 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) #if defined(__x86_64__) || defined(_M_X64) #if defined(__GNUC__) || defined(__clang__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. @@ -219,6 +217,7 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); + return false; #elif defined(_MSC_VER) int registers[4]; __cpuidex(registers, value, subleaf); @@ -226,6 +225,9 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; + return false; +#else + return true; #endif #elif defined(__i386__) || defined(_M_IX86) #if defined(__GNUC__) || defined(__clang__) @@ -234,6 +236,7 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); + return false; #elif defined(_MSC_VER) __asm { mov eax,value @@ -248,11 +251,10 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, mov esi,rEDX mov dword ptr [esi],edx } -#endif + return false; #else - assert(0 && "This method is defined only for x86."); + return true; #endif - return false; #else return true; #endif @@ -289,11 +291,10 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family, } } -static void getIntelProcessorTypeAndSubtype(unsigned Family, - unsigned Model, - unsigned Brand_id, - unsigned Features, - unsigned *Type, unsigned *Subtype) { +static void +getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, + unsigned Brand_id, unsigned Features, + unsigned *Type, unsigned *Subtype) { if (Brand_id != 0) return; switch (Family) { @@ -315,6 +316,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, *Type = INTEL_i486; break; } + break; case 5: switch (Model) { case 1: // Pentium OverDrive processor for Pentium processor (60, 66), @@ -336,6 +338,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, *Type = INTEL_PENTIUM; break; } + break; case 6: switch (Model) { case 0x01: // Pentium Pro processor @@ -391,7 +394,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. // As found in a Summer 2010 model iMac. case 0x1f: - case 0x2e: // Nehalem EX + case 0x2e: // Nehalem EX *Type = INTEL_COREI7; // "nehalem" *Subtype = INTEL_COREI7_NEHALEM; break; @@ -409,7 +412,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, *Subtype = INTEL_COREI7_SANDYBRIDGE; break; case 0x3a: - case 0x3e: // Ivy Bridge EP + case 0x3e: // Ivy Bridge EP *Type = INTEL_COREI7; // "ivybridge" *Subtype = INTEL_COREI7_IVYBRIDGE; break; @@ -443,7 +446,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, // Skylake Xeon: case 0x55: - *Type = INTEL_COREI7; // "skylake" + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" break; @@ -537,6 +540,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, *Type = INTEL_PENTIUM_PRO; break; } + break; case 15: { switch (Model) { case 0: // Pentium 4 processor, Intel Xeon processor. All processors are @@ -572,6 +576,7 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); break; } + break; } default: break; /*"generic"*/ @@ -587,6 +592,7 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, switch (Family) { case 4: *Type = AMD_i486; + break; case 5: *Type = AMDPENTIUM; switch (Model) { @@ -604,9 +610,8 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 10: *Subtype = AMDPENTIUM_GEODE; break; // "geode" - default: - break; } + break; case 6: *Type = AMDATHLON; switch (Model) { @@ -621,9 +626,8 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 10: *Subtype = AMDATHLON_XP; break; // "athlon-xp" - default: - break; } + break; case 15: *Type = AMDATHLON; if (Features & (1 << FEATURE_SSE3)) { @@ -641,6 +645,7 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Subtype = AMDATHLON_64; break; // "athlon64" } + break; case 16: *Type = AMDFAM10H; // "amdfam10" switch (Model) { @@ -653,21 +658,15 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 8: *Subtype = AMDFAM10H_ISTANBUL; break; - default: - break; } + break; case 20: *Type = AMDFAM14H; *Subtype = AMD_BTVER1; break; // "btver1"; case 21: *Type = AMDFAM15H; - if (!(Features & - (1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. - *Subtype = AMD_BTVER1; - break; // "btver1" - } - if (Model >= 0x50 && Model <= 0x6f) { + if (Model >= 0x60 && Model <= 0x7f) { *Subtype = AMDFAM15H_BDVER4; break; // "bdver4"; 50h-6Fh: Excavator } @@ -685,21 +684,11 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, } break; case 22: - *Type = AMDFAM16H; - if (!(Features & - (1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. - *Subtype = AMD_BTVER1; - break; // "btver1"; - } - *Subtype = AMD_BTVER2; + *Type = AMD_BTVER2; break; // "btver2" case 23: *Type = AMDFAM17H; - if (Features & (1 << FEATURE_ADX)) { - *Subtype = AMDFAM17H_ZNVER1; - break; // "znver1" - } - *Subtype = AMD_BTVER1; + *Subtype = AMDFAM17H_ZNVER1; break; default: break; // "generic" @@ -726,7 +715,8 @@ static unsigned getAvailableFeatures(unsigned ECX, unsigned EDX, bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); - bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + bool HasLeaf7 = + MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); -- cgit v1.2.1 From b8c00bd80457207a14e53c316ad857fbc8734f30 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jul 2017 18:55:33 +0000 Subject: Add an #if SANITIZER_MAC and a comment to lsan_common's suppression for "_os_trace". git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307567 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 7f2bc6379..db42ead83 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -74,11 +74,13 @@ static const char kStdSuppressions[] = // definition. "leak:*pthread_exit*\n" #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT +#if SANITIZER_MAC + // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 + "leak:*_os_trace*\n" +#endif // TLS leak in some glibc versions, described in // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*tls_get_addr*\n" - // For Darwin and os_log/os_trace. - "leak:*_os_trace*\n"; + "leak:*tls_get_addr*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); -- cgit v1.2.1 From de932deda4e6f1cc75151945bdc9aee206ef4fec Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 10 Jul 2017 20:06:06 +0000 Subject: Do not crash with missing symbolication when running in DEDUP mode Printing stacktrace from ASAN crashes with a segfault in DEDUP mode when symbolication is missing. Differential Revision: https://reviews.llvm.org/D34914 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307577 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc index 36c98d057..747a4a701 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -43,7 +43,8 @@ void StackTrace::Print() const { if (dedup_frames-- > 0) { if (dedup_token.length()) dedup_token.append("--"); - dedup_token.append(cur->info.function); + if (cur->info.function != nullptr) + dedup_token.append(cur->info.function); } } frames->ClearAll(); -- cgit v1.2.1 From 5b62d82e70980e8918f40e692d5bff572dbcad02 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Tue, 11 Jul 2017 13:03:48 +0000 Subject: Remove duplicate assignments in stat64/kernel_stat_to_stat functions Remove duplicate assignments in stat64_to_stat() and kernel_stat_to_stat(). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307657 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index f3994bfd0..c72fa436b 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -217,7 +217,6 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) { out->st_atime = in->st_atime; out->st_mtime = in->st_mtime; out->st_ctime = in->st_ctime; - out->st_ino = in->st_ino; } #endif @@ -237,7 +236,6 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { out->st_atime = in->st_atime_nsec; out->st_mtime = in->st_mtime_nsec; out->st_ctime = in->st_ctime_nsec; - out->st_ino = in->st_ino; } #endif -- cgit v1.2.1 From 093a9f1fc68d3adff00f60983971bd1893907298 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 11 Jul 2017 18:18:50 +0000 Subject: [asan] Fix asan_device_setup --use-su mode on Android 7.x. mount command does not accept -o remount,rw flag on some versions of Android. mount -o rw,remount works everywhere. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307685 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 79ac2f916..5a4f7c47c 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -52,7 +52,7 @@ function adb_remount { local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` if [ "$STORAGE" != "" ]; then echo Remounting $STORAGE at /system - $ADB shell su -c "mount -o remount,rw $STORAGE /system" + $ADB shell su -c "mount -o rw,remount $STORAGE /system" else echo Failed to get storage device name for "/system" mount point fi -- cgit v1.2.1 From 26482612ad1935ba0eff838325b4d254942f2b9d Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 11 Jul 2017 18:54:00 +0000 Subject: Refactor MemoryMappingLayout::Next to use a single struct instead of output parameters. NFC. Summary: This is the first in a series of patches to refactor sanitizer_procmaps to allow MachO section information to be exposed on darwin. In addition, grouping all segment information in a single struct is cleaner than passing it through a large set of output parameters, and avoids the need for annotations of NULL parameters for unneeded information. The filename string is optional and must be managed and supplied by the calling function. This is to allow the MemoryMappedSegment struct to be stored on the stack without causing overly large stack sizes. Reviewers: alekseyshl, kubamracek, glider Subscribers: emaste, llvm-commits Differential Revision: https://reviews.llvm.org/D35135 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307688 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 7 +- lib/asan/asan_linux.cc | 6 +- lib/esan/working_set.cpp | 19 ++--- lib/lsan/lsan_common.cc | 12 ++- lib/lsan/lsan_common.h | 2 +- lib/lsan/lsan_common_mac.cc | 2 +- lib/sanitizer_common/sanitizer_linux.cc | 10 +-- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 19 ++--- lib/sanitizer_common/sanitizer_posix.cc | 35 +++++---- lib/sanitizer_common/sanitizer_procmaps.h | 43 +++++++---- lib/sanitizer_common/sanitizer_procmaps_common.cc | 14 ++-- lib/sanitizer_common/sanitizer_procmaps_freebsd.cc | 33 +++----- lib/sanitizer_common/sanitizer_procmaps_linux.cc | 38 +++------- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 88 ++++++++-------------- lib/tsan/dd/dd_interceptors.cc | 19 +++-- lib/tsan/rtl/tsan_platform_linux.cc | 16 ++-- lib/tsan/rtl/tsan_platform_posix.cc | 18 ++--- 17 files changed, 165 insertions(+), 216 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 57490ad18..b7a38eb7c 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -61,10 +61,9 @@ static void MaybeDumpRegisters(void *context) { static void MaybeReportNonExecRegion(uptr pc) { #if SANITIZER_FREEBSD || SANITIZER_LINUX MemoryMappingLayout proc_maps(/*cache_enabled*/ true); - uptr start, end, protection; - while (proc_maps.Next(&start, &end, nullptr, nullptr, 0, &protection)) { - if (pc >= start && pc < end && - !(protection & MemoryMappingLayout::kProtectionExecute)) + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); } #endif diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 50ef84c39..b546bc1a6 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -140,9 +140,9 @@ void AsanCheckIncompatibleRT() { // system libraries, causing crashes later in ASan initialization. MemoryMappingLayout proc_maps(/*cache_enabled*/true); char filename[128]; - while (proc_maps.Next(nullptr, nullptr, nullptr, filename, - sizeof(filename), nullptr)) { - if (IsDynamicRTName(filename)) { + MemoryMappedSegment segment(filename, sizeof(filename)); + while (proc_maps.Next(&segment)) { + if (IsDynamicRTName(segment.filename)) { Report("Your application is linked against " "incompatible ASan runtimes.\n"); Die(); diff --git a/lib/esan/working_set.cpp b/lib/esan/working_set.cpp index f39111993..e56902c8f 100644 --- a/lib/esan/working_set.cpp +++ b/lib/esan/working_set.cpp @@ -160,15 +160,16 @@ static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, static u32 computeWorkingSizeAndReset(u32 BitIdx) { u32 WorkingSetSize = 0; MemoryMappingLayout MemIter(true/*cache*/); - uptr Start, End, Prot; - while (MemIter.Next(&Start, &End, nullptr/*offs*/, nullptr/*file*/, - 0/*file size*/, &Prot)) { - VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", - __FUNCTION__, Start, End, Prot, isAppMem(Start), - isShadowMem(Start)); - if (isShadowMem(Start) && (Prot & MemoryMappingLayout::kProtectionWrite)) { - VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Start, End); - WorkingSetSize += countAndClearShadowValues(BitIdx, Start, End); + MemoryMappedSegment Segment; + while (MemIter.Next(&Segment)) { + VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", __FUNCTION__, + Segment.start, Segment.end, Segment.protection, + isAppMem(Segment.start), isShadowMem(Segment.start)); + if (isShadowMem(Segment.start) && Segment.IsWritable()) { + VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Segment.start, + Segment.end); + WorkingSetSize += + countAndClearShadowValues(BitIdx, Segment.start, Segment.end); } } return WorkingSetSize; diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index db42ead83..4ffa91568 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -305,11 +305,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, - uptr region_begin, uptr region_end, uptr prot) { + uptr region_begin, uptr region_end, bool is_readable) { uptr intersection_begin = Max(root_region.begin, region_begin); uptr intersection_end = Min(region_end, root_region.begin + root_region.size); if (intersection_begin >= intersection_end) return; - bool is_readable = prot & MemoryMappingLayout::kProtectionRead; LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", root_region.begin, root_region.begin + root_region.size, region_begin, region_end, @@ -322,11 +321,10 @@ void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, static void ProcessRootRegion(Frontier *frontier, const RootRegion &root_region) { MemoryMappingLayout proc_maps(/*cache_enabled*/ true); - uptr begin, end, prot; - while (proc_maps.Next(&begin, &end, - /*offset*/ nullptr, /*filename*/ nullptr, - /*filename_size*/ 0, &prot)) { - ScanRootRegion(frontier, root_region, begin, end, prot); + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + ScanRootRegion(frontier, root_region, segment.start, segment.end, + segment.IsReadable()); } } diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index beb31d6f4..d93ac1b10 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -127,7 +127,7 @@ struct RootRegion { InternalMmapVector const *GetRootRegions(); void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, - uptr region_begin, uptr region_end, uptr prot); + uptr region_begin, uptr region_end, bool is_readable); // Run stoptheworld while holding any platform-specific locks. void DoStopTheWorld(StopTheWorldCallback callback, void* argument); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index adde3a1b4..f87c6b7e0 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -156,7 +156,7 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { if (flags()->use_root_regions) { for (uptr i = 0; i < root_regions->size(); i++) { ScanRootRegion(frontier, (*root_regions)[i], address, end_address, - info.protection); + info.protection & kProtectionRead); } } diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index c72fa436b..4f3845f00 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -830,13 +830,9 @@ static uptr GetKernelAreaSize() { // Firstly check if there are writable segments // mapped to top gigabyte (e.g. stack). MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr end, prot; - while (proc_maps.Next(/*start*/nullptr, &end, - /*offset*/nullptr, /*filename*/nullptr, - /*filename_size*/0, &prot)) { - if ((end >= 3 * gbyte) - && (prot & MemoryMappingLayout::kProtectionWrite) != 0) - return 0; + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; } #if !SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index b9a48a1e4..52196db12 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -81,28 +81,25 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, // Find the mapping that contains a stack variable. MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr start, end, offset; + MemoryMappedSegment segment; uptr prev_end = 0; - while (proc_maps.Next(&start, &end, &offset, nullptr, 0, - /* protection */nullptr)) { - if ((uptr)&rl < end) - break; - prev_end = end; + while (proc_maps.Next(&segment)) { + if ((uptr)&rl < segment.end) break; + prev_end = segment.end; } - CHECK((uptr)&rl >= start && (uptr)&rl < end); + CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end); // Get stacksize from rlimit, but clip it so that it does not overlap // with other mappings. uptr stacksize = rl.rlim_cur; - if (stacksize > end - prev_end) - stacksize = end - prev_end; + if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end; // When running with unlimited stack size, we still want to set some limit. // The unlimited stack size is caused by 'ulimit -s unlimited'. // Also, for some reason, GNU make spawns subprocesses with unlimited stack. if (stacksize > kMaxThreadStackSize) stacksize = kMaxThreadStackSize; - *stack_top = end; - *stack_bottom = end - stacksize; + *stack_top = segment.end; + *stack_bottom = segment.end - stacksize; return; } pthread_attr_t attr; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 4abc9d16d..8d3128ae1 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -231,13 +231,12 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1, // memory). bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr start, end; - while (proc_maps.Next(&start, &end, - /*offset*/nullptr, /*filename*/nullptr, - /*filename_size*/0, /*protection*/nullptr)) { - if (start == end) continue; // Empty range. - CHECK_NE(0, end); - if (!IntervalsAreSeparate(start, end - 1, range_start, range_end)) + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (segment.start == segment.end) continue; // Empty range. + CHECK_NE(0, segment.end); + if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, + range_end)) return false; } return true; @@ -245,13 +244,13 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { void DumpProcessMap() { MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr start, end; const sptr kBufSize = 4095; char *filename = (char*)MmapOrDie(kBufSize, __func__); + MemoryMappedSegment segment(filename, kBufSize); Report("Process memory map follows:\n"); - while (proc_maps.Next(&start, &end, /* file_offset */nullptr, - filename, kBufSize, /* protection */nullptr)) { - Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); + while (proc_maps.Next(&segment)) { + Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, + segment.filename); } Report("End of process memory map.\n"); UnmapOrDie(filename, kBufSize); @@ -281,14 +280,14 @@ void ReportFile::Write(const char *buffer, uptr length) { } bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { - uptr s, e, off, prot; - InternalScopedString buff(kMaxPathLength); MemoryMappingLayout proc_maps(/*cache_enabled*/false); - while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) { - if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 - && internal_strcmp(module, buff.data()) == 0) { - *start = s; - *end = e; + InternalScopedString buff(kMaxPathLength); + MemoryMappedSegment segment(buff.data(), kMaxPathLength); + while (proc_maps.Next(&segment)) { + if (segment.IsExecutable() && + internal_strcmp(module, segment.filename) == 0) { + *start = segment.start; + *end = segment.end; return true; } } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 5aad6b959..a0ac0b919 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -31,13 +31,37 @@ struct ProcSelfMapsBuff { void ReadProcMaps(ProcSelfMapsBuff *proc_maps); #endif // SANITIZER_FREEBSD || SANITIZER_LINUX +// Memory protection masks. +static const uptr kProtectionRead = 1; +static const uptr kProtectionWrite = 2; +static const uptr kProtectionExecute = 4; +static const uptr kProtectionShared = 8; + +struct MemoryMappedSegment { + MemoryMappedSegment(char *buff = nullptr, uptr size = 0) + : filename(buff), filename_size(size) {} + ~MemoryMappedSegment() {} + + bool IsReadable() { return protection & kProtectionRead; } + bool IsWritable() { return protection & kProtectionWrite; } + bool IsExecutable() { return protection & kProtectionExecute; } + bool IsShared() { return protection & kProtectionShared; } + + uptr start; + uptr end; + uptr offset; + char *filename; // owned by caller + uptr filename_size; + uptr protection; + ModuleArch arch; + u8 uuid[kModuleUUIDSize]; +}; + class MemoryMappingLayout { public: explicit MemoryMappingLayout(bool cache_enabled); ~MemoryMappingLayout(); - bool Next(uptr *start, uptr *end, uptr *offset, char filename[], - uptr filename_size, uptr *protection, ModuleArch *arch = nullptr, - u8 *uuid = nullptr); + bool Next(MemoryMappedSegment *segment); void Reset(); // In some cases, e.g. when running under a sandbox on Linux, ASan is unable // to obtain the memory mappings. It should fall back to pre-cached data @@ -47,12 +71,6 @@ class MemoryMappingLayout { // Adds all mapped objects into a vector. void DumpListOfModules(InternalMmapVector *modules); - // Memory protection masks. - static const uptr kProtectionRead = 1; - static const uptr kProtectionWrite = 2; - static const uptr kProtectionExecute = 4; - static const uptr kProtectionShared = 8; - private: void LoadFromCache(); @@ -67,10 +85,9 @@ class MemoryMappingLayout { static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_. # elif SANITIZER_MAC template - bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[], - uptr filename_size, ModuleArch *arch, u8 *uuid, - uptr *protection); - void GetSegmentAddrRange(uptr *start, uptr *end, uptr vmaddr, uptr vmsize); + bool NextSegmentLoad(MemoryMappedSegment *segment); + void GetSegmentAddrRange(MemoryMappedSegment *segment, uptr vmaddr, + uptr vmsize); int current_image_; u32 current_magic_; u32 current_filetype_; diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index c583f42f2..b95f301a4 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -119,12 +119,10 @@ void MemoryMappingLayout::LoadFromCache() { void MemoryMappingLayout::DumpListOfModules( InternalMmapVector *modules) { Reset(); - uptr cur_beg, cur_end, cur_offset, prot; InternalScopedString module_name(kMaxPathLength); - for (uptr i = 0; Next(&cur_beg, &cur_end, &cur_offset, module_name.data(), - module_name.size(), &prot); - i++) { - const char *cur_name = module_name.data(); + MemoryMappedSegment segment(module_name.data(), module_name.size()); + for (uptr i = 0; Next(&segment); i++) { + const char *cur_name = segment.filename; if (cur_name[0] == '\0') continue; // Don't subtract 'cur_beg' from the first entry: @@ -138,11 +136,11 @@ void MemoryMappingLayout::DumpListOfModules( // mapped high at address space (in particular, higher than // shadow memory of the tool), so the module can't be the // first entry. - uptr base_address = (i ? cur_beg : 0) - cur_offset; + uptr base_address = (i ? segment.start : 0) - segment.offset; LoadedModule cur_module; cur_module.set(cur_name, base_address); - cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, - prot & kProtectionWrite); + cur_module.addAddressRange(segment.start, segment.end, + segment.IsExecutable(), segment.IsWritable()); modules->push_back(cur_module); } } diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc index 302164563..f0cdbeb44 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc @@ -48,36 +48,27 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { proc_maps->len = Size; } -bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, - uptr *protection, ModuleArch *arch, u8 *uuid) { - CHECK(!arch && "not implemented"); - CHECK(!uuid && "not implemented"); +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { char *last = proc_self_maps_.data + proc_self_maps_.len; if (current_ >= last) return false; - uptr dummy; - if (!start) start = &dummy; - if (!end) end = &dummy; - if (!offset) offset = &dummy; - if (!protection) protection = &dummy; struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_; - *start = (uptr)VmEntry->kve_start; - *end = (uptr)VmEntry->kve_end; - *offset = (uptr)VmEntry->kve_offset; + segment->start = (uptr)VmEntry->kve_start; + segment->end = (uptr)VmEntry->kve_end; + segment->offset = (uptr)VmEntry->kve_offset; - *protection = 0; + segment->protection = 0; if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) - *protection |= kProtectionRead; + segment->protection |= kProtectionRead; if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) - *protection |= kProtectionWrite; + segment->protection |= kProtectionWrite; if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) - *protection |= kProtectionExecute; + segment->protection |= kProtectionExecute; - if (filename != NULL && filename_size > 0) { - internal_snprintf(filename, - Min(filename_size, (uptr)PATH_MAX), - "%s", VmEntry->kve_path); + if (segment->filename != NULL && segment->filename_size > 0) { + internal_snprintf(segment->filename, + Min(segment->filename_size, (uptr)PATH_MAX), "%s", + VmEntry->kve_path); } current_ += VmEntry->kve_structsize; diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc index 7e4a44be9..713bc2130 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -26,41 +26,28 @@ static bool IsOneOf(char c, char c1, char c2) { return c == c1 || c == c2; } -bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, - uptr *protection, ModuleArch *arch, u8 *uuid) { - CHECK(!arch && "not implemented"); - CHECK(!uuid && "not implemented"); +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { char *last = proc_self_maps_.data + proc_self_maps_.len; if (current_ >= last) return false; - uptr dummy; - if (!start) start = &dummy; - if (!end) end = &dummy; - if (!offset) offset = &dummy; - if (!protection) protection = &dummy; char *next_line = (char*)internal_memchr(current_, '\n', last - current_); if (next_line == 0) next_line = last; // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar - *start = ParseHex(¤t_); + segment->start = ParseHex(¤t_); CHECK_EQ(*current_++, '-'); - *end = ParseHex(¤t_); + segment->end = ParseHex(¤t_); CHECK_EQ(*current_++, ' '); CHECK(IsOneOf(*current_, '-', 'r')); - *protection = 0; - if (*current_++ == 'r') - *protection |= kProtectionRead; + segment->protection = 0; + if (*current_++ == 'r') segment->protection |= kProtectionRead; CHECK(IsOneOf(*current_, '-', 'w')); - if (*current_++ == 'w') - *protection |= kProtectionWrite; + if (*current_++ == 'w') segment->protection |= kProtectionWrite; CHECK(IsOneOf(*current_, '-', 'x')); - if (*current_++ == 'x') - *protection |= kProtectionExecute; + if (*current_++ == 'x') segment->protection |= kProtectionExecute; CHECK(IsOneOf(*current_, 's', 'p')); - if (*current_++ == 's') - *protection |= kProtectionShared; + if (*current_++ == 's') segment->protection |= kProtectionShared; CHECK_EQ(*current_++, ' '); - *offset = ParseHex(¤t_); + segment->offset = ParseHex(¤t_); CHECK_EQ(*current_++, ' '); ParseHex(¤t_); CHECK_EQ(*current_++, ':'); @@ -77,12 +64,11 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, // Fill in the filename. uptr i = 0; while (current_ < next_line) { - if (filename && i < filename_size - 1) - filename[i++] = *current_; + if (segment->filename && i < segment->filename_size - 1) + segment->filename[i++] = *current_; current_++; } - if (filename && i < filename_size) - filename[i] = 0; + if (segment->filename && i < segment->filename_size) segment->filename[i] = 0; current_ = next_line + 1; return true; } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 131017458..037022ee3 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -96,40 +96,24 @@ void MemoryMappingLayout::LoadFromCache() { // segment. // Note that the segment addresses are not necessarily sorted. template -bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, - ModuleArch *arch, u8 *uuid, - uptr *protection) { +bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { const char *lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - GetSegmentAddrRange(start, end, sc->vmaddr, sc->vmsize); - if (protection) { - // Return the initial protection. - *protection = sc->initprot; - } - if (offset) { - if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { - *offset = sc->vmaddr; - } else { - *offset = sc->fileoff; - } - } - if (filename) { - if (current_image_ == kDyldImageIdx) { - internal_strncpy(filename, kDyldPath, filename_size); - } else { - internal_strncpy(filename, _dyld_get_image_name(current_image_), - filename_size); - } - } - if (arch) { - *arch = current_arch_; - } - if (uuid) { - internal_memcpy(uuid, current_uuid_, kModuleUUIDSize); + GetSegmentAddrRange(segment, sc->vmaddr, sc->vmsize); + // Return the initial protection. + segment->protection = sc->initprot; + segment->offset = + (current_filetype_ == /*MH_EXECUTE*/ 0x2) ? sc->vmaddr : sc->fileoff; + if (segment->filename) { + const char *src = (current_image_ == kDyldImageIdx) + ? kDyldPath + : _dyld_get_image_name(current_image_); + internal_strncpy(segment->filename, src, segment->filename_size); } + segment->arch = current_arch_; + internal_memcpy(segment->uuid, current_uuid_, kModuleUUIDSize); return true; } return false; @@ -215,8 +199,7 @@ static mach_header *get_dyld_image_header() { (vm_region_info_t)&info, &count); if (err != KERN_SUCCESS) return nullptr; - if (size >= sizeof(mach_header) && - info.protection & MemoryMappingLayout::kProtectionRead) { + if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { mach_header *hdr = (mach_header *)address; if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && hdr->filetype == MH_DYLINKER) { @@ -233,7 +216,7 @@ const mach_header *get_dyld_hdr() { return dyld_hdr; } -void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, +void MemoryMappingLayout::GetSegmentAddrRange(MemoryMappedSegment *segment, uptr vmaddr, uptr vmsize) { if (current_image_ == kDyldImageIdx) { // vmaddr is masked with 0xfffff because on macOS versions < 10.12, @@ -242,18 +225,16 @@ void MemoryMappingLayout::GetSegmentAddrRange(uptr *start, uptr *end, // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - if (start) *start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - if (end) *end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); + segment->start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + segment->end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); } else { const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - if (start) *start = vmaddr + dlloff; - if (end) *end = vmaddr + vmsize + dlloff; + segment->start = vmaddr + dlloff; + segment->end = vmaddr + vmsize + dlloff; } } -bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, - uptr *protection, ModuleArch *arch, u8 *uuid) { +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { for (; current_image_ >= kDyldImageIdx; current_image_--) { const mach_header *hdr = (current_image_ == kDyldImageIdx) ? get_dyld_hdr() @@ -291,16 +272,13 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, #ifdef MH_MAGIC_64 case MH_MAGIC_64: { if (NextSegmentLoad( - start, end, offset, filename, filename_size, arch, uuid, - protection)) + segment)) return true; break; } #endif case MH_MAGIC: { - if (NextSegmentLoad( - start, end, offset, filename, filename_size, arch, uuid, - protection)) + if (NextSegmentLoad(segment)) return true; break; } @@ -315,28 +293,22 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, void MemoryMappingLayout::DumpListOfModules( InternalMmapVector *modules) { Reset(); - uptr cur_beg, cur_end, prot; - ModuleArch cur_arch; - u8 cur_uuid[kModuleUUIDSize]; InternalScopedString module_name(kMaxPathLength); - for (uptr i = 0; Next(&cur_beg, &cur_end, 0, module_name.data(), - module_name.size(), &prot, &cur_arch, &cur_uuid[0]); - i++) { - const char *cur_name = module_name.data(); - if (cur_name[0] == '\0') - continue; + MemoryMappedSegment segment(module_name.data(), kMaxPathLength); + for (uptr i = 0; Next(&segment); i++) { + if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && - 0 == internal_strcmp(cur_name, modules->back().full_name())) { + 0 == internal_strcmp(segment.filename, modules->back().full_name())) { cur_module = &modules->back(); } else { modules->push_back(LoadedModule()); cur_module = &modules->back(); - cur_module->set(cur_name, cur_beg, cur_arch, cur_uuid, - current_instrumented_); + cur_module->set(segment.filename, segment.start, segment.arch, + segment.uuid, current_instrumented_); } - cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute, - prot & kProtectionWrite); + cur_module->addAddressRange(segment.start, segment.end, + segment.IsExecutable(), segment.IsWritable()); } } diff --git a/lib/tsan/dd/dd_interceptors.cc b/lib/tsan/dd/dd_interceptors.cc index 97c72dd2b..a39218f04 100644 --- a/lib/tsan/dd/dd_interceptors.cc +++ b/lib/tsan/dd/dd_interceptors.cc @@ -270,20 +270,19 @@ namespace __dsan { static void InitDataSeg() { MemoryMappingLayout proc_maps(true); - uptr start, end, offset; char name[128]; + MemoryMappedSegment segment(name, ARRAY_SIZE(name)); bool prev_is_data = false; - while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), - /*protection*/ 0)) { - bool is_data = offset != 0 && name[0] != 0; + while (proc_maps.Next(&segment)) { + bool is_data = segment.offset != 0 && segment.filename[0] != 0; // BSS may get merged with [heap] in /proc/self/maps. This is not very // reliable. - bool is_bss = offset == 0 && - (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data; - if (g_data_start == 0 && is_data) - g_data_start = start; - if (is_bss) - g_data_end = end; + bool is_bss = segment.offset == 0 && + (segment.filename[0] == 0 || + internal_strcmp(segment.filename, "[heap]") == 0) && + prev_is_data; + if (g_data_start == 0 && is_data) g_data_start = segment.start; + if (is_bss) g_data_end = segment.end; prev_is_data = is_data; } VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 7d9638c09..0ba01babe 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -181,17 +181,15 @@ static void MapRodata() { } // Map the file into shadow of .rodata sections. MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr start, end, offset, prot; // Reusing the buffer 'name'. - while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) { - if (name[0] != 0 && name[0] != '[' - && (prot & MemoryMappingLayout::kProtectionRead) - && (prot & MemoryMappingLayout::kProtectionExecute) - && !(prot & MemoryMappingLayout::kProtectionWrite) - && IsAppMem(start)) { + MemoryMappedSegment segment(name, ARRAY_SIZE(name)); + while (proc_maps.Next(&segment)) { + if (segment.filename[0] != 0 && segment.filename[0] != '[' && + segment.IsReadable() && segment.IsExecutable() && + !segment.IsWritable() && IsAppMem(segment.start)) { // Assume it's .rodata - char *shadow_start = (char*)MemToShadow(start); - char *shadow_end = (char*)MemToShadow(end); + char *shadow_start = (char *)MemToShadow(segment.start); + char *shadow_end = (char *)MemToShadow(segment.end); for (char *p = shadow_start; p < shadow_end; p += marker.size()) { internal_mmap(p, Min(marker.size(), shadow_end - p), PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); diff --git a/lib/tsan/rtl/tsan_platform_posix.cc b/lib/tsan/rtl/tsan_platform_posix.cc index e89d955fe..e4f90a811 100644 --- a/lib/tsan/rtl/tsan_platform_posix.cc +++ b/lib/tsan/rtl/tsan_platform_posix.cc @@ -118,18 +118,16 @@ static void ProtectRange(uptr beg, uptr end) { void CheckAndProtect() { // Ensure that the binary is indeed compiled with -pie. MemoryMappingLayout proc_maps(true); - uptr p, end, prot; - while (proc_maps.Next(&p, &end, 0, 0, 0, &prot)) { - if (IsAppMem(p)) + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (IsAppMem(segment.start)) continue; + if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue; + if (segment.protection == 0) // Zero page or mprotected. continue; - if (p >= HeapMemEnd() && - p < HeapEnd()) - continue; - if (prot == 0) // Zero page or mprotected. - continue; - if (p >= VdsoBeg()) // vdso + if (segment.start >= VdsoBeg()) // vdso break; - Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end); + Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", + segment.start, segment.end); Die(); } -- cgit v1.2.1 From 0b770c1e37f7611e1b979e71e89b0fa99ddb7ab5 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 11 Jul 2017 19:40:53 +0000 Subject: Inline function to get mac segment address range Summary: This function is only called once and is fairly simple. Inline to keep API simple. Reviewers: alekseyshl, kubamracek Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35270 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307695 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 2 - lib/sanitizer_common/sanitizer_procmaps_mac.cc | 119 ++++++++++++------------- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index a0ac0b919..06d072b4d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -86,8 +86,6 @@ class MemoryMappingLayout { # elif SANITIZER_MAC template bool NextSegmentLoad(MemoryMappedSegment *segment); - void GetSegmentAddrRange(MemoryMappedSegment *segment, uptr vmaddr, - uptr vmsize); int current_image_; u32 current_magic_; u32 current_filetype_; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 037022ee3..560451a16 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -88,6 +88,48 @@ void MemoryMappingLayout::LoadFromCache() { // No-op on Mac for now. } +// _dyld_get_image_header() and related APIs don't report dyld itself. +// We work around this by manually recursing through the memory map +// until we hit a Mach header matching dyld instead. These recurse +// calls are expensive, but the first memory map generation occurs +// early in the process, when dyld is one of the only images loaded, +// so it will be hit after only a few iterations. +static mach_header *get_dyld_image_header() { + mach_port_name_t port; + if (task_for_pid(mach_task_self(), internal_getpid(), &port) != + KERN_SUCCESS) { + return nullptr; + } + + unsigned depth = 1; + vm_size_t size = 0; + vm_address_t address = 0; + kern_return_t err = KERN_SUCCESS; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + while (true) { + struct vm_region_submap_info_64 info; + err = vm_region_recurse_64(port, &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (err != KERN_SUCCESS) return nullptr; + + if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { + mach_header *hdr = (mach_header *)address; + if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && + hdr->filetype == MH_DYLINKER) { + return hdr; + } + } + address += size; + } +} + +const mach_header *get_dyld_hdr() { + if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); + + return dyld_hdr; +} + // Next and NextSegmentLoad were inspired by base/sysinfo.cc in // Google Perftools, https://github.com/gperftools/gperftools. @@ -101,7 +143,22 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - GetSegmentAddrRange(segment, sc->vmaddr, sc->vmsize); + + if (current_image_ == kDyldImageIdx) { + // vmaddr is masked with 0xfffff because on macOS versions < 10.12, + // it contains an absolute address rather than an offset for dyld. + // To make matters even more complicated, this absolute address + // isn't actually the absolute segment address, but the offset portion + // of the address is accurate when combined with the dyld base address, + // and the mask will give just this offset. + segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); + } else { + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + segment->start = sc->vmaddr + dlloff; + segment->end = sc->vmaddr + sc->vmsize + dlloff; + } + // Return the initial protection. segment->protection = sc->initprot; segment->offset = @@ -174,66 +231,6 @@ static bool IsModuleInstrumented(const load_command *first_lc) { return false; } -// _dyld_get_image_header() and related APIs don't report dyld itself. -// We work around this by manually recursing through the memory map -// until we hit a Mach header matching dyld instead. These recurse -// calls are expensive, but the first memory map generation occurs -// early in the process, when dyld is one of the only images loaded, -// so it will be hit after only a few iterations. -static mach_header *get_dyld_image_header() { - mach_port_name_t port; - if (task_for_pid(mach_task_self(), internal_getpid(), &port) != - KERN_SUCCESS) { - return nullptr; - } - - unsigned depth = 1; - vm_size_t size = 0; - vm_address_t address = 0; - kern_return_t err = KERN_SUCCESS; - mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; - - while (true) { - struct vm_region_submap_info_64 info; - err = vm_region_recurse_64(port, &address, &size, &depth, - (vm_region_info_t)&info, &count); - if (err != KERN_SUCCESS) return nullptr; - - if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { - mach_header *hdr = (mach_header *)address; - if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && - hdr->filetype == MH_DYLINKER) { - return hdr; - } - } - address += size; - } -} - -const mach_header *get_dyld_hdr() { - if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); - - return dyld_hdr; -} - -void MemoryMappingLayout::GetSegmentAddrRange(MemoryMappedSegment *segment, - uptr vmaddr, uptr vmsize) { - if (current_image_ == kDyldImageIdx) { - // vmaddr is masked with 0xfffff because on macOS versions < 10.12, - // it contains an absolute address rather than an offset for dyld. - // To make matters even more complicated, this absolute address - // isn't actually the absolute segment address, but the offset portion - // of the address is accurate when combined with the dyld base address, - // and the mask will give just this offset. - segment->start = (vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - segment->end = (vmaddr & 0xfffff) + vmsize + (uptr)get_dyld_hdr(); - } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - segment->start = vmaddr + dlloff; - segment->end = vmaddr + vmsize + dlloff; - } -} - bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { for (; current_image_ >= kDyldImageIdx; current_image_--) { const mach_header *hdr = (current_image_ == kDyldImageIdx) -- cgit v1.2.1 From b0d9af0a5e7ffdd1845a5750ccaf1ad1db1591b4 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 11 Jul 2017 19:40:54 +0000 Subject: Use internal_strncpy to copy filename in linux procmaps Cleaner than using a while loop to copy the string character by character. Reviewers: alekseyshl, glider Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35136 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307696 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_linux.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc index 713bc2130..1bcad2bf7 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -62,13 +62,12 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { while (current_ < next_line && *current_ == ' ') current_++; // Fill in the filename. - uptr i = 0; - while (current_ < next_line) { - if (segment->filename && i < segment->filename_size - 1) - segment->filename[i++] = *current_; - current_++; + if (segment->filename) { + uptr len = Min((uptr)(next_line - current_), segment->filename_size - 1); + internal_strncpy(segment->filename, current_, len); + segment->filename[len] = 0; } - if (segment->filename && i < segment->filename_size) segment->filename[i] = 0; + current_ = next_line + 1; return true; } -- cgit v1.2.1 From eb2931a5414c5d8644b904dd83f9f719ebd40cb0 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 12 Jul 2017 00:14:05 +0000 Subject: [tsan] Update test to r307338 r307338 enabled new optimization reducing number of operation in tested functions. There is no any performance regression detectable with TsanRtlTest DISABLED_BENCH.Mop* tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307739 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/check_analyze.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh index 22eb44419..54dd1b023 100755 --- a/lib/tsan/check_analyze.sh +++ b/lib/tsan/check_analyze.sh @@ -34,8 +34,8 @@ done for f in read1 read2 read4 read8; do check $f rsp 1 - check $f push 4 - check $f pop 4 + check $f push 3 + check $f pop 3 done for f in func_entry func_exit; do -- cgit v1.2.1 From 9cd8edacd314ca4374ab2e45ea61202f7cd9768b Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:23:31 +0000 Subject: tsan: add test for __tsan_java_find The test should have been added in 289682 "tsan: allow Java VM iterate over allocated objects" but I forgot to avn add. Author: Alexander Smundak (asmundak) Reviewed in https://reviews.llvm.org/D27720 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307776 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/java_find.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/tsan/java_find.cc diff --git a/test/tsan/java_find.cc b/test/tsan/java_find.cc new file mode 100644 index 000000000..078aac520 --- /dev/null +++ b/test/tsan/java_find.cc @@ -0,0 +1,69 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "java.h" + +int const kHeapSize = 1024 * 1024; + +static void verify_find(jptr from, jptr to, jptr expected_addr, + jptr expected_size) { + jptr addr = from; + jptr size = __tsan_java_find(&addr, to); + if (expected_size) { + if (!size) { + fprintf(stderr, "FAILED: range: [%p..%p): found nothing\n", (void *)from, + (void *)to); + return; + } else if (expected_size != size) { + fprintf(stderr, "FAILED: range: [%p..%p): wrong size, %lu instead of %lu\n", + (void *)from, (void *)to, size, expected_size); + return; + } + } else if (size) { + fprintf(stderr, + "FAILED: range [%p..%p): did not expect to find anything here\n", + (void *)from, (void *)to); + return; + } else { + return; + } + if (expected_addr != addr) { + fprintf( + stderr, + "FAILED: range [%p..%p): expected to find object at %p, found at %p\n", + (void *)from, (void *)to, (void *)expected_addr, (void *)addr); + } +} + +int main() { + const jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; + const jptr jheap_end = jheap + kHeapSize; + __tsan_java_init(jheap, kHeapSize); + const jptr addr1 = jheap; + const int size1 = 16; + __tsan_java_alloc(jheap, size1); + + const jptr addr2 = addr1 + size1; + const int size2 = 32; + __tsan_java_alloc(jheap + size1, size2); + + const jptr addr3 = addr2 + size2; + const int size3 = 1024; + __tsan_java_alloc(jheap + size1 + size2, size3); + + const jptr addr4 = addr3 + size3; + + verify_find(jheap, jheap_end, addr1, size1); + verify_find(jheap + 8, jheap_end, addr2, size2); + verify_find(addr2 + 8, jheap_end, addr3, size3); + verify_find(addr3 + 8, jheap_end, 0, 0); + + __tsan_java_move(addr2, addr4, size2); + verify_find(jheap + 8, jheap_end, addr3, size3); + verify_find(addr3 + 8, jheap_end, addr4, size2); + verify_find(addr4 + 8, jheap_end, 0, 0); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: FAILED +// CHECK: DONE -- cgit v1.2.1 From 38ecb5de33e6ce0e9a2d60f3571e268801eda8b3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:25:03 +0000 Subject: tsan: add another test for clock growth git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307777 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/tests/unit/tsan_clock_test.cc | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/tsan/tests/unit/tsan_clock_test.cc b/lib/tsan/tests/unit/tsan_clock_test.cc index 83e25fb5a..34850faaa 100644 --- a/lib/tsan/tests/unit/tsan_clock_test.cc +++ b/lib/tsan/tests/unit/tsan_clock_test.cc @@ -212,6 +212,42 @@ TEST(Clock, Growth) { } } +TEST(Clock, Growth2) { + // Test clock growth for every pair of sizes: + const uptr sizes[] = {0, 1, 2, 30, 61, 62, 63, 64, 65, 66, 100, 124, 125, 126, + 127, 128, 129, 130, 188, 189, 190, 191, 192, 193, 254, 255}; + const uptr n = sizeof(sizes) / sizeof(sizes[0]); + for (uptr fi = 0; fi < n; fi++) { + for (uptr ti = fi + 1; ti < n; ti++) { + const uptr from = sizes[fi]; + const uptr to = sizes[ti]; + SyncClock sync; + ThreadClock vector(0); + for (uptr i = 0; i < from; i++) + vector.set(i, i + 1); + if (from != 0) + vector.release(&cache, &sync); + ASSERT_EQ(sync.size(), from); + for (uptr i = 0; i < from; i++) + ASSERT_EQ(sync.get(i), i + 1); + for (uptr i = 0; i < to; i++) + vector.set(i, i + 1); + vector.release(&cache, &sync); + ASSERT_EQ(sync.size(), to); + for (uptr i = 0; i < to; i++) + ASSERT_EQ(sync.get(i), i + 1); + vector.set(to + 1, to + 1); + vector.release(&cache, &sync); + ASSERT_EQ(sync.size(), to + 2); + for (uptr i = 0; i < to; i++) + ASSERT_EQ(sync.get(i), i + 1); + ASSERT_EQ(sync.get(to), 0U); + ASSERT_EQ(sync.get(to + 1), to + 1); + sync.Reset(&cache); + } + } +} + const uptr kThreads = 4; const uptr kClocks = 4; -- cgit v1.2.1 From 5de8108ffc5363bc87abe057ba65b4a3fb0c1801 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:28:23 +0000 Subject: tsan: don't create sync objects on acquire-load Don't create sync object if it does not exist yet. For example, an atomic pointer is initialized to nullptr and then periodically acquire-loaded. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307778 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interface_atomic.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc index b22d5c1ec..d334394f5 100644 --- a/lib/tsan/rtl/tsan_interface_atomic.cc +++ b/lib/tsan/rtl/tsan_interface_atomic.cc @@ -220,8 +220,7 @@ static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) { #endif template -static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, - morder mo) { +static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, morder mo) { CHECK(IsLoadOrder(mo)); // This fast-path is critical for performance. // Assume the access is atomic. @@ -229,10 +228,17 @@ static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, MemoryReadAtomic(thr, pc, (uptr)a, SizeLog()); return NoTsanAtomicLoad(a, mo); } - SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false); - AcquireImpl(thr, pc, &s->clock); + // Don't create sync object if it does not exist yet. For example, an atomic + // pointer is initialized to nullptr and then periodically acquire-loaded. T v = NoTsanAtomicLoad(a, mo); - s->mtx.ReadUnlock(); + SyncVar *s = ctx->metamap.GetIfExistsAndLock((uptr)a, false); + if (s) { + AcquireImpl(thr, pc, &s->clock); + // Re-read under sync mutex because we need a consistent snapshot + // of the value and the clock we acquire. + v = NoTsanAtomicLoad(a, mo); + s->mtx.ReadUnlock(); + } MemoryReadAtomic(thr, pc, (uptr)a, SizeLog()); return v; } -- cgit v1.2.1 From bc135c12cd648ba828b723b7913e05440e5641e9 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:34:12 +0000 Subject: tsan: give debug names to dense allocators Improves crash message on dense alloc overflow. Allows to understand what alloc overflowed. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307780 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_dense_alloc.h | 11 ++++++++--- lib/tsan/rtl/tsan_rtl.cc | 3 ++- lib/tsan/rtl/tsan_sync.cc | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/tsan/rtl/tsan_dense_alloc.h b/lib/tsan/rtl/tsan_dense_alloc.h index e9815c90a..16dbdf391 100644 --- a/lib/tsan/rtl/tsan_dense_alloc.h +++ b/lib/tsan/rtl/tsan_dense_alloc.h @@ -39,7 +39,7 @@ class DenseSlabAlloc { typedef DenseSlabAllocCache Cache; typedef typename Cache::IndexT IndexT; - DenseSlabAlloc() { + explicit DenseSlabAlloc(const char *name) { // Check that kL1Size and kL2Size are sane. CHECK_EQ(kL1Size & (kL1Size - 1), 0); CHECK_EQ(kL2Size & (kL2Size - 1), 0); @@ -49,6 +49,7 @@ class DenseSlabAlloc { internal_memset(map_, 0, sizeof(map_)); freelist_ = 0; fillpos_ = 0; + name_ = name; } ~DenseSlabAlloc() { @@ -96,15 +97,19 @@ class DenseSlabAlloc { SpinMutex mtx_; IndexT freelist_; uptr fillpos_; + const char *name_; void Refill(Cache *c) { SpinMutexLock lock(&mtx_); if (freelist_ == 0) { if (fillpos_ == kL1Size) { - Printf("ThreadSanitizer: DenseSlabAllocator overflow. Dying.\n"); + Printf("ThreadSanitizer: %s overflow (%zu*%zu). Dying.\n", + name_, kL1Size, kL2Size); Die(); } - T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), "DenseSlabAllocator"); + VPrintf(2, "ThreadSanitizer: growing %s: %zu out of %zu*%zu\n", + name_, fillpos_, kL1Size, kL2Size); + T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), name_); // Reserve 0 as invalid index. IndexT start = fillpos_ == 0 ? 1 : 0; for (IndexT i = start; i < kL2Size; i++) { diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index fa60f3247..a01525302 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -104,7 +104,8 @@ Context::Context() , racy_stacks(MBlockRacyStacks) , racy_addresses(MBlockRacyAddresses) , fired_suppressions_mtx(MutexTypeFired, StatMtxFired) - , fired_suppressions(8) { + , fired_suppressions(8) + , clock_alloc("clock allocator") { } // The objects are allocated in TLS, so one may rely on zero-initialization. diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc index 4cc3cb89c..44ae558fa 100644 --- a/lib/tsan/rtl/tsan_sync.cc +++ b/lib/tsan/rtl/tsan_sync.cc @@ -53,7 +53,9 @@ void SyncVar::Reset(Processor *proc) { } } -MetaMap::MetaMap() { +MetaMap::MetaMap() + : block_alloc_("heap block allocator") + , sync_alloc_("sync allocator") { atomic_store(&uid_gen_, 0, memory_order_relaxed); } -- cgit v1.2.1 From 25473b0d43f8e612291b1eff7dde00b51ab4127e Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:36:44 +0000 Subject: tsan: s/-1/kInvalidTid/ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307781 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_rtl_report.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index 68b9f5030..85a982941 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -314,7 +314,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) { return; #if !SANITIZER_GO int fd = -1; - int creat_tid = -1; + int creat_tid = kInvalidTid; u32 creat_stack = 0; if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) { ReportLocation *loc = ReportLocation::New(ReportLocationFD); -- cgit v1.2.1 From 6e32365b3ee6d2661034d83a3e80eb2dea6da1a4 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:45:20 +0000 Subject: tsan: prepare clock for future changes Pass ClockCache to ThreadClock::set and introduce ThreadCache::ResetCached. For now both are unused, but will reduce future diffs. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307784 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_clock.cc | 5 ++++- lib/tsan/rtl/tsan_clock.h | 3 ++- lib/tsan/rtl/tsan_mman.cc | 2 ++ lib/tsan/rtl/tsan_rtl_mutex.cc | 12 ++++++------ lib/tsan/rtl/tsan_rtl_thread.cc | 4 ++++ lib/tsan/tests/unit/tsan_clock_test.cc | 32 +++++++++++++++++--------------- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc index 32435adfd..362921878 100644 --- a/lib/tsan/rtl/tsan_clock.cc +++ b/lib/tsan/rtl/tsan_clock.cc @@ -101,6 +101,9 @@ ThreadClock::ThreadClock(unsigned tid, unsigned reused) clk_[tid_].reused = reused_; } +void ThreadClock::ResetCached(ClockCache *c) { +} + void ThreadClock::acquire(ClockCache *c, const SyncClock *src) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(src->size_, kMaxTid); @@ -346,7 +349,7 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) { // Sets a single element in the vector clock. // This function is called only from weird places like AcquireGlobal. -void ThreadClock::set(unsigned tid, u64 v) { +void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) { DCHECK_LT(tid, kMaxTid); DCHECK_GE(v, clk_[tid].epoch); clk_[tid].epoch = v; diff --git a/lib/tsan/rtl/tsan_clock.h b/lib/tsan/rtl/tsan_clock.h index 4e352cb81..90eaca28a 100644 --- a/lib/tsan/rtl/tsan_clock.h +++ b/lib/tsan/rtl/tsan_clock.h @@ -89,7 +89,7 @@ struct ThreadClock { return clk_[tid].epoch; } - void set(unsigned tid, u64 v); + void set(ClockCache *c, unsigned tid, u64 v); void set(u64 v) { DCHECK_GE(v, clk_[tid_].epoch); @@ -108,6 +108,7 @@ struct ThreadClock { void release(ClockCache *c, SyncClock *dst) const; void acq_rel(ClockCache *c, SyncClock *dst); void ReleaseStore(ClockCache *c, SyncClock *dst) const; + void ResetCached(ClockCache *c); void DebugReset(); void DebugDump(int(*printf)(const char *s, ...)); diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 7169d5b02..1434cf688 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -294,6 +294,8 @@ uptr __sanitizer_get_allocated_size(const void *p) { void __tsan_on_thread_idle() { ThreadState *thr = cur_thread(); + thr->clock.ResetCached(&thr->proc()->clock_cache); + thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); allocator()->SwallowCache(&thr->proc()->alloc_cache); internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache); ctx->metamap.OnProcIdle(thr->proc()); diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index 54938f37e..2f8581162 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -413,10 +413,10 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) { static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { ThreadState *thr = reinterpret_cast(arg); ThreadContext *tctx = static_cast(tctx_base); + u64 epoch = tctx->epoch1; if (tctx->status == ThreadStatusRunning) - thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch()); - else - thr->clock.set(tctx->tid, tctx->epoch1); + epoch = tctx->thr->fast_state.epoch(); + thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); } void AcquireGlobal(ThreadState *thr, uptr pc) { @@ -456,10 +456,10 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) { ThreadState *thr = reinterpret_cast(arg); ThreadContext *tctx = static_cast(tctx_base); + u64 epoch = tctx->epoch1; if (tctx->status == ThreadStatusRunning) - thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch()); - else - thr->last_sleep_clock.set(tctx->tid, tctx->epoch1); + epoch = tctx->thr->fast_state.epoch(); + thr->last_sleep_clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); } void AfterSleep(ThreadState *thr, uptr pc) { diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index 67eebf5d0..83fab082a 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -142,6 +142,10 @@ void ThreadContext::OnFinished() { if (common_flags()->detect_deadlocks) ctx->dd->DestroyLogicalThread(thr->dd_lt); + thr->clock.ResetCached(&thr->proc()->clock_cache); +#if !SANITIZER_GO + thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); +#endif thr->~ThreadState(); #if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); diff --git a/lib/tsan/tests/unit/tsan_clock_test.cc b/lib/tsan/tests/unit/tsan_clock_test.cc index 34850faaa..73104dd6b 100644 --- a/lib/tsan/tests/unit/tsan_clock_test.cc +++ b/lib/tsan/tests/unit/tsan_clock_test.cc @@ -26,13 +26,13 @@ TEST(Clock, VectorBasic) { clk.tick(); ASSERT_EQ(clk.size(), 1U); ASSERT_EQ(clk.get(0), 1U); - clk.set(3, clk.get(3) + 1); + clk.set(&cache, 3, clk.get(3) + 1); ASSERT_EQ(clk.size(), 4U); ASSERT_EQ(clk.get(0), 1U); ASSERT_EQ(clk.get(1), 0U); ASSERT_EQ(clk.get(2), 0U); ASSERT_EQ(clk.get(3), 1U); - clk.set(3, clk.get(3) + 1); + clk.set(&cache, 3, clk.get(3) + 1); ASSERT_EQ(clk.get(3), 2U); } @@ -86,24 +86,26 @@ TEST(Clock, RepeatedAcquire) { TEST(Clock, ManyThreads) { SyncClock chunked; - for (unsigned i = 0; i < 100; i++) { + for (unsigned i = 0; i < 200; i++) { ThreadClock vector(0); vector.tick(); - vector.set(i, 1); + vector.set(&cache, i, i + 1); vector.release(&cache, &chunked); ASSERT_EQ(i + 1, chunked.size()); vector.acquire(&cache, &chunked); ASSERT_EQ(i + 1, vector.size()); } - for (unsigned i = 0; i < 100; i++) - ASSERT_EQ(1U, chunked.get(i)); + for (unsigned i = 0; i < 200; i++) { + printf("i=%d\n", i); + ASSERT_EQ(i + 1, chunked.get(i)); + } ThreadClock vector(1); vector.acquire(&cache, &chunked); - ASSERT_EQ(100U, vector.size()); - for (unsigned i = 0; i < 100; i++) - ASSERT_EQ(1U, vector.get(i)); + ASSERT_EQ(200U, vector.size()); + for (unsigned i = 0; i < 200; i++) + ASSERT_EQ(i + 1, vector.get(i)); chunked.Reset(&cache); } @@ -151,7 +153,7 @@ TEST(Clock, Growth) { { ThreadClock vector(10); vector.tick(); - vector.set(5, 42); + vector.set(&cache, 5, 42); SyncClock sync; vector.release(&cache, &sync); ASSERT_EQ(sync.size(), 11U); @@ -180,8 +182,8 @@ TEST(Clock, Growth) { { ThreadClock vector(100); vector.tick(); - vector.set(5, 42); - vector.set(90, 84); + vector.set(&cache, 5, 42); + vector.set(&cache, 90, 84); SyncClock sync; vector.release(&cache, &sync); ASSERT_EQ(sync.size(), 101U); @@ -224,19 +226,19 @@ TEST(Clock, Growth2) { SyncClock sync; ThreadClock vector(0); for (uptr i = 0; i < from; i++) - vector.set(i, i + 1); + vector.set(&cache, i, i + 1); if (from != 0) vector.release(&cache, &sync); ASSERT_EQ(sync.size(), from); for (uptr i = 0; i < from; i++) ASSERT_EQ(sync.get(i), i + 1); for (uptr i = 0; i < to; i++) - vector.set(i, i + 1); + vector.set(&cache, i, i + 1); vector.release(&cache, &sync); ASSERT_EQ(sync.size(), to); for (uptr i = 0; i < to; i++) ASSERT_EQ(sync.get(i), i + 1); - vector.set(to + 1, to + 1); + vector.set(&cache, to + 1, to + 1); vector.release(&cache, &sync); ASSERT_EQ(sync.size(), to + 2); for (uptr i = 0; i < to; i++) -- cgit v1.2.1 From 14a186f061650792da335633a278a409a5664ac1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:50:36 +0000 Subject: tsan: refactor SyncClock code 1. Add SyncClock::ResetImpl which removes code duplication between ctor and Reset. 2. Move SyncClock::Resize to SyncClock methods, currently it's defined between ThreadClock methods. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307785 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_clock.cc | 108 ++++++++++++++++++++++----------------------- lib/tsan/rtl/tsan_clock.h | 1 + 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc index 362921878..4a91683ea 100644 --- a/lib/tsan/rtl/tsan_clock.cc +++ b/lib/tsan/rtl/tsan_clock.cc @@ -300,53 +300,6 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const { return true; } -void SyncClock::Resize(ClockCache *c, uptr nclk) { - CPP_STAT_INC(StatClockReleaseResize); - if (RoundUpTo(nclk, ClockBlock::kClockCount) <= - RoundUpTo(size_, ClockBlock::kClockCount)) { - // Growing within the same block. - // Memory is already allocated, just increase the size. - size_ = nclk; - return; - } - if (nclk <= ClockBlock::kClockCount) { - // Grow from 0 to one-level table. - CHECK_EQ(size_, 0); - CHECK_EQ(tab_, 0); - CHECK_EQ(tab_idx_, 0); - size_ = nclk; - tab_idx_ = ctx->clock_alloc.Alloc(c); - tab_ = ctx->clock_alloc.Map(tab_idx_); - internal_memset(tab_, 0, sizeof(*tab_)); - return; - } - // Growing two-level table. - if (size_ == 0) { - // Allocate first level table. - tab_idx_ = ctx->clock_alloc.Alloc(c); - tab_ = ctx->clock_alloc.Map(tab_idx_); - internal_memset(tab_, 0, sizeof(*tab_)); - } else if (size_ <= ClockBlock::kClockCount) { - // Transform one-level table to two-level table. - u32 old = tab_idx_; - tab_idx_ = ctx->clock_alloc.Alloc(c); - tab_ = ctx->clock_alloc.Map(tab_idx_); - internal_memset(tab_, 0, sizeof(*tab_)); - tab_->table[0] = old; - } - // At this point we have first level table allocated. - // Add second level tables as necessary. - for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount); - i < nclk; i += ClockBlock::kClockCount) { - u32 idx = ctx->clock_alloc.Alloc(c); - ClockBlock *cb = ctx->clock_alloc.Map(idx); - internal_memset(cb, 0, sizeof(*cb)); - CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0); - tab_->table[i/ClockBlock::kClockCount] = idx; - } - size_ = nclk; -} - // Sets a single element in the vector clock. // This function is called only from weird places like AcquireGlobal. void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) { @@ -369,14 +322,8 @@ void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) { tid_, reused_, last_acquire_); } -SyncClock::SyncClock() - : release_store_tid_(kInvalidTid) - , release_store_reused_() - , tab_() - , tab_idx_() - , size_() { - for (uptr i = 0; i < kDirtyTids; i++) - dirty_tids_[i] = kInvalidTid; +SyncClock::SyncClock() { + ResetImpl(); } SyncClock::~SyncClock() { @@ -398,6 +345,10 @@ void SyncClock::Reset(ClockCache *c) { ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]); ctx->clock_alloc.Free(c, tab_idx_); } + ResetImpl(); +} + +void SyncClock::ResetImpl() { tab_ = 0; tab_idx_ = 0; size_ = 0; @@ -407,6 +358,53 @@ void SyncClock::Reset(ClockCache *c) { dirty_tids_[i] = kInvalidTid; } +void SyncClock::Resize(ClockCache *c, uptr nclk) { + CPP_STAT_INC(StatClockReleaseResize); + if (RoundUpTo(nclk, ClockBlock::kClockCount) <= + RoundUpTo(size_, ClockBlock::kClockCount)) { + // Growing within the same block. + // Memory is already allocated, just increase the size. + size_ = nclk; + return; + } + if (nclk <= ClockBlock::kClockCount) { + // Grow from 0 to one-level table. + CHECK_EQ(size_, 0); + CHECK_EQ(tab_, 0); + CHECK_EQ(tab_idx_, 0); + size_ = nclk; + tab_idx_ = ctx->clock_alloc.Alloc(c); + tab_ = ctx->clock_alloc.Map(tab_idx_); + internal_memset(tab_, 0, sizeof(*tab_)); + return; + } + // Growing two-level table. + if (size_ == 0) { + // Allocate first level table. + tab_idx_ = ctx->clock_alloc.Alloc(c); + tab_ = ctx->clock_alloc.Map(tab_idx_); + internal_memset(tab_, 0, sizeof(*tab_)); + } else if (size_ <= ClockBlock::kClockCount) { + // Transform one-level table to two-level table. + u32 old = tab_idx_; + tab_idx_ = ctx->clock_alloc.Alloc(c); + tab_ = ctx->clock_alloc.Map(tab_idx_); + internal_memset(tab_, 0, sizeof(*tab_)); + tab_->table[0] = old; + } + // At this point we have first level table allocated. + // Add second level tables as necessary. + for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount); + i < nclk; i += ClockBlock::kClockCount) { + u32 idx = ctx->clock_alloc.Alloc(c); + ClockBlock *cb = ctx->clock_alloc.Map(idx); + internal_memset(cb, 0, sizeof(*cb)); + CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0); + tab_->table[i/ClockBlock::kClockCount] = idx; + } + size_ = nclk; +} + ClockElem &SyncClock::elem(unsigned tid) const { DCHECK_LT(tid, size_); if (size_ <= ClockBlock::kClockCount) diff --git a/lib/tsan/rtl/tsan_clock.h b/lib/tsan/rtl/tsan_clock.h index 90eaca28a..378b550fd 100644 --- a/lib/tsan/rtl/tsan_clock.h +++ b/lib/tsan/rtl/tsan_clock.h @@ -74,6 +74,7 @@ class SyncClock { u32 tab_idx_; u32 size_; + void ResetImpl(); ClockElem &elem(unsigned tid) const; }; -- cgit v1.2.1 From d16bb5ca26596aa7986e89129e93047dc6ad91a0 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 12 Jul 2017 12:54:38 +0000 Subject: tsan: remove some clock-related stats The stats are too dependent on implementation and won't be relevant in future. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307786 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_clock.cc | 6 ++---- lib/tsan/rtl/tsan_stat.cc | 5 +---- lib/tsan/rtl/tsan_stat.h | 5 +---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc index 4a91683ea..9ee910428 100644 --- a/lib/tsan/rtl/tsan_clock.cc +++ b/lib/tsan/rtl/tsan_clock.cc @@ -119,9 +119,7 @@ void ThreadClock::acquire(ClockCache *c, const SyncClock *src) { // Check if we've already acquired src after the last release operation on src bool acquired = false; if (nclk > tid_) { - CPP_STAT_INC(StatClockAcquireLarge); if (src->elem(tid_).reused == reused_) { - CPP_STAT_INC(StatClockAcquireRepeat); for (unsigned i = 0; i < kDirtyTids; i++) { unsigned tid = src->dirty_tids_[i]; if (tid != kInvalidTid) { @@ -269,11 +267,11 @@ void ThreadClock::UpdateCurrentThread(SyncClock *dst) const { for (unsigned i = 0; i < kDirtyTids; i++) { if (dst->dirty_tids_[i] == tid_) { - CPP_STAT_INC(StatClockReleaseFast1); + CPP_STAT_INC(StatClockReleaseFast); return; } if (dst->dirty_tids_[i] == kInvalidTid) { - CPP_STAT_INC(StatClockReleaseFast2); + CPP_STAT_INC(StatClockReleaseFast); dst->dirty_tids_[i] = tid_; return; } diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc index 2ee688bf5..18c83d5c6 100644 --- a/lib/tsan/rtl/tsan_stat.cc +++ b/lib/tsan/rtl/tsan_stat.cc @@ -75,14 +75,11 @@ void StatOutput(u64 *stat) { name[StatClockAcquire] = "Clock acquire "; name[StatClockAcquireEmpty] = " empty clock "; name[StatClockAcquireFastRelease] = " fast from release-store "; - name[StatClockAcquireLarge] = " contains my tid "; - name[StatClockAcquireRepeat] = " repeated (fast) "; name[StatClockAcquireFull] = " full (slow) "; name[StatClockAcquiredSomething] = " acquired something "; name[StatClockRelease] = "Clock release "; name[StatClockReleaseResize] = " resize "; - name[StatClockReleaseFast1] = " fast1 "; - name[StatClockReleaseFast2] = " fast2 "; + name[StatClockReleaseFast] = " fast "; name[StatClockReleaseSlow] = " dirty overflow (slow) "; name[StatClockReleaseFull] = " full (slow) "; name[StatClockReleaseAcquired] = " was acquired "; diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h index 7d2791ebb..42d6a2b63 100644 --- a/lib/tsan/rtl/tsan_stat.h +++ b/lib/tsan/rtl/tsan_stat.h @@ -74,15 +74,12 @@ enum StatType { StatClockAcquire, StatClockAcquireEmpty, StatClockAcquireFastRelease, - StatClockAcquireLarge, - StatClockAcquireRepeat, StatClockAcquireFull, StatClockAcquiredSomething, // Clocks - release. StatClockRelease, StatClockReleaseResize, - StatClockReleaseFast1, - StatClockReleaseFast2, + StatClockReleaseFast, StatClockReleaseSlow, StatClockReleaseFull, StatClockReleaseAcquired, -- cgit v1.2.1 From e637b93bd999afb198d4a69e16c685026d016c30 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 12 Jul 2017 15:29:08 +0000 Subject: [scudo] PRNG makeover Summary: This follows the addition of `GetRandom` with D34412. We remove our `/dev/urandom` code and use the new function. Additionally, change the PRNG for a slightly faster version. One of the issues with the old code is that we have 64 full bits of randomness per "next", using only 8 of those for the Salt and discarding the rest. So we add a cached u64 in the PRNG that can serve up to 8 u8 before having to call the "next" function again. During some integration work, I also realized that some very early processes (like `init`) do not benefit from `/dev/urandom` yet. So if there is no `getrandom` syscall as well, we have to fallback to some sort of initialization of the PRNG. Now a few words on why XoRoShiRo and not something else. I have played a while with various PRNGs on 32 & 64 bit platforms. Some results are below. LCG 32 & 64 are usually faster but produce respectively 15 & 31 bits of entropy, meaning that to get a full 64-bit, you would need to call them several times. The simple XorShift is fast, produces 32 bits but is mediocre with regard to PRNG test suites, PCG is slower overall, and XoRoShiRo is faster than XorShift128+ and produces full 64 bits. %%% root@tulip-chiphd:/data # ./randtest.arm [+] starting xs32... [?] xs32 duration: 22431833053ns [+] starting lcg32... [?] lcg32 duration: 14941402090ns [+] starting pcg32... [?] pcg32 duration: 44941973771ns [+] starting xs128p... [?] xs128p duration: 48889786981ns [+] starting lcg64... [?] lcg64 duration: 33831042391ns [+] starting xos128p... [?] xos128p duration: 44850878605ns root@tulip-chiphd:/data # ./randtest.aarch64 [+] starting xs32... [?] xs32 duration: 22425151678ns [+] starting lcg32... [?] lcg32 duration: 14954255257ns [+] starting pcg32... [?] pcg32 duration: 37346265726ns [+] starting xs128p... [?] xs128p duration: 22523807219ns [+] starting lcg64... [?] lcg64 duration: 26141304679ns [+] starting xos128p... [?] xos128p duration: 14937033215ns %%% Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: aemerson, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D35221 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307798 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 16 ++++++------ lib/scudo/scudo_tls.h | 2 +- lib/scudo/scudo_utils.cpp | 36 --------------------------- lib/scudo/scudo_utils.h | 57 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 55 insertions(+), 56 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 00fa19218..ec9132f90 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -264,7 +264,7 @@ ScudoQuarantineCache *getQuarantineCache(ScudoThreadContext *ThreadContext) { ScudoQuarantineCache *>(ThreadContext->QuarantineCachePlaceHolder); } -Xorshift128Plus *getPrng(ScudoThreadContext *ThreadContext) { +ScudoPrng *getPrng(ScudoThreadContext *ThreadContext) { return &ThreadContext->Prng; } @@ -283,7 +283,7 @@ struct ScudoAllocator { StaticSpinMutex FallbackMutex; AllocatorCache FallbackAllocatorCache; ScudoQuarantineCache FallbackQuarantineCache; - Xorshift128Plus FallbackPrng; + ScudoPrng FallbackPrng; bool DeallocationTypeMismatch; bool ZeroContents; @@ -333,8 +333,8 @@ struct ScudoAllocator { static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); BackendAllocator.InitCache(&FallbackAllocatorCache); - FallbackPrng.initFromURandom(); - Cookie = FallbackPrng.getNext(); + FallbackPrng.init(); + Cookie = FallbackPrng.getU64(); } // Helper function that checks for a valid Scudo chunk. nullptr isn't. @@ -373,19 +373,19 @@ struct ScudoAllocator { bool FromPrimary = PrimaryAllocator::CanAllocate(AlignedSize, MinAlignment); void *Ptr; - uptr Salt; + u8 Salt; uptr AllocationSize = FromPrimary ? AlignedSize : NeededSize; uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { - Salt = getPrng(ThreadContext)->getNext(); + Salt = getPrng(ThreadContext)->getU8(); Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), AllocationSize, AllocationAlignment, FromPrimary); ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); - Salt = FallbackPrng.getNext(); + Salt = FallbackPrng.getU8(); Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize, AllocationAlignment, FromPrimary); } @@ -612,7 +612,7 @@ static void initScudoInternal(const AllocatorOptions &Options) { void ScudoThreadContext::init() { getBackendAllocator().InitCache(&Cache); - Prng.initFromURandom(); + Prng.init(); memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder)); } diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index f6039bebe..20c49204c 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -30,7 +30,7 @@ namespace __scudo { struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { AllocatorCache Cache; - Xorshift128Plus Prng; + ScudoPrng Prng; uptr QuarantineCachePlaceHolder[4]; void init(); void commitBack(); diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index 31c391946..f7903ff34 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -123,40 +123,4 @@ bool testCPUFeature(CPUFeature Feature) { } #endif // defined(__x86_64__) || defined(__i386__) -// readRetry will attempt to read Count bytes from the Fd specified, and if -// interrupted will retry to read additional bytes to reach Count. -static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) { - ssize_t AmountRead = 0; - while (static_cast(AmountRead) < Count) { - ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead); - if (Result > 0) - AmountRead += Result; - else if (!Result) - break; - else if (errno != EINTR) { - AmountRead = -1; - break; - } - } - return AmountRead; -} - -static void fillRandom(u8 *Data, ssize_t Size) { - int Fd = open("/dev/urandom", O_RDONLY); - if (Fd < 0) { - dieWithMessage("ERROR: failed to open /dev/urandom.\n"); - } - bool Success = readRetry(Fd, Data, Size) == Size; - close(Fd); - if (!Success) { - dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n"); - } -} - -// Seeds the xorshift state with /dev/urandom. -// TODO(kostyak): investigate using getrandom() if available. -void Xorshift128Plus::initFromURandom() { - fillRandom(reinterpret_cast(State), sizeof(State)); -} - } // namespace __scudo diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index 7198476f4..6c6c9d893 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -36,23 +36,58 @@ enum CPUFeature { }; bool testCPUFeature(CPUFeature feature); -// Tiny PRNG based on https://en.wikipedia.org/wiki/Xorshift#xorshift.2B -// The state (128 bits) will be stored in thread local storage. -struct Xorshift128Plus { +INLINE u64 rotl(const u64 X, int K) { + return (X << K) | (X >> (64 - K)); +} + +// XoRoShiRo128+ PRNG (http://xoroshiro.di.unimi.it/). +struct XoRoShiRo128Plus { public: - void initFromURandom(); - u64 getNext() { - u64 x = State[0]; - const u64 y = State[1]; - State[0] = y; - x ^= x << 23; - State[1] = x ^ y ^ (x >> 17) ^ (y >> 26); - return State[1] + y; + void init() { + if (UNLIKELY(!GetRandom(reinterpret_cast(State), sizeof(State)))) { + // Early processes (eg: init) do not have /dev/urandom yet, but we still + // have to provide them with some degree of entropy. Not having a secure + // seed is not as problematic for them, as they are less likely to be + // the target of heap based vulnerabilities exploitation attempts. + State[0] = NanoTime(); + State[1] = 0; + } + fillCache(); } + u8 getU8() { + if (UNLIKELY(isCacheEmpty())) + fillCache(); + const u8 Result = static_cast(CachedBytes & 0xff); + CachedBytes >>= 8; + CachedBytesAvailable--; + return Result; + } + u64 getU64() { return next(); } + private: + u8 CachedBytesAvailable; + u64 CachedBytes; u64 State[2]; + u64 next() { + const u64 S0 = State[0]; + u64 S1 = State[1]; + const u64 Result = S0 + S1; + S1 ^= S0; + State[0] = rotl(S0, 55) ^ S1 ^ (S1 << 14); + State[1] = rotl(S1, 36); + return Result; + } + bool isCacheEmpty() { + return CachedBytesAvailable == 0; + } + void fillCache() { + CachedBytes = next(); + CachedBytesAvailable = sizeof(CachedBytes); + } }; +typedef XoRoShiRo128Plus ScudoPrng; + } // namespace __scudo #endif // SCUDO_UTILS_H_ -- cgit v1.2.1 From 241fc072806134c13fa941788c4e529a35a26e46 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jul 2017 17:11:53 +0000 Subject: Fix the declaration of DARWIN_PREFER_PUBLIC_SDK cmake variable (move before the return). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307815 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTDarwinUtils.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index aaa97e33e..f64697547 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -5,11 +5,12 @@ include(CMakeParseArguments) # the current Xcode. function(find_darwin_sdk_dir var sdk_name) set(DARWIN_${sdk_name}_CACHED_SYSROOT "" CACHE STRING "Darwin SDK path for SDK ${sdk_name}.") + set(DARWIN_PREFER_PUBLIC_SDK OFF CACHE BOOL "Prefer Darwin public SDK, even when an internal SDK is present.") + if(DARWIN_${sdk_name}_CACHED_SYSROOT) set(${var} ${DARWIN_${sdk_name}_CACHED_SYSROOT} PARENT_SCOPE) return() endif() - set(DARWIN_PREFER_PUBLIC_SDK OFF CACHE BOOL "Prefer Darwin public SDK, even when an internal SDK is present.") if(NOT DARWIN_PREFER_PUBLIC_SDK) # Let's first try the internal SDK, otherwise use the public SDK. execute_process( -- cgit v1.2.1 From 880288aa6e7e6499b590fe792a16edec3193645a Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jul 2017 17:30:54 +0000 Subject: On Darwin, start building the TSan dylib for the iOS simulator. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307816 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 4 +--- lib/tsan/rtl/tsan_interceptors_mac.cc | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 0da98b9a4..aecf2e5cd 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -303,9 +303,7 @@ if(APPLE) if(DARWIN_${platform}sim_ARCHS) list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}sim) list(APPEND PROFILE_SUPPORTED_OS ${platform}sim) - if(DARWIN_${platform}_SYSROOT_INTERNAL) - list(APPEND TSAN_SUPPORTED_OS ${platform}sim) - endif() + list(APPEND TSAN_SUPPORTED_OS ${platform}sim) endif() foreach(arch ${DARWIN_${platform}sim_ARCHS}) list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch}) diff --git a/lib/tsan/rtl/tsan_interceptors_mac.cc b/lib/tsan/rtl/tsan_interceptors_mac.cc index f6bf8a0e5..4f1079467 100644 --- a/lib/tsan/rtl/tsan_interceptors_mac.cc +++ b/lib/tsan/rtl/tsan_interceptors_mac.cc @@ -21,7 +21,10 @@ #include "tsan_interface_ann.h" #include + +#if defined(__has_include) && __has_include() #include +#endif // #if defined(__has_include) && __has_include() typedef long long_t; // NOLINT @@ -235,6 +238,8 @@ TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) { REAL(os_lock_unlock)(lock); } +#if defined(__has_include) && __has_include() + TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler, xpc_connection_t connection, xpc_handler_t handler) { SCOPED_TSAN_INTERCEPTOR(xpc_connection_set_event_handler, connection, @@ -287,6 +292,8 @@ TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) { REAL(xpc_connection_cancel)(connection); } +#endif // #if defined(__has_include) && __has_include() + // On macOS, libc++ is always linked dynamically, so intercepting works the // usual way. #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR -- cgit v1.2.1 From 739a23efa7d57772b9a1aa509c3489b520a09c4e Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 12 Jul 2017 19:33:30 +0000 Subject: [builtins] Better Fuchsia support Add Fuchsia support to some builtings and avoid building builtins that are not and will never be used on Fuchsia. Differential Revision: https://reviews.llvm.org/D34075 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307832 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 13 +++++++++---- lib/builtins/int_util.c | 10 ++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 6556e7ac6..f0d3f5071 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -44,7 +44,6 @@ set(GENERIC_SOURCES ashrti3.c bswapdi2.c bswapsi2.c - clear_cache.c clzdi2.c clzsi2.c clzti2.c @@ -68,7 +67,6 @@ set(GENERIC_SOURCES divti3.c divtf3.c divxc3.c - eprintf.c extendsfdf2.c extendhfsf2.c ffsdi2.c @@ -191,11 +189,12 @@ option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" Off) -if(NOT COMPILER_RT_BAREMETAL_BUILD) +if(NOT FUCHSIA AND NOT COMPILER_RT_BAREMETAL_BUILD) set(GENERIC_SOURCES ${GENERIC_SOURCES} emutls.c - enable_execute_stack.c) + enable_execute_stack.c + eprintf.c) endif() if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN) @@ -221,6 +220,12 @@ if (HAVE_UNWIND_H) gcc_personality_v0.c) endif () +if (NOT FUCHSIA) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} + clear_cache.c) +endif() + if (NOT MSVC) set(x86_64_SOURCES x86_64/chkstk.S diff --git a/lib/builtins/int_util.c b/lib/builtins/int_util.c index 420d1e237..de87410db 100644 --- a/lib/builtins/int_util.c +++ b/lib/builtins/int_util.c @@ -45,6 +45,16 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) { __assert_rtn(function, file, line, "libcompiler_rt abort"); } +#elif __Fuchsia__ + +#ifndef _WIN32 +__attribute__((weak)) +__attribute__((visibility("hidden"))) +#endif +void compilerrt_abort_impl(const char *file, int line, const char *function) { + __builtin_trap(); +} + #else /* Get the system definition of abort() */ -- cgit v1.2.1 From b6742fdee94a488c5152e67bc7e0c84afade5236 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jul 2017 20:25:14 +0000 Subject: On Darwin, start building the TSan iOS dylib by default. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307839 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index aecf2e5cd..c329c6a97 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -328,6 +328,7 @@ if(APPLE) if(DARWIN_${platform}_ARCHS) list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}) list(APPEND PROFILE_SUPPORTED_OS ${platform}) + list(APPEND TSAN_SUPPORTED_OS ${platform}) endif() foreach(arch ${DARWIN_${platform}_ARCHS}) list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch}) -- cgit v1.2.1 From 835fb5484f8b11c84eeb366cbc2cd4f60eff1a47 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jul 2017 21:02:48 +0000 Subject: Add explicit CMake targets for ASan/TSan iOS Simulator testing and update the instructions how to run them. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307844 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/CMakeLists.txt | 17 +++++++++++++---- test/tsan/CMakeLists.txt | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 87fa9d138..8bfc15b5c 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -84,12 +84,13 @@ foreach(arch ${ASAN_TEST_ARCH}) endforeach() # iOS and iOS simulator test suites -# These are not added into "check-all", in order to run these tests, you have to -# manually call (from the build directory). They also require that an extra env +# These are not added into "check-all", in order to run these tests, use +# "check-asan-iossim-x86_64" and similar. They also require that an extra env # variable to select which iOS device or simulator to use, e.g.: -# $ SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER=BBE44C1C-8AAA-4000-8D06-91C89ED58172 -# $ ./bin/llvm-lit ./projects/compiler-rt/test/asan/IOSSimI386Config +# SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER="iPhone 6" if(APPLE) + set(EXCLUDE_FROM_ALL ON) + set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) set(ASAN_TEST_IOS "1") pythonize_bool(ASAN_TEST_IOS) @@ -108,6 +109,9 @@ if(APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg ) + add_lit_testsuite(check-asan-iossim-${arch} "AddressSanitizer iOS Simulator ${arch} tests" + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ + DEPENDS ${ASAN_TEST_DEPS}) endforeach() foreach (arch ${DARWIN_ios_ARCHS}) @@ -123,7 +127,12 @@ if(APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg ) + add_lit_testsuite(check-asan-ios-${arch} "AddressSanitizer iOS ${arch} tests" + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ + DEPENDS ${ASAN_TEST_DEPS}) endforeach() + + set(EXCLUDE_FROM_ALL OFF) endif() # Add unit tests. diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index 37b309d64..a68908612 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -43,12 +43,13 @@ foreach(arch ${TSAN_TEST_ARCH}) endforeach() # iOS and iOS simulator test suites -# These are not added into "check-all", in order to run these tests, you have to -# manually call (from the build directory). They also require that an extra env +# These are not added into "check-all", in order to run these tests, use +# "check-tsan-iossim-x86_64" and similar. They also require an extra environment # variable to select which iOS device or simulator to use, e.g.: -# $ SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER=BBE44C1C-8AAA-4000-8D06-91C89ED58172 -# $ ./bin/llvm-lit ./projects/compiler-rt/test/tsan/IOSSimX86_64Config +# SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER="iPhone 6" if(APPLE) + set(EXCLUDE_FROM_ALL ON) + set(TSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) set(TSAN_TEST_IOS "1") pythonize_bool(TSAN_TEST_IOS) @@ -65,6 +66,9 @@ if(APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg ) + add_lit_testsuite(check-tsan-iossim-${arch} "ThreadSanitizer iOS Simulator ${arch} tests" + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ + DEPENDS ${TSAN_TEST_DEPS}) set(arch "arm64") set(TSAN_TEST_IOSSIM "0") @@ -78,6 +82,11 @@ if(APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg ) + add_lit_testsuite(check-tsan-ios-${arch} "ThreadSanitizer iOS Simulator ${arch} tests" + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/ + DEPENDS ${TSAN_TEST_DEPS}) + + set(EXCLUDE_FROM_ALL OFF) endif() if(COMPILER_RT_INCLUDE_TESTS) -- cgit v1.2.1 From 1832be2ba37b2ca197edf7239eead2f5b43ed838 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Wed, 12 Jul 2017 23:28:45 +0000 Subject: [PGO] Add a test for 2-deep loop nest git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307864 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Linux/counter_promo_nest.c | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/profile/Linux/counter_promo_nest.c diff --git a/test/profile/Linux/counter_promo_nest.c b/test/profile/Linux/counter_promo_nest.c new file mode 100644 index 000000000..57e5c61d7 --- /dev/null +++ b/test/profile/Linux/counter_promo_nest.c @@ -0,0 +1,51 @@ +// RUN: rm -fr %t.promo.prof +// RUN: rm -fr %t.nopromo.prof +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen -O2 %s +// RUN: %clang_pgogen=%t.promo.prof/ -o %t.promo.gen.ll -emit-llvm -S -O2 %s +// RUN: cat %t.promo.gen.ll | FileCheck --check-prefix=PROMO %s +// RUN: %run %t.promo.gen +// RUN: llvm-profdata merge -o %t.promo.profdata %t.promo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.promo.profdata > %t.promo.dump +// RUN: %clang_pgogen=%t.nopromo.prof/ -mllvm -do-counter-promotion=false -o %t.nopromo.gen -O2 %s +// RUN: %run %t.nopromo.gen +// RUN: llvm-profdata merge -o %t.nopromo.profdata %t.nopromo.prof/ +// RUN: llvm-profdata show --counts --all-functions %t.nopromo.profdata > %t.nopromo.dump +// RUN: diff %t.promo.profdata %t.nopromo.profdata +int g; +__attribute__((noinline)) void bar() { + g++; +} + +extern int printf(const char*,...); + +int c = 10; + +int main() +// PROMO-LABEL: @main +// PROMO: load{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: load{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: load{{.*}}@__profc_main{{.*}} +// PROMO-NEXT: add +// PROMO-NEXT: store{{.*}}@__profc_main{{.*}} +{ + int i, j, k; + + g = 0; + for (i = 0; i < c; i++) + for (j = 0; j < c; j++) + for (k = 0; k < c; k++) + bar(); + + for (i = 0; i < c; i++) + for (j = 0; j < 10*c;j++) + bar(); + + for (i = 0; i < 100*c; i++) + bar(); + + return 0; +} -- cgit v1.2.1 From b40ba7db5e71b65a5c6a12d997403bf8fbac35f3 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jul 2017 23:29:21 +0000 Subject: [asan] For iOS/AArch64, if the dynamic shadow doesn't fit, restrict the VM space On iOS/AArch64, the address space is very limited and has a dynamic maximum address based on the configuration of the device. We're already using a dynamic shadow, and we find a large-enough "gap" in the VM where we place the shadow memory. In some cases and some device configuration, we might not be able to find a large-enough gap: E.g. if the main executable is linked against a large number of libraries that are not part of the system, these libraries can fragment the address space, and this happens before ASan starts initializing. This patch has a solution, where we have a "backup plan" when we cannot find a large-enough gap: We will restrict the address space (via MmapFixedNoAccess) to a limit, for which the shadow limit will fit. Differential Revision: https://reviews.llvm.org/D35098 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307865 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_internal.h | 1 + lib/asan/asan_linux.cc | 5 +++++ lib/asan/asan_mac.cc | 23 ++++++++++++++++++++ lib/asan/asan_rtl.cc | 10 +-------- lib/asan/asan_win.cc | 12 +++++++++++ lib/sanitizer_common/CMakeLists.txt | 1 + lib/sanitizer_common/sanitizer_common.h | 3 ++- lib/sanitizer_common/sanitizer_linux.cc | 3 ++- lib/sanitizer_common/sanitizer_mac.cc | 17 ++++++++++----- lib/sanitizer_common/sanitizer_mac.h | 2 ++ lib/sanitizer_common/sanitizer_mac_libcdep.cc | 30 +++++++++++++++++++++++++++ lib/sanitizer_common/sanitizer_win.cc | 3 ++- 12 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_mac_libcdep.cc diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 3b7069524..f09bbd83a 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -75,6 +75,7 @@ void NORETURN ShowStatsAndAbort(); void ReplaceSystemMalloc(); // asan_linux.cc / asan_mac.cc / asan_win.cc +uptr FindDynamicShadowStart(); void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index b546bc1a6..6d47ba432 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -77,6 +77,11 @@ void *AsanDoesNotSupportStaticLinkage() { return &_DYNAMIC; // defined in link.h } +uptr FindDynamicShadowStart() { + UNREACHABLE("FindDynamicShadowStart is not available"); + return 0; +} + void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 3c93b26d9..b7af1a586 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -55,6 +55,29 @@ void *AsanDoesNotSupportStaticLinkage() { return 0; } +uptr FindDynamicShadowStart() { + uptr granularity = GetMmapGranularity(); + uptr alignment = 8 * granularity; + uptr left_padding = granularity; + uptr space_size = kHighShadowEnd + left_padding; + + uptr largest_gap_found = 0; + uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, + granularity, &largest_gap_found); + // If the shadow doesn't fit, restrict the address space to make it fit. + if (shadow_start == 0) { + uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); + RestrictMemoryToMaxAddress(new_max_vm); + kHighMemEnd = new_max_vm - 1; + space_size = kHighShadowEnd + left_padding; + shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); + } + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + // No-op. Mac does not support static linkage anyway. void AsanCheckDynamicRTPrereqs() {} diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index d9d7d7e4f..5ae3568ae 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -438,15 +438,7 @@ static void InitializeShadowMemory() { if (shadow_start == kDefaultShadowSentinel) { __asan_shadow_memory_dynamic_address = 0; CHECK_EQ(0, kLowShadowBeg); - - uptr granularity = GetMmapGranularity(); - uptr alignment = 8 * granularity; - uptr left_padding = granularity; - uptr space_size = kHighShadowEnd + left_padding; - - shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity); - CHECK_NE((uptr)0, shadow_start); - CHECK(IsAligned(shadow_start, alignment)); + shadow_start = FindDynamicShadowStart(); } // Update the shadow memory address (potentially) used by instrumentation. __asan_shadow_memory_dynamic_address = shadow_start; diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 26db32465..8a839d913 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -217,6 +217,18 @@ void *AsanDoesNotSupportStaticLinkage() { return 0; } +uptr FindDynamicShadowStart() { + uptr granularity = GetMmapGranularity(); + uptr alignment = 8 * granularity; + uptr left_padding = granularity; + uptr space_size = kHighShadowEnd + left_padding; + uptr shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 26ea071ef..a17bd1299 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -58,6 +58,7 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_coverage_libcdep_new.cc sanitizer_coverage_win_sections.cc sanitizer_linux_libcdep.cc + sanitizer_mac_libcdep.cc sanitizer_posix_libcdep.cc sanitizer_stacktrace_libcdep.cc sanitizer_stoptheworld_linux_libcdep.cc diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index d44c71513..89aae5798 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -107,7 +107,8 @@ bool MprotectNoAccess(uptr addr, uptr size); bool MprotectReadOnly(uptr addr, uptr size); // Find an available address space. -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding); +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found); // Used to check if we can map shadow memory to a fixed location. bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 4f3845f00..a79a2a155 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1671,7 +1671,8 @@ void CheckNoDeepBind(const char *filename, int flag) { #endif } -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found) { UNREACHABLE("FindAvailableMemoryRange is not available"); return 0; } diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index d6e61f207..8df01815f 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -840,7 +840,8 @@ uptr GetMaxVirtualAddress() { uptr FindAvailableMemoryRange(uptr shadow_size, uptr alignment, - uptr left_padding) { + uptr left_padding, + uptr *largest_gap_found) { typedef vm_region_submap_short_info_data_64_t RegionInfo; enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; // Start searching for available memory region past PAGEZERO, which is @@ -851,6 +852,7 @@ uptr FindAvailableMemoryRange(uptr shadow_size, mach_vm_address_t address = start_address; mach_vm_address_t free_begin = start_address; kern_return_t kr = KERN_SUCCESS; + if (largest_gap_found) *largest_gap_found = 0; while (kr == KERN_SUCCESS) { mach_vm_size_t vmsize = 0; natural_t depth = 0; @@ -860,10 +862,15 @@ uptr FindAvailableMemoryRange(uptr shadow_size, (vm_region_info_t)&vminfo, &count); if (free_begin != address) { // We found a free region [free_begin..address-1]. - uptr shadow_address = RoundUpTo((uptr)free_begin + left_padding, - alignment); - if (shadow_address + shadow_size < (uptr)address) { - return shadow_address; + uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); + uptr gap_end = RoundDownTo((uptr)address, alignment); + uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; + if (shadow_size < gap_size) { + return gap_start; + } + + if (largest_gap_found && *largest_gap_found < gap_size) { + *largest_gap_found = gap_size; } } // Move to the next region. diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h index 636d9bfea..3f1c68c86 100644 --- a/lib/sanitizer_common/sanitizer_mac.h +++ b/lib/sanitizer_common/sanitizer_mac.h @@ -36,6 +36,8 @@ MacosVersion GetMacosVersion(); char **GetEnviron(); +void RestrictMemoryToMaxAddress(uptr max_address); + } // namespace __sanitizer extern "C" { diff --git a/lib/sanitizer_common/sanitizer_mac_libcdep.cc b/lib/sanitizer_common/sanitizer_mac_libcdep.cc new file mode 100644 index 000000000..c95daa937 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_mac_libcdep.cc @@ -0,0 +1,30 @@ +//===-- sanitizer_mac_libcdep.cc ------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements OSX-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_mac.h" + +#include + +namespace __sanitizer { + +void RestrictMemoryToMaxAddress(uptr max_address) { + uptr size_to_mmap = GetMaxVirtualAddress() + 1 - max_address; + void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap"); + CHECK(res != MAP_FAILED); +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 89d9cf61c..de01e8d11 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -291,7 +291,8 @@ void DontDumpShadowMemory(uptr addr, uptr length) { // FIXME: add madvise-analog when we move to 64-bits. } -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found) { uptr address = 0; while (true) { MEMORY_BASIC_INFORMATION info; -- cgit v1.2.1 From 39ef995bef47dcae535ae2d528013c20cf03896b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 12 Jul 2017 23:59:22 +0000 Subject: [asan] Avoid recompilation of the same code in the test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307868 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/allow_user_segv.cc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc index fee589430..4bec6ad89 100644 --- a/test/asan/TestCases/Posix/allow_user_segv.cc +++ b/test/asan/TestCases/Posix/allow_user_segv.cc @@ -1,22 +1,21 @@ // Regression test for // https://code.google.com/p/address-sanitizer/issues/detail?id=180 -// 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 +// clang-format off +// RUN: %clangxx_asan -O0 %s -o %t -// 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: %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// 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 +// RUN: %env_asan_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_asan_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_asan_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 - -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_asan_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_asan_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_asan_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// clang-format on #include #include -- cgit v1.2.1 From c071d1bfb8a5e2534358b84802739b7884eb921c Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Thu, 13 Jul 2017 00:22:01 +0000 Subject: Fix broken test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307869 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Linux/counter_promo_nest.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/profile/Linux/counter_promo_nest.c b/test/profile/Linux/counter_promo_nest.c index 57e5c61d7..0792f0c76 100644 --- a/test/profile/Linux/counter_promo_nest.c +++ b/test/profile/Linux/counter_promo_nest.c @@ -28,9 +28,6 @@ int main() // PROMO-NEXT: load{{.*}}@__profc_main{{.*}} // PROMO-NEXT: add // PROMO-NEXT: store{{.*}}@__profc_main{{.*}} -// PROMO-NEXT: load{{.*}}@__profc_main{{.*}} -// PROMO-NEXT: add -// PROMO-NEXT: store{{.*}}@__profc_main{{.*}} { int i, j, k; -- cgit v1.2.1 From 5ebaa70bf9a2b2a8faa0cf0c19159d4f8e24c01c Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 13 Jul 2017 02:56:24 +0000 Subject: [compiler-rt][X86] Match the detection of cpu's for __cpu_model to the latest version of gcc Summary: We were missing many feature flags that newer gcc supports and we had our own set of feature flags that gcc didnt' support that were overlapping. Clang's implementation assumes gcc's features list so a mismatch here is problematic. I've also matched the cpu type/subtype lists with gcc and removed all the cpus that gcc doesn't support. I've also removed the fallback autodetection logic that was taken from Host.cpp. It was the main reason we had extra feature flags relative to gcc. I don't think gcc does this in libgcc. Once this support is in place we can consider implementing __builtin_cpu_is in clang. This could also be needed for function dispatching that Erich Keane is working on. Reviewers: echristo, asbirlea, RKSimon, erichkeane, zvi Reviewed By: asbirlea Subscribers: dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D35214 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307878 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 418 ++++++++++++----------------------------------- 1 file changed, 109 insertions(+), 309 deletions(-) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 1b03f0f78..c6b30eda0 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -44,29 +44,15 @@ enum ProcessorVendors { }; enum ProcessorTypes { - INTEL_ATOM = 1, + INTEL_BONNELL = 1, INTEL_CORE2, INTEL_COREI7, AMDFAM10H, AMDFAM15H, - INTEL_i386, - INTEL_i486, - INTEL_PENTIUM, - INTEL_PENTIUM_PRO, - INTEL_PENTIUM_II, - INTEL_PENTIUM_III, - INTEL_PENTIUM_IV, - INTEL_PENTIUM_M, - INTEL_CORE_DUO, - INTEL_XEONPHI, - INTEL_X86_64, - INTEL_NOCONA, - INTEL_PRESCOTT, - AMD_i486, - AMDPENTIUM, - AMDATHLON, - AMDFAM14H, - AMDFAM16H, + INTEL_SILVERMONT, + INTEL_KNL, + AMD_BTVER1, + AMD_BTVER2, AMDFAM17H, CPU_TYPE_MAX }; @@ -80,33 +66,14 @@ enum ProcessorSubtypes { AMDFAM10H_ISTANBUL, AMDFAM15H_BDVER1, AMDFAM15H_BDVER2, - INTEL_PENTIUM_MMX, - INTEL_CORE2_65, - INTEL_CORE2_45, + AMDFAM15H_BDVER3, + AMDFAM15H_BDVER4, + AMDFAM17H_ZNVER1, INTEL_COREI7_IVYBRIDGE, INTEL_COREI7_HASWELL, INTEL_COREI7_BROADWELL, INTEL_COREI7_SKYLAKE, INTEL_COREI7_SKYLAKE_AVX512, - INTEL_ATOM_BONNELL, - INTEL_ATOM_SILVERMONT, - INTEL_KNIGHTS_LANDING, - AMDPENTIUM_K6, - AMDPENTIUM_K62, - AMDPENTIUM_K63, - AMDPENTIUM_GEODE, - AMDATHLON_TBIRD, - AMDATHLON_MP, - AMDATHLON_XP, - AMDATHLON_K8SSE3, - AMDATHLON_OPTERON, - AMDATHLON_FX, - AMDATHLON_64, - AMD_BTVER1, - AMD_BTVER2, - AMDFAM15H_BDVER3, - AMDFAM15H_BDVER4, - AMDFAM17H_ZNVER1, CPU_SUBTYPE_MAX }; @@ -122,11 +89,26 @@ enum ProcessorFeatures { FEATURE_SSE4_2, FEATURE_AVX, FEATURE_AVX2, - FEATURE_AVX512, - FEATURE_AVX512SAVE, - FEATURE_MOVBE, - FEATURE_ADX, - FEATURE_EM64T + FEATURE_SSE4_A, + FEATURE_FMA4, + FEATURE_XOP, + FEATURE_FMA, + FEATURE_AVX512F, + FEATURE_BMI, + FEATURE_BMI2, + FEATURE_AES, + FEATURE_PCLMUL, + FEATURE_AVX512VL, + FEATURE_AVX512BW, + FEATURE_AVX512DQ, + FEATURE_AVX512CD, + FEATURE_AVX512ER, + FEATURE_AVX512PF, + FEATURE_AVX512VBMI, + FEATURE_AVX512IFMA, + FEATURE_AVX5124VNNIW, + FEATURE_AVX5124FMAPS, + FEATURE_AVX512VPOPCNTDQ }; // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). @@ -298,78 +280,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, if (Brand_id != 0) return; switch (Family) { - case 3: - *Type = INTEL_i386; - break; - case 4: - switch (Model) { - case 0: // Intel486 DX processors - case 1: // Intel486 DX processors - case 2: // Intel486 SX processors - case 3: // Intel487 processors, IntelDX2 OverDrive processors, - // IntelDX2 processors - case 4: // Intel486 SL processor - case 5: // IntelSX2 processors - case 7: // Write-Back Enhanced IntelDX2 processors - case 8: // IntelDX4 OverDrive processors, IntelDX4 processors - default: - *Type = INTEL_i486; - break; - } - break; - case 5: - switch (Model) { - case 1: // Pentium OverDrive processor for Pentium processor (60, 66), - // Pentium processors (60, 66) - case 2: // Pentium OverDrive processor for Pentium processor (75, 90, - // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, - // 150, 166, 200) - case 3: // Pentium OverDrive processors for Intel486 processor-based - // systems - *Type = INTEL_PENTIUM; - break; - case 4: // Pentium OverDrive processor with MMX technology for Pentium - // processor (75, 90, 100, 120, 133), Pentium processor with - // MMX technology (166, 200) - *Type = INTEL_PENTIUM; - *Subtype = INTEL_PENTIUM_MMX; - break; - default: - *Type = INTEL_PENTIUM; - break; - } - break; case 6: switch (Model) { - case 0x01: // Pentium Pro processor - *Type = INTEL_PENTIUM_PRO; - break; - case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, - // model 03 - case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, - // model 05, and Intel Celeron processor, model 05 - case 0x06: // Celeron processor, model 06 - *Type = INTEL_PENTIUM_II; - break; - case 0x07: // Pentium III processor, model 07, and Pentium III Xeon - // processor, model 07 - case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, - // model 08, and Celeron processor, model 08 - case 0x0a: // Pentium III Xeon processor, model 0Ah - case 0x0b: // Pentium III processor, model 0Bh - *Type = INTEL_PENTIUM_III; - break; - case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. - case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model - // 0Dh. All processors are manufactured using the 90 nm process. - case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 - // Integrated Processor with Intel QuickAssist Technology - *Type = INTEL_PENTIUM_M; - break; - case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model - // 0Eh. All processors are manufactured using the 65 nm process. - *Type = INTEL_CORE_DUO; - break; // yonah case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile // processor, Intel Core 2 Quad processor, Intel Core 2 Quad // mobile processor, Intel Core 2 Extreme processor, Intel @@ -377,9 +289,6 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // 0Fh. All processors are manufactured using the 65 nm process. case 0x16: // Intel Celeron processor model 16h. All processors are // manufactured using the 65 nm process - *Type = INTEL_CORE2; // "core2" - *Subtype = INTEL_CORE2_65; - break; case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. // @@ -387,7 +296,6 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x1d: // Intel Xeon processor MP. All processors are manufactured using // the 45 nm process. *Type = INTEL_CORE2; // "penryn" - *Subtype = INTEL_CORE2_45; break; case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. @@ -455,8 +363,7 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x27: // 32 nm Atom Medfield case 0x35: // 32 nm Atom Midview case 0x36: // 32 nm Atom Midview - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_BONNELL; + *Type = INTEL_BONNELL; break; // "bonnell" // Atom Silvermont codes from the Intel software optimization guide. @@ -466,120 +373,19 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x5a: case 0x5d: case 0x4c: // really airmont - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_SILVERMONT; + *Type = INTEL_SILVERMONT; break; // "silvermont" case 0x57: - *Type = INTEL_XEONPHI; // knl - *Subtype = INTEL_KNIGHTS_LANDING; + *Type = INTEL_KNL; // knl break; - default: // Unknown family 6 CPU, try to guess. - if (Features & (1 << FEATURE_AVX512)) { - *Type = INTEL_XEONPHI; // knl - *Subtype = INTEL_KNIGHTS_LANDING; - break; - } - if (Features & (1 << FEATURE_ADX)) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_BROADWELL; - break; - } - if (Features & (1 << FEATURE_AVX2)) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_HASWELL; - break; - } - if (Features & (1 << FEATURE_AVX)) { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_SANDYBRIDGE; - break; - } - if (Features & (1 << FEATURE_SSE4_2)) { - if (Features & (1 << FEATURE_MOVBE)) { - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_SILVERMONT; - } else { - *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_NEHALEM; - } - break; - } - if (Features & (1 << FEATURE_SSE4_1)) { - *Type = INTEL_CORE2; // "penryn" - *Subtype = INTEL_CORE2_45; - break; - } - if (Features & (1 << FEATURE_SSSE3)) { - if (Features & (1 << FEATURE_MOVBE)) { - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_BONNELL; // "bonnell" - } else { - *Type = INTEL_CORE2; // "core2" - *Subtype = INTEL_CORE2_65; - } - break; - } - if (Features & (1 << FEATURE_EM64T)) { - *Type = INTEL_X86_64; - break; // x86-64 - } - if (Features & (1 << FEATURE_SSE2)) { - *Type = INTEL_PENTIUM_M; - break; - } - if (Features & (1 << FEATURE_SSE)) { - *Type = INTEL_PENTIUM_III; - break; - } - if (Features & (1 << FEATURE_MMX)) { - *Type = INTEL_PENTIUM_II; - break; - } - *Type = INTEL_PENTIUM_PRO; + default: // Unknown family 6 CPU. break; - } break; - case 15: { - switch (Model) { - case 0: // Pentium 4 processor, Intel Xeon processor. All processors are - // model 00h and manufactured using the 0.18 micron process. - case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon - // processor MP, and Intel Celeron processor. All processors are - // model 01h and manufactured using the 0.18 micron process. - case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, - // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron - // processor, and Mobile Intel Celeron processor. All processors - // are model 02h and manufactured using the 0.13 micron process. - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); - break; - - case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D - // processor. All processors are model 03h and manufactured using - // the 90 nm process. - case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, - // Pentium D processor, Intel Xeon processor, Intel Xeon - // processor MP, Intel Celeron D processor. All processors are - // model 04h and manufactured using the 90 nm process. - case 6: // Pentium 4 processor, Pentium D processor, Pentium processor - // Extreme Edition, Intel Xeon processor, Intel Xeon processor - // MP, Intel Celeron D processor. All processors are model 06h - // and manufactured using the 65 nm process. - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); - break; - - default: - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); - break; } - break; - } default: - break; /*"generic"*/ + break; // Unknown. } } @@ -590,62 +396,6 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, // appears to be no way to generate the wide variety of AMD-specific targets // from the information returned from CPUID. switch (Family) { - case 4: - *Type = AMD_i486; - break; - case 5: - *Type = AMDPENTIUM; - switch (Model) { - case 6: - case 7: - *Subtype = AMDPENTIUM_K6; - break; // "k6" - case 8: - *Subtype = AMDPENTIUM_K62; - break; // "k6-2" - case 9: - case 13: - *Subtype = AMDPENTIUM_K63; - break; // "k6-3" - case 10: - *Subtype = AMDPENTIUM_GEODE; - break; // "geode" - } - break; - case 6: - *Type = AMDATHLON; - switch (Model) { - case 4: - *Subtype = AMDATHLON_TBIRD; - break; // "athlon-tbird" - case 6: - case 7: - case 8: - *Subtype = AMDATHLON_MP; - break; // "athlon-mp" - case 10: - *Subtype = AMDATHLON_XP; - break; // "athlon-xp" - } - break; - case 15: - *Type = AMDATHLON; - if (Features & (1 << FEATURE_SSE3)) { - *Subtype = AMDATHLON_K8SSE3; - break; // "k8-sse3" - } - switch (Model) { - case 1: - *Subtype = AMDATHLON_OPTERON; - break; // "opteron" - case 5: - *Subtype = AMDATHLON_FX; - break; // "athlon-fx"; also opteron - default: - *Subtype = AMDATHLON_64; - break; // "athlon64" - } - break; case 16: *Type = AMDFAM10H; // "amdfam10" switch (Model) { @@ -661,14 +411,13 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, } break; case 20: - *Type = AMDFAM14H; - *Subtype = AMD_BTVER1; + *Type = AMD_BTVER1; break; // "btver1"; case 21: *Type = AMDFAM15H; if (Model >= 0x60 && Model <= 0x7f) { *Subtype = AMDFAM15H_BDVER4; - break; // "bdver4"; 50h-6Fh: Excavator + break; // "bdver4"; 60h-7Fh: Excavator } if (Model >= 0x30 && Model <= 0x3f) { *Subtype = AMDFAM15H_BDVER3; @@ -695,18 +444,36 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, } } -static unsigned getAvailableFeatures(unsigned ECX, unsigned EDX, - unsigned MaxLeaf) { +static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, + unsigned *FeaturesOut) { unsigned Features = 0; unsigned EAX, EBX; - Features |= (((EDX >> 23) & 1) << FEATURE_MMX); - Features |= (((EDX >> 25) & 1) << FEATURE_SSE); - Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); - Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); - Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); - Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); - Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); - Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); + + if ((EDX >> 15) & 1) + Features |= 1 << FEATURE_CMOV; + if ((EDX >> 23) & 1) + Features |= 1 << FEATURE_MMX; + if ((EDX >> 25) & 1) + Features |= 1 << FEATURE_SSE; + if ((EDX >> 26) & 1) + Features |= 1 << FEATURE_SSE2; + + if ((ECX >> 0) & 1) + Features |= 1 << FEATURE_SSE3; + if ((ECX >> 1) & 1) + Features |= 1 << FEATURE_PCLMUL; + if ((ECX >> 9) & 1) + Features |= 1 << FEATURE_SSSE3; + if ((ECX >> 12) & 1) + Features |= 1 << FEATURE_FMA; + if ((ECX >> 19) & 1) + Features |= 1 << FEATURE_SSE4_1; + if ((ECX >> 20) & 1) + Features |= 1 << FEATURE_SSE4_2; + if ((ECX >> 23) & 1) + Features |= 1 << FEATURE_POPCNT; + if ((ECX >> 25) & 1) + Features |= 1 << FEATURE_AES; // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context @@ -715,26 +482,59 @@ static unsigned getAvailableFeatures(unsigned ECX, unsigned EDX, bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + + if (HasAVX) + Features |= 1 << FEATURE_AVX; + bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); - bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); - bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); - bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); - Features |= (HasAVX << FEATURE_AVX); - Features |= (HasAVX2 << FEATURE_AVX2); - Features |= (HasAVX512 << FEATURE_AVX512); - Features |= (HasAVX512Save << FEATURE_AVX512SAVE); - Features |= (HasADX << FEATURE_ADX); + + if (HasLeaf7 && ((EBX >> 3) & 1)) + Features |= 1 << FEATURE_BMI; + if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) + Features |= 1 << FEATURE_AVX2; + if (HasLeaf7 && ((EBX >> 9) & 1)) + Features |= 1 << FEATURE_BMI2; + if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512F; + if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512DQ; + if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512IFMA; + if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512PF; + if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512ER; + if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512CD; + if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512BW; + if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VL; + + if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VBMI; + if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VPOPCNTDQ; + + if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX5124VNNIW; + if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX5124FMAPS; unsigned MaxExtLevel; getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - if (HasExtLeaf1) - Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); - - return Features; + if (HasExtLeaf1 && ((ECX >> 6) & 1)) + Features |= 1 << FEATURE_SSE4_A; + if (HasExtLeaf1 && ((ECX >> 11) & 1)) + Features |= 1 << FEATURE_XOP; + if (HasExtLeaf1 && ((ECX >> 16) & 1)) + Features |= 1 << FEATURE_FMA4; + + *FeaturesOut = Features; } #if defined(HAVE_INIT_PRIORITY) @@ -787,7 +587,7 @@ __cpu_indicator_init(void) { Brand_id = EBX & 0xff; /* Find available features. */ - Features = getAvailableFeatures(ECX, EDX, MaxLeaf); + getAvailableFeatures(ECX, EDX, MaxLeaf, &Features); __cpu_model.__cpu_features[0] = Features; if (Vendor == SIG_INTEL) { -- cgit v1.2.1 From 4b50dbfc29cbed04215a5c5e062bcfab488b29ec Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 13 Jul 2017 20:02:45 +0000 Subject: For Darwin's GetTaskInfoMaxAddress, define the real structure with real fields to avoid confusion. NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307945 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_mac.cc | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 8df01815f..1edd4157f 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -805,14 +805,35 @@ char **GetArgv() { // fields only available in 10.12+. Declare the struct manually to be able to // build against older SDKs. struct __sanitizer_task_vm_info { - uptr _unused[(SANITIZER_WORDSIZE == 32) ? 20 : 19]; - uptr min_address; - uptr max_address; + mach_vm_size_t virtual_size; + integer_t region_count; + integer_t page_size; + mach_vm_size_t resident_size; + mach_vm_size_t resident_size_peak; + mach_vm_size_t device; + mach_vm_size_t device_peak; + mach_vm_size_t internal; + mach_vm_size_t internal_peak; + mach_vm_size_t external; + mach_vm_size_t external_peak; + mach_vm_size_t reusable; + mach_vm_size_t reusable_peak; + mach_vm_size_t purgeable_volatile_pmap; + mach_vm_size_t purgeable_volatile_resident; + mach_vm_size_t purgeable_volatile_virtual; + mach_vm_size_t compressed; + mach_vm_size_t compressed_peak; + mach_vm_size_t compressed_lifetime; + mach_vm_size_t phys_footprint; + mach_vm_address_t min_address; + mach_vm_address_t max_address; }; +#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ + (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) uptr GetTaskInfoMaxAddress() { - __sanitizer_task_vm_info vm_info = {{0}, 0, 0}; - mach_msg_type_number_t count = sizeof(vm_info) / sizeof(int); + __sanitizer_task_vm_info vm_info = {}; + mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); if (err == 0) { return vm_info.max_address - 1; -- cgit v1.2.1 From e985282fd0ee3c143f62b3faf920341d0575b265 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 13 Jul 2017 20:55:41 +0000 Subject: [ubsan] Teach the pointer overflow check that "p - <= p" (compiler-rt) Compiler-rt changes associated with: D34121 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307956 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 15 ++++++++++----- .../ubsan/TestCases/Pointer/unsigned-index-expression.cpp | 15 +++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 185752719..75a4490a1 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -573,14 +573,19 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ScopedReport R(Opts, Loc, ET); - if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) - Diag(Loc, DL_Error, "unsigned pointer index expression result is %0, " - "preceding its base %1") - << (void *)Result << (void *)Base; - else + if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { + if (Base > Result) + Diag(Loc, DL_Error, "addition of unsigned offset to %0 overflowed to %1") + << (void *)Base << (void *)Result; + else + Diag(Loc, DL_Error, + "subtraction of unsigned offset from %0 overflowed to %1") + << (void *)Base << (void *)Result; + } else { Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1") << (void *)Base << (void *)Result; + } } void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, diff --git a/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp b/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp index 991374b5a..0002c713f 100644 --- a/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp +++ b/test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp @@ -1,13 +1,20 @@ -// RUN: %clangxx -fsanitize=pointer-overflow %s -o %t +// RUN: %clangxx -std=c++11 -fsanitize=pointer-overflow %s -o %t // RUN: %t 2>&1 | FileCheck %s int main(int argc, char *argv[]) { char c; char *p = &c; - unsigned long long offset = -1; + unsigned long long neg_1 = -1; - // CHECK: unsigned-index-expression.cpp:[[@LINE+1]]:15: runtime error: unsigned pointer index expression result is 0x{{.*}}, preceding its base 0x{{.*}} - char *q = p + offset; + // CHECK: unsigned-index-expression.cpp:[[@LINE+1]]:15: runtime error: addition of unsigned offset to 0x{{.*}} overflowed to 0x{{.*}} + char *q = p + neg_1; + + // CHECK: unsigned-index-expression.cpp:[[@LINE+1]]:16: runtime error: subtraction of unsigned offset from 0x{{.*}} overflowed to 0x{{.*}} + char *q1 = p - neg_1; + + // CHECK: unsigned-index-expression.cpp:[[@LINE+2]]:16: runtime error: pointer index expression with base 0x{{0*}} overflowed to 0x{{.*}} + char *n = nullptr; + char *q2 = n - 1ULL; return 0; } -- cgit v1.2.1 From 4b8b9fa3562b063d33afb711ebc8e532904eae03 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 13 Jul 2017 21:01:19 +0000 Subject: [scudo] Do not grab a cache for secondary allocation & per related changes Summary: Secondary backed allocations do not require a cache. While it's not necessary an issue when each thread has its cache, it becomes one with a shared pool of caches (Android), as a Secondary backed allocation or deallocation holds a cache that could be useful to another thread doing a Primary backed allocation. We introduce an additional PRNG and its mutex (to avoid contention with the Fallback one for Primary allocations) that will provide the `Salt` needed for Secondary backed allocations. I changed some of the code in a way that feels more readable to me (eg: using some values directly rather than going through ternary assigned variables, using directly `true`/`false` rather than `FromPrimary`). I will let reviewers decide if it actually is. An additional change is to mark `CheckForCallocOverflow` as `UNLIKELY`. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35358 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307958 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 100 +++++++++++++++++++++-------------- lib/scudo/scudo_allocator_combined.h | 34 +++++++----- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index ec9132f90..057db6281 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -73,7 +73,7 @@ struct ScudoChunk : UnpackedHeader { // beginning of the user data to the end of the backend allocated chunk. uptr getUsableSize(UnpackedHeader *Header) { uptr Size = - getBackendAllocator().GetActuallyAllocatedSize(getAllocBeg(Header), + getBackendAllocator().getActuallyAllocatedSize(getAllocBeg(Header), Header->FromPrimary); if (Size == 0) return 0; @@ -232,7 +232,10 @@ struct QuarantineCallback { } Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(&Header); - getBackendAllocator().Deallocate(Cache_, Ptr, Header.FromPrimary); + if (Header.FromPrimary) + getBackendAllocator().deallocatePrimary(Cache_, Ptr); + else + getBackendAllocator().deallocateSecondary(Ptr); } // Internal quarantine allocation and deallocation functions. We first check @@ -240,11 +243,11 @@ struct QuarantineCallback { // TODO(kostyak): figure out the best way to protect the batches. COMPILER_CHECK(sizeof(QuarantineBatch) < SizeClassMap::kMaxSize); void *Allocate(uptr Size) { - return getBackendAllocator().Allocate(Cache_, Size, MinAlignment, true); + return getBackendAllocator().allocatePrimary(Cache_, Size); } void Deallocate(void *Ptr) { - getBackendAllocator().Deallocate(Cache_, Ptr, true); + getBackendAllocator().deallocatePrimary(Cache_, Ptr); } AllocatorCache *Cache_; @@ -277,6 +280,9 @@ struct ScudoAllocator { ScudoBackendAllocator BackendAllocator; ScudoQuarantine AllocatorQuarantine; + StaticSpinMutex GlobalPrngMutex; + ScudoPrng GlobalPrng; + // The fallback caches are used when the thread local caches have been // 'detroyed' on thread tear-down. They are protected by a Mutex as they can // be accessed by different threads. @@ -303,10 +309,10 @@ struct ScudoAllocator { // result, the maximum offset will be at most the maximum alignment for the // last size class minus the header size, in multiples of MinAlignment. UnpackedHeader Header = {}; - uptr MaxPrimaryAlignment = 1 << MostSignificantSetBitIndex( - SizeClassMap::kMaxSize - MinAlignment); - uptr MaxOffset = (MaxPrimaryAlignment - AlignedChunkHeaderSize) >> - MinAlignmentLog; + uptr MaxPrimaryAlignment = + 1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment); + uptr MaxOffset = + (MaxPrimaryAlignment - AlignedChunkHeaderSize) >> MinAlignmentLog; Header.Offset = MaxOffset; if (Header.Offset != MaxOffset) { dieWithMessage("ERROR: the maximum possible offset doesn't fit in the " @@ -328,13 +334,14 @@ struct ScudoAllocator { DeleteSizeMismatch = Options.DeleteSizeMismatch; ZeroContents = Options.ZeroContents; SetAllocatorMayReturnNull(Options.MayReturnNull); - BackendAllocator.Init(Options.ReleaseToOSIntervalMs); + BackendAllocator.init(Options.ReleaseToOSIntervalMs); AllocatorQuarantine.Init( static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); - BackendAllocator.InitCache(&FallbackAllocatorCache); + GlobalPrng.init(); + Cookie = GlobalPrng.getU64(); + BackendAllocator.initCache(&FallbackAllocatorCache); FallbackPrng.init(); - Cookie = FallbackPrng.getU64(); } // Helper function that checks for a valid Scudo chunk. nullptr isn't. @@ -374,28 +381,36 @@ struct ScudoAllocator { void *Ptr; u8 Salt; - uptr AllocationSize = FromPrimary ? AlignedSize : NeededSize; - uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; - ScudoThreadContext *ThreadContext = getThreadContextAndLock(); - if (LIKELY(ThreadContext)) { - Salt = getPrng(ThreadContext)->getU8(); - Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), - AllocationSize, AllocationAlignment, - FromPrimary); - ThreadContext->unlock(); + uptr AllocSize; + if (FromPrimary) { + AllocSize = AlignedSize; + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); + if (LIKELY(ThreadContext)) { + Salt = getPrng(ThreadContext)->getU8(); + Ptr = BackendAllocator.allocatePrimary(getAllocatorCache(ThreadContext), + AllocSize); + ThreadContext->unlock(); + } else { + SpinMutexLock l(&FallbackMutex); + Salt = FallbackPrng.getU8(); + Ptr = BackendAllocator.allocatePrimary(&FallbackAllocatorCache, + AllocSize); + } } else { - SpinMutexLock l(&FallbackMutex); - Salt = FallbackPrng.getU8(); - Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize, - AllocationAlignment, FromPrimary); + { + SpinMutexLock l(&GlobalPrngMutex); + Salt = GlobalPrng.getU8(); + } + AllocSize = NeededSize; + Ptr = BackendAllocator.allocateSecondary(AllocSize, Alignment); } if (UNLIKELY(!Ptr)) return FailureHandler::OnOOM(); // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && FromPrimary) - memset(Ptr, 0, - BackendAllocator.GetActuallyAllocatedSize(Ptr, FromPrimary)); + memset(Ptr, 0, BackendAllocator.getActuallyAllocatedSize( + Ptr, /*FromPrimary=*/true)); UnpackedHeader Header = {}; uptr AllocBeg = reinterpret_cast(Ptr); @@ -409,11 +424,11 @@ struct ScudoAllocator { uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg; Header.Offset = Offset >> MinAlignmentLog; } - CHECK_LE(UserBeg + Size, AllocBeg + AllocationSize); + CHECK_LE(UserBeg + Size, AllocBeg + AllocSize); Header.State = ChunkAllocated; Header.AllocType = Type; if (FromPrimary) { - Header.FromPrimary = FromPrimary; + Header.FromPrimary = 1; Header.SizeOrUnusedBytes = Size; } else { // The secondary fits the allocations to a page, so the amount of unused @@ -424,7 +439,7 @@ struct ScudoAllocator { if (TrailingBytes) Header.SizeOrUnusedBytes = PageSize - TrailingBytes; } - Header.Salt = static_cast(Salt); + Header.Salt = Salt; getScudoChunk(UserBeg)->storeHeader(&Header); void *UserPtr = reinterpret_cast(UserBeg); // if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(UserPtr, Size); @@ -442,15 +457,18 @@ struct ScudoAllocator { if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); - ScudoThreadContext *ThreadContext = getThreadContextAndLock(); - if (LIKELY(ThreadContext)) { - getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr, - FromPrimary); - ThreadContext->unlock(); + if (FromPrimary) { + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); + if (LIKELY(ThreadContext)) { + getBackendAllocator().deallocatePrimary( + getAllocatorCache(ThreadContext), Ptr); + ThreadContext->unlock(); + } else { + SpinMutexLock Lock(&FallbackMutex); + getBackendAllocator().deallocatePrimary(&FallbackAllocatorCache, Ptr); + } } else { - SpinMutexLock Lock(&FallbackMutex); - getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr, - FromPrimary); + getBackendAllocator().deallocateSecondary(Ptr); } } else { UnpackedHeader NewHeader = *Header; @@ -580,7 +598,7 @@ struct ScudoAllocator { void *calloc(uptr NMemB, uptr Size) { initThreadMaybe(); - if (CheckForCallocOverflow(NMemB, Size)) + if (UNLIKELY(CheckForCallocOverflow(NMemB, Size))) return FailureHandler::OnBadRequest(); return allocate(NMemB * Size, MinAlignment, FromMalloc, true); } @@ -589,13 +607,13 @@ struct ScudoAllocator { AllocatorCache *Cache = getAllocatorCache(ThreadContext); AllocatorQuarantine.Drain(getQuarantineCache(ThreadContext), QuarantineCallback(Cache)); - BackendAllocator.DestroyCache(Cache); + BackendAllocator.destroyCache(Cache); } uptr getStats(AllocatorStat StatType) { initThreadMaybe(); uptr stats[AllocatorStatCount]; - BackendAllocator.GetStats(stats); + BackendAllocator.getStats(stats); return stats[StatType]; } }; @@ -611,7 +629,7 @@ static void initScudoInternal(const AllocatorOptions &Options) { } void ScudoThreadContext::init() { - getBackendAllocator().InitCache(&Cache); + getBackendAllocator().initCache(&Cache); Prng.init(); memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder)); } diff --git a/lib/scudo/scudo_allocator_combined.h b/lib/scudo/scudo_allocator_combined.h index 818272868..7599c12ab 100644 --- a/lib/scudo/scudo_allocator_combined.h +++ b/lib/scudo/scudo_allocator_combined.h @@ -23,41 +23,47 @@ template class ScudoCombinedAllocator { public: - void Init(s32 ReleaseToOSIntervalMs) { + void init(s32 ReleaseToOSIntervalMs) { Primary.Init(ReleaseToOSIntervalMs); Secondary.Init(); Stats.Init(); } - void *Allocate(AllocatorCache *Cache, uptr Size, uptr Alignment, - bool FromPrimary) { - if (FromPrimary) - return Cache->Allocate(&Primary, Primary.ClassID(Size)); + // Primary allocations are always MinAlignment aligned, and as such do not + // require an Alignment parameter. + void *allocatePrimary(AllocatorCache *Cache, uptr Size) { + return Cache->Allocate(&Primary, Primary.ClassID(Size)); + } + + // Secondary allocations do not require a Cache, but do require an Alignment + // parameter. + void *allocateSecondary(uptr Size, uptr Alignment) { return Secondary.Allocate(&Stats, Size, Alignment); } - void Deallocate(AllocatorCache *Cache, void *Ptr, bool FromPrimary) { - if (FromPrimary) - Cache->Deallocate(&Primary, Primary.GetSizeClass(Ptr), Ptr); - else - Secondary.Deallocate(&Stats, Ptr); + void deallocatePrimary(AllocatorCache *Cache, void *Ptr) { + Cache->Deallocate(&Primary, Primary.GetSizeClass(Ptr), Ptr); + } + + void deallocateSecondary(void *Ptr) { + Secondary.Deallocate(&Stats, Ptr); } - uptr GetActuallyAllocatedSize(void *Ptr, bool FromPrimary) { + uptr getActuallyAllocatedSize(void *Ptr, bool FromPrimary) { if (FromPrimary) return PrimaryAllocator::ClassIdToSize(Primary.GetSizeClass(Ptr)); return Secondary.GetActuallyAllocatedSize(Ptr); } - void InitCache(AllocatorCache *Cache) { + void initCache(AllocatorCache *Cache) { Cache->Init(&Stats); } - void DestroyCache(AllocatorCache *Cache) { + void destroyCache(AllocatorCache *Cache) { Cache->Destroy(&Primary, &Stats); } - void GetStats(AllocatorStatCounters StatType) const { + void getStats(AllocatorStatCounters StatType) const { Stats.Get(StatType); } -- cgit v1.2.1 From 8a5e425a68de4d2c80ff00a97bbcb3722a4716da Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 13 Jul 2017 21:59:01 +0000 Subject: Fix sanitizer build against latest glibc Summary: libsanitizer doesn't build against latest glibc anymore, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81066 for details. One of the changes is that stack_t changed from typedef struct sigaltstack { ... } stack_t; to typedef struct { ... } stack_t; for conformance reasons. And the other change is that the glibc internal __need_res_state macro is now ignored, so when doing ``` #define __need_res_state #include ``` the effect is now the same as just ``` #include ``` and thus one doesn't get just the ``` struct __res_state { ... }; ``` definition, but newly also the ``` extern struct __res_state *__res_state(void) __attribute__ ((__const__)); ``` prototype. So __res_state is no longer a type, but a function. Reviewers: kcc, ygribov Reviewed By: kcc Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D35246 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@307969 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 3 +-- lib/sanitizer_common/sanitizer_linux.h | 4 +--- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc | 2 +- lib/tsan/rtl/tsan_platform_linux.cc | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index a79a2a155..8c3c1e5d6 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -629,8 +629,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { } #endif -uptr internal_sigaltstack(const struct sigaltstack *ss, - struct sigaltstack *oss) { +uptr internal_sigaltstack(const void *ss, void *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index ee336f7dd..11cad6b80 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -21,7 +21,6 @@ #include "sanitizer_platform_limits_posix.h" struct link_map; // Opaque type returned by dlopen(). -struct sigaltstack; namespace __sanitizer { // Dirent structure for getdents(). Note that this structure is different from @@ -30,8 +29,7 @@ struct linux_dirent; // Syscall wrappers. uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); -uptr internal_sigaltstack(const struct sigaltstack* ss, - struct sigaltstack* oss); +uptr internal_sigaltstack(const void* ss, void* oss); uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 03f73ae88..d7fa5f645 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -287,7 +287,7 @@ static int TracerThread(void* argument) { // Alternate stack for signal handling. InternalScopedBuffer handler_stack_memory(kHandlerStackSize); - struct sigaltstack handler_stack; + stack_t handler_stack; internal_memset(&handler_stack, 0, sizeof(handler_stack)); handler_stack.ss_sp = handler_stack_memory.data(); handler_stack.ss_size = kHandlerStackSize; diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 0ba01babe..ead1e5704 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -286,7 +286,7 @@ void InitializePlatform() { int ExtractResolvFDs(void *state, int *fds, int nfd) { #if SANITIZER_LINUX && !SANITIZER_ANDROID int cnt = 0; - __res_state *statp = (__res_state*)state; + struct __res_state *statp = (struct __res_state*)state; for (int i = 0; i < MAXNS && cnt < nfd; i++) { if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1) fds[cnt++] = statp->_u._ext.nssocks[i]; -- cgit v1.2.1 From 12d16901ebba5bc7185298e9efa3c4d265fa52ce Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 14 Jul 2017 11:30:06 +0000 Subject: tsan: optimize sync clock memory consumption This change implements 2 optimizations of sync clocks that reduce memory consumption: Use previously unused first level block space to store clock elements. Currently a clock for 100 threads consumes 3 512-byte blocks: 2 64-bit second level blocks to store clock elements +1 32-bit first level block to store indices to second level blocks Only 8 bytes of the first level block are actually used. With this change such clock consumes only 2 blocks. Share similar clocks differing only by a single clock entry for the current thread. When a thread does several release operations on fresh sync objects without intervening acquire operations in between (e.g. initialization of several fields in ctor), the resulting clocks differ only by a single entry for the current thread. This change reuses a single clock for such release operations. The current thread time (which is different for different clocks) is stored in dirty entries. We are experiencing issues with a large program that eats all 64M clock blocks (32GB of non-flushable memory) and crashes with dense allocator overflow. Max number of threads in the program is ~170 which is currently quite unfortunate (consume 4 blocks per clock). Currently it crashes after consuming 60+ GB of memory. The first optimization brings clock block consumption down to ~40M and allows the program to work. The second optimization further reduces block consumption to "modest" 16M blocks (~8GB of RAM) and reduces overall RAM consumption to ~30GB. Measurements on another real world C++ RPC benchmark show RSS reduction from 3.491G to 3.186G and a modest speedup of ~5%. Go parallel client/server HTTP benchmark: https://github.com/golang/benchmarks/blob/master/http/http.go shows RSS reduction from 320MB to 240MB and a few percent speedup. Reviewed in https://reviews.llvm.org/D35323 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308018 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_clock.cc | 436 +++++++++++++++++++++++---------- lib/tsan/rtl/tsan_clock.h | 207 +++++++++++----- lib/tsan/rtl/tsan_defs.h | 33 ++- lib/tsan/tests/unit/tsan_clock_test.cc | 33 ++- 4 files changed, 512 insertions(+), 197 deletions(-) diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc index 9ee910428..ef984a45c 100644 --- a/lib/tsan/rtl/tsan_clock.cc +++ b/lib/tsan/rtl/tsan_clock.cc @@ -61,20 +61,13 @@ // an exclusive lock; ThreadClock's are private to respective threads and so // do not need any protection. // -// Description of ThreadClock state: -// clk_ - fixed size vector clock. -// nclk_ - effective size of the vector clock (the rest is zeros). -// tid_ - index of the thread associated with he clock ("current thread"). -// last_acquire_ - current thread time when it acquired something from -// other threads. -// // Description of SyncClock state: // clk_ - variable size vector clock, low kClkBits hold timestamp, // the remaining bits hold "acquired" flag (the actual value is thread's // reused counter); // if acquried == thr->reused_, then the respective thread has already -// acquired this clock (except possibly dirty_tids_). -// dirty_tids_ - holds up to two indeces in the vector clock that other threads +// acquired this clock (except possibly for dirty elements). +// dirty_ - holds up to two indeces in the vector clock that other threads // need to acquire regardless of "acquired" flag value; // release_store_tid_ - denotes that the clock state is a result of // release-store operation by the thread with release_store_tid_ index. @@ -90,21 +83,51 @@ namespace __tsan { +static atomic_uint32_t *ref_ptr(ClockBlock *cb) { + return reinterpret_cast(&cb->table[ClockBlock::kRefIdx]); +} + +// Drop reference to the first level block idx. +static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) { + ClockBlock *cb = ctx->clock_alloc.Map(idx); + atomic_uint32_t *ref = ref_ptr(cb); + u32 v = atomic_load(ref, memory_order_acquire); + for (;;) { + CHECK_GT(v, 0); + if (v == 1) + break; + if (atomic_compare_exchange_strong(ref, &v, v - 1, memory_order_acq_rel)) + return; + } + // First level block owns second level blocks, so them as well. + for (uptr i = 0; i < blocks; i++) + ctx->clock_alloc.Free(c, cb->table[ClockBlock::kBlockIdx - i]); + ctx->clock_alloc.Free(c, idx); +} + ThreadClock::ThreadClock(unsigned tid, unsigned reused) : tid_(tid) - , reused_(reused + 1) { // 0 has special meaning + , reused_(reused + 1) // 0 has special meaning + , cached_idx_() + , cached_size_() + , cached_blocks_() { CHECK_LT(tid, kMaxTidInClock); CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits); nclk_ = tid_ + 1; last_acquire_ = 0; internal_memset(clk_, 0, sizeof(clk_)); - clk_[tid_].reused = reused_; } void ThreadClock::ResetCached(ClockCache *c) { + if (cached_idx_) { + UnrefClockBlock(c, cached_idx_, cached_blocks_); + cached_idx_ = 0; + cached_size_ = 0; + cached_blocks_ = 0; + } } -void ThreadClock::acquire(ClockCache *c, const SyncClock *src) { +void ThreadClock::acquire(ClockCache *c, SyncClock *src) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(src->size_, kMaxTid); CPP_STAT_INC(StatClockAcquire); @@ -116,50 +139,46 @@ void ThreadClock::acquire(ClockCache *c, const SyncClock *src) { return; } - // Check if we've already acquired src after the last release operation on src bool acquired = false; - if (nclk > tid_) { - if (src->elem(tid_).reused == reused_) { - for (unsigned i = 0; i < kDirtyTids; i++) { - unsigned tid = src->dirty_tids_[i]; - if (tid != kInvalidTid) { - u64 epoch = src->elem(tid).epoch; - if (clk_[tid].epoch < epoch) { - clk_[tid].epoch = epoch; - acquired = true; - } - } - } - if (acquired) { - CPP_STAT_INC(StatClockAcquiredSomething); - last_acquire_ = clk_[tid_].epoch; + for (unsigned i = 0; i < kDirtyTids; i++) { + SyncClock::Dirty dirty = src->dirty_[i]; + unsigned tid = dirty.tid; + if (tid != kInvalidTid) { + if (clk_[tid] < dirty.epoch) { + clk_[tid] = dirty.epoch; + acquired = true; } - return; } } - // O(N) acquire. - CPP_STAT_INC(StatClockAcquireFull); - nclk_ = max(nclk_, nclk); - for (uptr i = 0; i < nclk; i++) { - u64 epoch = src->elem(i).epoch; - if (clk_[i].epoch < epoch) { - clk_[i].epoch = epoch; - acquired = true; + // Check if we've already acquired src after the last release operation on src + if (tid_ >= nclk || src->elem(tid_).reused != reused_) { + // O(N) acquire. + CPP_STAT_INC(StatClockAcquireFull); + nclk_ = max(nclk_, nclk); + u64 *dst_pos = &clk_[0]; + for (ClockElem &src_elem : *src) { + u64 epoch = src_elem.epoch; + if (*dst_pos < epoch) { + *dst_pos = epoch; + acquired = true; + } + dst_pos++; } - } - // Remember that this thread has acquired this clock. - if (nclk > tid_) - src->elem(tid_).reused = reused_; + // Remember that this thread has acquired this clock. + if (nclk > tid_) + src->elem(tid_).reused = reused_; + } if (acquired) { CPP_STAT_INC(StatClockAcquiredSomething); - last_acquire_ = clk_[tid_].epoch; + last_acquire_ = clk_[tid_]; + ResetCached(c); } } -void ThreadClock::release(ClockCache *c, SyncClock *dst) const { +void ThreadClock::release(ClockCache *c, SyncClock *dst) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(dst->size_, kMaxTid); @@ -179,7 +198,7 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const { // since the last release on dst. If so, we need to update // only dst->elem(tid_). if (dst->elem(tid_).epoch > last_acquire_) { - UpdateCurrentThread(dst); + UpdateCurrentThread(c, dst); if (dst->release_store_tid_ != tid_ || dst->release_store_reused_ != reused_) dst->release_store_tid_ = kInvalidTid; @@ -188,23 +207,24 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const { // O(N) release. CPP_STAT_INC(StatClockReleaseFull); + dst->Unshare(c); // First, remember whether we've acquired dst. bool acquired = IsAlreadyAcquired(dst); if (acquired) CPP_STAT_INC(StatClockReleaseAcquired); // Update dst->clk_. - for (uptr i = 0; i < nclk_; i++) { - ClockElem &ce = dst->elem(i); - ce.epoch = max(ce.epoch, clk_[i].epoch); + dst->FlushDirty(); + uptr i = 0; + for (ClockElem &ce : *dst) { + ce.epoch = max(ce.epoch, clk_[i]); ce.reused = 0; + i++; } // Clear 'acquired' flag in the remaining elements. if (nclk_ < dst->size_) CPP_STAT_INC(StatClockReleaseClearTail); for (uptr i = nclk_; i < dst->size_; i++) dst->elem(i).reused = 0; - for (unsigned i = 0; i < kDirtyTids; i++) - dst->dirty_tids_[i] = kInvalidTid; dst->release_store_tid_ = kInvalidTid; dst->release_store_reused_ = 0; // If we've acquired dst, remember this fact, @@ -213,11 +233,37 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const { dst->elem(tid_).reused = reused_; } -void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const { +void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(dst->size_, kMaxTid); CPP_STAT_INC(StatClockStore); + if (dst->size_ == 0 && cached_idx_ != 0) { + // Reuse the cached clock. + // Note: we could reuse/cache the cached clock in more cases: + // we could update the existing clock and cache it, or replace it with the + // currently cached clock and release the old one. And for a shared + // existing clock, we could replace it with the currently cached; + // or unshare, update and cache. But, for simplicity, we currnetly reuse + // cached clock only when the target clock is empty. + dst->tab_ = ctx->clock_alloc.Map(cached_idx_); + dst->tab_idx_ = cached_idx_; + dst->size_ = cached_size_; + dst->blocks_ = cached_blocks_; + CHECK_EQ(dst->dirty_[0].tid, kInvalidTid); + // The cached clock is shared (immutable), + // so this is where we store the current clock. + dst->dirty_[0].tid = tid_; + dst->dirty_[0].epoch = clk_[tid_]; + dst->release_store_tid_ = tid_; + dst->release_store_reused_ = reused_; + // Rememeber that we don't need to acquire it in future. + dst->elem(tid_).reused = reused_; + // Grab a reference. + atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed); + return; + } + // Check if we need to resize dst. if (dst->size_ < nclk_) dst->Resize(c, nclk_); @@ -226,32 +272,41 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const { dst->release_store_reused_ == reused_ && dst->elem(tid_).epoch > last_acquire_) { CPP_STAT_INC(StatClockStoreFast); - UpdateCurrentThread(dst); + UpdateCurrentThread(c, dst); return; } // O(N) release-store. CPP_STAT_INC(StatClockStoreFull); - for (uptr i = 0; i < nclk_; i++) { - ClockElem &ce = dst->elem(i); - ce.epoch = clk_[i].epoch; + dst->Unshare(c); + // Note: dst can be larger than this ThreadClock. + // This is fine since clk_ beyond size is all zeros. + uptr i = 0; + for (ClockElem &ce : *dst) { + ce.epoch = clk_[i]; ce.reused = 0; + i++; } - // Clear the tail of dst->clk_. - if (nclk_ < dst->size_) { - for (uptr i = nclk_; i < dst->size_; i++) { - ClockElem &ce = dst->elem(i); - ce.epoch = 0; - ce.reused = 0; - } - CPP_STAT_INC(StatClockStoreTail); - } - for (unsigned i = 0; i < kDirtyTids; i++) - dst->dirty_tids_[i] = kInvalidTid; + for (uptr i = 0; i < kDirtyTids; i++) + dst->dirty_[i].tid = kInvalidTid; dst->release_store_tid_ = tid_; dst->release_store_reused_ = reused_; // Rememeber that we don't need to acquire it in future. dst->elem(tid_).reused = reused_; + + // If the resulting clock is cachable, cache it for future release operations. + // The clock is always cachable if we released to an empty sync object. + if (cached_idx_ == 0 && dst->Cachable()) { + // Grab a reference to the ClockBlock. + atomic_uint32_t *ref = ref_ptr(dst->tab_); + if (atomic_load(ref, memory_order_acquire) == 1) + atomic_store_relaxed(ref, 2); + else + atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed); + cached_idx_ = dst->tab_idx_; + cached_size_ = dst->size_; + cached_blocks_ = dst->blocks_; + } } void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) { @@ -261,37 +316,36 @@ void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) { } // Updates only single element related to the current thread in dst->clk_. -void ThreadClock::UpdateCurrentThread(SyncClock *dst) const { +void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const { // Update the threads time, but preserve 'acquired' flag. - dst->elem(tid_).epoch = clk_[tid_].epoch; - for (unsigned i = 0; i < kDirtyTids; i++) { - if (dst->dirty_tids_[i] == tid_) { + SyncClock::Dirty *dirty = &dst->dirty_[i]; + const unsigned tid = dirty->tid; + if (tid == tid_ || tid == kInvalidTid) { CPP_STAT_INC(StatClockReleaseFast); - return; - } - if (dst->dirty_tids_[i] == kInvalidTid) { - CPP_STAT_INC(StatClockReleaseFast); - dst->dirty_tids_[i] = tid_; + dirty->tid = tid_; + dirty->epoch = clk_[tid_]; return; } } // Reset all 'acquired' flags, O(N). + // We are going to touch dst elements, so we need to unshare it. + dst->Unshare(c); CPP_STAT_INC(StatClockReleaseSlow); + dst->elem(tid_).epoch = clk_[tid_]; for (uptr i = 0; i < dst->size_; i++) dst->elem(i).reused = 0; - for (unsigned i = 0; i < kDirtyTids; i++) - dst->dirty_tids_[i] = kInvalidTid; + dst->FlushDirty(); } -// Checks whether the current threads has already acquired src. +// Checks whether the current thread has already acquired src. bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const { if (src->elem(tid_).reused != reused_) return false; for (unsigned i = 0; i < kDirtyTids; i++) { - unsigned tid = src->dirty_tids_[i]; - if (tid != kInvalidTid) { - if (clk_[tid].epoch < src->elem(tid).epoch) + SyncClock::Dirty dirty = src->dirty_[i]; + if (dirty.tid != kInvalidTid) { + if (clk_[dirty.tid] < dirty.epoch) return false; } } @@ -302,22 +356,19 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const { // This function is called only from weird places like AcquireGlobal. void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) { DCHECK_LT(tid, kMaxTid); - DCHECK_GE(v, clk_[tid].epoch); - clk_[tid].epoch = v; + DCHECK_GE(v, clk_[tid]); + clk_[tid] = v; if (nclk_ <= tid) nclk_ = tid + 1; - last_acquire_ = clk_[tid_].epoch; + last_acquire_ = clk_[tid_]; + ResetCached(c); } void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) { printf("clock=["); for (uptr i = 0; i < nclk_; i++) - printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch); - printf("] reused=["); - for (uptr i = 0; i < nclk_; i++) - printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused); - printf("] tid=%u/%u last_acq=%llu", - tid_, reused_, last_acquire_); + printf("%s%llu", i == 0 ? "" : ",", clk_[i]); + printf("] tid=%u/%u last_acq=%llu", tid_, reused_, last_acquire_); } SyncClock::SyncClock() { @@ -327,22 +378,14 @@ SyncClock::SyncClock() { SyncClock::~SyncClock() { // Reset must be called before dtor. CHECK_EQ(size_, 0); + CHECK_EQ(blocks_, 0); CHECK_EQ(tab_, 0); CHECK_EQ(tab_idx_, 0); } void SyncClock::Reset(ClockCache *c) { - if (size_ == 0) { - // nothing - } else if (size_ <= ClockBlock::kClockCount) { - // One-level table. - ctx->clock_alloc.Free(c, tab_idx_); - } else { - // Two-level table. - for (uptr i = 0; i < size_; i += ClockBlock::kClockCount) - ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]); - ctx->clock_alloc.Free(c, tab_idx_); - } + if (size_) + UnrefClockBlock(c, tab_idx_, blocks_); ResetImpl(); } @@ -350,66 +393,171 @@ void SyncClock::ResetImpl() { tab_ = 0; tab_idx_ = 0; size_ = 0; + blocks_ = 0; release_store_tid_ = kInvalidTid; release_store_reused_ = 0; for (uptr i = 0; i < kDirtyTids; i++) - dirty_tids_[i] = kInvalidTid; + dirty_[i].tid = kInvalidTid; } void SyncClock::Resize(ClockCache *c, uptr nclk) { CPP_STAT_INC(StatClockReleaseResize); - if (RoundUpTo(nclk, ClockBlock::kClockCount) <= - RoundUpTo(size_, ClockBlock::kClockCount)) { - // Growing within the same block. + Unshare(c); + if (nclk <= capacity()) { // Memory is already allocated, just increase the size. size_ = nclk; return; } - if (nclk <= ClockBlock::kClockCount) { + if (size_ == 0) { // Grow from 0 to one-level table. CHECK_EQ(size_, 0); + CHECK_EQ(blocks_, 0); CHECK_EQ(tab_, 0); CHECK_EQ(tab_idx_, 0); - size_ = nclk; - tab_idx_ = ctx->clock_alloc.Alloc(c); - tab_ = ctx->clock_alloc.Map(tab_idx_); - internal_memset(tab_, 0, sizeof(*tab_)); - return; - } - // Growing two-level table. - if (size_ == 0) { - // Allocate first level table. - tab_idx_ = ctx->clock_alloc.Alloc(c); - tab_ = ctx->clock_alloc.Map(tab_idx_); - internal_memset(tab_, 0, sizeof(*tab_)); - } else if (size_ <= ClockBlock::kClockCount) { - // Transform one-level table to two-level table. - u32 old = tab_idx_; tab_idx_ = ctx->clock_alloc.Alloc(c); tab_ = ctx->clock_alloc.Map(tab_idx_); internal_memset(tab_, 0, sizeof(*tab_)); - tab_->table[0] = old; + atomic_store_relaxed(ref_ptr(tab_), 1); + size_ = 1; + } else if (size_ > blocks_ * ClockBlock::kClockCount) { + u32 idx = ctx->clock_alloc.Alloc(c); + ClockBlock *new_cb = ctx->clock_alloc.Map(idx); + uptr top = size_ - blocks_ * ClockBlock::kClockCount; + CHECK_LT(top, ClockBlock::kClockCount); + const uptr move = top * sizeof(tab_->clock[0]); + internal_memcpy(&new_cb->clock[0], tab_->clock, move); + internal_memset(&new_cb->clock[top], 0, sizeof(*new_cb) - move); + internal_memset(tab_->clock, 0, move); + append_block(idx); } - // At this point we have first level table allocated. + // At this point we have first level table allocated and all clock elements + // are evacuated from it to a second level block. // Add second level tables as necessary. - for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount); - i < nclk; i += ClockBlock::kClockCount) { + while (nclk > capacity()) { u32 idx = ctx->clock_alloc.Alloc(c); ClockBlock *cb = ctx->clock_alloc.Map(idx); internal_memset(cb, 0, sizeof(*cb)); - CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0); - tab_->table[i/ClockBlock::kClockCount] = idx; + append_block(idx); } size_ = nclk; } -ClockElem &SyncClock::elem(unsigned tid) const { +// Flushes all dirty elements into the main clock array. +void SyncClock::FlushDirty() { + for (unsigned i = 0; i < kDirtyTids; i++) { + Dirty *dirty = &dirty_[i]; + if (dirty->tid != kInvalidTid) { + CHECK_LT(dirty->tid, size_); + elem(dirty->tid).epoch = dirty->epoch; + dirty->tid = kInvalidTid; + } + } +} + +bool SyncClock::IsShared() const { + if (size_ == 0) + return false; + atomic_uint32_t *ref = ref_ptr(tab_); + u32 v = atomic_load(ref, memory_order_acquire); + CHECK_GT(v, 0); + return v > 1; +} + +// Unshares the current clock if it's shared. +// Shared clocks are immutable, so they need to be unshared before any updates. +// Note: this does not apply to dirty entries as they are not shared. +void SyncClock::Unshare(ClockCache *c) { + if (!IsShared()) + return; + // First, copy current state into old. + SyncClock old; + old.tab_ = tab_; + old.tab_idx_ = tab_idx_; + old.size_ = size_; + old.blocks_ = blocks_; + old.release_store_tid_ = release_store_tid_; + old.release_store_reused_ = release_store_reused_; + for (unsigned i = 0; i < kDirtyTids; i++) + old.dirty_[i] = dirty_[i]; + // Then, clear current object. + ResetImpl(); + // Allocate brand new clock in the current object. + Resize(c, old.size_); + // Now copy state back into this object. + Iter old_iter(&old); + for (ClockElem &ce : *this) { + ce = *old_iter; + ++old_iter; + } + release_store_tid_ = old.release_store_tid_; + release_store_reused_ = old.release_store_reused_; + for (unsigned i = 0; i < kDirtyTids; i++) + dirty_[i] = old.dirty_[i]; + // Drop reference to old and delete if necessary. + old.Reset(c); +} + +// Can we cache this clock for future release operations? +ALWAYS_INLINE bool SyncClock::Cachable() const { + if (size_ == 0) + return false; + for (unsigned i = 0; i < kDirtyTids; i++) { + if (dirty_[i].tid != kInvalidTid) + return false; + } + return atomic_load_relaxed(ref_ptr(tab_)) == 1; +} + +// elem linearizes the two-level structure into linear array. +// Note: this is used only for one time accesses, vector operations use +// the iterator as it is much faster. +ALWAYS_INLINE ClockElem &SyncClock::elem(unsigned tid) const { DCHECK_LT(tid, size_); - if (size_ <= ClockBlock::kClockCount) + const uptr block = tid / ClockBlock::kClockCount; + DCHECK_LE(block, blocks_); + tid %= ClockBlock::kClockCount; + if (block == blocks_) return tab_->clock[tid]; - u32 idx = tab_->table[tid / ClockBlock::kClockCount]; + u32 idx = get_block(block); ClockBlock *cb = ctx->clock_alloc.Map(idx); - return cb->clock[tid % ClockBlock::kClockCount]; + return cb->clock[tid]; +} + +ALWAYS_INLINE uptr SyncClock::capacity() const { + if (size_ == 0) + return 0; + uptr ratio = sizeof(ClockBlock::clock[0]) / sizeof(ClockBlock::table[0]); + // How many clock elements we can fit into the first level block. + // +1 for ref counter. + uptr top = ClockBlock::kClockCount - RoundUpTo(blocks_ + 1, ratio) / ratio; + return blocks_ * ClockBlock::kClockCount + top; +} + +ALWAYS_INLINE u32 SyncClock::get_block(uptr bi) const { + DCHECK(size_); + DCHECK_LT(bi, blocks_); + return tab_->table[ClockBlock::kBlockIdx - bi]; +} + +ALWAYS_INLINE void SyncClock::append_block(u32 idx) { + uptr bi = blocks_++; + CHECK_EQ(get_block(bi), 0); + tab_->table[ClockBlock::kBlockIdx - bi] = idx; +} + +// Used only by tests. +u64 SyncClock::get(unsigned tid) const { + for (unsigned i = 0; i < kDirtyTids; i++) { + Dirty dirty = dirty_[i]; + if (dirty.tid == tid) + return dirty.epoch; + } + return elem(tid).epoch; +} + +// Used only by Iter test. +u64 SyncClock::get_clean(unsigned tid) const { + return elem(tid).epoch; } void SyncClock::DebugDump(int(*printf)(const char *s, ...)) { @@ -419,8 +567,32 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) { printf("] reused=["); for (uptr i = 0; i < size_; i++) printf("%s%llu", i == 0 ? "" : ",", elem(i).reused); - printf("] release_store_tid=%d/%d dirty_tids=%d/%d", + printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]", release_store_tid_, release_store_reused_, - dirty_tids_[0], dirty_tids_[1]); + dirty_[0].tid, dirty_[0].epoch, + dirty_[1].tid, dirty_[1].epoch); +} + +void SyncClock::Iter::Next() { + // Finished with the current block, move on to the next one. + block_++; + if (block_ < parent_->blocks_) { + // Iterate over the next second level block. + u32 idx = parent_->get_block(block_); + ClockBlock *cb = ctx->clock_alloc.Map(idx); + pos_ = &cb->clock[0]; + end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount, + ClockBlock::kClockCount); + return; + } + if (block_ == parent_->blocks_ && + parent_->size_ > parent_->blocks_ * ClockBlock::kClockCount) { + // Iterate over elements in the first level block. + pos_ = &parent_->tab_->clock[0]; + end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount, + ClockBlock::kClockCount); + return; + } + parent_ = nullptr; // denotes end } } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_clock.h b/lib/tsan/rtl/tsan_clock.h index 378b550fd..a891d7bbd 100644 --- a/lib/tsan/rtl/tsan_clock.h +++ b/lib/tsan/rtl/tsan_clock.h @@ -18,25 +18,6 @@ namespace __tsan { -struct ClockElem { - u64 epoch : kClkBits; - u64 reused : 64 - kClkBits; -}; - -struct ClockBlock { - static const uptr kSize = 512; - static const uptr kTableSize = kSize / sizeof(u32); - static const uptr kClockCount = kSize / sizeof(ClockElem); - - union { - u32 table[kTableSize]; - ClockElem clock[kClockCount]; - }; - - ClockBlock() { - } -}; - typedef DenseSlabAlloc ClockAlloc; typedef DenseSlabAllocCache ClockCache; @@ -46,69 +27,117 @@ class SyncClock { SyncClock(); ~SyncClock(); - uptr size() const { - return size_; - } + uptr size() const; - u64 get(unsigned tid) const { - return elem(tid).epoch; - } + // These are used only in tests. + u64 get(unsigned tid) const; + u64 get_clean(unsigned tid) const; void Resize(ClockCache *c, uptr nclk); void Reset(ClockCache *c); void DebugDump(int(*printf)(const char *s, ...)); + // Clock element iterator. + // Note: it iterates only over the table without regard to dirty entries. + class Iter { + public: + explicit Iter(SyncClock* parent); + Iter& operator++(); + bool operator!=(const Iter& other); + ClockElem &operator*(); + + private: + SyncClock *parent_; + // [pos_, end_) is the current continuous range of clock elements. + ClockElem *pos_; + ClockElem *end_; + int block_; // Current number of second level block. + + NOINLINE void Next(); + }; + + Iter begin(); + Iter end(); + private: - friend struct ThreadClock; + friend class ThreadClock; + friend class Iter; static const uptr kDirtyTids = 2; + struct Dirty { + u64 epoch : kClkBits; + u64 tid : 64 - kClkBits; // kInvalidId if not active + }; + unsigned release_store_tid_; unsigned release_store_reused_; - unsigned dirty_tids_[kDirtyTids]; - // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc. - // If size_ <= 64, then tab_ points to an array with 64 ClockElem's. - // Otherwise, tab_ points to an array with 128 u32 elements, + Dirty dirty_[kDirtyTids]; + // If size_ is 0, tab_ is nullptr. + // If size <= 64 (kClockCount), tab_ contains pointer to an array with + // 64 ClockElem's (ClockBlock::clock). + // Otherwise, tab_ points to an array with up to 127 u32 elements, // each pointing to the second-level 512b block with 64 ClockElem's. + // Unused space in the first level ClockBlock is used to store additional + // clock elements. + // The last u32 element in the first level ClockBlock is always used as + // reference counter. + // + // See the following scheme for details. + // All memory blocks are 512 bytes (allocated from ClockAlloc). + // Clock (clk) elements are 64 bits. + // Idx and ref are 32 bits. + // + // tab_ + // | + // \/ + // +----------------------------------------------------+ + // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref | + // +----------------------------------------------------+ + // | | + // | \/ + // | +----------------+ + // | | clk0 ... clk63 | + // | +----------------+ + // \/ + // +------------------+ + // | clk64 ... clk127 | + // +------------------+ + // + // Note: dirty entries, if active, always override what's stored in the clock. ClockBlock *tab_; u32 tab_idx_; - u32 size_; + u16 size_; + u16 blocks_; // Number of second level blocks. + void Unshare(ClockCache *c); + bool IsShared() const; + bool Cachable() const; void ResetImpl(); + void FlushDirty(); + uptr capacity() const; + u32 get_block(uptr bi) const; + void append_block(u32 idx); ClockElem &elem(unsigned tid) const; }; // The clock that lives in threads. -struct ThreadClock { +class ThreadClock { public: typedef DenseSlabAllocCache Cache; explicit ThreadClock(unsigned tid, unsigned reused = 0); - u64 get(unsigned tid) const { - DCHECK_LT(tid, kMaxTidInClock); - return clk_[tid].epoch; - } - + u64 get(unsigned tid) const; void set(ClockCache *c, unsigned tid, u64 v); + void set(u64 v); + void tick(); + uptr size() const; - void set(u64 v) { - DCHECK_GE(v, clk_[tid_].epoch); - clk_[tid_].epoch = v; - } - - void tick() { - clk_[tid_].epoch++; - } - - uptr size() const { - return nclk_; - } - - void acquire(ClockCache *c, const SyncClock *src); - void release(ClockCache *c, SyncClock *dst) const; + void acquire(ClockCache *c, SyncClock *src); + void release(ClockCache *c, SyncClock *dst); void acq_rel(ClockCache *c, SyncClock *dst); - void ReleaseStore(ClockCache *c, SyncClock *dst) const; + void ReleaseStore(ClockCache *c, SyncClock *dst); void ResetCached(ClockCache *c); void DebugReset(); @@ -116,16 +145,82 @@ struct ThreadClock { private: static const uptr kDirtyTids = SyncClock::kDirtyTids; + // Index of the thread associated with he clock ("current thread"). const unsigned tid_; - const unsigned reused_; + const unsigned reused_; // tid_ reuse count. + // Current thread time when it acquired something from other threads. u64 last_acquire_; + + // Cached SyncClock (without dirty entries and release_store_tid_). + // We reuse it for subsequent store-release operations without intervening + // acquire operations. Since it is shared (and thus constant), clock value + // for the current thread is then stored in dirty entries in the SyncClock. + // We host a refernece to the table while it is cached here. + u32 cached_idx_; + u16 cached_size_; + u16 cached_blocks_; + + // Number of active elements in the clk_ table (the rest is zeros). uptr nclk_; - ClockElem clk_[kMaxTidInClock]; + u64 clk_[kMaxTidInClock]; // Fixed size vector clock. bool IsAlreadyAcquired(const SyncClock *src) const; - void UpdateCurrentThread(SyncClock *dst) const; + void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const; }; +ALWAYS_INLINE u64 ThreadClock::get(unsigned tid) const { + DCHECK_LT(tid, kMaxTidInClock); + return clk_[tid]; +} + +ALWAYS_INLINE void ThreadClock::set(u64 v) { + DCHECK_GE(v, clk_[tid_]); + clk_[tid_] = v; +} + +ALWAYS_INLINE void ThreadClock::tick() { + clk_[tid_]++; +} + +ALWAYS_INLINE uptr ThreadClock::size() const { + return nclk_; +} + +ALWAYS_INLINE SyncClock::Iter SyncClock::begin() { + return Iter(this); +} + +ALWAYS_INLINE SyncClock::Iter SyncClock::end() { + return Iter(nullptr); +} + +ALWAYS_INLINE uptr SyncClock::size() const { + return size_; +} + +ALWAYS_INLINE SyncClock::Iter::Iter(SyncClock* parent) + : parent_(parent) + , pos_(nullptr) + , end_(nullptr) + , block_(-1) { + if (parent) + Next(); +} + +ALWAYS_INLINE SyncClock::Iter& SyncClock::Iter::operator++() { + pos_++; + if (UNLIKELY(pos_ >= end_)) + Next(); + return *this; +} + +ALWAYS_INLINE bool SyncClock::Iter::operator!=(const SyncClock::Iter& other) { + return parent_ != other.parent_; +} + +ALWAYS_INLINE ClockElem &SyncClock::Iter::operator*() { + return *pos_; +} } // namespace __tsan #endif // TSAN_CLOCK_H diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h index 8977fea7c..3c775debf 100644 --- a/lib/tsan/rtl/tsan_defs.h +++ b/lib/tsan/rtl/tsan_defs.h @@ -38,15 +38,40 @@ namespace __tsan { +const int kClkBits = 42; +const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1; + +struct ClockElem { + u64 epoch : kClkBits; + u64 reused : 64 - kClkBits; // tid reuse count +}; + +struct ClockBlock { + static const uptr kSize = 512; + static const uptr kTableSize = kSize / sizeof(u32); + static const uptr kClockCount = kSize / sizeof(ClockElem); + static const uptr kRefIdx = kTableSize - 1; + static const uptr kBlockIdx = kTableSize - 2; + + union { + u32 table[kTableSize]; + ClockElem clock[kClockCount]; + }; + + ClockBlock() { + } +}; + const int kTidBits = 13; -const unsigned kMaxTid = 1 << kTidBits; +// Reduce kMaxTid by kClockCount because one slot in ClockBlock table is +// occupied by reference counter, so total number of elements we can store +// in SyncClock is kClockCount * (kTableSize - 1). +const unsigned kMaxTid = (1 << kTidBits) - ClockBlock::kClockCount; #if !SANITIZER_GO const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit. #else const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory. #endif -const int kClkBits = 42; -const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1; const uptr kShadowStackSize = 64 * 1024; // Count of shadow values in a shadow cell. @@ -74,7 +99,7 @@ const bool kCollectHistory = false; const bool kCollectHistory = true; #endif -const unsigned kInvalidTid = (unsigned)-1; +const u16 kInvalidTid = kMaxTid + 1; // The following "build consistency" machinery ensures that all source files // are built in the same configuration. Inconsistent builds lead to diff --git a/lib/tsan/tests/unit/tsan_clock_test.cc b/lib/tsan/tests/unit/tsan_clock_test.cc index 73104dd6b..f6230e1be 100644 --- a/lib/tsan/tests/unit/tsan_clock_test.cc +++ b/lib/tsan/tests/unit/tsan_clock_test.cc @@ -53,6 +53,31 @@ TEST(Clock, ChunkedBasic) { chunked.Reset(&cache); } +static const uptr interesting_sizes[] = {0, 1, 2, 30, 61, 62, 63, 64, 65, 66, + 100, 124, 125, 126, 127, 128, 129, 130, 188, 189, 190, 191, 192, 193, 254, + 255}; + +TEST(Clock, Iter) { + const uptr n = ARRAY_SIZE(interesting_sizes); + for (uptr fi = 0; fi < n; fi++) { + const uptr size = interesting_sizes[fi]; + SyncClock sync; + ThreadClock vector(0); + for (uptr i = 0; i < size; i++) + vector.set(&cache, i, i + 1); + if (size != 0) + vector.release(&cache, &sync); + uptr i = 0; + for (ClockElem &ce : sync) { + ASSERT_LT(i, size); + ASSERT_EQ(sync.get_clean(i), ce.epoch); + i++; + } + ASSERT_EQ(i, size); + sync.Reset(&cache); + } +} + TEST(Clock, AcquireRelease) { ThreadClock vector1(100); vector1.tick(); @@ -216,13 +241,11 @@ TEST(Clock, Growth) { TEST(Clock, Growth2) { // Test clock growth for every pair of sizes: - const uptr sizes[] = {0, 1, 2, 30, 61, 62, 63, 64, 65, 66, 100, 124, 125, 126, - 127, 128, 129, 130, 188, 189, 190, 191, 192, 193, 254, 255}; - const uptr n = sizeof(sizes) / sizeof(sizes[0]); + const uptr n = ARRAY_SIZE(interesting_sizes); for (uptr fi = 0; fi < n; fi++) { for (uptr ti = fi + 1; ti < n; ti++) { - const uptr from = sizes[fi]; - const uptr to = sizes[ti]; + const uptr from = interesting_sizes[fi]; + const uptr to = interesting_sizes[ti]; SyncClock sync; ThreadClock vector(0); for (uptr i = 0; i < from; i++) -- cgit v1.2.1 From e474b1c4087b0b9f9f2edaa514a256c42f345db6 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 14 Jul 2017 21:17:16 +0000 Subject: [Sanitizers] Scudo allocator set errno on failure. Summary: Set proper errno code on alloction failure and change pvalloc and posix_memalign implementation to satisfy their man-specified requirements. Reviewers: cryptoad Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35429 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308053 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 50 +++++++++++++++++++++++++------------------ test/scudo/memalign.cpp | 8 +++---- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 057db6281..102d1d0df 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -20,9 +20,9 @@ #include "scudo_utils.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_quarantine.h" -#include #include namespace __scudo { @@ -638,8 +638,14 @@ void ScudoThreadContext::commitBack() { Instance.commitBack(this); } +INLINE void *checkPtr(void *Ptr) { + if (UNLIKELY(!Ptr)) + errno = errno_ENOMEM; + return Ptr; +} + void *scudoMalloc(uptr Size, AllocType Type) { - return Instance.allocate(Size, MinAlignment, Type); + return checkPtr(Instance.allocate(Size, MinAlignment, Type)); } void scudoFree(void *Ptr, AllocType Type) { @@ -652,54 +658,56 @@ void scudoSizedFree(void *Ptr, uptr Size, AllocType Type) { void *scudoRealloc(void *Ptr, uptr Size) { if (!Ptr) - return Instance.allocate(Size, MinAlignment, FromMalloc); + return checkPtr(Instance.allocate(Size, MinAlignment, FromMalloc)); if (Size == 0) { Instance.deallocate(Ptr, 0, FromMalloc); return nullptr; } - return Instance.reallocate(Ptr, Size); + return checkPtr(Instance.reallocate(Ptr, Size)); } void *scudoCalloc(uptr NMemB, uptr Size) { - return Instance.calloc(NMemB, Size); + return checkPtr(Instance.calloc(NMemB, Size)); } void *scudoValloc(uptr Size) { - return Instance.allocate(Size, GetPageSizeCached(), FromMemalign); + return checkPtr(Instance.allocate(Size, GetPageSizeCached(), FromMemalign)); } void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); - Size = RoundUpTo(Size, PageSize); - if (Size == 0) { - // pvalloc(0) should allocate one page. - Size = PageSize; - } - return Instance.allocate(Size, PageSize, FromMemalign); + // pvalloc(0) should allocate one page. + Size = Size ? RoundUpTo(Size, PageSize) : PageSize; + return checkPtr(Instance.allocate(Size, PageSize, FromMemalign)); } void *scudoMemalign(uptr Alignment, uptr Size) { - if (UNLIKELY(!IsPowerOfTwo(Alignment))) + if (UNLIKELY(!IsPowerOfTwo(Alignment))) { + errno = errno_EINVAL; return ScudoAllocator::FailureHandler::OnBadRequest(); - return Instance.allocate(Size, Alignment, FromMemalign); + } + return checkPtr(Instance.allocate(Size, Alignment, FromMemalign)); } int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Alignment % sizeof(void *)) != 0)) { - *MemPtr = ScudoAllocator::FailureHandler::OnBadRequest(); - return EINVAL; + ScudoAllocator::FailureHandler::OnBadRequest(); + return errno_EINVAL; } - *MemPtr = Instance.allocate(Size, Alignment, FromMemalign); - if (!*MemPtr) - return ENOMEM; + void *Ptr = Instance.allocate(Size, Alignment, FromMemalign); + if (!Ptr) + return errno_ENOMEM; + *MemPtr = Ptr; return 0; } void *scudoAlignedAlloc(uptr Alignment, uptr Size) { // Alignment must be a power of 2, Size must be a multiple of Alignment. - if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0)) + if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0)) { + errno = errno_EINVAL; return ScudoAllocator::FailureHandler::OnBadRequest(); - return Instance.allocate(Size, Alignment, FromMalloc); + } + return checkPtr(Instance.allocate(Size, Alignment, FromMalloc)); } uptr scudoMallocUsableSize(void *Ptr) { diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 856128f24..82c54af8b 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -65,15 +65,15 @@ int main(int argc, char **argv) // Size is not a multiple of alignment. p = aligned_alloc(alignment, size >> 1); assert(!p); - p = (void *)0x42UL; + void *p_unchanged = (void *)0x42UL; + p = p_unchanged; // Alignment is not a power of 2. err = posix_memalign(&p, 3, size); - assert(!p); + assert(p == p_unchanged); assert(err == EINVAL); - p = (void *)0x42UL; // Alignment is a power of 2, but not a multiple of size(void *). err = posix_memalign(&p, 2, size); - assert(!p); + assert(p == p_unchanged); assert(err == EINVAL); } return 0; -- cgit v1.2.1 From 2706e2583c3e18af76761f5907e981d831850eff Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 14 Jul 2017 22:23:46 +0000 Subject: [Sanitizers] LSan allocator set errno on failure. Set proper errno code on alloction failures and change valloc and memalign implementations to satisfy their man-specified requirements. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308063 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.cc | 34 +++++++++++++++++++-------- test/lsan/TestCases/allocator_returns_null.cc | 10 +++++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 6514aea6f..96d5cb6a9 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -16,6 +16,7 @@ #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" @@ -86,6 +87,13 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, return p; } +static void *Calloc(uptr nmemb, uptr size, const StackTrace &stack) { + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) + return Allocator::FailureHandler::OnBadRequest(); + size *= nmemb; + return Allocate(stack, size, 1, true); +} + void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RunFreeHooks(p); @@ -117,12 +125,22 @@ uptr GetMallocUsableSize(const void *p) { return m->requested_size; } +inline void *check_ptr(void *ptr) { + if (UNLIKELY(!ptr)) + errno = errno_ENOMEM; + return ptr; +} + void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) { - return Allocate(stack, size, alignment, kAlwaysClearMemory); + if (UNLIKELY(!IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + return Allocator::FailureHandler::OnBadRequest(); + } + return check_ptr(Allocate(stack, size, alignment, kAlwaysClearMemory)); } void *lsan_malloc(uptr size, const StackTrace &stack) { - return Allocate(stack, size, 1, kAlwaysClearMemory); + return check_ptr(Allocate(stack, size, 1, kAlwaysClearMemory)); } void lsan_free(void *p) { @@ -130,20 +148,16 @@ void lsan_free(void *p) { } void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { - return Reallocate(stack, p, size, 1); + return check_ptr(Reallocate(stack, p, size, 1)); } void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { - if (CheckForCallocOverflow(size, nmemb)) - return Allocator::FailureHandler::OnBadRequest(); - size *= nmemb; - return Allocate(stack, size, 1, true); + return check_ptr(Calloc(nmemb, size, stack)); } void *lsan_valloc(uptr size, const StackTrace &stack) { - if (size == 0) - size = GetPageSizeCached(); - return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); + return check_ptr( + Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory)); } uptr lsan_mz_size(const void *p) { diff --git a/test/lsan/TestCases/allocator_returns_null.cc b/test/lsan/TestCases/allocator_returns_null.cc index ab2c734e1..28dd696dc 100644 --- a/test/lsan/TestCases/allocator_returns_null.cc +++ b/test/lsan/TestCases/allocator_returns_null.cc @@ -37,9 +37,10 @@ // RUN: | FileCheck %s --check-prefix=CHECK-nnNULL #include -#include +#include #include #include +#include #include #include @@ -86,6 +87,8 @@ int main(int argc, char **argv) { assert(0); } + fprintf(stderr, "errno: %d\n", errno); + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %zu\n", (size_t)x); @@ -110,14 +113,19 @@ int main(int argc, char **argv) { // CHECK-nnCRASH: Sanitizer's allocator is terminating the process // CHECK-mNULL: malloc: +// CHECK-mNULL: errno: 12 // CHECK-mNULL: x: 0 // CHECK-cNULL: calloc: +// CHECK-cNULL: errno: 12 // CHECK-cNULL: x: 0 // CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: errno: 12 // CHECK-coNULL: x: 0 // CHECK-rNULL: realloc: +// CHECK-rNULL: errno: 12 // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: errno: 12 // CHECK-mrNULL: x: 0 // CHECK-nnNULL: new-nothrow: // CHECK-nnNULL: x: 0 -- cgit v1.2.1 From dd3d6da1dfc6833e39650a23b570a81b1e85aff8 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 14 Jul 2017 22:23:47 +0000 Subject: [Sanitizers] ASan and LSan allocator set errno on failure. Summary: Set proper errno code on alloction failures and change some implementations to satisfy their man-specified requirements: LSan: valloc and memalign ASan: pvalloc, memalign and posix_memalign Changing both allocators in one patch since LSan depends on ASan allocator in some configurations. Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D35440 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308064 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 47 ++++++++++++++++++--------- lib/asan/tests/asan_test.cc | 18 ++++++++-- test/asan/TestCases/allocator_returns_null.cc | 10 +++++- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index de6613f56..0c7c7465f 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -22,6 +22,7 @@ #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" @@ -799,11 +800,6 @@ void PrintInternalAllocatorStats() { instance.PrintStats(); } -void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, - AllocType alloc_type) { - return instance.Allocate(size, alignment, stack, alloc_type, true); -} - void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { instance.Deallocate(ptr, 0, stack, alloc_type); } @@ -813,17 +809,23 @@ void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, instance.Deallocate(ptr, size, stack, alloc_type); } +inline void *check_ptr(void *ptr) { + if (UNLIKELY(!ptr)) + errno = errno_ENOMEM; + return ptr; +} + void *asan_malloc(uptr size, BufferedStackTrace *stack) { - return instance.Allocate(size, 8, stack, FROM_MALLOC, true); + return check_ptr(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); } void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { - return instance.Calloc(nmemb, size, stack); + return check_ptr(instance.Calloc(nmemb, size, stack)); } void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { if (!p) - return instance.Allocate(size, 8, stack, FROM_MALLOC, true); + return check_ptr(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); if (size == 0) { if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { instance.Deallocate(p, 0, stack, FROM_MALLOC); @@ -832,26 +834,41 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { // Allocate a size of 1 if we shouldn't free() on Realloc to 0 size = 1; } - return instance.Reallocate(p, size, stack); + return check_ptr(instance.Reallocate(p, size, stack)); } void *asan_valloc(uptr size, BufferedStackTrace *stack) { - return instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true); + return check_ptr( + instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true)); } void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); - size = RoundUpTo(size, PageSize); - if (size == 0) { - // pvalloc(0) should allocate one page. - size = PageSize; + // pvalloc(0) should allocate one page. + size = size ? RoundUpTo(size, PageSize) : PageSize; + return check_ptr(instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); +} + +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, + AllocType alloc_type) { + if (UNLIKELY(!IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + return AsanAllocator::FailureHandler::OnBadRequest(); } - return instance.Allocate(size, PageSize, stack, FROM_MALLOC, true); + return check_ptr( + instance.Allocate(size, alignment, stack, alloc_type, true)); } int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack) { + if (UNLIKELY(!IsPowerOfTwo(alignment) || + (alignment % sizeof(void *)) != 0)) { // NOLINT + AsanAllocator::FailureHandler::OnBadRequest(); + return errno_EINVAL; + } void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true); + if (!ptr) + return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; return 0; diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index d0128e34d..78c3a0e4e 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "asan_test_utils.h" +#include + NOINLINE void *malloc_fff(size_t size) { void *res = malloc/**/(size); break_optimization(0); return res;} NOINLINE void *malloc_eee(size_t size) { @@ -74,10 +76,19 @@ TEST(AddressSanitizer, VariousMallocsTest) { delete c; #if SANITIZER_TEST_HAS_POSIX_MEMALIGN - int *pm; - int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize); + void *pm = 0; + // Valid allocation. + int pm_res = posix_memalign(&pm, kPageSize, kPageSize); EXPECT_EQ(0, pm_res); + EXPECT_NE(nullptr, pm); free(pm); + + // Alignment is not a power of 2. + EXPECT_DEATH(posix_memalign(&pm, 3, kPageSize), + "allocator is terminating the process instead of returning 0"); + // Alignment is a power of 2, but not a multiple of size(void *). + EXPECT_DEATH(posix_memalign(&pm, 2, kPageSize), + "allocator is terminating the process instead of returning 0"); #endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN #if SANITIZER_TEST_HAS_MEMALIGN @@ -85,6 +96,9 @@ TEST(AddressSanitizer, VariousMallocsTest) { EXPECT_EQ(0U, (uintptr_t)ma % kPageSize); ma[123] = 0; free(ma); + + EXPECT_DEATH(memalign(3, kPageSize), + "allocator is terminating the process instead of returning 0"); #endif // SANITIZER_TEST_HAS_MEMALIGN } diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc index 90e25b55e..309814451 100644 --- a/test/asan/TestCases/allocator_returns_null.cc +++ b/test/asan/TestCases/allocator_returns_null.cc @@ -37,9 +37,10 @@ // RUN: | FileCheck %s --check-prefix=CHECK-nnNULL #include -#include +#include #include #include +#include #include #include @@ -84,6 +85,8 @@ int main(int argc, char **argv) { assert(0); } + fprintf(stderr, "errno: %d\n", errno); + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %lx\n", (long)x); @@ -108,14 +111,19 @@ int main(int argc, char **argv) { // CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process // CHECK-mNULL: malloc: +// CHECK-mNULL: errno: 12 // CHECK-mNULL: x: 0 // CHECK-cNULL: calloc: +// CHECK-cNULL: errno: 12 // CHECK-cNULL: x: 0 // CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: errno: 12 // CHECK-coNULL: x: 0 // CHECK-rNULL: realloc: +// CHECK-rNULL: errno: 12 // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: errno: 12 // CHECK-mrNULL: x: 0 // CHECK-nnNULL: new-nothrow: // CHECK-nnNULL: x: 0 -- cgit v1.2.1 From e6b35153993505d9192614d1403b67893868c178 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sat, 15 Jul 2017 00:30:46 +0000 Subject: [compiler-rt] [CMake] Build compiler-rt with no optimizations if the flag says so Differential Revision: https://reviews.llvm.org/D35400 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308072 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3195de1e5..f997c5341 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,10 +172,16 @@ endif() append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS) -# Build with optimization, unless we're in debug mode. If we're using MSVC, +# If we're using MSVC, # always respect the optimization flags set by CMAKE_BUILD_TYPE instead. -if(NOT COMPILER_RT_DEBUG AND NOT MSVC) - list(APPEND SANITIZER_COMMON_CFLAGS -O3) +if (NOT MSVC) + + # Build with optimization, unless we're in debug mode. + if(COMPILER_RT_DEBUG) + list(APPEND SANITIZER_COMMON_CFLAGS -O0) + else() + list(APPEND SANITIZER_COMMON_CFLAGS -O3) + endif() endif() # Determine if we should restrict stack frame sizes. -- cgit v1.2.1 From b2f847ad587215d72ea4e900df48ea17ab97c8c6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 16 Jul 2017 00:17:11 +0000 Subject: [compiler-rt] Fix fix format specifies type in test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308117 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/tests/sanitizer_bitvector_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc index dec5459b2..669365b80 100644 --- a/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc @@ -62,14 +62,14 @@ void Print(const BV &bv) { t.copyFrom(bv); while (!t.empty()) { uptr idx = t.getAndClearFirstOne(); - fprintf(stderr, "%zd ", idx); + fprintf(stderr, "%lu ", idx); } fprintf(stderr, "\n"); } void Print(const set &s) { for (set::iterator it = s.begin(); it != s.end(); ++it) { - fprintf(stderr, "%zd ", *it); + fprintf(stderr, "%lu ", *it); } fprintf(stderr, "\n"); } -- cgit v1.2.1 From cd32bdd8af41ab15441f6f3416843283e416b293 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 16 Jul 2017 00:40:40 +0000 Subject: [asan] Attempt to fix test in Windows after r308064 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308120 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_errno.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_errno.h b/lib/sanitizer_common/sanitizer_errno.h index c405307ba..7872b89c2 100644 --- a/lib/sanitizer_common/sanitizer_errno.h +++ b/lib/sanitizer_common/sanitizer_errno.h @@ -26,6 +26,8 @@ # define __errno_location __error #elif SANITIZER_ANDROID # define __errno_location __errno +#elif SANITIZER_WINDOWS +# define __errno_location _errno #endif extern "C" int *__errno_location(); -- cgit v1.2.1 From 102b89dd5821036179b0419685b31bb35abcd9cd Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 16 Jul 2017 01:05:37 +0000 Subject: [tsan] Disable test with debug runtime Test expects at least -O1 compiled runtime. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308121 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Linux/check_memcpy.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/tsan/Linux/check_memcpy.cc b/test/tsan/Linux/check_memcpy.cc index 8ad04c07c..b81efa42a 100644 --- a/test/tsan/Linux/check_memcpy.cc +++ b/test/tsan/Linux/check_memcpy.cc @@ -5,6 +5,8 @@ // RUN: %clangxx_tsan -O1 %s -o %t // RUN: llvm-objdump -d %t | FileCheck %s +// REQUIRES: compiler-rt-optimized + int main() { return 0; } -- cgit v1.2.1 From 773be72a9c628f15bd754de98692405e8af7b1bc Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 16 Jul 2017 01:19:35 +0000 Subject: [msan] Add missing include for fix test on Windows git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308122 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/msan/allocator_returns_null.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/msan/allocator_returns_null.cc b/test/msan/allocator_returns_null.cc index 2c7c32d40..b3bc1a365 100644 --- a/test/msan/allocator_returns_null.cc +++ b/test/msan/allocator_returns_null.cc @@ -38,6 +38,7 @@ #include +#include #include #include #include -- cgit v1.2.1 From b5b7b0b8b2e80a6fc48244f7eb43e6efa492c7d9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 16 Jul 2017 01:28:40 +0000 Subject: [asan] Disable not working new test on Windows git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308123 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/allocator_returns_null.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc index 309814451..8ce002f04 100644 --- a/test/asan/TestCases/allocator_returns_null.cc +++ b/test/asan/TestCases/allocator_returns_null.cc @@ -36,6 +36,8 @@ // RUN: %env_asan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-nnNULL +// UNSUPPORTED: win32 + #include #include #include -- cgit v1.2.1 From c8095ce74118dee8544b0f1ffaba8f46aa10215c Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 17 Jul 2017 20:09:20 +0000 Subject: Add MemoryMappedSection struct for two-level memory map iteration Summary: This will allow sanitizer_procmaps on mac to expose section information. Reviewers: kubamracek, alekseyshl, kcc Subscribers: llvm-commits, emaste Differential Revision: https://reviews.llvm.org/D35422 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308210 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 18 ++++++++++- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 45 +++++++++++++++++++++----- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 06d072b4d..76685661c 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,7 +37,8 @@ static const uptr kProtectionWrite = 2; static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -struct MemoryMappedSegment { +class MemoryMappedSegment { + public: MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size) {} ~MemoryMappedSegment() {} @@ -55,6 +56,21 @@ struct MemoryMappedSegment { uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; + +#if SANITIZER_MAC + + private: + friend class MemoryMappingLayout; + + template + void NextSectionLoad(LoadedModule *module); + void AddAddressRanges(LoadedModule *module); + + uptr nsects_; + char *current_load_cmd_addr_; + u32 lc_type_; + uptr base_virt_addr_; +#endif }; class MemoryMappingLayout { diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 560451a16..411bbd39d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -35,6 +35,32 @@ #endif namespace __sanitizer { +template +void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { + const Section *sc = (const Section *)current_load_cmd_addr_; + current_load_cmd_addr_ += sizeof(Section); + + uptr sec_start = sc->addr + base_virt_addr_; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + if (!nsects_) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); + return; + } + + do { + if (lc_type_ == LC_SEGMENT) { + NextSectionLoad(module); +#ifdef MH_MAGIC_64 + } else if (lc_type_ == LC_SEGMENT_64) { + NextSectionLoad(module); +#endif + } + } while (--nsects_); +} MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); @@ -143,21 +169,25 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; + segment->current_load_cmd_addr_ = (char *)lc + sizeof(SegmentCommand); + segment->lc_type_ = kLCSegment; + segment->nsects_ = sc->nsects; if (current_image_ == kDyldImageIdx) { + segment->base_virt_addr_ = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); + segment->start = (sc->vmaddr & 0xfffff) + segment->base_virt_addr_; } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - segment->start = sc->vmaddr + dlloff; - segment->end = sc->vmaddr + sc->vmsize + dlloff; + segment->base_virt_addr_ = + (uptr)_dyld_get_image_vmaddr_slide(current_image_); + segment->start = sc->vmaddr + segment->base_virt_addr_; } + segment->end = segment->start + sc->vmsize; // Return the initial protection. segment->protection = sc->initprot; @@ -292,7 +322,7 @@ void MemoryMappingLayout::DumpListOfModules( Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - for (uptr i = 0; Next(&segment); i++) { + while (Next(&segment)) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -304,8 +334,7 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - cur_module->addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(cur_module); } } -- cgit v1.2.1 From f36d180d7c9ab78ae0cb313fb612b266fe6c859e Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 17 Jul 2017 20:47:53 +0000 Subject: Introduce SANITIZER_NETBSD in sanitizer_platform.h Summary: Add defines for new NetBSD: SANITIZER_NETBSD, it will be used across the codebase for sanitizers. NetBSD is a POSIX-like platform, add it to SANITIZER_POSIX. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, dim, alekseyshl, filcab, eugenis, vitalybuka Reviewed By: kcc Subscribers: kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35467 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308216 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 49732aa32..1df5fa34f 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -13,7 +13,7 @@ #ifndef SANITIZER_PLATFORM_H #define SANITIZER_PLATFORM_H -#if !defined(__linux__) && !defined(__FreeBSD__) && \ +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) \ !defined(__APPLE__) && !defined(_WIN32) # error "This operating system is not supported" #endif @@ -30,6 +30,12 @@ # define SANITIZER_FREEBSD 0 #endif +#if defined(__NetBSD__) +# define SANITIZER_NETBSD 1 +#else +# define SANITIZER_NETBSD 0 +#endif + #if defined(__APPLE__) # define SANITIZER_MAC 1 # include @@ -79,7 +85,8 @@ # define SANITIZER_ANDROID 0 #endif -#define SANITIZER_POSIX (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC) +#define SANITIZER_POSIX \ + (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 -- cgit v1.2.1 From 0d60e8eeb8c0719a8f7ba982de106a520837ffb4 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 17 Jul 2017 20:49:13 +0000 Subject: Add NetBSD support in platform_interceptors.h Summary: Introduce SI_NETBSD for NetBSD. Add NetBSD support for appropriate `SANITIZER_INTERCEPT_*`. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, dim, kcc, alekseyshl, filcab, eugenis, vitalybuka Reviewed By: vitalybuka Subscribers: srhines, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35468 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308217 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_platform_interceptors.h | 98 +++++++++++++--------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 1bc43e817..12e8ecbe8 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -49,6 +49,12 @@ # define SI_FREEBSD 0 #endif +#if SANITIZER_NETBSD +# define SI_NETBSD 1 +#else +# define SI_NETBSD 0 +#endif + #if SANITIZER_LINUX # define SI_LINUX 1 #else @@ -111,7 +117,7 @@ #define SANITIZER_INTERCEPT_MEMMEM \ SI_NOT_WINDOWS && !SI_MAC_DEPLOYMENT_BELOW_10_7 #define SANITIZER_INTERCEPT_MEMCHR 1 -#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX +#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX || SI_NETBSD #define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS @@ -127,7 +133,8 @@ #define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PREADV SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PREADV \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID @@ -142,7 +149,7 @@ #ifndef SANITIZER_INTERCEPT_PRINTF # define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS -# define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD +# define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD || SI_NETBSD # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif @@ -151,13 +158,14 @@ #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPWENT \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_GETPWENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETPWENT_R \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_LINUX +#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_NETBSD || SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID @@ -200,41 +208,43 @@ #define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSNRTOMBS \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCRTOMB \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CONFSTR \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WORDEXP \ - SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGSETOPS \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_BACKTRACE SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_BACKTRACE \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS64 \ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STATVFS SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_STATVFS \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS @@ -242,18 +252,19 @@ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_ETHER_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SHMCTL \ - ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) + SI_NETBSD || \ + ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ - SI_MAC || SI_LINUX_NOT_ANDROID + SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ - SI_MAC || SI_LINUX_NOT_ANDROID + SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS @@ -272,29 +283,31 @@ #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_RAND_R \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_ICONV SI_FREEBSD || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_ICONV \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS // FIXME: getline seems to be available on OSX 10.7 -#define SANITIZER_INTERCEPT_GETLINE SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETLINE \ + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_MAC +#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETRESID SI_LINUX #define SANITIZER_INTERCEPT_GETIFADDRS \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_IF_INDEXTONAME \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID #if SI_LINUX && defined(__arm__) #define SANITIZER_INTERCEPT_AEABI_MEM 1 @@ -302,32 +315,33 @@ #define SANITIZER_INTERCEPT_AEABI_MEM 0 #endif #define SANITIZER_INTERCEPT___BZERO SI_MAC -#define SANITIZER_INTERCEPT_FTIME !SI_FREEBSD && SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FTIME !SI_FREEBSD && !SI_NETBSD && SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID || SI_NETBSD #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE #define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ - SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC + SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC #endif -#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD +#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD || SI_NETBSD #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_MINCORE SI_LINUX +#define SANITIZER_INTERCEPT_MINCORE SI_LINUX || SI_NETBSD #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX -#define SANITIZER_INTERCEPT_CTERMID SI_LINUX || SI_MAC || SI_FREEBSD +#define SANITIZER_INTERCEPT_CTERMID \ + SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD #define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD #define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX || SI_MAC || SI_WINDOWS @@ -335,7 +349,8 @@ #define SANITIZER_INTERCEPT_SEND_SENDTO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX -#define SANITIZER_INTERCEPT_STAT (SI_FREEBSD || SI_MAC || SI_ANDROID) +#define SANITIZER_INTERCEPT_STAT \ + (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD) #define SANITIZER_INTERCEPT___XSTAT !SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT @@ -345,12 +360,13 @@ #define SANITIZER_INTERCEPT_UTMPX SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD #define SANITIZER_INTERCEPT_GETLOADAVG \ - SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD + SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (!SI_FREEBSD && !SI_MAC) -#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC) -#define SANITIZER_INTERCEPT_PVALLOC (!SI_FREEBSD && !SI_MAC) -#define SANITIZER_INTERCEPT_CFREE (!SI_FREEBSD && !SI_MAC) +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PVALLOC (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_CFREE (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID -- cgit v1.2.1 From fbc6b650e7abdb769c4ffae0c37c1681b67366b2 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 17 Jul 2017 21:09:34 +0000 Subject: Add missing && to fix syntax. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308221 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 1df5fa34f..396f7c934 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -13,7 +13,7 @@ #ifndef SANITIZER_PLATFORM_H #define SANITIZER_PLATFORM_H -#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) \ +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) # error "This operating system is not supported" #endif -- cgit v1.2.1 From 76862cd3ca43eb49946214b6263a22046a0033b2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 17 Jul 2017 22:49:46 +0000 Subject: [sanitizers] Make sure that all complex macros uses parenthesis Summary: Without them expressions like this may have different values. (SANITIZER_INTERCEPT_MEMRCHR && SANITIZER_INTERCEPT_PREADV) Reviewers: alekseyshl Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D35512 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308228 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_platform_interceptors.h | 116 +++++++++++---------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 12e8ecbe8..0380cee92 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -115,9 +115,9 @@ // memmem on Darwin doesn't exist on 10.6 // FIXME: enable memmem on Windows. #define SANITIZER_INTERCEPT_MEMMEM \ - SI_NOT_WINDOWS && !SI_MAC_DEPLOYMENT_BELOW_10_7 + (SI_NOT_WINDOWS && !SI_MAC_DEPLOYMENT_BELOW_10_7) #define SANITIZER_INTERCEPT_MEMCHR 1 -#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX || SI_NETBSD +#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) #define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS @@ -134,7 +134,7 @@ #define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREADV \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID @@ -149,7 +149,7 @@ #ifndef SANITIZER_INTERCEPT_PRINTF # define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS -# define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD || SI_NETBSD +# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif @@ -158,14 +158,14 @@ #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETPWENT \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPWENT_R \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_NETBSD || SI_LINUX + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_SETPWENT (SI_MAC || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_CLOCK_GETTIME (SI_FREEBSD || SI_NETBSD || SI_LINUX) #define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID @@ -176,10 +176,11 @@ #define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_FREEBSD || SI_LINUX -#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_FREEBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_FREEBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R (SI_FREEBSD || SI_LINUX) +#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R \ + (SI_FREEBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID @@ -205,66 +206,67 @@ #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_MBSNRTOWCS (SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSNRTOMBS \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_WCRTOMB \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CONFSTR \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WORDEXP \ - SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGSETOPS \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_BACKTRACE \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STATFS SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_STATFS \ + (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATFS64 \ - (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID + ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ETHER_HOST \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_ETHER_R SI_FREEBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SHMCTL \ - SI_NETBSD || \ - ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) + (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_SHMCTL \ + (SI_NETBSD || ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ + SANITIZER_WORDSIZE == 64)) // NOLINT #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ - SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ - SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS @@ -279,35 +281,36 @@ #define SANITIZER_INTERCEPT_SINCOS SI_LINUX #define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_LGAMMA_R SI_FREEBSD || SI_LINUX +#define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX) #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_RAND_R \ - SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ICONV \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC +#define SANITIZER_INTERCEPT__EXIT \ + (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC) #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETRESID SI_LINUX #define SANITIZER_INTERCEPT_GETIFADDRS \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC) #define SANITIZER_INTERCEPT_IF_INDEXTONAME \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC) #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID #if SI_LINUX && defined(__arm__) #define SANITIZER_INTERCEPT_AEABI_MEM 1 @@ -315,52 +318,55 @@ #define SANITIZER_INTERCEPT_AEABI_MEM 0 #endif #define SANITIZER_INTERCEPT___BZERO SI_MAC -#define SANITIZER_INTERCEPT_FTIME !SI_FREEBSD && !SI_NETBSD && SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_NOT_WINDOWS) #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD +#define SANITIZER_INTERCEPT_TSEARCH \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID || SI_NETBSD +#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM (SI_LINUX_NOT_ANDROID || SI_NETBSD) #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE #define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ - SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC) #endif -#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD +#define SANITIZER_INTERCEPT_GETPASS \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD || SI_NETBSD +#define SANITIZER_INTERCEPT_SEM (SI_LINUX || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_MINCORE SI_LINUX || SI_NETBSD +#define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD) #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX #define SANITIZER_INTERCEPT_CTERMID \ - SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD -#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD + (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD) -#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX || SI_MAC || SI_WINDOWS +#define SANITIZER_INTERCEPTOR_HOOKS (SI_LINUX || SI_MAC || SI_WINDOWS) #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SEND_SENDTO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX #define SANITIZER_INTERCEPT_STAT \ (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD) -#define SANITIZER_INTERCEPT___XSTAT !SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT___XSTAT \ + (!SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS) #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT #define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_UTMP SI_NOT_WINDOWS && !SI_MAC && !SI_FREEBSD -#define SANITIZER_INTERCEPT_UTMPX SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD +#define SANITIZER_INTERCEPT_UTMP (SI_NOT_WINDOWS && !SI_MAC && !SI_FREEBSD) +#define SANITIZER_INTERCEPT_UTMPX (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD) #define SANITIZER_INTERCEPT_GETLOADAVG \ - SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) -- cgit v1.2.1 From 7e46d78d47832f03ce42adcf56417fbfd47cbaad Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 17 Jul 2017 23:03:03 +0000 Subject: Only scan global sections containing data in LSan on darwin Summary: __DATA segments on Darwin contain a large number of separate sections, most of which cannot actually contain pointers, and contain const values or objc metadata. Only scanning sections which can contain pointers greatly improves performance. On a medium-sized (~4000 files) internal project, I saw a speedup of about 50% in standalone LSan's execution time (50% improvement in the time spent running LSan, not the total program time). Reviewers: kcc, kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35432 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308231 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 15 +++++++++++---- lib/sanitizer_common/sanitizer_common.cc | 5 +++-- lib/sanitizer_common/sanitizer_common.h | 12 +++++++++--- lib/sanitizer_common/sanitizer_procmaps.h | 1 + lib/sanitizer_common/sanitizer_procmaps_mac.cc | 6 ++++-- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index f87c6b7e0..c0fa36fd9 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -92,8 +92,15 @@ LoadedModule *GetLinker() { return nullptr; } // required on Darwin. void InitializePlatformSpecificModules() {} +// Sections which may contain global variables +static const char *kGlobalVarSecNames[] = { + "__DATA", "__bss", "__common", "__data", + "__objc_data", "__objc_opt_rw", "__objc_opt_ptrs"}; + // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { + for (auto name : kGlobalVarSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName); + MemoryMappingLayout memory_mapping(false); InternalMmapVector modules(/*initial_capacity*/ 128); memory_mapping.DumpListOfModules(&modules); @@ -104,10 +111,10 @@ void ProcessGlobalRegions(Frontier *frontier) { for (const __sanitizer::LoadedModule::AddressRange &range : modules[i].ranges()) { - // Sections storing global variables are writable and non-executable - if (range.executable || !range.writable) continue; - - ScanGlobalRange(range.beg, range.end, frontier); + for (auto name : kGlobalVarSecNames) { + if (!internal_strcmp(range.name, name)) + ScanGlobalRange(range.beg, range.end, frontier); + } } } } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 7e6f8fce7..3868d5469 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -285,9 +285,10 @@ void LoadedModule::clear() { } void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, - bool writable) { + bool writable, const char *name) { void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = new(mem) AddressRange(beg, end, executable, writable); + AddressRange *r = + new(mem) AddressRange(beg, end, executable, writable, name); ranges_.push_back(r); if (executable && end > max_executable_address_) max_executable_address_ = end; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 89aae5798..f684271d4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -702,6 +702,7 @@ inline const char *ModuleArchToString(ModuleArch arch) { } const uptr kModuleUUIDSize = 16; +const uptr kMaxSegName = 16; // Represents a binary loaded into virtual memory (e.g. this can be an // executable or a shared object). @@ -720,7 +721,8 @@ class LoadedModule { void set(const char *module_name, uptr base_address, ModuleArch arch, u8 uuid[kModuleUUIDSize], bool instrumented); void clear(); - void addAddressRange(uptr beg, uptr end, bool executable, bool writable); + void addAddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name = nullptr); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } @@ -736,13 +738,17 @@ class LoadedModule { uptr end; bool executable; bool writable; + char name[kMaxSegName]; - AddressRange(uptr beg, uptr end, bool executable, bool writable) + AddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name) : next(nullptr), beg(beg), end(end), executable(executable), - writable(writable) {} + writable(writable) { + internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name)); + } }; const IntrusiveList &ranges() const { return ranges_; } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 76685661c..50753c4e6 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -58,6 +58,7 @@ class MemoryMappedSegment { u8 uuid[kModuleUUIDSize]; #if SANITIZER_MAC + char name[kMaxSegName]; private: friend class MemoryMappingLayout; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 411bbd39d..277d2b194 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -42,12 +42,13 @@ void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { uptr sec_start = sc->addr + base_virt_addr_; uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); + module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable(), + sc->sectname); } void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { if (!nsects_) { - module->addAddressRange(start, end, IsExecutable(), IsWritable()); + module->addAddressRange(start, end, IsExecutable(), IsWritable(), name); return; } @@ -199,6 +200,7 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { : _dyld_get_image_name(current_image_); internal_strncpy(segment->filename, src, segment->filename_size); } + internal_strncpy(segment->name, sc->segname, ARRAY_SIZE(segment->name)); segment->arch = current_arch_; internal_memcpy(segment->uuid, current_uuid_, kModuleUUIDSize); return true; -- cgit v1.2.1 From e726963d587b1d95320da4f5f05cd563e36eb8fe Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 18 Jul 2017 01:39:56 +0000 Subject: [asan] Remove recent asan tests which expect death in allocator These tests assume allocator_may_return_null=false If allocator_may_return_null=true, gtest would not be able to switch it. Tests needs to be re-implemented as lit tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308254 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test.cc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 78c3a0e4e..7e9cf3bab 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -82,13 +82,6 @@ TEST(AddressSanitizer, VariousMallocsTest) { EXPECT_EQ(0, pm_res); EXPECT_NE(nullptr, pm); free(pm); - - // Alignment is not a power of 2. - EXPECT_DEATH(posix_memalign(&pm, 3, kPageSize), - "allocator is terminating the process instead of returning 0"); - // Alignment is a power of 2, but not a multiple of size(void *). - EXPECT_DEATH(posix_memalign(&pm, 2, kPageSize), - "allocator is terminating the process instead of returning 0"); #endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN #if SANITIZER_TEST_HAS_MEMALIGN @@ -96,9 +89,6 @@ TEST(AddressSanitizer, VariousMallocsTest) { EXPECT_EQ(0U, (uintptr_t)ma % kPageSize); ma[123] = 0; free(ma); - - EXPECT_DEATH(memalign(3, kPageSize), - "allocator is terminating the process instead of returning 0"); #endif // SANITIZER_TEST_HAS_MEMALIGN } -- cgit v1.2.1 From 13c2d08571baab9982f01acb1d302049bdace581 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Tue, 18 Jul 2017 19:11:04 +0000 Subject: [Sanitizers] ASan/MSan/LSan allocators set errno on failure. Summary: ASan/MSan/LSan allocators set errno on allocation failures according to malloc/calloc/etc. expected behavior. MSan allocator was refactored a bit to make its structure more similar with other allocators. Also switch Scudo allocator to the internal errno definitions. TSan allocator changes will follow. Reviewers: eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D35275 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308344 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 27 +++---- lib/lsan/lsan_allocator.cc | 17 ++--- lib/msan/msan.h | 14 +++- lib/msan/msan_allocator.cc | 85 ++++++++++++++++++----- lib/msan/msan_interceptors.cc | 49 +++++-------- lib/msan/msan_new_delete.cc | 2 +- lib/sanitizer_common/sanitizer_allocator.cc | 9 +-- lib/sanitizer_common/sanitizer_allocator.h | 5 -- lib/sanitizer_common/sanitizer_allocator_checks.h | 64 +++++++++++++++++ lib/scudo/scudo_allocator.cpp | 31 ++++----- lib/tsan/rtl/tsan_mman.cc | 1 + test/msan/allocator_returns_null.cc | 10 ++- 12 files changed, 202 insertions(+), 112 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.h diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 0c7c7465f..92963ddfc 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -21,6 +21,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" +#include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_flags.h" @@ -809,23 +810,17 @@ void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, instance.Deallocate(ptr, size, stack, alloc_type); } -inline void *check_ptr(void *ptr) { - if (UNLIKELY(!ptr)) - errno = errno_ENOMEM; - return ptr; -} - void *asan_malloc(uptr size, BufferedStackTrace *stack) { - return check_ptr(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); + return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); } void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { - return check_ptr(instance.Calloc(nmemb, size, stack)); + return SetErrnoOnNull(instance.Calloc(nmemb, size, stack)); } void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { if (!p) - return check_ptr(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); + return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); if (size == 0) { if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { instance.Deallocate(p, 0, stack, FROM_MALLOC); @@ -834,11 +829,11 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { // Allocate a size of 1 if we shouldn't free() on Realloc to 0 size = 1; } - return check_ptr(instance.Reallocate(p, size, stack)); + return SetErrnoOnNull(instance.Reallocate(p, size, stack)); } void *asan_valloc(uptr size, BufferedStackTrace *stack) { - return check_ptr( + return SetErrnoOnNull( instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true)); } @@ -846,7 +841,8 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); // pvalloc(0) should allocate one page. size = size ? RoundUpTo(size, PageSize) : PageSize; - return check_ptr(instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); + return SetErrnoOnNull( + instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); } void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, @@ -855,19 +851,18 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, errno = errno_EINVAL; return AsanAllocator::FailureHandler::OnBadRequest(); } - return check_ptr( + return SetErrnoOnNull( instance.Allocate(size, alignment, stack, alloc_type, true)); } int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack) { - if (UNLIKELY(!IsPowerOfTwo(alignment) || - (alignment % sizeof(void *)) != 0)) { // NOLINT + if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { AsanAllocator::FailureHandler::OnBadRequest(); return errno_EINVAL; } void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true); - if (!ptr) + if (UNLIKELY(!ptr)) return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc index 96d5cb6a9..2df58b44f 100644 --- a/lib/lsan/lsan_allocator.cc +++ b/lib/lsan/lsan_allocator.cc @@ -15,6 +15,7 @@ #include "lsan_allocator.h" #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_internal_defs.h" @@ -125,22 +126,16 @@ uptr GetMallocUsableSize(const void *p) { return m->requested_size; } -inline void *check_ptr(void *ptr) { - if (UNLIKELY(!ptr)) - errno = errno_ENOMEM; - return ptr; -} - void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; return Allocator::FailureHandler::OnBadRequest(); } - return check_ptr(Allocate(stack, size, alignment, kAlwaysClearMemory)); + return SetErrnoOnNull(Allocate(stack, size, alignment, kAlwaysClearMemory)); } void *lsan_malloc(uptr size, const StackTrace &stack) { - return check_ptr(Allocate(stack, size, 1, kAlwaysClearMemory)); + return SetErrnoOnNull(Allocate(stack, size, 1, kAlwaysClearMemory)); } void lsan_free(void *p) { @@ -148,15 +143,15 @@ void lsan_free(void *p) { } void *lsan_realloc(void *p, uptr size, const StackTrace &stack) { - return check_ptr(Reallocate(stack, p, size, 1)); + return SetErrnoOnNull(Reallocate(stack, p, size, 1)); } void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) { - return check_ptr(Calloc(nmemb, size, stack)); + return SetErrnoOnNull(Calloc(nmemb, size, stack)); } void *lsan_valloc(uptr size, const StackTrace &stack) { - return check_ptr( + return SetErrnoOnNull( Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory)); } diff --git a/lib/msan/msan.h b/lib/msan/msan.h index 0709260ee..fa9c15b88 100644 --- a/lib/msan/msan.h +++ b/lib/msan/msan.h @@ -280,10 +280,18 @@ void InitializeInterceptors(); void MsanAllocatorInit(); void MsanAllocatorThreadFinish(); -void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size); -void *MsanReallocate(StackTrace *stack, void *oldp, uptr size, - uptr alignment, bool zeroise); void MsanDeallocate(StackTrace *stack, void *ptr); + +void *msan_malloc(uptr size, StackTrace *stack); +void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack); +void *msan_realloc(void *ptr, uptr size, StackTrace *stack); +void *msan_valloc(uptr size, StackTrace *stack); +void *msan_pvalloc(uptr size, StackTrace *stack); +void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); +void *msan_memalign(uptr alignment, uptr size, StackTrace *stack); +int msan_posix_memalign(void **memptr, uptr alignment, uptr size, + StackTrace *stack); + void InstallTrapHandler(); void InstallAtExitHandler(); diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index a92b7fd12..1034dbdf9 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -13,7 +13,9 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_errno.h" #include "msan.h" #include "msan_allocator.h" #include "msan_origin.h" @@ -194,20 +196,8 @@ void MsanDeallocate(StackTrace *stack, void *p) { } } -void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { - if (CheckForCallocOverflow(size, nmemb)) - return Allocator::FailureHandler::OnBadRequest(); - return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true); -} - void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, - uptr alignment, bool zeroise) { - if (!old_p) - return MsanAllocate(stack, new_size, alignment, zeroise); - if (!new_size) { - MsanDeallocate(stack, old_p); - return nullptr; - } + uptr alignment) { Metadata *meta = reinterpret_cast(allocator.GetMetaData(old_p)); uptr old_size = meta->requested_size; uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); @@ -215,10 +205,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, // We are not reallocating here. meta->requested_size = new_size; if (new_size > old_size) { - if (zeroise) { - __msan_clear_and_unpoison((char *)old_p + old_size, - new_size - old_size); - } else if (flags()->poison_in_malloc) { + if (flags()->poison_in_malloc) { stack->tag = StackTrace::TAG_ALLOC; PoisonMemory((char *)old_p + old_size, new_size - old_size, stack); } @@ -226,8 +213,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, return old_p; } uptr memcpy_size = Min(new_size, old_size); - void *new_p = MsanAllocate(stack, new_size, alignment, zeroise); - // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size); + void *new_p = MsanAllocate(stack, new_size, alignment, false /*zeroise*/); if (new_p) { CopyMemory(new_p, old_p, memcpy_size, stack); MsanDeallocate(stack, old_p); @@ -243,6 +229,67 @@ static uptr AllocationSize(const void *p) { return b->requested_size; } +void *msan_malloc(uptr size, StackTrace *stack) { + return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); +} + +void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) { + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) + return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); + return SetErrnoOnNull(MsanAllocate(stack, nmemb * size, sizeof(u64), true)); +} + +void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { + if (!ptr) + return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); + if (size == 0) { + MsanDeallocate(stack, ptr); + return nullptr; + } + return SetErrnoOnNull(MsanReallocate(stack, ptr, size, sizeof(u64))); +} + +void *msan_valloc(uptr size, StackTrace *stack) { + return SetErrnoOnNull(MsanAllocate(stack, size, GetPageSizeCached(), false)); +} + +void *msan_pvalloc(uptr size, StackTrace *stack) { + uptr PageSize = GetPageSizeCached(); + // pvalloc(0) should allocate one page. + size = size == 0 ? PageSize : RoundUpTo(size, PageSize); + return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); +} + +void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { + if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { + errno = errno_EINVAL; + return Allocator::FailureHandler::OnBadRequest(); + } + return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); +} + +void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) { + if (UNLIKELY(!IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + return Allocator::FailureHandler::OnBadRequest(); + } + return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); +} + +int msan_posix_memalign(void **memptr, uptr alignment, uptr size, + StackTrace *stack) { + if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { + Allocator::FailureHandler::OnBadRequest(); + return errno_EINVAL; + } + void *ptr = MsanAllocate(stack, size, alignment, false); + if (UNLIKELY(!ptr)) + return errno_ENOMEM; + CHECK(IsAligned((uptr)ptr, alignment)); + *memptr = ptr; + return 0; +} + } // namespace __msan using namespace __msan; diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 069777c7f..b5d22baca 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -161,58 +161,45 @@ INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) { INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; - CHECK_EQ(alignment & (alignment - 1), 0); CHECK_NE(memptr, 0); - *memptr = MsanReallocate(&stack, nullptr, size, alignment, false); - CHECK_NE(*memptr, 0); - __msan_unpoison(memptr, sizeof(*memptr)); - return 0; + int res = msan_posix_memalign(memptr, alignment, size, &stack); + if (!res) + __msan_unpoison(memptr, sizeof(*memptr)); + return res; } #if !SANITIZER_FREEBSD -INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) { +INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; - CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); - return ptr; + return msan_memalign(alignment, size, &stack); } #define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) #else #define MSAN_MAYBE_INTERCEPT_MEMALIGN #endif -INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) { +INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; - CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); - return ptr; + return msan_aligned_alloc(alignment, size, &stack); } -INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) { +INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; - CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); - DTLS_on_libc_memalign(ptr, size); + void *ptr = msan_memalign(alignment, size, &stack); + if (ptr) + DTLS_on_libc_memalign(ptr, size); return ptr; } INTERCEPTOR(void *, valloc, SIZE_T size) { GET_MALLOC_STACK_TRACE; - void *ptr = MsanReallocate(&stack, nullptr, size, GetPageSizeCached(), false); - return ptr; + return msan_valloc(size, &stack); } #if !SANITIZER_FREEBSD INTERCEPTOR(void *, pvalloc, SIZE_T size) { GET_MALLOC_STACK_TRACE; - uptr PageSize = GetPageSizeCached(); - size = RoundUpTo(size, PageSize); - if (size == 0) { - // pvalloc(0) should allocate one page. - size = PageSize; - } - void *ptr = MsanReallocate(&stack, nullptr, size, PageSize, false); - return ptr; + return msan_pvalloc(size, &stack); } #define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) #else @@ -853,7 +840,7 @@ INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { if (UNLIKELY(!msan_inited)) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); - return MsanCalloc(&stack, nmemb, size); + return msan_calloc(nmemb, size, &stack); } INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { @@ -866,12 +853,12 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { new_ptr = AllocateFromLocalPool(copy_size); } else { copy_size = size; - new_ptr = MsanReallocate(&stack, nullptr, copy_size, sizeof(u64), false); + new_ptr = msan_malloc(copy_size, &stack); } internal_memcpy(new_ptr, ptr, copy_size); return new_ptr; } - return MsanReallocate(&stack, ptr, size, sizeof(u64), false); + return msan_realloc(ptr, size, &stack); } INTERCEPTOR(void *, malloc, SIZE_T size) { @@ -879,7 +866,7 @@ INTERCEPTOR(void *, malloc, SIZE_T size) { if (UNLIKELY(!msan_inited)) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); - return MsanReallocate(&stack, nullptr, size, sizeof(u64), false); + return msan_malloc(size, &stack); } void __msan_allocated_memory(const void *data, uptr size) { diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc index c7295feeb..721926791 100644 --- a/lib/msan/msan_new_delete.cc +++ b/lib/msan/msan_new_delete.cc @@ -31,7 +31,7 @@ namespace std { // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. #define OPERATOR_NEW_BODY(nothrow) \ GET_MALLOC_STACK_TRACE; \ - void *res = MsanReallocate(&stack, 0, size, sizeof(u64), false);\ + void *res = msan_malloc(size, &stack);\ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ return res diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index 2f8f6e3f9..84f523c5e 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -14,6 +14,7 @@ #include "sanitizer_allocator.h" +#include "sanitizer_allocator_checks.h" #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" @@ -160,7 +161,7 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { } void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { - if (CheckForCallocOverflow(count, size)) + if (UNLIKELY(CheckForCallocOverflow(count, size))) return InternalAllocator::FailureHandler::OnBadRequest(); void *p = InternalAlloc(count * size, cache); if (p) internal_memset(p, 0, count * size); @@ -202,12 +203,6 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { low_level_alloc_callback = callback; } -bool CheckForCallocOverflow(uptr size, uptr n) { - if (!size) return false; - uptr max = (uptr)-1L; - return (max / size) < n; -} - static atomic_uint8_t allocator_out_of_memory = {0}; static atomic_uint8_t allocator_may_return_null = {0}; diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index 0fb8a087e..8c5696ea7 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -56,11 +56,6 @@ struct NoOpMapUnmapCallback { // Callback type for iterating over chunks. typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); -// Returns true if calloc(size, n) call overflows on size*n calculation. -// The caller should "return POLICY::OnBadRequest();" where POLICY is the -// current allocator failure handling policy. -bool CheckForCallocOverflow(uptr size, uptr n); - #include "sanitizer_allocator_size_class_map.h" #include "sanitizer_allocator_stats.h" #include "sanitizer_allocator_primary64.h" diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h new file mode 100644 index 000000000..202916eae --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -0,0 +1,64 @@ +//===-- sanitizer_allocator_checks.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_CHECKS_H +#define SANITIZER_ALLOCATOR_CHECKS_H + +#include "sanitizer_errno.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { + +// A common errno setting logic shared by almost all sanitizer allocator APIs. +INLINE void *SetErrnoOnNull(void *ptr) { + if (UNLIKELY(!ptr)) + errno = errno_ENOMEM; + return ptr; +} + +// In case of the check failure, the caller of the following Check... functions +// should "return POLICY::OnBadRequest();" where POLICY is the current allocator +// failure handling policy. + +// Checks aligned_alloc() parameters, verifies that the alignment is a power of +// two and that the size is a multiple of alignment for POSIX implementation, +// and a bit relaxed requirement for non-POSIX ones, that the size is a multiple +// of alignment. +INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { +#if SANITIZER_POSIX + return IsPowerOfTwo(alignment) && (size & (alignment - 1)) == 0; +#else + return size % alignment == 0; +#endif +} + +// Checks posix_memalign() parameters, verifies that alignment is a power of two +// and a multiple of sizeof(void *). +INLINE bool CheckPosixMemalignAlignment(uptr alignment) { + return IsPowerOfTwo(alignment) && (alignment % sizeof(void *)) == 0; // NOLINT +} + +// Returns true if calloc(size, n) call overflows on size*n calculation. +INLINE bool CheckForCallocOverflow(uptr size, uptr n) { + if (!size) + return false; + uptr max = (uptr)-1L; + return (max / size) < n; +} + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_CHECKS_H diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 102d1d0df..6f30ee987 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -19,6 +19,7 @@ #include "scudo_tls.h" #include "scudo_utils.h" +#include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_quarantine.h" @@ -638,14 +639,8 @@ void ScudoThreadContext::commitBack() { Instance.commitBack(this); } -INLINE void *checkPtr(void *Ptr) { - if (UNLIKELY(!Ptr)) - errno = errno_ENOMEM; - return Ptr; -} - void *scudoMalloc(uptr Size, AllocType Type) { - return checkPtr(Instance.allocate(Size, MinAlignment, Type)); + return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, Type)); } void scudoFree(void *Ptr, AllocType Type) { @@ -658,27 +653,28 @@ void scudoSizedFree(void *Ptr, uptr Size, AllocType Type) { void *scudoRealloc(void *Ptr, uptr Size) { if (!Ptr) - return checkPtr(Instance.allocate(Size, MinAlignment, FromMalloc)); + return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, FromMalloc)); if (Size == 0) { Instance.deallocate(Ptr, 0, FromMalloc); return nullptr; } - return checkPtr(Instance.reallocate(Ptr, Size)); + return SetErrnoOnNull(Instance.reallocate(Ptr, Size)); } void *scudoCalloc(uptr NMemB, uptr Size) { - return checkPtr(Instance.calloc(NMemB, Size)); + return SetErrnoOnNull(Instance.calloc(NMemB, Size)); } void *scudoValloc(uptr Size) { - return checkPtr(Instance.allocate(Size, GetPageSizeCached(), FromMemalign)); + return SetErrnoOnNull( + Instance.allocate(Size, GetPageSizeCached(), FromMemalign)); } void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); // pvalloc(0) should allocate one page. Size = Size ? RoundUpTo(Size, PageSize) : PageSize; - return checkPtr(Instance.allocate(Size, PageSize, FromMemalign)); + return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign)); } void *scudoMemalign(uptr Alignment, uptr Size) { @@ -686,28 +682,27 @@ void *scudoMemalign(uptr Alignment, uptr Size) { errno = errno_EINVAL; return ScudoAllocator::FailureHandler::OnBadRequest(); } - return checkPtr(Instance.allocate(Size, Alignment, FromMemalign)); + return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign)); } int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { - if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Alignment % sizeof(void *)) != 0)) { + if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) { ScudoAllocator::FailureHandler::OnBadRequest(); return errno_EINVAL; } void *Ptr = Instance.allocate(Size, Alignment, FromMemalign); - if (!Ptr) + if (UNLIKELY(!Ptr)) return errno_ENOMEM; *MemPtr = Ptr; return 0; } void *scudoAlignedAlloc(uptr Alignment, uptr Size) { - // Alignment must be a power of 2, Size must be a multiple of Alignment. - if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0)) { + if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) { errno = errno_EINVAL; return ScudoAllocator::FailureHandler::OnBadRequest(); } - return checkPtr(Instance.allocate(Size, Alignment, FromMalloc)); + return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc)); } uptr scudoMallocUsableSize(void *Ptr) { diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 1434cf688..f79dccddb 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -10,6 +10,7 @@ // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" diff --git a/test/msan/allocator_returns_null.cc b/test/msan/allocator_returns_null.cc index b3bc1a365..583b5b4f7 100644 --- a/test/msan/allocator_returns_null.cc +++ b/test/msan/allocator_returns_null.cc @@ -36,12 +36,13 @@ // RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-nnNULL +// UNSUPPORTED: win32 #include #include -#include #include #include +#include #include #include @@ -86,6 +87,8 @@ int main(int argc, char **argv) { assert(0); } + fprintf(stderr, "errno: %d\n", errno); + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %lx\n", (long)x); @@ -110,14 +113,19 @@ int main(int argc, char **argv) { // CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process // CHECK-mNULL: malloc: +// CHECK-mNULL: errno: 12 // CHECK-mNULL: x: 0 // CHECK-cNULL: calloc: +// CHECK-cNULL: errno: 12 // CHECK-cNULL: x: 0 // CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: errno: 12 // CHECK-coNULL: x: 0 // CHECK-rNULL: realloc: +// CHECK-rNULL: errno: 12 // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: errno: 12 // CHECK-mrNULL: x: 0 // CHECK-nnNULL: new-nothrow: // CHECK-nnNULL: x: 0 -- cgit v1.2.1 From f9d9566dc29f527537dffe68cf2a2deb1d12b177 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Jul 2017 20:18:32 +0000 Subject: Don't call exit() from atexit handlers on Darwin Summary: Calling exit() from an atexit handler is undefined behavior. On Linux, it's unavoidable, since we cannot intercept exit (_exit isn't called if a user program uses return instead of exit()), and I haven't seen it cause issues regardless. However, on Darwin, I have a fairly complex internal test that hangs roughly once in every 300 runs after leak reporting finishes, which is resolved with this patch, and is presumably due to the undefined behavior (since the Die() is the only thing that happens after the end of leak reporting). In addition, this is the way TSan works as well, where an atexit handler+Die() is used on Linux, and an _exit() interceptor is used on Darwin. I'm not sure if it's intentionally structured that way in TSan, since TSan sets up the atexit handler and the _exit() interceptor on both platforms, but I have observed that on Darwin, only the _exit() interceptor is used, and on Linux the atexit handler is used. There is some additional related discussion here: https://reviews.llvm.org/D35085 Reviewers: alekseyshl, kubamracek Subscribers: eugenis, vsk, llvm-commits Differential Revision: https://reviews.llvm.org/D35513 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308353 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 4 ++++ lib/lsan/lsan_common.cc | 12 +++++------- lib/lsan/lsan_common.h | 6 ++++++ lib/lsan/lsan_common_linux.cc | 7 +++++++ lib/lsan/lsan_common_mac.cc | 5 +++++ lib/lsan/lsan_interceptors.cc | 6 ++++++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index ed12a9ac9..34ca22b86 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -178,6 +178,10 @@ void SetThreadName(const char *name) { } int OnExit() { + if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks && + __lsan::HasReportedLeaks()) { + return common_flags()->exitcode; + } // FIXME: ask frontend whether we need to return failure. return 0; } diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 4ffa91568..c121e6a8f 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -576,18 +576,16 @@ static bool CheckForLeaks() { return false; } +static bool has_reported_leaks = false; +bool HasReportedLeaks() { return has_reported_leaks; } + void DoLeakCheck() { BlockingMutexLock l(&global_mutex); static bool already_done; if (already_done) return; already_done = true; - bool have_leaks = CheckForLeaks(); - if (!have_leaks) { - return; - } - if (common_flags()->exitcode) { - Die(); - } + has_reported_leaks = CheckForLeaks(); + if (has_reported_leaks) HandleLeaks(); } static int DoRecoverableLeakCheck() { diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index d93ac1b10..31bf3eb1d 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -226,6 +226,12 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p); // Return the linker module, if valid for the platform. LoadedModule *GetLinker(); +// Return true if LSan has finished leak checking and reported leaks. +bool HasReportedLeaks(); + +// Run platform-specific leak handlers. +void HandleLeaks(); + // Wrapper for chunk metadata operations. class LsanMetadata { public: diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index c903be42d..5042c7b3a 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -100,6 +100,13 @@ struct DoStopTheWorldParam { void *argument; }; +// While calling Die() here is undefined behavior and can potentially +// cause race conditions, it isn't possible to intercept exit on linux, +// so we have no choice but to call Die() from the atexit handler. +void HandleLeaks() { + if (common_flags()->exitcode) Die(); +} + static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size, void *data) { DoStopTheWorldParam *param = reinterpret_cast(data); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index c0fa36fd9..147e62d1f 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -171,6 +171,11 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { } } +// On darwin, we can intercept _exit gracefully, and return a failing exit code +// if required at that point. Calling Die() here is undefined behavior and +// causes rare race conditions. +void HandleLeaks() {} + void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { StopTheWorld(callback, argument); } diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 7d514402a..168868b01 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -352,6 +352,11 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) { return res; } +INTERCEPTOR(void, _exit, int status) { + if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; + REAL(_exit)(status); +} + namespace __lsan { void InitializeInterceptors() { @@ -371,6 +376,7 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_MALLOPT; INTERCEPT_FUNCTION(pthread_create); INTERCEPT_FUNCTION(pthread_join); + INTERCEPT_FUNCTION(_exit); if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); -- cgit v1.2.1 From f326d7dfb080c1f02f44957b4f491b333b8a3adb Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Jul 2017 23:51:44 +0000 Subject: Revert "Only scan global sections containing data in LSan on darwin" This reverts commit 7e46d78d47832f03ce42adcf56417fbfd47cbaad. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308394 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 15 ++++----------- lib/sanitizer_common/sanitizer_common.cc | 5 ++--- lib/sanitizer_common/sanitizer_common.h | 12 +++--------- lib/sanitizer_common/sanitizer_procmaps.h | 1 - lib/sanitizer_common/sanitizer_procmaps_mac.cc | 6 ++---- 5 files changed, 11 insertions(+), 28 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index 147e62d1f..ade94340a 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -92,15 +92,8 @@ LoadedModule *GetLinker() { return nullptr; } // required on Darwin. void InitializePlatformSpecificModules() {} -// Sections which may contain global variables -static const char *kGlobalVarSecNames[] = { - "__DATA", "__bss", "__common", "__data", - "__objc_data", "__objc_opt_rw", "__objc_opt_ptrs"}; - // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { - for (auto name : kGlobalVarSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName); - MemoryMappingLayout memory_mapping(false); InternalMmapVector modules(/*initial_capacity*/ 128); memory_mapping.DumpListOfModules(&modules); @@ -111,10 +104,10 @@ void ProcessGlobalRegions(Frontier *frontier) { for (const __sanitizer::LoadedModule::AddressRange &range : modules[i].ranges()) { - for (auto name : kGlobalVarSecNames) { - if (!internal_strcmp(range.name, name)) - ScanGlobalRange(range.beg, range.end, frontier); - } + // Sections storing global variables are writable and non-executable + if (range.executable || !range.writable) continue; + + ScanGlobalRange(range.beg, range.end, frontier); } } } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 3868d5469..7e6f8fce7 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -285,10 +285,9 @@ void LoadedModule::clear() { } void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, - bool writable, const char *name) { + bool writable) { void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = - new(mem) AddressRange(beg, end, executable, writable, name); + AddressRange *r = new(mem) AddressRange(beg, end, executable, writable); ranges_.push_back(r); if (executable && end > max_executable_address_) max_executable_address_ = end; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index f684271d4..89aae5798 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -702,7 +702,6 @@ inline const char *ModuleArchToString(ModuleArch arch) { } const uptr kModuleUUIDSize = 16; -const uptr kMaxSegName = 16; // Represents a binary loaded into virtual memory (e.g. this can be an // executable or a shared object). @@ -721,8 +720,7 @@ class LoadedModule { void set(const char *module_name, uptr base_address, ModuleArch arch, u8 uuid[kModuleUUIDSize], bool instrumented); void clear(); - void addAddressRange(uptr beg, uptr end, bool executable, bool writable, - const char *name = nullptr); + void addAddressRange(uptr beg, uptr end, bool executable, bool writable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } @@ -738,17 +736,13 @@ class LoadedModule { uptr end; bool executable; bool writable; - char name[kMaxSegName]; - AddressRange(uptr beg, uptr end, bool executable, bool writable, - const char *name) + AddressRange(uptr beg, uptr end, bool executable, bool writable) : next(nullptr), beg(beg), end(end), executable(executable), - writable(writable) { - internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name)); - } + writable(writable) {} }; const IntrusiveList &ranges() const { return ranges_; } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 50753c4e6..76685661c 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -58,7 +58,6 @@ class MemoryMappedSegment { u8 uuid[kModuleUUIDSize]; #if SANITIZER_MAC - char name[kMaxSegName]; private: friend class MemoryMappingLayout; diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 277d2b194..411bbd39d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -42,13 +42,12 @@ void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { uptr sec_start = sc->addr + base_virt_addr_; uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable(), - sc->sectname); + module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); } void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { if (!nsects_) { - module->addAddressRange(start, end, IsExecutable(), IsWritable(), name); + module->addAddressRange(start, end, IsExecutable(), IsWritable()); return; } @@ -200,7 +199,6 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { : _dyld_get_image_name(current_image_); internal_strncpy(segment->filename, src, segment->filename_size); } - internal_strncpy(segment->name, sc->segname, ARRAY_SIZE(segment->name)); segment->arch = current_arch_; internal_memcpy(segment->uuid, current_uuid_, kModuleUUIDSize); return true; -- cgit v1.2.1 From 02a9951ea0c9257c1968f0613c06f2aed1e48e00 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 18 Jul 2017 23:51:47 +0000 Subject: Revert "Add MemoryMappedSection struct for two-level memory map iteration" This reverts commit c8095ce74118dee8544b0f1ffaba8f46aa10215c. Reverted due to some buildbot timeouts, perhaps due to 10.11 issues. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308395 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 18 +---------- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 45 +++++--------------------- 2 files changed, 9 insertions(+), 54 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 76685661c..06d072b4d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,8 +37,7 @@ static const uptr kProtectionWrite = 2; static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -class MemoryMappedSegment { - public: +struct MemoryMappedSegment { MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size) {} ~MemoryMappedSegment() {} @@ -56,21 +55,6 @@ class MemoryMappedSegment { uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; - -#if SANITIZER_MAC - - private: - friend class MemoryMappingLayout; - - template - void NextSectionLoad(LoadedModule *module); - void AddAddressRanges(LoadedModule *module); - - uptr nsects_; - char *current_load_cmd_addr_; - u32 lc_type_; - uptr base_virt_addr_; -#endif }; class MemoryMappingLayout { diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 411bbd39d..560451a16 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -35,32 +35,6 @@ #endif namespace __sanitizer { -template -void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { - const Section *sc = (const Section *)current_load_cmd_addr_; - current_load_cmd_addr_ += sizeof(Section); - - uptr sec_start = sc->addr + base_virt_addr_; - uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); -} - -void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { - if (!nsects_) { - module->addAddressRange(start, end, IsExecutable(), IsWritable()); - return; - } - - do { - if (lc_type_ == LC_SEGMENT) { - NextSectionLoad(module); -#ifdef MH_MAGIC_64 - } else if (lc_type_ == LC_SEGMENT_64) { - NextSectionLoad(module); -#endif - } - } while (--nsects_); -} MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); @@ -169,25 +143,21 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - segment->current_load_cmd_addr_ = (char *)lc + sizeof(SegmentCommand); - segment->lc_type_ = kLCSegment; - segment->nsects_ = sc->nsects; if (current_image_ == kDyldImageIdx) { - segment->base_virt_addr_ = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->start = (sc->vmaddr & 0xfffff) + segment->base_virt_addr_; + segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); } else { - segment->base_virt_addr_ = - (uptr)_dyld_get_image_vmaddr_slide(current_image_); - segment->start = sc->vmaddr + segment->base_virt_addr_; + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + segment->start = sc->vmaddr + dlloff; + segment->end = sc->vmaddr + sc->vmsize + dlloff; } - segment->end = segment->start + sc->vmsize; // Return the initial protection. segment->protection = sc->initprot; @@ -322,7 +292,7 @@ void MemoryMappingLayout::DumpListOfModules( Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - while (Next(&segment)) { + for (uptr i = 0; Next(&segment); i++) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -334,7 +304,8 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - segment.AddAddressRanges(cur_module); + cur_module->addAddressRange(segment.start, segment.end, + segment.IsExecutable(), segment.IsWritable()); } } -- cgit v1.2.1 From 6553f3f19ef0f5bdcdde8f4ffc6303da06087e81 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 19 Jul 2017 05:11:20 +0000 Subject: [X86][builtins] Sync getX86CpuIDAndInfoEx with llvm's Host.cpp again. We now use __cpuidex intrinsics intead of inline asm on 32-bit Windows. We already used it on 64-bit. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308420 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index c6b30eda0..83ea7a49f 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -190,8 +190,8 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__x86_64__) || defined(_M_X64) #if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. // FIXME: should we save this for Clang? __asm__("movq\t%%rbx, %%rsi\n\t" @@ -200,43 +200,24 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); return false; -#elif defined(_MSC_VER) - int registers[4]; - __cpuidex(registers, value, subleaf); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; -#else - return true; -#endif -#elif defined(__i386__) || defined(_M_IX86) -#if defined(__GNUC__) || defined(__clang__) +#elif defined(__i386__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); return false; -#elif defined(_MSC_VER) - __asm { - mov eax,value - mov ecx,subleaf - cpuid - mov esi,rEAX - mov dword ptr [esi],eax - mov esi,rEBX - mov dword ptr [esi],ebx - mov esi,rECX - mov dword ptr [esi],ecx - mov esi,rEDX - mov dword ptr [esi],edx - } - return false; #else return true; #endif +#elif defined(_MSC_VER) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; #else return true; #endif -- cgit v1.2.1 From 3a390dc512db0f74e9875546d9b7c4093fcb07b5 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 20 Jul 2017 01:29:01 +0000 Subject: [asan] Move memcpy, memmove, memset code out of asan_interceptors.cc This is a pure refactoring change. It simply moves all the code and macros related to defining the ASan interceptor versions of memcpy, memmove, and memset into a separate file. This makes it cleaner to disable all the other interceptor code while still using these three, for a port that defines these but not the other common interceptors. Reviewers: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35590 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308575 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/CMakeLists.txt | 1 + lib/asan/asan_interceptors.cc | 131 ------------------------ lib/asan/asan_interceptors.h | 3 +- lib/asan/asan_interceptors_memintrinsics.cc | 32 ++++++ lib/asan/asan_interceptors_memintrinsics.h | 148 ++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 133 deletions(-) create mode 100644 lib/asan/asan_interceptors_memintrinsics.cc create mode 100644 lib/asan/asan_interceptors_memintrinsics.h diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index a2d4630df..47afa79bd 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -11,6 +11,7 @@ set(ASAN_SOURCES asan_globals.cc asan_globals_win.cc asan_interceptors.cc + asan_interceptors_memintrinsics.cc asan_linux.cc asan_mac.cc asan_malloc_linux.cc diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 34ca22b86..999c799fe 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -36,108 +36,6 @@ namespace __asan { -// Return true if we can quickly decide that the region is unpoisoned. -// We assume that a redzone is at least 16 bytes. -static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { - if (size == 0) return true; - if (size <= 32) - return !AddressIsPoisoned(beg) && - !AddressIsPoisoned(beg + size - 1) && - !AddressIsPoisoned(beg + size / 2); - if (size <= 64) - return !AddressIsPoisoned(beg) && - !AddressIsPoisoned(beg + size / 4) && - !AddressIsPoisoned(beg + size - 1) && - !AddressIsPoisoned(beg + 3 * size / 4) && - !AddressIsPoisoned(beg + size / 2); - return false; -} - -struct AsanInterceptorContext { - const char *interceptor_name; -}; - -// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE, -// and ASAN_WRITE_RANGE as macro instead of function so -// that no extra frames are created, and stack trace contains -// relevant information only. -// We check all shadow bytes. -#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \ - uptr __offset = (uptr)(offset); \ - uptr __size = (uptr)(size); \ - uptr __bad = 0; \ - if (__offset > __offset + __size) { \ - GET_STACK_TRACE_FATAL_HERE; \ - ReportStringFunctionSizeOverflow(__offset, __size, &stack); \ - } \ - if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \ - (__bad = __asan_region_is_poisoned(__offset, __size))) { \ - AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \ - bool suppressed = false; \ - if (_ctx) { \ - suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \ - if (!suppressed && HaveStackTraceBasedSuppressions()) { \ - GET_STACK_TRACE_FATAL_HERE; \ - suppressed = IsStackTraceSuppressed(&stack); \ - } \ - } \ - if (!suppressed) { \ - GET_CURRENT_PC_BP_SP; \ - ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\ - } \ - } \ - } while (0) - -// memcpy is called during __asan_init() from the internals of printf(...). -// We do not treat memcpy with to==from as a bug. -// See http://llvm.org/bugs/show_bug.cgi?id=11763. -#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \ - do { \ - if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \ - if (asan_init_is_running) { \ - return REAL(memcpy)(to, from, size); \ - } \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - if (to != from) { \ - CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \ - } \ - ASAN_READ_RANGE(ctx, from, size); \ - ASAN_WRITE_RANGE(ctx, to, size); \ - } \ - return REAL(memcpy)(to, from, size); \ - } while (0) - -// memset is called inside Printf. -#define ASAN_MEMSET_IMPL(ctx, block, c, size) \ - do { \ - if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \ - if (asan_init_is_running) { \ - return REAL(memset)(block, c, size); \ - } \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - ASAN_WRITE_RANGE(ctx, block, size); \ - } \ - return REAL(memset)(block, c, size); \ - } while (0) - -#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \ - do { \ - if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - ASAN_READ_RANGE(ctx, from, size); \ - ASAN_WRITE_RANGE(ctx, to, size); \ - } \ - return internal_memmove(to, from, size); \ - } while (0) - -#define ASAN_READ_RANGE(ctx, offset, size) \ - ACCESS_MEMORY_RANGE(ctx, offset, size, false) -#define ASAN_WRITE_RANGE(ctx, offset, size) \ - ACCESS_MEMORY_RANGE(ctx, offset, size, true) - #define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ ASAN_READ_RANGE((ctx), (s), \ common_flags()->strict_string_checks ? (len) + 1 : (n)) @@ -145,23 +43,6 @@ struct AsanInterceptorContext { #define ASAN_READ_STRING(ctx, s, n) \ ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) -// Behavior of functions like "memcpy" or "strcpy" is undefined -// if memory intervals overlap. We report error in this case. -// Macro is used to avoid creation of new frames. -static inline bool RangesOverlap(const char *offset1, uptr length1, - const char *offset2, uptr length2) { - return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1)); -} -#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ - const char *offset1 = (const char*)_offset1; \ - const char *offset2 = (const char*)_offset2; \ - if (RangesOverlap(offset1, length1, offset2, length2)) { \ - GET_STACK_TRACE_FATAL_HERE; \ - ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ - offset2, length2, &stack); \ - } \ -} while (0) - static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { #if SANITIZER_INTERCEPT_STRNLEN if (REAL(strnlen)) { @@ -462,18 +343,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif -void *__asan_memcpy(void *to, const void *from, uptr size) { - ASAN_MEMCPY_IMPL(nullptr, to, from, size); -} - -void *__asan_memset(void *block, int c, uptr size) { - ASAN_MEMSET_IMPL(nullptr, block, c, size); -} - -void *__asan_memmove(void *to, const void *from, uptr size) { - ASAN_MEMMOVE_IMPL(nullptr, to, from, size); -} - #if ASAN_INTERCEPT_INDEX # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX INTERCEPTOR(char*, index, const char *string, int c) diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 93fca4f67..5bc621724 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -15,6 +15,7 @@ #define ASAN_INTERCEPTORS_H #include "asan_internal.h" +#include "asan_interceptors_memintrinsics.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" @@ -85,8 +86,6 @@ #endif DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) -DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size) -DECLARE_REAL(void*, memset, void *block, int c, uptr size) DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size) diff --git a/lib/asan/asan_interceptors_memintrinsics.cc b/lib/asan/asan_interceptors_memintrinsics.cc new file mode 100644 index 000000000..7a59e7c5f --- /dev/null +++ b/lib/asan/asan_interceptors_memintrinsics.cc @@ -0,0 +1,32 @@ +//===-- asan_interceptors_memintrinsics.cc --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan versions of memcpy, memmove, and memset. +//===---------------------------------------------------------------------===// + +#include "asan_interceptors_memintrinsics.h" +#include "asan_report.h" +#include "asan_stack.h" +#include "asan_suppressions.h" + +using namespace __asan; // NOLINT + +void *__asan_memcpy(void *to, const void *from, uptr size) { + ASAN_MEMCPY_IMPL(nullptr, to, from, size); +} + +void *__asan_memset(void *block, int c, uptr size) { + ASAN_MEMSET_IMPL(nullptr, block, c, size); +} + +void *__asan_memmove(void *to, const void *from, uptr size) { + ASAN_MEMMOVE_IMPL(nullptr, to, from, size); +} diff --git a/lib/asan/asan_interceptors_memintrinsics.h b/lib/asan/asan_interceptors_memintrinsics.h new file mode 100644 index 000000000..5a8339a23 --- /dev/null +++ b/lib/asan/asan_interceptors_memintrinsics.h @@ -0,0 +1,148 @@ +//===-- asan_interceptors_memintrinsics.h -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan-private header for asan_memintrin.cc +//===---------------------------------------------------------------------===// +#ifndef ASAN_MEMINTRIN_H +#define ASAN_MEMINTRIN_H + +#include "asan_interface_internal.h" +#include "asan_internal.h" +#include "asan_mapping.h" +#include "interception/interception.h" + +DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size) +DECLARE_REAL(void*, memset, void *block, int c, uptr size) + +namespace __asan { + +// Return true if we can quickly decide that the region is unpoisoned. +// We assume that a redzone is at least 16 bytes. +static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { + if (size == 0) return true; + if (size <= 32) + return !AddressIsPoisoned(beg) && + !AddressIsPoisoned(beg + size - 1) && + !AddressIsPoisoned(beg + size / 2); + if (size <= 64) + return !AddressIsPoisoned(beg) && + !AddressIsPoisoned(beg + size / 4) && + !AddressIsPoisoned(beg + size - 1) && + !AddressIsPoisoned(beg + 3 * size / 4) && + !AddressIsPoisoned(beg + size / 2); + return false; +} + +struct AsanInterceptorContext { + const char *interceptor_name; +}; + +// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE, +// and ASAN_WRITE_RANGE as macro instead of function so +// that no extra frames are created, and stack trace contains +// relevant information only. +// We check all shadow bytes. +#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \ + uptr __offset = (uptr)(offset); \ + uptr __size = (uptr)(size); \ + uptr __bad = 0; \ + if (__offset > __offset + __size) { \ + GET_STACK_TRACE_FATAL_HERE; \ + ReportStringFunctionSizeOverflow(__offset, __size, &stack); \ + } \ + if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \ + (__bad = __asan_region_is_poisoned(__offset, __size))) { \ + AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \ + bool suppressed = false; \ + if (_ctx) { \ + suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \ + if (!suppressed && HaveStackTraceBasedSuppressions()) { \ + GET_STACK_TRACE_FATAL_HERE; \ + suppressed = IsStackTraceSuppressed(&stack); \ + } \ + } \ + if (!suppressed) { \ + GET_CURRENT_PC_BP_SP; \ + ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\ + } \ + } \ + } while (0) + +// memcpy is called during __asan_init() from the internals of printf(...). +// We do not treat memcpy with to==from as a bug. +// See http://llvm.org/bugs/show_bug.cgi?id=11763. +#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \ + if (asan_init_is_running) { \ + return REAL(memcpy)(to, from, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + if (to != from) { \ + CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \ + } \ + ASAN_READ_RANGE(ctx, from, size); \ + ASAN_WRITE_RANGE(ctx, to, size); \ + } \ + return REAL(memcpy)(to, from, size); \ + } while (0) + +// memset is called inside Printf. +#define ASAN_MEMSET_IMPL(ctx, block, c, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \ + if (asan_init_is_running) { \ + return REAL(memset)(block, c, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_WRITE_RANGE(ctx, block, size); \ + } \ + return REAL(memset)(block, c, size); \ + } while (0) + +#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_READ_RANGE(ctx, from, size); \ + ASAN_WRITE_RANGE(ctx, to, size); \ + } \ + return internal_memmove(to, from, size); \ + } while (0) + +#define ASAN_READ_RANGE(ctx, offset, size) \ + ACCESS_MEMORY_RANGE(ctx, offset, size, false) +#define ASAN_WRITE_RANGE(ctx, offset, size) \ + ACCESS_MEMORY_RANGE(ctx, offset, size, true) + +// Behavior of functions like "memcpy" or "strcpy" is undefined +// if memory intervals overlap. We report error in this case. +// Macro is used to avoid creation of new frames. +static inline bool RangesOverlap(const char *offset1, uptr length1, + const char *offset2, uptr length2) { + return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1)); +} +#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ + const char *offset1 = (const char*)_offset1; \ + const char *offset2 = (const char*)_offset2; \ + if (RangesOverlap(offset1, length1, offset2, length2)) { \ + GET_STACK_TRACE_FATAL_HERE; \ + ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ + offset2, length2, &stack); \ + } \ +} while (0) + +} // namespace __asan + +#endif // ASAN_MEMINTRIN_H -- cgit v1.2.1 From c1d813b64db93eae19ee40dd194de1e5b9d6f93f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 01:36:16 +0000 Subject: [compiler-rt] Replace VPrintf with VReport in sanitizer_tls_get_addr.cc Summary: Thread id will be added to VRerort. Having thread here is useful. This is also common place for logging for all sanitizers, so I can use this in common test. Reviewers: kcc, alekseyshl Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D35655 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308578 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_tls_get_addr.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 29db37b8a..6fa0e9298 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -45,7 +45,7 @@ static const uptr kDestroyedThread = -1; static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) { if (!size) return; - VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); UnmapOrDie(dtv, size * sizeof(DTLS::DTV)); atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); } @@ -58,7 +58,7 @@ static inline void DTLS_Resize(uptr new_size) { (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); uptr num_live_dtls = atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); - VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); + VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); CHECK_LT(num_live_dtls, 1 << 20); uptr old_dtv_size = dtls.dtv_size; DTLS::DTV *old_dtv = dtls.dtv; @@ -72,7 +72,7 @@ static inline void DTLS_Resize(uptr new_size) { void DTLS_Destroy() { if (!common_flags()->intercept_tls_get_addr) return; - VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); + VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); uptr s = dtls.dtv_size; dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. DTLS_Deallocate(dtls.dtv, s); @@ -97,28 +97,28 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, if (dtls.dtv[dso_id].beg) return 0; uptr tls_size = 0; uptr tls_beg = reinterpret_cast(res) - arg->offset - kDtvOffset; - VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " + VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " "num_live_dtls %zd\n", arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, atomic_load(&number_of_live_dtls, memory_order_relaxed)); if (dtls.last_memalign_ptr == tls_beg) { tls_size = dtls.last_memalign_size; - VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", + VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", tls_beg, tls_size); } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { // This is the static TLS block which was initialized / unpoisoned at thread // creation. - VPrintf(2, "__tls_get_addr: static tls: %p\n", tls_beg); + VReport(2, "__tls_get_addr: static tls: %p\n", tls_beg); tls_size = 0; } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { // We may want to check gnu_get_libc_version(). Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; tls_size = header->size; tls_beg = header->start; - VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", + VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", tls_beg, tls_size); } else { - VPrintf(2, "__tls_get_addr: Can't guess glibc version\n"); + VReport(2, "__tls_get_addr: Can't guess glibc version\n"); // This may happen inside the DTOR of main thread, so just ignore it. tls_size = 0; } @@ -129,7 +129,7 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, void DTLS_on_libc_memalign(void *ptr, uptr size) { if (!common_flags()->intercept_tls_get_addr) return; - VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); + VReport(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); dtls.last_memalign_ptr = reinterpret_cast(ptr); dtls.last_memalign_size = size; } -- cgit v1.2.1 From edb67e932289e0f5eae5d6c96ff8209f8cf949ff Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 20 Jul 2017 13:28:28 +0000 Subject: Add NetBSD support in sanitizer_procmaps_common.cc Summary: Reuse Linux and FreeBSD code - no NetBSD specific changes. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab Reviewed By: filcab Subscribers: emaste, kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35632 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308614 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_common.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index b95f301a4..dac68ffe8 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -12,7 +12,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_common.h" #include "sanitizer_placement_new.h" @@ -171,4 +171,4 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -- cgit v1.2.1 From 088d8f4e65bd47f7d26a892b70d5bf700033c586 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 20 Jul 2017 13:31:06 +0000 Subject: Add NetBSD support in sanitizer_procmaps.h Summary: Reuse Linux and FreeBSD - no NetBSD specific changes. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, filcab, kcc, vitalybuka Reviewed By: filcab Subscribers: llvm-commits, emaste, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35629 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308615 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 06d072b4d..7e7997454 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -20,7 +20,7 @@ namespace __sanitizer { -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD struct ProcSelfMapsBuff { char *data; uptr mmaped_size; @@ -29,7 +29,7 @@ struct ProcSelfMapsBuff { // Reads process memory map in an OS-specific way. void ReadProcMaps(ProcSelfMapsBuff *proc_maps); -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD // Memory protection masks. static const uptr kProtectionRead = 1; @@ -76,7 +76,7 @@ class MemoryMappingLayout { // FIXME: Hide implementation details for different platforms in // platform-specific files. -# if SANITIZER_FREEBSD || SANITIZER_LINUX +# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ProcSelfMapsBuff proc_self_maps_; const char *current_; -- cgit v1.2.1 From 4df023aead95df63f9024ffd61ae1610ec5e7837 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 20 Jul 2017 13:33:06 +0000 Subject: Add NetBSD support in sanitizer_libignore.cc Summary: Reuse Linux, FreeBSD and Apple code - no NetBSD specific changes. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, vitalybuka, filcab, kcc Reviewed By: filcab Subscribers: emaste, kubamracek, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35628 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308616 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_libignore.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc index aa4fa88ef..fbb4f3e47 100644 --- a/lib/sanitizer_common/sanitizer_libignore.cc +++ b/lib/sanitizer_common/sanitizer_libignore.cc @@ -9,7 +9,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD #include "sanitizer_libignore.h" #include "sanitizer_flags.h" @@ -125,4 +125,4 @@ void LibIgnore::OnLibraryUnloaded() { } // namespace __sanitizer -#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD -- cgit v1.2.1 From 6a1564dd475f3cd3a5cec309b3ec45312da2ec37 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 20 Jul 2017 14:15:00 +0000 Subject: Honour 80-character line limit git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308620 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_libignore.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc index fbb4f3e47..0df055eda 100644 --- a/lib/sanitizer_common/sanitizer_libignore.cc +++ b/lib/sanitizer_common/sanitizer_libignore.cc @@ -125,4 +125,5 @@ void LibIgnore::OnLibraryUnloaded() { } // namespace __sanitizer -#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || + // SANITIZER_NETBSD -- cgit v1.2.1 From 971e3334155801f5b7727d1888acfdcab1d2aecd Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 17:31:08 +0000 Subject: [compiler-rt] Include thread ID into sanitizers logs Reviewers: kcc, alekseyshl Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D35654 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308637 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 9 ++++----- test/sanitizer_common/TestCases/Linux/vreport.cc | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 test/sanitizer_common/TestCases/Linux/vreport.cc diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index 99b7ff1b5..b14675a06 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -260,16 +260,15 @@ static void SharedPrintfCode(bool append_pid, const char *format, "Buffer in Report is too short!\n"); \ } if (append_pid) { - int pid = internal_getpid(); const char *exe_name = GetProcessName(); if (common_flags()->log_exe_name && exe_name) { needed_length += internal_snprintf(buffer, buffer_size, "==%s", exe_name); CHECK_NEEDED_LENGTH } - needed_length += internal_snprintf(buffer + needed_length, - buffer_size - needed_length, - "==%d==", pid); + needed_length += + internal_snprintf(buffer + needed_length, buffer_size - needed_length, + "==%d:%d==", internal_getpid(), GetTid()); CHECK_NEEDED_LENGTH } needed_length += VSNPrintf(buffer + needed_length, @@ -300,7 +299,7 @@ void Printf(const char *format, ...) { va_end(args); } -// Like Printf, but prints the current PID before the output string. +// Like Printf, but prints the current PID:TID before the output string. FORMAT(1, 2) void Report(const char *format, ...) { va_list args; diff --git a/test/sanitizer_common/TestCases/Linux/vreport.cc b/test/sanitizer_common/TestCases/Linux/vreport.cc new file mode 100644 index 000000000..2357932ff --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/vreport.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx -O0 %s -o %t && %env_tool_opts=verbosity=10 %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include + +void *thread(void *unused) { + printf("PID: %d\n", getpid()); + printf("TID: %ld\n", syscall(SYS_gettid)); + fflush(stdout); + return 0; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, thread, 0); + pthread_join(t, 0); + return 0; +} +// CHECK: PID: [[PID:[0-9]+]] +// CHECK: TID: [[TID:[0-9]+]] +// CHECK: ==[[PID]]:[[TID]]== -- cgit v1.2.1 From 3139224a27831570b278640087187155adc4fd05 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 20 Jul 2017 17:48:42 +0000 Subject: [sanitizer_common] Move filesystem-related code out of sanitizer_common.cc This is a pure refactoring change. It just moves code that is related to filesystem operations from sanitizer_common.{cc,h} to sanitizer_file.{cc,h}. This makes it cleaner to disable the filesystem-related code for a new port that doesn't want it. Commiting for mcgrathr. Reviewers: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35591 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308640 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 6 +- lib/dfsan/dfsan.cc | 1 + lib/sanitizer_common/CMakeLists.txt | 2 + lib/sanitizer_common/sanitizer_common.cc | 141 ----------------- lib/sanitizer_common/sanitizer_common.h | 80 +--------- lib/sanitizer_common/sanitizer_common_libcdep.cc | 1 + .../sanitizer_coverage_libcdep_new.cc | 1 + lib/sanitizer_common/sanitizer_file.cc | 171 +++++++++++++++++++++ lib/sanitizer_common/sanitizer_file.h | 110 +++++++++++++ lib/sanitizer_common/sanitizer_linux_libcdep.cc | 1 + lib/sanitizer_common/sanitizer_posix.cc | 1 + .../sanitizer_stacktrace_printer.cc | 1 + lib/sanitizer_common/sanitizer_suppressions.cc | 1 + .../sanitizer_symbolizer_internal.h | 1 + .../sanitizer_symbolizer_posix_libcdep.cc | 1 + .../tests/sanitizer_common_test.cc | 1 + lib/sanitizer_common/tests/sanitizer_libc_test.cc | 1 + lib/sanitizer_common/tests/sanitizer_linux_test.cc | 1 + lib/stats/stats.cc | 1 + lib/tsan/go/buildgo.sh | 1 + lib/tsan/rtl/tsan_report.cc | 1 + lib/tsan/rtl/tsan_rtl.cc | 1 + 22 files changed, 303 insertions(+), 223 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_file.cc create mode 100644 lib/sanitizer_common/sanitizer_file.h diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 2e477f258..8e3d9454f 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -141,9 +141,9 @@ class ScopedInErrorReport { // Can't use Report() here because of potential deadlocks // in nested signal handlers. - const char msg[] = "AddressSanitizer: nested bug in the same thread, " - "aborting.\n"; - WriteToFile(kStderrFd, msg, sizeof(msg)); + static const char msg[] = + "AddressSanitizer: nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); internal__exit(common_flags()->exitcode); } diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index 3aa99b7f9..9e360c959 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -21,6 +21,7 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index a17bd1299..a0831e80e 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -7,6 +7,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc sanitizer_errno.cc + sanitizer_file.cc sanitizer_flags.cc sanitizer_flag_parser.cc sanitizer_libc.cc @@ -96,6 +97,7 @@ set(SANITIZER_HEADERS sanitizer_deadlock_detector_interface.h sanitizer_errno.h sanitizer_errno_codes.h + sanitizer_file.h sanitizer_flag_parser.h sanitizer_flags.h sanitizer_flags.inc diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 7e6f8fce7..8d51e1ed1 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -27,72 +27,6 @@ const char *SanitizerToolName = "SanitizerTool"; atomic_uint32_t current_verbosity; uptr PageSizeCached; -StaticSpinMutex report_file_mu; -ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; - -void RawWrite(const char *buffer) { - report_file.Write(buffer, internal_strlen(buffer)); -} - -void ReportFile::ReopenIfNecessary() { - mu->CheckLocked(); - if (fd == kStdoutFd || fd == kStderrFd) return; - - uptr pid = internal_getpid(); - // If in tracer, use the parent's file. - if (pid == stoptheworld_tracer_pid) - pid = stoptheworld_tracer_ppid; - if (fd != kInvalidFd) { - // If the report file is already opened by the current process, - // do nothing. Otherwise the report file was opened by the parent - // process, close it now. - if (fd_pid == pid) - return; - else - CloseFile(fd); - } - - const char *exe_name = GetProcessName(); - if (common_flags()->log_exe_name && exe_name) { - internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, - exe_name, pid); - } else { - internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); - } - fd = OpenFile(full_path, WrOnly); - if (fd == kInvalidFd) { - const char *ErrorMsgPrefix = "ERROR: Can't open file: "; - WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); - WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); - Die(); - } - fd_pid = pid; -} - -void ReportFile::SetReportPath(const char *path) { - if (!path) - return; - uptr len = internal_strlen(path); - if (len > sizeof(path_prefix) - 100) { - Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); - Die(); - } - - SpinMutexLock l(mu); - if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) - CloseFile(fd); - fd = kInvalidFd; - if (internal_strcmp(path, "stdout") == 0) { - fd = kStdoutFd; - } else if (internal_strcmp(path, "stderr") == 0) { - fd = kStderrFd; - } else { - internal_snprintf(path_prefix, kMaxPathLength, "%s", path); - } -} - // PID of the tracer task in StopTheWorld. It shares the address space with the // main process, but has a different PID and thus requires special handling. uptr stoptheworld_tracer_pid = 0; @@ -120,42 +54,6 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, UNREACHABLE("unable to mmap"); } -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr *read_len, uptr max_len, error_t *errno_p) { - uptr PageSize = GetPageSizeCached(); - uptr kMinFileLen = PageSize; - *buff = nullptr; - *buff_size = 0; - *read_len = 0; - // The files we usually open are not seekable, so try different buffer sizes. - for (uptr size = kMinFileLen; size <= max_len; size *= 2) { - fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) return false; - UnmapOrDie(*buff, *buff_size); - *buff = (char*)MmapOrDie(size, __func__); - *buff_size = size; - *read_len = 0; - // Read up to one page at a time. - bool reached_eof = false; - while (*read_len + PageSize <= size) { - uptr just_read; - if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { - UnmapOrDie(*buff, *buff_size); - return false; - } - if (just_read == 0) { - reached_eof = true; - break; - } - *read_len += just_read; - } - CloseFile(fd); - if (reached_eof) // We've read the whole file. - break; - } - return true; -} - typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); @@ -359,36 +257,6 @@ bool TemplateMatch(const char *templ, const char *str) { return true; } -static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; - -char *FindPathToBinary(const char *name) { - if (FileExists(name)) { - return internal_strdup(name); - } - - const char *path = GetEnv("PATH"); - if (!path) - return nullptr; - uptr name_len = internal_strlen(name); - InternalScopedBuffer buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, kPathSeparator); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return nullptr; -} - static char binary_name_cache_str[kMaxPathLength]; static char process_name_cache_str[kMaxPathLength]; @@ -482,15 +350,6 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), using namespace __sanitizer; // NOLINT extern "C" { -void __sanitizer_set_report_path(const char *path) { - report_file.SetReportPath(path); -} - -void __sanitizer_set_report_fd(void *fd) { - report_file.fd = (fd_t)reinterpret_cast(fd); - report_file.fd_pid = internal_getpid(); -} - SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, const char *error_summary) { Printf("%s\n", error_summary); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 89aae5798..9c801f151 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -185,6 +185,7 @@ typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); // IO +void CatastrophicErrorWrite(const char *buffer, uptr length); void RawWrite(const char *buffer); bool ColorizeReports(); void RemoveANSIEscapeSequencesFromString(char *buffer); @@ -203,64 +204,9 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)); // Can be used to prevent mixing error reports from different sanitizers. extern StaticSpinMutex CommonSanitizerReportMutex; -struct ReportFile { - void Write(const char *buffer, uptr length); - bool SupportsColors(); - void SetReportPath(const char *path); - - // Don't use fields directly. They are only declared public to allow - // aggregate initialization. - - // Protects fields below. - StaticSpinMutex *mu; - // Opened file descriptor. Defaults to stderr. It may be equal to - // kInvalidFd, in which case new file will be opened when necessary. - fd_t fd; - // Path prefix of report file, set via __sanitizer_set_report_path. - char path_prefix[kMaxPathLength]; - // Full path to report, obtained as .PID - char full_path[kMaxPathLength]; - // PID of the process that opened fd. If a fork() occurs, - // the PID of child will be different from fd_pid. - uptr fd_pid; - - private: - void ReopenIfNecessary(); -}; -extern ReportFile report_file; - extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; -enum FileAccessMode { - RdOnly, - WrOnly, - RdWr -}; - -// Returns kInvalidFd on error. -fd_t OpenFile(const char *filename, FileAccessMode mode, - error_t *errno_p = nullptr); -void CloseFile(fd_t); - -// Return true on success, false on error. -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, - uptr *bytes_read = nullptr, error_t *error_p = nullptr); -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, - uptr *bytes_written = nullptr, error_t *error_p = nullptr); - -bool RenameFile(const char *oldpath, const char *newpath, - error_t *error_p = nullptr); - -// Scoped file handle closer. -struct FileCloser { - explicit FileCloser(fd_t fd) : fd(fd) {} - ~FileCloser() { CloseFile(fd); } - fd_t fd; -}; - -bool SupportsColoredOutput(fd_t fd); - // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size'. @@ -269,11 +215,6 @@ bool SupportsColoredOutput(fd_t fd); bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr *read_len, uptr max_len = 1 << 26, error_t *errno_p = nullptr); -// Maps given file to virtual memory, and returns pointer to it -// (or NULL if mapping fails). Stores the size of mmaped region -// in '*buff_size'. -void *MapFileToMemory(const char *file_name, uptr *buff_size); -void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); bool IsAccessibleMemoryRange(uptr beg, uptr size); @@ -293,27 +234,8 @@ void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); void PrintModuleMap(); -bool FileExists(const char *filename); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); -const char *GetPwd(); -char *FindPathToBinary(const char *name); -bool IsPathSeparator(const char c); -bool IsAbsolutePath(const char *path); -// Starts a subprocess and returs its pid. -// If *_fd parameters are not kInvalidFd their corresponding input/output -// streams will be redirect to the file. The files will always be closed -// in parent process even in case of an error. -// The child process will close all fds after STDERR_FILENO -// before passing control to a program. -pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); -// Checks if specified process is still running -bool IsProcessRunning(pid_t pid); -// Waits for the process to finish and returns its exit code. -// Returns -1 in case of an error. -int WaitForProcess(pid_t pid); u32 GetUid(); void ReExec(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index cf200512d..82d223a29 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -14,6 +14,7 @@ #include "sanitizer_common.h" #include "sanitizer_allocator_interface.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 24433356c..ac9be2704 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -12,6 +12,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_symbolizer.h" using namespace __sanitizer; diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc new file mode 100644 index 000000000..dfbe99c56 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_file.cc @@ -0,0 +1,171 @@ +//===-- sanitizer_file.cc ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. It defines filesystem-related interfaces. This +// is separate from sanitizer_common.cc so that it's simpler to disable +// all the filesystem support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +namespace __sanitizer { + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + WriteToFile(kStderrFd, buffer, length); +} + +StaticSpinMutex report_file_mu; +ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + +void RawWrite(const char *buffer) { + report_file.Write(buffer, internal_strlen(buffer)); +} + +void ReportFile::ReopenIfNecessary() { + mu->CheckLocked(); + if (fd == kStdoutFd || fd == kStderrFd) return; + + uptr pid = internal_getpid(); + // If in tracer, use the parent's file. + if (pid == stoptheworld_tracer_pid) + pid = stoptheworld_tracer_ppid; + if (fd != kInvalidFd) { + // If the report file is already opened by the current process, + // do nothing. Otherwise the report file was opened by the parent + // process, close it now. + if (fd_pid == pid) + return; + else + CloseFile(fd); + } + + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + fd = OpenFile(full_path, WrOnly); + if (fd == kInvalidFd) { + const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + Die(); + } + fd_pid = pid; +} + +void ReportFile::SetReportPath(const char *path) { + if (!path) + return; + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", + path[0], path[1], path[2], path[3], + path[4], path[5], path[6], path[7]); + Die(); + } + + SpinMutexLock l(mu); + if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) + CloseFile(fd); + fd = kInvalidFd; + if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; + } else if (internal_strcmp(path, "stderr") == 0) { + fd = kStderrFd; + } else { + internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + } +} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + uptr PageSize = GetPageSizeCached(); + uptr kMinFileLen = PageSize; + *buff = nullptr; + *buff_size = 0; + *read_len = 0; + // The files we usually open are not seekable, so try different buffer sizes. + for (uptr size = kMinFileLen; size <= max_len; size *= 2) { + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) return false; + UnmapOrDie(*buff, *buff_size); + *buff = (char*)MmapOrDie(size, __func__); + *buff_size = size; + *read_len = 0; + // Read up to one page at a time. + bool reached_eof = false; + while (*read_len + PageSize <= size) { + uptr just_read; + if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { + UnmapOrDie(*buff, *buff_size); + return false; + } + if (just_read == 0) { + reached_eof = true; + break; + } + *read_len += just_read; + } + CloseFile(fd); + if (reached_eof) // We've read the whole file. + break; + } + return true; +} + +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + if (FileExists(name)) { + return internal_strdup(name); + } + + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalScopedBuffer buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + +} // namespace __sanitizer + +using namespace __sanitizer; // NOLINT + +extern "C" { +void __sanitizer_set_report_path(const char *path) { + report_file.SetReportPath(path); +} + +void __sanitizer_set_report_fd(void *fd) { + report_file.fd = (fd_t)reinterpret_cast(fd); + report_file.fd_pid = internal_getpid(); +} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_file.h b/lib/sanitizer_common/sanitizer_file.h new file mode 100644 index 000000000..9a12ab734 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_file.h @@ -0,0 +1,110 @@ +//===-- sanitizer_file.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is shared between run-time libraries of sanitizers. +// It declares filesystem-related interfaces. This is separate from +// sanitizer_common.h so that it's simpler to disable all the filesystem +// support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// +#ifndef SANITIZER_FILE_H +#define SANITIZER_FILE_H + +#include "sanitizer_interface_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +struct ReportFile { + void Write(const char *buffer, uptr length); + bool SupportsColors(); + void SetReportPath(const char *path); + + // Don't use fields directly. They are only declared public to allow + // aggregate initialization. + + // Protects fields below. + StaticSpinMutex *mu; + // Opened file descriptor. Defaults to stderr. It may be equal to + // kInvalidFd, in which case new file will be opened when necessary. + fd_t fd; + // Path prefix of report file, set via __sanitizer_set_report_path. + char path_prefix[kMaxPathLength]; + // Full path to report, obtained as .PID + char full_path[kMaxPathLength]; + // PID of the process that opened fd. If a fork() occurs, + // the PID of child will be different from fd_pid. + uptr fd_pid; + + private: + void ReopenIfNecessary(); +}; +extern ReportFile report_file; + +enum FileAccessMode { + RdOnly, + WrOnly, + RdWr +}; + +// Returns kInvalidFd on error. +fd_t OpenFile(const char *filename, FileAccessMode mode, + error_t *errno_p = nullptr); +void CloseFile(fd_t); + +// Return true on success, false on error. +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, + uptr *bytes_read = nullptr, error_t *error_p = nullptr); +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, + uptr *bytes_written = nullptr, error_t *error_p = nullptr); + +bool RenameFile(const char *oldpath, const char *newpath, + error_t *error_p = nullptr); + +// Scoped file handle closer. +struct FileCloser { + explicit FileCloser(fd_t fd) : fd(fd) {} + ~FileCloser() { CloseFile(fd); } + fd_t fd; +}; + +bool SupportsColoredOutput(fd_t fd); + +// OS +const char *GetPwd(); +bool FileExists(const char *filename); +char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); +// Starts a subprocess and returs its pid. +// If *_fd parameters are not kInvalidFd their corresponding input/output +// streams will be redirect to the file. The files will always be closed +// in parent process even in case of an error. +// The child process will close all fds after STDERR_FILENO +// before passing control to a program. +pid_t StartSubprocess(const char *filename, const char *const argv[], + fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, + fd_t stderr_fd = kInvalidFd); +// Checks if specified process is still running +bool IsProcessRunning(pid_t pid); +// Waits for the process to finish and returns its exit code. +// Returns -1 in case of an error. +int WaitForProcess(pid_t pid); + +// Maps given file to virtual memory, and returns pointer to it +// (or NULL if mapping fails). Stores the size of mmaped region +// in '*buff_size'. +void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); + +} // namespace __sanitizer + +#endif // SANITIZER_FILE_H diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 52196db12..3a159078a 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -19,6 +19,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_freebsd.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 8d3128ae1..b8f4575f7 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -17,6 +17,7 @@ #if SANITIZER_POSIX #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index 377f1ce75..587817f8e 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_stacktrace_printer.h" +#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index f0f2c9c72..d9e26b8fc 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -16,6 +16,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 2ae42b338..a2ac11882 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -15,6 +15,7 @@ #define SANITIZER_SYMBOLIZER_INTERNAL_H #include "sanitizer_symbolizer.h" +#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 60ec7506c..3af733c3b 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -16,6 +16,7 @@ #if SANITIZER_POSIX #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 93a8794ee..d92c9d9c3 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -14,6 +14,7 @@ #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index 625257622..a73c65a51 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -11,6 +11,7 @@ #include #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" #include "gtest/gtest.h" diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index fb6b109ee..8a6afab65 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "gtest/gtest.h" #include diff --git a/lib/stats/stats.cc b/lib/stats/stats.cc index df9845a38..6a6eb3a3c 100644 --- a/lib/stats/stats.cc +++ b/lib/stats/stats.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_internal_defs.h" #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 617dd9e11..9d4d7d7fc 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -24,6 +24,7 @@ SRCS=" ../../sanitizer_common/sanitizer_common.cc ../../sanitizer_common/sanitizer_common_libcdep.cc ../../sanitizer_common/sanitizer_deadlock_detector2.cc + ../../sanitizer_common/sanitizer_file.cc ../../sanitizer_common/sanitizer_flag_parser.cc ../../sanitizer_common/sanitizer_flags.cc ../../sanitizer_common/sanitizer_libc.cc diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 32cc3325f..b2c30ec9a 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -13,6 +13,7 @@ #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_rtl.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index a01525302..882e06765 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -14,6 +14,7 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_placement_new.h" -- cgit v1.2.1 From 35ad307c385e384f47a7fb348c14b3602d3a33c4 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 20 Jul 2017 18:06:02 +0000 Subject: Add MemoryMappedSection struct for two-level memory map iteration Summary: This will allow sanitizer_procmaps on mac to expose section information. Reviewers: kubamracek, alekseyshl, kcc Subscribers: llvm-commits, emaste Differential Revision: https://reviews.llvm.org/D35422 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308644 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 19 ++++++++++- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 47 +++++++++++++++++++++----- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 7e7997454..eb9e6c109 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,7 +37,8 @@ static const uptr kProtectionWrite = 2; static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -struct MemoryMappedSegment { +class MemoryMappedSegment { + public: MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size) {} ~MemoryMappedSegment() {} @@ -55,6 +56,22 @@ struct MemoryMappedSegment { uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; + +#if SANITIZER_MAC + + private: + friend class MemoryMappingLayout; + + template + void NextSectionLoad(LoadedModule *module); + void AddAddressRanges(LoadedModule *module); + + uptr nsects_; + char *current_load_cmd_addr_; + u32 lc_type_; + uptr base_virt_addr_; + uptr addr_mask_; +#endif }; class MemoryMappingLayout { diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 560451a16..65236da1a 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -35,6 +35,32 @@ #endif namespace __sanitizer { +template +void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { + const Section *sc = (const Section *)current_load_cmd_addr_; + current_load_cmd_addr_ += sizeof(Section); + + uptr sec_start = (sc->addr & addr_mask_) + base_virt_addr_; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + if (!nsects_) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); + return; + } + + do { + if (lc_type_ == LC_SEGMENT) { + NextSectionLoad(module); +#ifdef MH_MAGIC_64 + } else if (lc_type_ == LC_SEGMENT_64) { + NextSectionLoad(module); +#endif + } + } while (--nsects_); +} MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); @@ -143,21 +169,27 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; + segment->current_load_cmd_addr_ = (char *)lc + sizeof(SegmentCommand); + segment->lc_type_ = kLCSegment; + segment->nsects_ = sc->nsects; if (current_image_ == kDyldImageIdx) { + segment->base_virt_addr_ = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); + segment->addr_mask_ = 0xfffff; } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - segment->start = sc->vmaddr + dlloff; - segment->end = sc->vmaddr + sc->vmsize + dlloff; + segment->base_virt_addr_ = + (uptr)_dyld_get_image_vmaddr_slide(current_image_); + segment->addr_mask_ = ~0; } + segment->start = + (sc->vmaddr & segment->addr_mask_) + segment->base_virt_addr_; + segment->end = segment->start + sc->vmsize; // Return the initial protection. segment->protection = sc->initprot; @@ -292,7 +324,7 @@ void MemoryMappingLayout::DumpListOfModules( Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - for (uptr i = 0; Next(&segment); i++) { + while (Next(&segment)) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -304,8 +336,7 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - cur_module->addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(cur_module); } } -- cgit v1.2.1 From a0aa7cee546359f17b5ba681f2997725c2a1de91 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:20:12 +0000 Subject: [asan] Update unittest for changes in logging r308637 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308647 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Windows/shadow_conflict_32.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asan/TestCases/Windows/shadow_conflict_32.cc b/test/asan/TestCases/Windows/shadow_conflict_32.cc index 7c6d94b37..a2b6b4688 100644 --- a/test/asan/TestCases/Windows/shadow_conflict_32.cc +++ b/test/asan/TestCases/Windows/shadow_conflict_32.cc @@ -20,9 +20,9 @@ int main() { extern "C" __declspec(dllexport) int test_function() { return 0; } #endif -// CHECK: =={{[0-9]+}}==Shadow memory range interleaves with an existing memory mapping. ASan cannot proceed correctly. ABORTING. -// CHECK: =={{[0-9]+}}==ASan shadow was supposed to be located in the [0x2fff0000-0x3fffffff] range. -// CHECK: =={{[0-9]+}}==Dumping process modules +// CHECK: =={{[0-9:]+}}==Shadow memory range interleaves with an existing memory mapping. ASan cannot proceed correctly. ABORTING. +// CHECK: =={{[0-9:]+}}==ASan shadow was supposed to be located in the [0x2fff0000-0x3fffffff] range. +// CHECK: =={{[0-9:]+}}==Dumping process modules // CHECK-DAG: {{0x30000000-0x300.....}} {{.*}}\shadow_conflict_32.cc.tmp_dll.dll // CHECK-DAG: {{0x........-0x........}} {{.*}}\shadow_conflict_32.cc.tmp.exe -- cgit v1.2.1 From 8d06014e5dd7cdfa69d9fb2389f311ffa5a0b25f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:24:45 +0000 Subject: Revert "[sanitizer_common] Move filesystem-related code out of sanitizer_common.cc" Breaks Windows build. This reverts commit r308640. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308648 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 6 +- lib/dfsan/dfsan.cc | 1 - lib/sanitizer_common/CMakeLists.txt | 2 - lib/sanitizer_common/sanitizer_common.cc | 141 +++++++++++++++++ lib/sanitizer_common/sanitizer_common.h | 80 +++++++++- lib/sanitizer_common/sanitizer_common_libcdep.cc | 1 - .../sanitizer_coverage_libcdep_new.cc | 1 - lib/sanitizer_common/sanitizer_file.cc | 171 --------------------- lib/sanitizer_common/sanitizer_file.h | 110 ------------- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 1 - lib/sanitizer_common/sanitizer_posix.cc | 1 - .../sanitizer_stacktrace_printer.cc | 1 - lib/sanitizer_common/sanitizer_suppressions.cc | 1 - .../sanitizer_symbolizer_internal.h | 1 - .../sanitizer_symbolizer_posix_libcdep.cc | 1 - .../tests/sanitizer_common_test.cc | 1 - lib/sanitizer_common/tests/sanitizer_libc_test.cc | 1 - lib/sanitizer_common/tests/sanitizer_linux_test.cc | 1 - lib/stats/stats.cc | 1 - lib/tsan/go/buildgo.sh | 1 - lib/tsan/rtl/tsan_report.cc | 1 - lib/tsan/rtl/tsan_rtl.cc | 1 - 22 files changed, 223 insertions(+), 303 deletions(-) delete mode 100644 lib/sanitizer_common/sanitizer_file.cc delete mode 100644 lib/sanitizer_common/sanitizer_file.h diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 8e3d9454f..2e477f258 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -141,9 +141,9 @@ class ScopedInErrorReport { // Can't use Report() here because of potential deadlocks // in nested signal handlers. - static const char msg[] = - "AddressSanitizer: nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); + const char msg[] = "AddressSanitizer: nested bug in the same thread, " + "aborting.\n"; + WriteToFile(kStderrFd, msg, sizeof(msg)); internal__exit(common_flags()->exitcode); } diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index 9e360c959..3aa99b7f9 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -21,7 +21,6 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index a0831e80e..a17bd1299 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -7,7 +7,6 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc sanitizer_errno.cc - sanitizer_file.cc sanitizer_flags.cc sanitizer_flag_parser.cc sanitizer_libc.cc @@ -97,7 +96,6 @@ set(SANITIZER_HEADERS sanitizer_deadlock_detector_interface.h sanitizer_errno.h sanitizer_errno_codes.h - sanitizer_file.h sanitizer_flag_parser.h sanitizer_flags.h sanitizer_flags.inc diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 8d51e1ed1..7e6f8fce7 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -27,6 +27,72 @@ const char *SanitizerToolName = "SanitizerTool"; atomic_uint32_t current_verbosity; uptr PageSizeCached; +StaticSpinMutex report_file_mu; +ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + +void RawWrite(const char *buffer) { + report_file.Write(buffer, internal_strlen(buffer)); +} + +void ReportFile::ReopenIfNecessary() { + mu->CheckLocked(); + if (fd == kStdoutFd || fd == kStderrFd) return; + + uptr pid = internal_getpid(); + // If in tracer, use the parent's file. + if (pid == stoptheworld_tracer_pid) + pid = stoptheworld_tracer_ppid; + if (fd != kInvalidFd) { + // If the report file is already opened by the current process, + // do nothing. Otherwise the report file was opened by the parent + // process, close it now. + if (fd_pid == pid) + return; + else + CloseFile(fd); + } + + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + fd = OpenFile(full_path, WrOnly); + if (fd == kInvalidFd) { + const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + Die(); + } + fd_pid = pid; +} + +void ReportFile::SetReportPath(const char *path) { + if (!path) + return; + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", + path[0], path[1], path[2], path[3], + path[4], path[5], path[6], path[7]); + Die(); + } + + SpinMutexLock l(mu); + if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) + CloseFile(fd); + fd = kInvalidFd; + if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; + } else if (internal_strcmp(path, "stderr") == 0) { + fd = kStderrFd; + } else { + internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + } +} + // PID of the tracer task in StopTheWorld. It shares the address space with the // main process, but has a different PID and thus requires special handling. uptr stoptheworld_tracer_pid = 0; @@ -54,6 +120,42 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, UNREACHABLE("unable to mmap"); } +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + uptr PageSize = GetPageSizeCached(); + uptr kMinFileLen = PageSize; + *buff = nullptr; + *buff_size = 0; + *read_len = 0; + // The files we usually open are not seekable, so try different buffer sizes. + for (uptr size = kMinFileLen; size <= max_len; size *= 2) { + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) return false; + UnmapOrDie(*buff, *buff_size); + *buff = (char*)MmapOrDie(size, __func__); + *buff_size = size; + *read_len = 0; + // Read up to one page at a time. + bool reached_eof = false; + while (*read_len + PageSize <= size) { + uptr just_read; + if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { + UnmapOrDie(*buff, *buff_size); + return false; + } + if (just_read == 0) { + reached_eof = true; + break; + } + *read_len += just_read; + } + CloseFile(fd); + if (reached_eof) // We've read the whole file. + break; + } + return true; +} + typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); @@ -257,6 +359,36 @@ bool TemplateMatch(const char *templ, const char *str) { return true; } +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + if (FileExists(name)) { + return internal_strdup(name); + } + + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalScopedBuffer buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + static char binary_name_cache_str[kMaxPathLength]; static char process_name_cache_str[kMaxPathLength]; @@ -350,6 +482,15 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), using namespace __sanitizer; // NOLINT extern "C" { +void __sanitizer_set_report_path(const char *path) { + report_file.SetReportPath(path); +} + +void __sanitizer_set_report_fd(void *fd) { + report_file.fd = (fd_t)reinterpret_cast(fd); + report_file.fd_pid = internal_getpid(); +} + SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, const char *error_summary) { Printf("%s\n", error_summary); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9c801f151..89aae5798 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -185,7 +185,6 @@ typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); // IO -void CatastrophicErrorWrite(const char *buffer, uptr length); void RawWrite(const char *buffer); bool ColorizeReports(); void RemoveANSIEscapeSequencesFromString(char *buffer); @@ -204,9 +203,64 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)); // Can be used to prevent mixing error reports from different sanitizers. extern StaticSpinMutex CommonSanitizerReportMutex; +struct ReportFile { + void Write(const char *buffer, uptr length); + bool SupportsColors(); + void SetReportPath(const char *path); + + // Don't use fields directly. They are only declared public to allow + // aggregate initialization. + + // Protects fields below. + StaticSpinMutex *mu; + // Opened file descriptor. Defaults to stderr. It may be equal to + // kInvalidFd, in which case new file will be opened when necessary. + fd_t fd; + // Path prefix of report file, set via __sanitizer_set_report_path. + char path_prefix[kMaxPathLength]; + // Full path to report, obtained as .PID + char full_path[kMaxPathLength]; + // PID of the process that opened fd. If a fork() occurs, + // the PID of child will be different from fd_pid. + uptr fd_pid; + + private: + void ReopenIfNecessary(); +}; +extern ReportFile report_file; + extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; +enum FileAccessMode { + RdOnly, + WrOnly, + RdWr +}; + +// Returns kInvalidFd on error. +fd_t OpenFile(const char *filename, FileAccessMode mode, + error_t *errno_p = nullptr); +void CloseFile(fd_t); + +// Return true on success, false on error. +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, + uptr *bytes_read = nullptr, error_t *error_p = nullptr); +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, + uptr *bytes_written = nullptr, error_t *error_p = nullptr); + +bool RenameFile(const char *oldpath, const char *newpath, + error_t *error_p = nullptr); + +// Scoped file handle closer. +struct FileCloser { + explicit FileCloser(fd_t fd) : fd(fd) {} + ~FileCloser() { CloseFile(fd); } + fd_t fd; +}; + +bool SupportsColoredOutput(fd_t fd); + // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size'. @@ -215,6 +269,11 @@ extern uptr stoptheworld_tracer_ppid; bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr *read_len, uptr max_len = 1 << 26, error_t *errno_p = nullptr); +// Maps given file to virtual memory, and returns pointer to it +// (or NULL if mapping fails). Stores the size of mmaped region +// in '*buff_size'. +void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); bool IsAccessibleMemoryRange(uptr beg, uptr size); @@ -234,8 +293,27 @@ void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); void PrintModuleMap(); +bool FileExists(const char *filename); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); +const char *GetPwd(); +char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); +// Starts a subprocess and returs its pid. +// If *_fd parameters are not kInvalidFd their corresponding input/output +// streams will be redirect to the file. The files will always be closed +// in parent process even in case of an error. +// The child process will close all fds after STDERR_FILENO +// before passing control to a program. +pid_t StartSubprocess(const char *filename, const char *const argv[], + fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, + fd_t stderr_fd = kInvalidFd); +// Checks if specified process is still running +bool IsProcessRunning(pid_t pid); +// Waits for the process to finish and returns its exit code. +// Returns -1 in case of an error. +int WaitForProcess(pid_t pid); u32 GetUid(); void ReExec(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 82d223a29..cf200512d 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -14,7 +14,6 @@ #include "sanitizer_common.h" #include "sanitizer_allocator_interface.h" -#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index ac9be2704..24433356c 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -12,7 +12,6 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" -#include "sanitizer_file.h" #include "sanitizer_symbolizer.h" using namespace __sanitizer; diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc deleted file mode 100644 index dfbe99c56..000000000 --- a/lib/sanitizer_common/sanitizer_file.cc +++ /dev/null @@ -1,171 +0,0 @@ -//===-- sanitizer_file.cc ------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. It defines filesystem-related interfaces. This -// is separate from sanitizer_common.cc so that it's simpler to disable -// all the filesystem support code for a port that doesn't use it. -// -//===---------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_file.h" - -namespace __sanitizer { - -void CatastrophicErrorWrite(const char *buffer, uptr length) { - WriteToFile(kStderrFd, buffer, length); -} - -StaticSpinMutex report_file_mu; -ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; - -void RawWrite(const char *buffer) { - report_file.Write(buffer, internal_strlen(buffer)); -} - -void ReportFile::ReopenIfNecessary() { - mu->CheckLocked(); - if (fd == kStdoutFd || fd == kStderrFd) return; - - uptr pid = internal_getpid(); - // If in tracer, use the parent's file. - if (pid == stoptheworld_tracer_pid) - pid = stoptheworld_tracer_ppid; - if (fd != kInvalidFd) { - // If the report file is already opened by the current process, - // do nothing. Otherwise the report file was opened by the parent - // process, close it now. - if (fd_pid == pid) - return; - else - CloseFile(fd); - } - - const char *exe_name = GetProcessName(); - if (common_flags()->log_exe_name && exe_name) { - internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, - exe_name, pid); - } else { - internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); - } - fd = OpenFile(full_path, WrOnly); - if (fd == kInvalidFd) { - const char *ErrorMsgPrefix = "ERROR: Can't open file: "; - WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); - WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); - Die(); - } - fd_pid = pid; -} - -void ReportFile::SetReportPath(const char *path) { - if (!path) - return; - uptr len = internal_strlen(path); - if (len > sizeof(path_prefix) - 100) { - Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); - Die(); - } - - SpinMutexLock l(mu); - if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) - CloseFile(fd); - fd = kInvalidFd; - if (internal_strcmp(path, "stdout") == 0) { - fd = kStdoutFd; - } else if (internal_strcmp(path, "stderr") == 0) { - fd = kStderrFd; - } else { - internal_snprintf(path_prefix, kMaxPathLength, "%s", path); - } -} - -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr *read_len, uptr max_len, error_t *errno_p) { - uptr PageSize = GetPageSizeCached(); - uptr kMinFileLen = PageSize; - *buff = nullptr; - *buff_size = 0; - *read_len = 0; - // The files we usually open are not seekable, so try different buffer sizes. - for (uptr size = kMinFileLen; size <= max_len; size *= 2) { - fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) return false; - UnmapOrDie(*buff, *buff_size); - *buff = (char*)MmapOrDie(size, __func__); - *buff_size = size; - *read_len = 0; - // Read up to one page at a time. - bool reached_eof = false; - while (*read_len + PageSize <= size) { - uptr just_read; - if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { - UnmapOrDie(*buff, *buff_size); - return false; - } - if (just_read == 0) { - reached_eof = true; - break; - } - *read_len += just_read; - } - CloseFile(fd); - if (reached_eof) // We've read the whole file. - break; - } - return true; -} - -static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; - -char *FindPathToBinary(const char *name) { - if (FileExists(name)) { - return internal_strdup(name); - } - - const char *path = GetEnv("PATH"); - if (!path) - return nullptr; - uptr name_len = internal_strlen(name); - InternalScopedBuffer buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, kPathSeparator); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return nullptr; -} - -} // namespace __sanitizer - -using namespace __sanitizer; // NOLINT - -extern "C" { -void __sanitizer_set_report_path(const char *path) { - report_file.SetReportPath(path); -} - -void __sanitizer_set_report_fd(void *fd) { - report_file.fd = (fd_t)reinterpret_cast(fd); - report_file.fd_pid = internal_getpid(); -} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_file.h b/lib/sanitizer_common/sanitizer_file.h deleted file mode 100644 index 9a12ab734..000000000 --- a/lib/sanitizer_common/sanitizer_file.h +++ /dev/null @@ -1,110 +0,0 @@ -//===-- sanitizer_file.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// -// -// This file is shared between run-time libraries of sanitizers. -// It declares filesystem-related interfaces. This is separate from -// sanitizer_common.h so that it's simpler to disable all the filesystem -// support code for a port that doesn't use it. -// -//===---------------------------------------------------------------------===// -#ifndef SANITIZER_FILE_H -#define SANITIZER_FILE_H - -#include "sanitizer_interface_internal.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" - -namespace __sanitizer { - -struct ReportFile { - void Write(const char *buffer, uptr length); - bool SupportsColors(); - void SetReportPath(const char *path); - - // Don't use fields directly. They are only declared public to allow - // aggregate initialization. - - // Protects fields below. - StaticSpinMutex *mu; - // Opened file descriptor. Defaults to stderr. It may be equal to - // kInvalidFd, in which case new file will be opened when necessary. - fd_t fd; - // Path prefix of report file, set via __sanitizer_set_report_path. - char path_prefix[kMaxPathLength]; - // Full path to report, obtained as .PID - char full_path[kMaxPathLength]; - // PID of the process that opened fd. If a fork() occurs, - // the PID of child will be different from fd_pid. - uptr fd_pid; - - private: - void ReopenIfNecessary(); -}; -extern ReportFile report_file; - -enum FileAccessMode { - RdOnly, - WrOnly, - RdWr -}; - -// Returns kInvalidFd on error. -fd_t OpenFile(const char *filename, FileAccessMode mode, - error_t *errno_p = nullptr); -void CloseFile(fd_t); - -// Return true on success, false on error. -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, - uptr *bytes_read = nullptr, error_t *error_p = nullptr); -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, - uptr *bytes_written = nullptr, error_t *error_p = nullptr); - -bool RenameFile(const char *oldpath, const char *newpath, - error_t *error_p = nullptr); - -// Scoped file handle closer. -struct FileCloser { - explicit FileCloser(fd_t fd) : fd(fd) {} - ~FileCloser() { CloseFile(fd); } - fd_t fd; -}; - -bool SupportsColoredOutput(fd_t fd); - -// OS -const char *GetPwd(); -bool FileExists(const char *filename); -char *FindPathToBinary(const char *name); -bool IsPathSeparator(const char c); -bool IsAbsolutePath(const char *path); -// Starts a subprocess and returs its pid. -// If *_fd parameters are not kInvalidFd their corresponding input/output -// streams will be redirect to the file. The files will always be closed -// in parent process even in case of an error. -// The child process will close all fds after STDERR_FILENO -// before passing control to a program. -pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); -// Checks if specified process is still running -bool IsProcessRunning(pid_t pid); -// Waits for the process to finish and returns its exit code. -// Returns -1 in case of an error. -int WaitForProcess(pid_t pid); - -// Maps given file to virtual memory, and returns pointer to it -// (or NULL if mapping fails). Stores the size of mmaped region -// in '*buff_size'. -void *MapFileToMemory(const char *file_name, uptr *buff_size); -void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); - -} // namespace __sanitizer - -#endif // SANITIZER_FILE_H diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 3a159078a..52196db12 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -19,7 +19,6 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" -#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_freebsd.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index b8f4575f7..8d3128ae1 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -17,7 +17,6 @@ #if SANITIZER_POSIX #include "sanitizer_common.h" -#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index 587817f8e..377f1ce75 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "sanitizer_stacktrace_printer.h" -#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index d9e26b8fc..f0f2c9c72 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -16,7 +16,6 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" -#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h index a2ac11882..2ae42b338 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -15,7 +15,6 @@ #define SANITIZER_SYMBOLIZER_INTERNAL_H #include "sanitizer_symbolizer.h" -#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 3af733c3b..60ec7506c 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -16,7 +16,6 @@ #if SANITIZER_POSIX #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" -#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index d92c9d9c3..93a8794ee 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -14,7 +14,6 @@ #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index a73c65a51..625257622 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -11,7 +11,6 @@ #include #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" #include "gtest/gtest.h" diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index 8a6afab65..fb6b109ee 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -17,7 +17,6 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "gtest/gtest.h" #include diff --git a/lib/stats/stats.cc b/lib/stats/stats.cc index 6a6eb3a3c..df9845a38 100644 --- a/lib/stats/stats.cc +++ b/lib/stats/stats.cc @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_internal_defs.h" #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 9d4d7d7fc..617dd9e11 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -24,7 +24,6 @@ SRCS=" ../../sanitizer_common/sanitizer_common.cc ../../sanitizer_common/sanitizer_common_libcdep.cc ../../sanitizer_common/sanitizer_deadlock_detector2.cc - ../../sanitizer_common/sanitizer_file.cc ../../sanitizer_common/sanitizer_flag_parser.cc ../../sanitizer_common/sanitizer_flags.cc ../../sanitizer_common/sanitizer_libc.cc diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index b2c30ec9a..32cc3325f 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -13,7 +13,6 @@ #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_rtl.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index 882e06765..a01525302 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -14,7 +14,6 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_placement_new.h" -- cgit v1.2.1 From e2c4c417be08a7314b178e772dfdea4d10c27f81 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:43:09 +0000 Subject: [compiler-rt] Reorder functions to have smaller stack frames git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308650 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index b14675a06..101c3fb79 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -231,17 +231,23 @@ static void CallPrintfAndReportCallback(const char *str) { static void SharedPrintfCode(bool append_pid, const char *format, va_list args) { - va_list args2; - va_copy(args2, args); - const int kLen = 16 * 1024; // |local_buffer| is small enough not to overflow the stack and/or violate // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other // hand, the bigger the buffer is, the more the chance the error report will // fit into it. char local_buffer[400]; + SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), + format, va_list args); +} + +static void SharedPrintfCodeNoBuffer(bool append_pid, char *local_buffer, + int buffer_size, const char *format, + va_list args) { + va_list args2; + va_copy(args2, args); + const int kLen = 16 * 1024; int needed_length; char *buffer = local_buffer; - int buffer_size = ARRAY_SIZE(local_buffer); // First try to print a message using a local buffer, and then fall back to // mmaped buffer. for (int use_mmap = 0; use_mmap < 2; use_mmap++) { -- cgit v1.2.1 From d4b10e1df682ce22888b197a907e7ceb08cd3539 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:43:56 +0000 Subject: Revert "[compiler-rt] Reorder functions to have smaller stack frames" Does not compile. This reverts commit r308650. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308651 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index 101c3fb79..b14675a06 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -231,23 +231,17 @@ static void CallPrintfAndReportCallback(const char *str) { static void SharedPrintfCode(bool append_pid, const char *format, va_list args) { + va_list args2; + va_copy(args2, args); + const int kLen = 16 * 1024; // |local_buffer| is small enough not to overflow the stack and/or violate // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other // hand, the bigger the buffer is, the more the chance the error report will // fit into it. char local_buffer[400]; - SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), - format, va_list args); -} - -static void SharedPrintfCodeNoBuffer(bool append_pid, char *local_buffer, - int buffer_size, const char *format, - va_list args) { - va_list args2; - va_copy(args2, args); - const int kLen = 16 * 1024; int needed_length; char *buffer = local_buffer; + int buffer_size = ARRAY_SIZE(local_buffer); // First try to print a message using a local buffer, and then fall back to // mmaped buffer. for (int use_mmap = 0; use_mmap < 2; use_mmap++) { -- cgit v1.2.1 From 75ed905e2dc63208af04d37b782e54941e331897 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:47:01 +0000 Subject: [compiler-rt] Reorder functions to shrink stack frames git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308652 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index b14675a06..f36eba55d 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -229,19 +229,14 @@ static void CallPrintfAndReportCallback(const char *str) { PrintfAndReportCallback(str); } -static void SharedPrintfCode(bool append_pid, const char *format, - va_list args) { +static void SharedPrintfCodeNoBuffer(bool append_pid, char *local_buffer, + int buffer_size, const char *format, + va_list args) { va_list args2; va_copy(args2, args); const int kLen = 16 * 1024; - // |local_buffer| is small enough not to overflow the stack and/or violate - // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other - // hand, the bigger the buffer is, the more the chance the error report will - // fit into it. - char local_buffer[400]; int needed_length; char *buffer = local_buffer; - int buffer_size = ARRAY_SIZE(local_buffer); // First try to print a message using a local buffer, and then fall back to // mmaped buffer. for (int use_mmap = 0; use_mmap < 2; use_mmap++) { @@ -291,6 +286,17 @@ static void SharedPrintfCode(bool append_pid, const char *format, va_end(args2); } +static void SharedPrintfCode(bool append_pid, const char *format, + va_list args) { + // |local_buffer| is small enough not to overflow the stack and/or violate + // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other + // hand, the bigger the buffer is, the more the chance the error report will + // fit into it. + char local_buffer[400]; + SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), + format, args); +} + FORMAT(1, 2) void Printf(const char *format, ...) { va_list args; -- cgit v1.2.1 From 47ee1da2bb2096a44a59d08172aa3e75396538e8 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 18:54:26 +0000 Subject: [compiler-rt] Use NOINLE to shrink stack frames git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308654 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index f36eba55d..f81e15357 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -229,9 +229,11 @@ static void CallPrintfAndReportCallback(const char *str) { PrintfAndReportCallback(str); } -static void SharedPrintfCodeNoBuffer(bool append_pid, char *local_buffer, - int buffer_size, const char *format, - va_list args) { +static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, + char *local_buffer, + int buffer_size, + const char *format, + va_list args) { va_list args2; va_copy(args2, args); const int kLen = 16 * 1024; @@ -286,8 +288,8 @@ static void SharedPrintfCodeNoBuffer(bool append_pid, char *local_buffer, va_end(args2); } -static void SharedPrintfCode(bool append_pid, const char *format, - va_list args) { +static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, + va_list args) { // |local_buffer| is small enough not to overflow the stack and/or violate // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other // hand, the bigger the buffer is, the more the chance the error report will -- cgit v1.2.1 From 66c4a26305e73d350c2638798fe77e0031fae7f9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 20:06:00 +0000 Subject: [tsan] Update unittest for logging changes of r308637 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308660 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/esan/TestCases/large-stack-linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/esan/TestCases/large-stack-linux.c b/test/esan/TestCases/large-stack-linux.c index 3e024fc4e..1af32f8ba 100644 --- a/test/esan/TestCases/large-stack-linux.c +++ b/test/esan/TestCases/large-stack-linux.c @@ -56,14 +56,14 @@ int main(int argc, char *argv[]) { // CHECK: in esan::initializeLibrary // CHECK: Testing child with infinite stack // CHECK-NEXT: in esan::initializeLibrary - // CHECK-NEXT: =={{[0-9]+}}==The stack size limit is beyond the maximum supported. + // CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported. // CHECK-NEXT: Re-execing with a stack size below 1TB. // CHECK-NEXT: in esan::initializeLibrary // CHECK: done // CHECK: in esan::finalizeLibrary // CHECK: Testing child with 1TB stack // CHECK-NEXT: in esan::initializeLibrary - // CHECK-NEXT: =={{[0-9]+}}==The stack size limit is beyond the maximum supported. + // CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported. // CHECK-NEXT: Re-execing with a stack size below 1TB. // CHECK-NEXT: in esan::initializeLibrary // CHECK: done -- cgit v1.2.1 From eb87176f80444bae9500e10d07531956f7142cac Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 20 Jul 2017 21:23:14 +0000 Subject: Revert "Add MemoryMappedSection struct for two-level memory map iteration" This probably broke lib0 tsan unit test on 10.11 buildbots This reverts commit 35ad307c385e384f47a7fb348c14b3602d3a33c4. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308676 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 19 +---------- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 47 +++++--------------------- 2 files changed, 9 insertions(+), 57 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index eb9e6c109..7e7997454 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,8 +37,7 @@ static const uptr kProtectionWrite = 2; static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -class MemoryMappedSegment { - public: +struct MemoryMappedSegment { MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size) {} ~MemoryMappedSegment() {} @@ -56,22 +55,6 @@ class MemoryMappedSegment { uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; - -#if SANITIZER_MAC - - private: - friend class MemoryMappingLayout; - - template - void NextSectionLoad(LoadedModule *module); - void AddAddressRanges(LoadedModule *module); - - uptr nsects_; - char *current_load_cmd_addr_; - u32 lc_type_; - uptr base_virt_addr_; - uptr addr_mask_; -#endif }; class MemoryMappingLayout { diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 65236da1a..560451a16 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -35,32 +35,6 @@ #endif namespace __sanitizer { -template -void MemoryMappedSegment::NextSectionLoad(LoadedModule *module) { - const Section *sc = (const Section *)current_load_cmd_addr_; - current_load_cmd_addr_ += sizeof(Section); - - uptr sec_start = (sc->addr & addr_mask_) + base_virt_addr_; - uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, IsExecutable(), IsWritable()); -} - -void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { - if (!nsects_) { - module->addAddressRange(start, end, IsExecutable(), IsWritable()); - return; - } - - do { - if (lc_type_ == LC_SEGMENT) { - NextSectionLoad(module); -#ifdef MH_MAGIC_64 - } else if (lc_type_ == LC_SEGMENT_64) { - NextSectionLoad(module); -#endif - } - } while (--nsects_); -} MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); @@ -169,27 +143,21 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - segment->current_load_cmd_addr_ = (char *)lc + sizeof(SegmentCommand); - segment->lc_type_ = kLCSegment; - segment->nsects_ = sc->nsects; if (current_image_ == kDyldImageIdx) { - segment->base_virt_addr_ = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->addr_mask_ = 0xfffff; + segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); + segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); } else { - segment->base_virt_addr_ = - (uptr)_dyld_get_image_vmaddr_slide(current_image_); - segment->addr_mask_ = ~0; + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + segment->start = sc->vmaddr + dlloff; + segment->end = sc->vmaddr + sc->vmsize + dlloff; } - segment->start = - (sc->vmaddr & segment->addr_mask_) + segment->base_virt_addr_; - segment->end = segment->start + sc->vmsize; // Return the initial protection. segment->protection = sc->initprot; @@ -324,7 +292,7 @@ void MemoryMappingLayout::DumpListOfModules( Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - while (Next(&segment)) { + for (uptr i = 0; Next(&segment); i++) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -336,7 +304,8 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - segment.AddAddressRanges(cur_module); + cur_module->addAddressRange(segment.start, segment.end, + segment.IsExecutable(), segment.IsWritable()); } } -- cgit v1.2.1 From 41f1143000e1f670261565345294707571c7a0b3 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 20 Jul 2017 21:40:53 +0000 Subject: Add end-to-end tests for overflows of byval arguments. Summary: Included is one test for passing structs by value and one test for passing C++ objects by value. Submitted on behalf of Matt Morehouse. Reviewers: eugenis, vitalybuka Reviewed By: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34827 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308677 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../test/asan/TestCases/pass-object-byval.cc | 36 ++++++++++++++++++++ .../test/asan/TestCases/pass-struct-byval-uar.cc | 38 ++++++++++++++++++++++ .../test/asan/TestCases/pass-struct-byval.cc | 23 +++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 compiler-rt/test/asan/TestCases/pass-object-byval.cc create mode 100644 compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc create mode 100644 compiler-rt/test/asan/TestCases/pass-struct-byval.cc diff --git a/compiler-rt/test/asan/TestCases/pass-object-byval.cc b/compiler-rt/test/asan/TestCases/pass-object-byval.cc new file mode 100644 index 000000000..189fcbeb2 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/pass-object-byval.cc @@ -0,0 +1,36 @@ +// Verify that objects passed by value get red zones and that the copy +// constructor is called. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ +// RUN: Assertion{{.*}}failed +#include + +class A { + public: + A() : me(this) {} + A(const A &other) : me(this) { + for (int i = 0; i < 8; ++i) a[i] = other.a[i]; + } + + int a[8]; + A *me; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + assert(a.me == &a); + bar(&a); +} + +int main() { + A a; + foo(a); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread diff --git a/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc b/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc new file mode 100644 index 000000000..3f2fd09c6 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc @@ -0,0 +1,38 @@ +// Test that use-after-return works with arguments passed by value. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-NO-UAR %s +// RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-UAR %s +// +// On several architectures, the IR does not use byval arguments for foo() and +// instead creates a copy in main() and gives foo() a pointer to the copy. In +// that case, ASAN has nothing to poison on return from foo() and will not +// detect the UAR. +// REQUIRES: x86_64-target-arch, linux, not-android + +#include + +struct A { + int a[8]; +}; + +A *foo(A a) { + return &a; +} + +int main() { + A *a = foo(A()); + a->a[0] = 7; + std::fprintf(stderr, "\n"); // Ensures some output is generated for FileCheck + // to verify in the case where UAR is not + // detected. +} + +// CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-NO-UAR-NOT: WRITE of size 4 at +// CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable +// +// CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-UAR: WRITE of size 4 at +// CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable diff --git a/compiler-rt/test/asan/TestCases/pass-struct-byval.cc b/compiler-rt/test/asan/TestCases/pass-struct-byval.cc new file mode 100644 index 000000000..ba49eccf4 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/pass-struct-byval.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +struct A { + int a[8]; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + bar(&a); +} + +int main() { + foo(A()); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-underflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread -- cgit v1.2.1 From ecbdaaaa7a191059b66291b93f6874e7189e4ed9 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 21 Jul 2017 00:30:04 +0000 Subject: [XRay][compiler-rt] Update test to account for change in logging format. Fixes build breakage for some bots after we've started logging both the process id and the thread id. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308701 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-thread-order.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index b43a0fe40..e5e5cd020 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) { t2.join(); __xray_log_finalize(); __xray_log_flushLog(); - // CHECK: =={{[0-9]+}}==XRay: Log file in '{{.*}}' + // CHECK: {{.*}}XRay: Log file in '{{.*}}' } // We want to make sure that the order of the function log doesn't matter. -- cgit v1.2.1 From ce339bb5f5f79904d6e39b9ca152873aaae840ab Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 21 Jul 2017 22:47:46 +0000 Subject: Remove Bitrig: CompilerRT Changes Bitrig code has been merged back to OpenBSD, thus the OS has been abandoned. Differential Revision: https://reviews.llvm.org/D35709 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308798 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 4 ++-- lib/builtins/int_endianness.h | 4 ++-- test/builtins/Unit/endianness.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 25570fc21..37c5fbe7d 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -23,7 +23,7 @@ uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress, uintptr_t GetCurrentProcess(void); #endif -#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__) +#if defined(__FreeBSD__) && defined(__arm__) #include #include #endif @@ -96,7 +96,7 @@ void __clear_cache(void *start, void *end) { * so there is nothing to do */ #elif defined(__arm__) && !defined(__APPLE__) - #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__) + #if defined(__FreeBSD__) || defined(__NetBSD__) struct arm_sync_icache_args arg; arg.addr = (uintptr_t)start; diff --git a/lib/builtins/int_endianness.h b/lib/builtins/int_endianness.h index 7995ddbb9..e2586c56b 100644 --- a/lib/builtins/int_endianness.h +++ b/lib/builtins/int_endianness.h @@ -61,7 +61,7 @@ #endif /* *BSD */ -#if defined(__OpenBSD__) || defined(__Bitrig__) +#if defined(__OpenBSD__) #include #if _BYTE_ORDER == _BIG_ENDIAN @@ -72,7 +72,7 @@ #define _YUGA_BIG_ENDIAN 0 #endif /* _BYTE_ORDER */ -#endif /* OpenBSD and Bitrig. */ +#endif /* OpenBSD */ /* .. */ diff --git a/test/builtins/Unit/endianness.h b/test/builtins/Unit/endianness.h index 06c53de0b..9cecd2165 100644 --- a/test/builtins/Unit/endianness.h +++ b/test/builtins/Unit/endianness.h @@ -51,7 +51,7 @@ /* .. */ -#if defined(__OpenBSD__) || defined(__Bitrig__) +#if defined(__OpenBSD__) #include #if _BYTE_ORDER == _BIG_ENDIAN @@ -62,7 +62,7 @@ #define _YUGA_BIG_ENDIAN 0 #endif /* _BYTE_ORDER */ -#endif /* OpenBSD and Bitrig. */ +#endif /* OpenBSD */ /* .. */ -- cgit v1.2.1 From f2d5726e3687bc8aa439e22cbd5f719a0a9c6299 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 22 Jul 2017 01:46:40 +0000 Subject: [sanitizer_common] Move filesystem-related code out of sanitizer_common.cc Summary: This is a pure refactoring change. It just moves code that is related to filesystem operations from sanitizer_common.{cc,h} to sanitizer_file.{cc,h}. This makes it cleaner to disable the filesystem-related code for a new port that doesn't want it. Submitted on behalf of Roland McGrath. Reviewers: kcc, eugenis, alekseyshl Reviewed By: alekseyshl Subscribers: vitalybuka, llvm-commits, kubamracek, mgorny, phosek Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35591 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308819 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 6 +- lib/dfsan/dfsan.cc | 1 + lib/sanitizer_common/CMakeLists.txt | 2 + lib/sanitizer_common/sanitizer_common.cc | 141 ----------------- lib/sanitizer_common/sanitizer_common.h | 80 +--------- lib/sanitizer_common/sanitizer_common_libcdep.cc | 1 + .../sanitizer_coverage_libcdep_new.cc | 1 + lib/sanitizer_common/sanitizer_file.cc | 171 +++++++++++++++++++++ lib/sanitizer_common/sanitizer_file.h | 110 +++++++++++++ lib/sanitizer_common/sanitizer_linux_libcdep.cc | 1 + lib/sanitizer_common/sanitizer_mac.cc | 1 + lib/sanitizer_common/sanitizer_posix.cc | 1 + .../sanitizer_stacktrace_printer.cc | 1 + lib/sanitizer_common/sanitizer_suppressions.cc | 1 + .../sanitizer_symbolizer_internal.h | 1 + .../sanitizer_symbolizer_posix_libcdep.cc | 1 + lib/sanitizer_common/sanitizer_win.cc | 1 + .../tests/sanitizer_common_test.cc | 1 + lib/sanitizer_common/tests/sanitizer_libc_test.cc | 1 + lib/sanitizer_common/tests/sanitizer_linux_test.cc | 1 + lib/stats/stats.cc | 1 + lib/tsan/go/buildgo.sh | 1 + lib/tsan/rtl/tsan_report.cc | 1 + lib/tsan/rtl/tsan_rtl.cc | 1 + 24 files changed, 305 insertions(+), 223 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_file.cc create mode 100644 lib/sanitizer_common/sanitizer_file.h diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 2e477f258..8e3d9454f 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -141,9 +141,9 @@ class ScopedInErrorReport { // Can't use Report() here because of potential deadlocks // in nested signal handlers. - const char msg[] = "AddressSanitizer: nested bug in the same thread, " - "aborting.\n"; - WriteToFile(kStderrFd, msg, sizeof(msg)); + static const char msg[] = + "AddressSanitizer: nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); internal__exit(common_flags()->exitcode); } diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index 3aa99b7f9..9e360c959 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -21,6 +21,7 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index a17bd1299..a0831e80e 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -7,6 +7,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc sanitizer_errno.cc + sanitizer_file.cc sanitizer_flags.cc sanitizer_flag_parser.cc sanitizer_libc.cc @@ -96,6 +97,7 @@ set(SANITIZER_HEADERS sanitizer_deadlock_detector_interface.h sanitizer_errno.h sanitizer_errno_codes.h + sanitizer_file.h sanitizer_flag_parser.h sanitizer_flags.h sanitizer_flags.inc diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 7e6f8fce7..8d51e1ed1 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -27,72 +27,6 @@ const char *SanitizerToolName = "SanitizerTool"; atomic_uint32_t current_verbosity; uptr PageSizeCached; -StaticSpinMutex report_file_mu; -ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; - -void RawWrite(const char *buffer) { - report_file.Write(buffer, internal_strlen(buffer)); -} - -void ReportFile::ReopenIfNecessary() { - mu->CheckLocked(); - if (fd == kStdoutFd || fd == kStderrFd) return; - - uptr pid = internal_getpid(); - // If in tracer, use the parent's file. - if (pid == stoptheworld_tracer_pid) - pid = stoptheworld_tracer_ppid; - if (fd != kInvalidFd) { - // If the report file is already opened by the current process, - // do nothing. Otherwise the report file was opened by the parent - // process, close it now. - if (fd_pid == pid) - return; - else - CloseFile(fd); - } - - const char *exe_name = GetProcessName(); - if (common_flags()->log_exe_name && exe_name) { - internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, - exe_name, pid); - } else { - internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); - } - fd = OpenFile(full_path, WrOnly); - if (fd == kInvalidFd) { - const char *ErrorMsgPrefix = "ERROR: Can't open file: "; - WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); - WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); - Die(); - } - fd_pid = pid; -} - -void ReportFile::SetReportPath(const char *path) { - if (!path) - return; - uptr len = internal_strlen(path); - if (len > sizeof(path_prefix) - 100) { - Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); - Die(); - } - - SpinMutexLock l(mu); - if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) - CloseFile(fd); - fd = kInvalidFd; - if (internal_strcmp(path, "stdout") == 0) { - fd = kStdoutFd; - } else if (internal_strcmp(path, "stderr") == 0) { - fd = kStderrFd; - } else { - internal_snprintf(path_prefix, kMaxPathLength, "%s", path); - } -} - // PID of the tracer task in StopTheWorld. It shares the address space with the // main process, but has a different PID and thus requires special handling. uptr stoptheworld_tracer_pid = 0; @@ -120,42 +54,6 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, UNREACHABLE("unable to mmap"); } -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr *read_len, uptr max_len, error_t *errno_p) { - uptr PageSize = GetPageSizeCached(); - uptr kMinFileLen = PageSize; - *buff = nullptr; - *buff_size = 0; - *read_len = 0; - // The files we usually open are not seekable, so try different buffer sizes. - for (uptr size = kMinFileLen; size <= max_len; size *= 2) { - fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) return false; - UnmapOrDie(*buff, *buff_size); - *buff = (char*)MmapOrDie(size, __func__); - *buff_size = size; - *read_len = 0; - // Read up to one page at a time. - bool reached_eof = false; - while (*read_len + PageSize <= size) { - uptr just_read; - if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { - UnmapOrDie(*buff, *buff_size); - return false; - } - if (just_read == 0) { - reached_eof = true; - break; - } - *read_len += just_read; - } - CloseFile(fd); - if (reached_eof) // We've read the whole file. - break; - } - return true; -} - typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); @@ -359,36 +257,6 @@ bool TemplateMatch(const char *templ, const char *str) { return true; } -static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; - -char *FindPathToBinary(const char *name) { - if (FileExists(name)) { - return internal_strdup(name); - } - - const char *path = GetEnv("PATH"); - if (!path) - return nullptr; - uptr name_len = internal_strlen(name); - InternalScopedBuffer buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, kPathSeparator); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return nullptr; -} - static char binary_name_cache_str[kMaxPathLength]; static char process_name_cache_str[kMaxPathLength]; @@ -482,15 +350,6 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), using namespace __sanitizer; // NOLINT extern "C" { -void __sanitizer_set_report_path(const char *path) { - report_file.SetReportPath(path); -} - -void __sanitizer_set_report_fd(void *fd) { - report_file.fd = (fd_t)reinterpret_cast(fd); - report_file.fd_pid = internal_getpid(); -} - SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, const char *error_summary) { Printf("%s\n", error_summary); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 89aae5798..9c801f151 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -185,6 +185,7 @@ typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); // IO +void CatastrophicErrorWrite(const char *buffer, uptr length); void RawWrite(const char *buffer); bool ColorizeReports(); void RemoveANSIEscapeSequencesFromString(char *buffer); @@ -203,64 +204,9 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)); // Can be used to prevent mixing error reports from different sanitizers. extern StaticSpinMutex CommonSanitizerReportMutex; -struct ReportFile { - void Write(const char *buffer, uptr length); - bool SupportsColors(); - void SetReportPath(const char *path); - - // Don't use fields directly. They are only declared public to allow - // aggregate initialization. - - // Protects fields below. - StaticSpinMutex *mu; - // Opened file descriptor. Defaults to stderr. It may be equal to - // kInvalidFd, in which case new file will be opened when necessary. - fd_t fd; - // Path prefix of report file, set via __sanitizer_set_report_path. - char path_prefix[kMaxPathLength]; - // Full path to report, obtained as .PID - char full_path[kMaxPathLength]; - // PID of the process that opened fd. If a fork() occurs, - // the PID of child will be different from fd_pid. - uptr fd_pid; - - private: - void ReopenIfNecessary(); -}; -extern ReportFile report_file; - extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; -enum FileAccessMode { - RdOnly, - WrOnly, - RdWr -}; - -// Returns kInvalidFd on error. -fd_t OpenFile(const char *filename, FileAccessMode mode, - error_t *errno_p = nullptr); -void CloseFile(fd_t); - -// Return true on success, false on error. -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, - uptr *bytes_read = nullptr, error_t *error_p = nullptr); -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, - uptr *bytes_written = nullptr, error_t *error_p = nullptr); - -bool RenameFile(const char *oldpath, const char *newpath, - error_t *error_p = nullptr); - -// Scoped file handle closer. -struct FileCloser { - explicit FileCloser(fd_t fd) : fd(fd) {} - ~FileCloser() { CloseFile(fd); } - fd_t fd; -}; - -bool SupportsColoredOutput(fd_t fd); - // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size'. @@ -269,11 +215,6 @@ bool SupportsColoredOutput(fd_t fd); bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr *read_len, uptr max_len = 1 << 26, error_t *errno_p = nullptr); -// Maps given file to virtual memory, and returns pointer to it -// (or NULL if mapping fails). Stores the size of mmaped region -// in '*buff_size'. -void *MapFileToMemory(const char *file_name, uptr *buff_size); -void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); bool IsAccessibleMemoryRange(uptr beg, uptr size); @@ -293,27 +234,8 @@ void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); void PrintModuleMap(); -bool FileExists(const char *filename); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); -const char *GetPwd(); -char *FindPathToBinary(const char *name); -bool IsPathSeparator(const char c); -bool IsAbsolutePath(const char *path); -// Starts a subprocess and returs its pid. -// If *_fd parameters are not kInvalidFd their corresponding input/output -// streams will be redirect to the file. The files will always be closed -// in parent process even in case of an error. -// The child process will close all fds after STDERR_FILENO -// before passing control to a program. -pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); -// Checks if specified process is still running -bool IsProcessRunning(pid_t pid); -// Waits for the process to finish and returns its exit code. -// Returns -1 in case of an error. -int WaitForProcess(pid_t pid); u32 GetUid(); void ReExec(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index cf200512d..82d223a29 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -14,6 +14,7 @@ #include "sanitizer_common.h" #include "sanitizer_allocator_interface.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 24433356c..ac9be2704 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -12,6 +12,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_symbolizer.h" using namespace __sanitizer; diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc new file mode 100644 index 000000000..dfbe99c56 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_file.cc @@ -0,0 +1,171 @@ +//===-- sanitizer_file.cc ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. It defines filesystem-related interfaces. This +// is separate from sanitizer_common.cc so that it's simpler to disable +// all the filesystem support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +namespace __sanitizer { + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + WriteToFile(kStderrFd, buffer, length); +} + +StaticSpinMutex report_file_mu; +ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + +void RawWrite(const char *buffer) { + report_file.Write(buffer, internal_strlen(buffer)); +} + +void ReportFile::ReopenIfNecessary() { + mu->CheckLocked(); + if (fd == kStdoutFd || fd == kStderrFd) return; + + uptr pid = internal_getpid(); + // If in tracer, use the parent's file. + if (pid == stoptheworld_tracer_pid) + pid = stoptheworld_tracer_ppid; + if (fd != kInvalidFd) { + // If the report file is already opened by the current process, + // do nothing. Otherwise the report file was opened by the parent + // process, close it now. + if (fd_pid == pid) + return; + else + CloseFile(fd); + } + + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + fd = OpenFile(full_path, WrOnly); + if (fd == kInvalidFd) { + const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + Die(); + } + fd_pid = pid; +} + +void ReportFile::SetReportPath(const char *path) { + if (!path) + return; + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", + path[0], path[1], path[2], path[3], + path[4], path[5], path[6], path[7]); + Die(); + } + + SpinMutexLock l(mu); + if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) + CloseFile(fd); + fd = kInvalidFd; + if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; + } else if (internal_strcmp(path, "stderr") == 0) { + fd = kStderrFd; + } else { + internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + } +} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + uptr PageSize = GetPageSizeCached(); + uptr kMinFileLen = PageSize; + *buff = nullptr; + *buff_size = 0; + *read_len = 0; + // The files we usually open are not seekable, so try different buffer sizes. + for (uptr size = kMinFileLen; size <= max_len; size *= 2) { + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) return false; + UnmapOrDie(*buff, *buff_size); + *buff = (char*)MmapOrDie(size, __func__); + *buff_size = size; + *read_len = 0; + // Read up to one page at a time. + bool reached_eof = false; + while (*read_len + PageSize <= size) { + uptr just_read; + if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { + UnmapOrDie(*buff, *buff_size); + return false; + } + if (just_read == 0) { + reached_eof = true; + break; + } + *read_len += just_read; + } + CloseFile(fd); + if (reached_eof) // We've read the whole file. + break; + } + return true; +} + +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + if (FileExists(name)) { + return internal_strdup(name); + } + + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalScopedBuffer buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + +} // namespace __sanitizer + +using namespace __sanitizer; // NOLINT + +extern "C" { +void __sanitizer_set_report_path(const char *path) { + report_file.SetReportPath(path); +} + +void __sanitizer_set_report_fd(void *fd) { + report_file.fd = (fd_t)reinterpret_cast(fd); + report_file.fd_pid = internal_getpid(); +} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_file.h b/lib/sanitizer_common/sanitizer_file.h new file mode 100644 index 000000000..9a12ab734 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_file.h @@ -0,0 +1,110 @@ +//===-- sanitizer_file.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is shared between run-time libraries of sanitizers. +// It declares filesystem-related interfaces. This is separate from +// sanitizer_common.h so that it's simpler to disable all the filesystem +// support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// +#ifndef SANITIZER_FILE_H +#define SANITIZER_FILE_H + +#include "sanitizer_interface_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +struct ReportFile { + void Write(const char *buffer, uptr length); + bool SupportsColors(); + void SetReportPath(const char *path); + + // Don't use fields directly. They are only declared public to allow + // aggregate initialization. + + // Protects fields below. + StaticSpinMutex *mu; + // Opened file descriptor. Defaults to stderr. It may be equal to + // kInvalidFd, in which case new file will be opened when necessary. + fd_t fd; + // Path prefix of report file, set via __sanitizer_set_report_path. + char path_prefix[kMaxPathLength]; + // Full path to report, obtained as .PID + char full_path[kMaxPathLength]; + // PID of the process that opened fd. If a fork() occurs, + // the PID of child will be different from fd_pid. + uptr fd_pid; + + private: + void ReopenIfNecessary(); +}; +extern ReportFile report_file; + +enum FileAccessMode { + RdOnly, + WrOnly, + RdWr +}; + +// Returns kInvalidFd on error. +fd_t OpenFile(const char *filename, FileAccessMode mode, + error_t *errno_p = nullptr); +void CloseFile(fd_t); + +// Return true on success, false on error. +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, + uptr *bytes_read = nullptr, error_t *error_p = nullptr); +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, + uptr *bytes_written = nullptr, error_t *error_p = nullptr); + +bool RenameFile(const char *oldpath, const char *newpath, + error_t *error_p = nullptr); + +// Scoped file handle closer. +struct FileCloser { + explicit FileCloser(fd_t fd) : fd(fd) {} + ~FileCloser() { CloseFile(fd); } + fd_t fd; +}; + +bool SupportsColoredOutput(fd_t fd); + +// OS +const char *GetPwd(); +bool FileExists(const char *filename); +char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); +// Starts a subprocess and returs its pid. +// If *_fd parameters are not kInvalidFd their corresponding input/output +// streams will be redirect to the file. The files will always be closed +// in parent process even in case of an error. +// The child process will close all fds after STDERR_FILENO +// before passing control to a program. +pid_t StartSubprocess(const char *filename, const char *const argv[], + fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, + fd_t stderr_fd = kInvalidFd); +// Checks if specified process is still running +bool IsProcessRunning(pid_t pid); +// Waits for the process to finish and returns its exit code. +// Returns -1 in case of an error. +int WaitForProcess(pid_t pid); + +// Maps given file to virtual memory, and returns pointer to it +// (or NULL if mapping fails). Stores the size of mmaped region +// in '*buff_size'. +void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); + +} // namespace __sanitizer + +#endif // SANITIZER_FILE_H diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 52196db12..3a159078a 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -19,6 +19,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_freebsd.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1edd4157f..38b418314 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -23,6 +23,7 @@ #include #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 8d3128ae1..b8f4575f7 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -17,6 +17,7 @@ #if SANITIZER_POSIX #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index 377f1ce75..587817f8e 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_stacktrace_printer.h" +#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index f0f2c9c72..d9e26b8fc 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -16,6 +16,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 2ae42b338..a2ac11882 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -15,6 +15,7 @@ #define SANITIZER_SYMBOLIZER_INTERNAL_H #include "sanitizer_symbolizer.h" +#include "sanitizer_file.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 60ec7506c..3af733c3b 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -16,6 +16,7 @@ #if SANITIZER_POSIX #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_linux.h" diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index de01e8d11..c7772213a 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -24,6 +24,7 @@ #include "sanitizer_common.h" #include "sanitizer_dbghelp.h" +#include "sanitizer_file.h" #include "sanitizer_libc.h" #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 93a8794ee..d92c9d9c3 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -14,6 +14,7 @@ #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index 625257622..a73c65a51 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -11,6 +11,7 @@ #include #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" #include "gtest/gtest.h" diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index fb6b109ee..8a6afab65 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "gtest/gtest.h" #include diff --git a/lib/stats/stats.cc b/lib/stats/stats.cc index df9845a38..6a6eb3a3c 100644 --- a/lib/stats/stats.cc +++ b/lib/stats/stats.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_internal_defs.h" #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 617dd9e11..9d4d7d7fc 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -24,6 +24,7 @@ SRCS=" ../../sanitizer_common/sanitizer_common.cc ../../sanitizer_common/sanitizer_common_libcdep.cc ../../sanitizer_common/sanitizer_deadlock_detector2.cc + ../../sanitizer_common/sanitizer_file.cc ../../sanitizer_common/sanitizer_flag_parser.cc ../../sanitizer_common/sanitizer_flags.cc ../../sanitizer_common/sanitizer_libc.cc diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 32cc3325f..b2c30ec9a 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -13,6 +13,7 @@ #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_rtl.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index a01525302..882e06765 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -14,6 +14,7 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_placement_new.h" -- cgit v1.2.1 From 614a50c1049b7616fe968def766b79713c12f64e Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 24 Jul 2017 14:31:01 +0000 Subject: [compiler-rt] Add missing const specifier to MemoryMappedSegment functions git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308881 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 7e7997454..539a53bc3 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -42,10 +42,10 @@ struct MemoryMappedSegment { : filename(buff), filename_size(size) {} ~MemoryMappedSegment() {} - bool IsReadable() { return protection & kProtectionRead; } - bool IsWritable() { return protection & kProtectionWrite; } - bool IsExecutable() { return protection & kProtectionExecute; } - bool IsShared() { return protection & kProtectionShared; } + bool IsReadable() const { return protection & kProtectionRead; } + bool IsWritable() const { return protection & kProtectionWrite; } + bool IsExecutable() const { return protection & kProtectionExecute; } + bool IsShared() const { return protection & kProtectionShared; } uptr start; uptr end; -- cgit v1.2.1 From 5884a6648ad229cc07706b32bfc3734e3313f231 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 24 Jul 2017 15:29:38 +0000 Subject: [scudo] Quarantine overhaul Summary: First, some context. The main feedback we get about the quarantine is that it's too memory hungry. A single MB of quarantine will have an impact of 3 to 4MB of PSS/RSS, and things quickly get out of hand in terms of memory usage, and the quarantine ends up disabled. The main objective of the quarantine is to protect from use-after-free exploitation by making it harder for an attacker to reallocate a controlled chunk in place of the targeted freed chunk. This is achieved by not making it available to the backend right away for reuse, but holding it a little while. Historically, what has usually been the target of such attacks was objects, where vtable pointers or other function pointers could constitute a valuable targeti to replace. Those are usually on the smaller side. There is barely any advantage in putting the quarantine several megabytes of RGB data or the like. Now for the patch. This patch introduces a new way the Quarantine behaves in Scudo. First of all, the size of the Quarantine will be defined in KB instead of MB, then we introduce a new option: the size up to which (lower than or equal to) a chunk will be quarantined. This way, we only quarantine smaller chunks, and the size of the quarantine remains manageable. It also prevents someone from triggering a recycle by allocating something huge. We default to 512 bytes on 32-bit and 2048 bytes on 64-bit platforms. In details, the patches includes the following: - introduce `QuarantineSizeKb`, but honor `QuarantineSizeMb` if set to fall back to the old behavior (meaning no threshold in that case); `QuarantineSizeMb` is described as deprecated in the options descriptios; documentation update will follow; - introduce `QuarantineChunksUpToSize`, the new threshold value; - update the `quarantine.cpp` test, and other tests using `QuarantineSizeMb`; - remove `AllocatorOptions::copyTo`, it wasn't used; - slightly change the logic around `quarantineOrDeallocateChunk` to accomodate for the new logic; rename a couple of variables there as well; Rewriting the tests, I found a somewhat annoying bug where non-default aligned chunks would account for more than needed when placed in the quarantine due to `<< MinAlignment` instead of `<< MinAlignmentLog`. This is fixed and tested for now. Reviewers: alekseyshl, kcc Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35694 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308884 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 69 ++++++++++++++++++---------------------- lib/scudo/scudo_flags.cpp | 49 ++++++++++++++++++++++------- lib/scudo/scudo_flags.inc | 22 +++++++++---- test/scudo/overflow.cpp | 6 ++-- test/scudo/quarantine.cpp | 73 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 154 insertions(+), 65 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 6f30ee987..38522de4d 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -161,8 +161,9 @@ ScudoChunk *getScudoChunk(uptr UserBeg) { } struct AllocatorOptions { - u32 QuarantineSizeMb; + u32 QuarantineSizeKb; u32 ThreadLocalQuarantineSizeKb; + u32 QuarantineChunksUpToSize; bool MayReturnNull; s32 ReleaseToOSIntervalMs; bool DeallocationTypeMismatch; @@ -170,29 +171,19 @@ struct AllocatorOptions { bool ZeroContents; void setFrom(const Flags *f, const CommonFlags *cf); - void copyTo(Flags *f, CommonFlags *cf) const; }; void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) { MayReturnNull = cf->allocator_may_return_null; ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms; - QuarantineSizeMb = f->QuarantineSizeMb; + QuarantineSizeKb = f->QuarantineSizeKb; ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb; + QuarantineChunksUpToSize = f->QuarantineChunksUpToSize; DeallocationTypeMismatch = f->DeallocationTypeMismatch; DeleteSizeMismatch = f->DeleteSizeMismatch; ZeroContents = f->ZeroContents; } -void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const { - cf->allocator_may_return_null = MayReturnNull; - cf->allocator_release_to_os_interval_ms = ReleaseToOSIntervalMs; - f->QuarantineSizeMb = QuarantineSizeMb; - f->ThreadLocalQuarantineSizeKb = ThreadLocalQuarantineSizeKb; - f->DeallocationTypeMismatch = DeallocationTypeMismatch; - f->DeleteSizeMismatch = DeleteSizeMismatch; - f->ZeroContents = ZeroContents; -} - static void initScudoInternal(const AllocatorOptions &Options); static bool ScudoInitIsRunning = false; @@ -292,6 +283,8 @@ struct ScudoAllocator { ScudoQuarantineCache FallbackQuarantineCache; ScudoPrng FallbackPrng; + u32 QuarantineChunksUpToSize; + bool DeallocationTypeMismatch; bool ZeroContents; bool DeleteSizeMismatch; @@ -337,8 +330,9 @@ struct ScudoAllocator { SetAllocatorMayReturnNull(Options.MayReturnNull); BackendAllocator.init(Options.ReleaseToOSIntervalMs); AllocatorQuarantine.Init( - static_cast(Options.QuarantineSizeMb) << 20, + static_cast(Options.QuarantineSizeKb) << 10, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); + QuarantineChunksUpToSize = Options.QuarantineChunksUpToSize; GlobalPrng.init(); Cookie = GlobalPrng.getU64(); BackendAllocator.initCache(&FallbackAllocatorCache); @@ -447,18 +441,17 @@ struct ScudoAllocator { return UserPtr; } - // Place a chunk in the quarantine. In the event of a zero-sized quarantine, - // we directly deallocate the chunk, otherwise the flow would lead to the - // chunk being loaded (and checked) twice, and stored (and checksummed) once, - // with no additional security value. + // Place a chunk in the quarantine or directly deallocate it in the event of + // a zero-sized quarantine, or if the size of the chunk is greater than the + // quarantine chunk size threshold. void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header, uptr Size) { - bool FromPrimary = Header->FromPrimary; - bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0); + const bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0) || + (Size > QuarantineChunksUpToSize); if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); - if (FromPrimary) { + if (Header->FromPrimary) { ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { getBackendAllocator().deallocatePrimary( @@ -472,6 +465,12 @@ struct ScudoAllocator { getBackendAllocator().deallocateSecondary(Ptr); } } else { + // If a small memory amount was allocated with a larger alignment, we want + // to take that into account. Otherwise the Quarantine would be filled + // with tiny chunks, taking a lot of VA memory. This is an approximation + // of the usable size, that allows us to not call + // GetActuallyAllocatedSize. + uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog); UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); @@ -480,13 +479,13 @@ struct ScudoAllocator { AllocatorQuarantine.Put(getQuarantineCache(ThreadContext), QuarantineCallback( getAllocatorCache(ThreadContext)), - Chunk, Size); + Chunk, EstimatedSize); ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, QuarantineCallback(&FallbackAllocatorCache), - Chunk, Size); + Chunk, EstimatedSize); } } } @@ -504,37 +503,31 @@ struct ScudoAllocator { "aligned at address %p\n", UserPtr); } ScudoChunk *Chunk = getScudoChunk(UserBeg); - UnpackedHeader OldHeader; - Chunk->loadHeader(&OldHeader); - if (UNLIKELY(OldHeader.State != ChunkAllocated)) { + UnpackedHeader Header; + Chunk->loadHeader(&Header); + if (UNLIKELY(Header.State != ChunkAllocated)) { dieWithMessage("ERROR: invalid chunk state when deallocating address " "%p\n", UserPtr); } if (DeallocationTypeMismatch) { // The deallocation type has to match the allocation one. - if (OldHeader.AllocType != Type) { + if (Header.AllocType != Type) { // With the exception of memalign'd Chunks, that can be still be free'd. - if (OldHeader.AllocType != FromMemalign || Type != FromMalloc) { + if (Header.AllocType != FromMemalign || Type != FromMalloc) { dieWithMessage("ERROR: allocation type mismatch on address %p\n", UserPtr); } } } - uptr Size = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : - Chunk->getUsableSize(&OldHeader) - OldHeader.SizeOrUnusedBytes; + uptr Size = Header.FromPrimary ? Header.SizeOrUnusedBytes : + Chunk->getUsableSize(&Header) - Header.SizeOrUnusedBytes; if (DeleteSizeMismatch) { if (DeleteSize && DeleteSize != Size) { dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", UserPtr); } } - - // If a small memory amount was allocated with a larger alignment, we want - // to take that into account. Otherwise the Quarantine would be filled with - // tiny chunks, taking a lot of VA memory. This is an approximation of the - // usable size, that allows us to not call GetActuallyAllocatedSize. - uptr LiableSize = Size + (OldHeader.Offset << MinAlignment); - quarantineOrDeallocateChunk(Chunk, &OldHeader, LiableSize); + quarantineOrDeallocateChunk(Chunk, &Header, Size); } // Reallocates a chunk. We can save on a new allocation if the new requested @@ -575,7 +568,7 @@ struct ScudoAllocator { uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : UsableSize - OldHeader.SizeOrUnusedBytes; memcpy(NewPtr, OldPtr, Min(NewSize, OldSize)); - quarantineOrDeallocateChunk(Chunk, &OldHeader, UsableSize); + quarantineOrDeallocateChunk(Chunk, &OldHeader, OldSize); } return NewPtr; } diff --git a/lib/scudo/scudo_flags.cpp b/lib/scudo/scudo_flags.cpp index 90f0cbf4b..ab94afac9 100644 --- a/lib/scudo/scudo_flags.cpp +++ b/lib/scudo/scudo_flags.cpp @@ -67,27 +67,52 @@ void initFlags() { // Sanity checks and default settings for the Quarantine parameters. - if (f->QuarantineSizeMb < 0) { - const int DefaultQuarantineSizeMb = FIRST_32_SECOND_64(4, 16); - f->QuarantineSizeMb = DefaultQuarantineSizeMb; + if (f->QuarantineSizeMb >= 0) { + // Backward compatible logic if QuarantineSizeMb is set. + if (f->QuarantineSizeKb >= 0) { + dieWithMessage("ERROR: please use either QuarantineSizeMb (deprecated) " + "or QuarantineSizeKb, but not both\n"); + } + if (f->QuarantineChunksUpToSize >= 0) { + dieWithMessage("ERROR: QuarantineChunksUpToSize cannot be used in " + " conjunction with the deprecated QuarantineSizeMb option\n"); + } + // If everything is in order, update QuarantineSizeKb accordingly. + f->QuarantineSizeKb = f->QuarantineSizeMb * 1024; + } else { + // Otherwise proceed with the new options. + if (f->QuarantineSizeKb < 0) { + const int DefaultQuarantineSizeKb = FIRST_32_SECOND_64(64, 256); + f->QuarantineSizeKb = DefaultQuarantineSizeKb; + } + if (f->QuarantineChunksUpToSize < 0) { + const int DefaultQuarantineChunksUpToSize = FIRST_32_SECOND_64(512, 2048); + f->QuarantineChunksUpToSize = DefaultQuarantineChunksUpToSize; + } } - // We enforce an upper limit for the quarantine size of 4Gb. - if (f->QuarantineSizeMb > (4 * 1024)) { + + // We enforce an upper limit for the chunk quarantine threshold of 4Mb. + if (f->QuarantineChunksUpToSize > (4 * 1024 * 1024)) { + dieWithMessage("ERROR: the chunk quarantine threshold is too large\n"); + } + + // We enforce an upper limit for the quarantine size of 32Mb. + if (f->QuarantineSizeKb > (32 * 1024)) { dieWithMessage("ERROR: the quarantine size is too large\n"); } + if (f->ThreadLocalQuarantineSizeKb < 0) { - const int DefaultThreadLocalQuarantineSizeKb = - FIRST_32_SECOND_64(64, 256); + const int DefaultThreadLocalQuarantineSizeKb = FIRST_32_SECOND_64(16, 64); f->ThreadLocalQuarantineSizeKb = DefaultThreadLocalQuarantineSizeKb; } - // And an upper limit of 128Mb for the thread quarantine cache. - if (f->ThreadLocalQuarantineSizeKb > (128 * 1024)) { + // And an upper limit of 8Mb for the thread quarantine cache. + if (f->ThreadLocalQuarantineSizeKb > (8 * 1024)) { dieWithMessage("ERROR: the per thread quarantine cache size is too " - "large\n"); + "large\n"); } - if (f->ThreadLocalQuarantineSizeKb == 0 && f->QuarantineSizeMb > 0) { + if (f->ThreadLocalQuarantineSizeKb == 0 && f->QuarantineSizeKb > 0) { dieWithMessage("ERROR: ThreadLocalQuarantineSizeKb can be set to 0 only " - "when QuarantineSizeMb is set to 0\n"); + "when QuarantineSizeKb is set to 0\n"); } } diff --git a/lib/scudo/scudo_flags.inc b/lib/scudo/scudo_flags.inc index 45f9ea846..f180478fd 100644 --- a/lib/scudo/scudo_flags.inc +++ b/lib/scudo/scudo_flags.inc @@ -15,17 +15,27 @@ # error "Define SCUDO_FLAG prior to including this file!" #endif -// Default value is set in scudo_flags.cpp based on architecture. SCUDO_FLAG(int, QuarantineSizeMb, -1, - "Size (in Mb) of quarantine used to delay the actual deallocation " - "of chunks. Lower value may reduce memory usage but decrease the " - "effectiveness of the mitigation.") + "Deprecated. Please use QuarantineSizeKb.") + +// Default value is set in scudo_flags.cpp based on architecture. +SCUDO_FLAG(int, QuarantineSizeKb, -1, + "Size in KB of quarantine used to delay the actual deallocation of " + "chunks. Lower value may reduce memory usage but decrease the " + "effectiveness of the mitigation. Defaults to 64KB (32-bit) or " + "256KB (64-bit)") // Default value is set in scudo_flags.cpp based on architecture. SCUDO_FLAG(int, ThreadLocalQuarantineSizeKb, -1, - "Size (in Kb) of per-thread cache used to offload the global " + "Size in KB of per-thread cache used to offload the global " "quarantine. Lower value may reduce memory usage but might increase " - "the contention on the global quarantine.") + "the contention on the global quarantine. Defaults to 16KB (32-bit) " + "or 64KB (64-bit)") + +// Default value is set in scudo_flags.cpp based on architecture. +SCUDO_FLAG(int, QuarantineChunksUpToSize, -1, + "Size in bytes up to which chunks will be quarantined (if lower than" + "or equal to). Defaults to 256 (32-bit) or 2048 (64-bit)") SCUDO_FLAG(bool, DeallocationTypeMismatch, true, "Report errors on malloc/delete, new/free, new/delete[], etc.") diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp index d12824578..82ea10fd1 100644 --- a/test/scudo/overflow.cpp +++ b/test/scudo/overflow.cpp @@ -1,6 +1,6 @@ // RUN: %clang_scudo %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=QuarantineSizeMb=1 not %run %t quarantine 2>&1 | FileCheck %s +// RUN: not %run %t malloc 2>&1 | FileCheck %s +// RUN: SCUDO_OPTIONS=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s // Tests that header corruption of an allocated or quarantined chunk is caught. @@ -29,7 +29,7 @@ int main(int argc, char **argv) ((char *)p)[-(offset + 2)] ^= 1; // Trigger the quarantine recycle for (int i = 0; i < 0x100; i++) { - p = malloc(1U << 16); + p = malloc(1U << 8); free(p); } } diff --git a/test/scudo/quarantine.cpp b/test/scudo/quarantine.cpp index 39ce1bd91..cfa9aa919 100644 --- a/test/scudo/quarantine.cpp +++ b/test/scudo/quarantine.cpp @@ -1,10 +1,15 @@ // RUN: %clang_scudo %s -o %t -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 -// RUN: SCUDO_OPTIONS=QuarantineSizeMb=1 %run %t smallquarantine 2>&1 +// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 +// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 +// RUN: SCUDO_OPTIONS="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 +// RUN: SCUDO_OPTIONS=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 +// RUN: SCUDO_OPTIONS=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 +// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 // Tests that the quarantine prevents a chunk from being reused right away. // Also tests that a chunk will eventually become available again for -// allocation when the recycling criteria has been met. +// allocation when the recycling criteria has been met. Finally, tests the +// threshold up to which a chunk is quarantine, and the old quarantine behavior. #include #include @@ -16,9 +21,16 @@ int main(int argc, char **argv) { void *p, *old_p; - size_t allocated_bytes, size = 1U << 16; + size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8; assert(argc == 2); + // First, warm up the allocator for the classes used. + p = malloc(size); + assert(p); + free(p); + assert(posix_memalign(&p, alignment, size) == 0); + assert(p); + free(p); if (!strcmp(argv[1], "zeroquarantine")) { // Verifies that a chunk is deallocated right away when the local and @@ -44,13 +56,62 @@ int main(int argc, char **argv) // Eventually the chunk should become available again. bool found = false; - for (int i = 0; i < 0x100 && found == false; i++) { + for (int i = 0; i < 0x200 && !found; i++) { p = malloc(size); assert(p); found = (p == old_p); free(p); } - assert(found == true); + assert(found); + } + if (!strcmp(argv[1], "threshold")) { + // Verifies that a chunk of size greater than the threshold will be freed + // right away. Alignment has no impact on the threshold. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(size + 1); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); + assert(posix_memalign(&p, alignment, size + 1) == 0); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); + // Verifies that a chunk of size lower or equal to the threshold will be + // quarantined. + p = malloc(size); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + assert(posix_memalign(&p, alignment, size) == 0); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + } + if (!strcmp(argv[1], "oldquarantine")) { + // Verifies that we quarantine everything if the deprecated quarantine + // option is specified. Alignment has no impact on the threshold. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(size); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + assert(posix_memalign(&p, alignment, size) == 0); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + // Secondary backed allocation. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(1U << 19); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); } return 0; -- cgit v1.2.1 From 50bfae49ead55180ef53c2975a2c8141327cbd55 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 24 Jul 2017 18:22:33 +0000 Subject: [scudo] Fix QuarantineChunksUpToSize failing test on AArch64 Summary: Warm-up the other 2 sizes used by the tests, which should get rid of a failure on AArch64. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: aemerson, rengolin, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D35806 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308907 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/scudo/quarantine.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/scudo/quarantine.cpp b/test/scudo/quarantine.cpp index cfa9aa919..89560dffd 100644 --- a/test/scudo/quarantine.cpp +++ b/test/scudo/quarantine.cpp @@ -28,9 +28,15 @@ int main(int argc, char **argv) p = malloc(size); assert(p); free(p); + p = malloc(size + 1); + assert(p); + free(p); assert(posix_memalign(&p, alignment, size) == 0); assert(p); free(p); + assert(posix_memalign(&p, alignment, size + 1) == 0); + assert(p); + free(p); if (!strcmp(argv[1], "zeroquarantine")) { // Verifies that a chunk is deallocated right away when the local and -- cgit v1.2.1 From b5e384b31de35dea3296a55d726a724c42a1b8ef Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 24 Jul 2017 18:24:08 +0000 Subject: Prefer atos to llvm-symbolizer on Darwin atos is the default symbolizer on Apple's compiler for quite a few years now. llvm-symbolizer is quite fragile on Darwin: for example, unless a .dSYM file was explicitly generated symbolication would not work. It is also very convenient when the behavior of LLVM open source compiler matches to that of Apple's compiler on Apple's platform. Furthermore, llvm-symbolizer is not installed on Apple's platform by default, which leads to strange behavior during debugging: the test might fail under lit (where it has llvm-symbolizer) but would run properly when launched on the command line (where it does not, and atos would be used). Indeed, there's a downside: atos does not work properly with inlined functions, hence the test change. We do not think that this is a major problem, as users would often compile with -O0 when debugging, and in any case it is preferable to symbolizer not being able to symbolize. Differential Revision: https://reviews.llvm.org/D35745 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308908 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_symbolizer_posix_libcdep.cc | 8 +++---- .../asan/TestCases/Darwin/suppressions-function.cc | 28 ++++++++++++++++++++++ test/asan/TestCases/suppressions-function.cc | 4 ++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 test/asan/TestCases/Darwin/suppressions-function.cc diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 3af733c3b..5ef91c7cf 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -471,16 +471,16 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { // Otherwise symbolizer program is unknown, let's search $PATH CHECK(path == nullptr); - if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { - VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); - return new(*allocator) LLVMSymbolizer(found_path, allocator); - } #if SANITIZER_MAC if (const char *found_path = FindPathToBinary("atos")) { VReport(2, "Using atos found at: %s\n", found_path); return new(*allocator) AtosSymbolizer(found_path, allocator); } #endif // SANITIZER_MAC + if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); + return new(*allocator) LLVMSymbolizer(found_path, allocator); + } if (common_flags()->allow_addr2line) { if (const char *found_path = FindPathToBinary("addr2line")) { VReport(2, "Using addr2line found at: %s\n", found_path); diff --git a/test/asan/TestCases/Darwin/suppressions-function.cc b/test/asan/TestCases/Darwin/suppressions-function.cc new file mode 100644 index 000000000..f58796fb8 --- /dev/null +++ b/test/asan/TestCases/Darwin/suppressions-function.cc @@ -0,0 +1,28 @@ +// Check that without suppressions, we catch the issue. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s + +// RUN: echo "interceptor_via_fun:crash_function" > %t.supp +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s + +// UNSUPPORTED: ios + +#include +#include +#include + +void crash_function() { + char *a = (char *)malloc(6); + free(a); + size_t len = strlen(a); // BOOM + fprintf(stderr, "strlen ignored, len = %zu\n", len); +} + +int main() { + crash_function(); +} + +// CHECK-CRASH: AddressSanitizer: heap-use-after-free +// CHECK-CRASH-NOT: strlen ignored +// CHECK-IGNORE-NOT: AddressSanitizer: heap-use-after-free +// CHECK-IGNORE: strlen ignored diff --git a/test/asan/TestCases/suppressions-function.cc b/test/asan/TestCases/suppressions-function.cc index c7f1ebe66..becefa2ee 100644 --- a/test/asan/TestCases/suppressions-function.cc +++ b/test/asan/TestCases/suppressions-function.cc @@ -10,6 +10,10 @@ // XFAIL: android,win32 // UNSUPPORTED: ios +// FIXME: atos does not work for inlined functions, yet llvm-symbolizer +// does not always work with debug info on Darwin. +// UNSUPPORTED: darwin + #include #include #include -- cgit v1.2.1 From 3af3bf6f524275649606bfd6765d1c7ed34a958b Mon Sep 17 00:00:00 2001 From: Stephen Hines Date: Mon, 24 Jul 2017 20:25:08 +0000 Subject: [mips] Switch asm to __asm__ for non-GNU compiles. Summary: Using asm works fine for gnu11, but fails if the compiler uses C11. Switch to the more consistent __asm__, since that is what the rest of the source is using. Reviewers: petarj Reviewed By: petarj Subscribers: llvm-commits, sdardis, arichardson, pirama Differential Revision: https://reviews.llvm.org/D35756 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 37c5fbe7d..af4ca619a 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -41,7 +41,7 @@ uintptr_t GetCurrentProcess(void); * clear_mips_cache - Invalidates instruction cache for Mips. */ static void clear_mips_cache(const void* Addr, size_t Size) { - asm volatile ( + __asm__ volatile ( ".set push\n" ".set noreorder\n" ".set noat\n" -- cgit v1.2.1 From c78e1b8ec98c38eb26d139313711548e1f82464a Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 24 Jul 2017 20:35:20 +0000 Subject: Splitting out test for Darwin for print-stack-trace: New default symbolizer can not symbolize inlined function which appear under -O3. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308925 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Darwin/print-stack-trace.cc | 19 +++++++++++++++++++ test/sanitizer_common/TestCases/print-stack-trace.cc | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 test/sanitizer_common/TestCases/Darwin/print-stack-trace.cc diff --git a/test/sanitizer_common/TestCases/Darwin/print-stack-trace.cc b/test/sanitizer_common/TestCases/Darwin/print-stack-trace.cc new file mode 100644 index 000000000..715282fd7 --- /dev/null +++ b/test/sanitizer_common/TestCases/Darwin/print-stack-trace.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx -O0 %s -o %t && %env_tool_opts=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s +// RUN: %env_tool_opts=stack_trace_format='"frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM + +#include + +static inline void FooBarBaz() { + __sanitizer_print_stack_trace(); +} + +int main() { + FooBarBaz(); + return 0; +} +// CHECK: {{ #0 0x.* in __sanitizer_print_stack_trace}} +// CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*}}print-stack-trace.cc:[[@LINE-8]] +// CHECK: {{ #2 0x.* in main.*}}print-stack-trace.cc:[[@LINE-5]] + +// CUSTOM: frame:1 lineno:[[@LINE-11]] +// CUSTOM: frame:2 lineno:[[@LINE-8]] diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc index 0055b2796..a6eca0b75 100644 --- a/test/sanitizer_common/TestCases/print-stack-trace.cc +++ b/test/sanitizer_common/TestCases/print-stack-trace.cc @@ -3,6 +3,8 @@ // RUN: %env_tool_opts=stack_trace_format='"frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM // RUN: %env_tool_opts=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE +// UNSUPPORTED: darwin + #include static inline void FooBarBaz() { -- cgit v1.2.1 From f728f46988ea1fc5c921dfdf53eea02a1050f80e Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 24 Jul 2017 21:22:59 +0000 Subject: [Sanitizers] TSan allocator set errno on failure. Summary: Set proper errno code on allocation failures and change realloc, pvalloc, aligned_alloc, memalign and posix_memalign implementation to satisfy their man-specified requirements. Modify allocator API implementation to bring it closer to other sanitizers allocators. Reviewers: dvyukov Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D35690 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308929 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_fd.cc | 6 +-- lib/tsan/rtl/tsan_interceptors.cc | 16 +++---- lib/tsan/rtl/tsan_libdispatch_mac.cc | 3 +- lib/tsan/rtl/tsan_malloc_mac.cc | 4 +- lib/tsan/rtl/tsan_mman.cc | 86 +++++++++++++++++++++++++++-------- lib/tsan/rtl/tsan_mman.h | 15 ++++-- lib/tsan/tests/unit/tsan_mman_test.cc | 83 ++++++++++++++++++++++++++++++--- test/tsan/allocator_returns_null.cc | 12 ++++- 8 files changed, 181 insertions(+), 44 deletions(-) diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc index d84df4a64..f13a7432e 100644 --- a/lib/tsan/rtl/tsan_fd.cc +++ b/lib/tsan/rtl/tsan_fd.cc @@ -48,8 +48,8 @@ static bool bogusfd(int fd) { } static FdSync *allocsync(ThreadState *thr, uptr pc) { - FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment, - false); + FdSync *s = (FdSync*)user_alloc_internal(thr, pc, sizeof(FdSync), + kDefaultAlignment, false); atomic_store(&s->rc, 1, memory_order_relaxed); return s; } @@ -79,7 +79,7 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) { if (l1 == 0) { uptr size = kTableSizeL2 * sizeof(FdDesc); // We need this to reside in user memory to properly catch races on it. - void *p = user_alloc(thr, pc, size, kDefaultAlignment, false); + void *p = user_alloc_internal(thr, pc, size, kDefaultAlignment, false); internal_memset(p, 0, size); MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size); if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel)) diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 001123f49..4c24c46eb 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -584,7 +584,7 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) { TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz); - return user_alloc(thr, pc, sz, align); + return user_memalign(thr, pc, align, sz); } TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { @@ -730,7 +730,7 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { #if SANITIZER_LINUX TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { SCOPED_INTERCEPTOR_RAW(memalign, align, sz); - return user_alloc(thr, pc, sz, align); + return user_memalign(thr, pc, align, sz); } #define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign) #else @@ -739,21 +739,20 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { #if !SANITIZER_MAC TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { - SCOPED_INTERCEPTOR_RAW(memalign, align, sz); - return user_alloc(thr, pc, sz, align); + SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz); + return user_aligned_alloc(thr, pc, align, sz); } TSAN_INTERCEPTOR(void*, valloc, uptr sz) { SCOPED_INTERCEPTOR_RAW(valloc, sz); - return user_alloc(thr, pc, sz, GetPageSizeCached()); + return user_valloc(thr, pc, sz); } #endif #if SANITIZER_LINUX TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { SCOPED_INTERCEPTOR_RAW(pvalloc, sz); - sz = RoundUp(sz, GetPageSizeCached()); - return user_alloc(thr, pc, sz, GetPageSizeCached()); + return user_pvalloc(thr, pc, sz); } #define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc) #else @@ -763,8 +762,7 @@ TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { #if !SANITIZER_MAC TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); - *memptr = user_alloc(thr, pc, sz, align); - return 0; + return user_posix_memalign(thr, pc, memptr, align, sz); } #endif diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc index 8c759a3be..4a36f03ff 100644 --- a/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -86,7 +86,8 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc, void *orig_context, dispatch_function_t orig_work) { tsan_block_context_t *new_context = - (tsan_block_context_t *)user_alloc(thr, pc, sizeof(tsan_block_context_t)); + (tsan_block_context_t *)user_alloc_internal(thr, pc, + sizeof(tsan_block_context_t)); new_context->queue = queue; new_context->orig_context = orig_context; new_context->orig_work = orig_work; diff --git a/lib/tsan/rtl/tsan_malloc_mac.cc b/lib/tsan/rtl/tsan_malloc_mac.cc index 8d31ccbca..455c95df6 100644 --- a/lib/tsan/rtl/tsan_malloc_mac.cc +++ b/lib/tsan/rtl/tsan_malloc_mac.cc @@ -26,7 +26,7 @@ using namespace __tsan; #define COMMON_MALLOC_FORCE_UNLOCK() #define COMMON_MALLOC_MEMALIGN(alignment, size) \ void *p = \ - user_alloc(cur_thread(), StackTrace::GetCurrentPc(), size, alignment) + user_memalign(cur_thread(), StackTrace::GetCurrentPc(), alignment, size) #define COMMON_MALLOC_MALLOC(size) \ if (cur_thread()->in_symbolizer) return InternalAlloc(size); \ SCOPED_INTERCEPTOR_RAW(malloc, size); \ @@ -43,7 +43,7 @@ using namespace __tsan; if (cur_thread()->in_symbolizer) \ return InternalAlloc(size, nullptr, GetPageSizeCached()); \ SCOPED_INTERCEPTOR_RAW(valloc, size); \ - void *p = user_alloc(thr, pc, size, GetPageSizeCached()) + void *p = user_valloc(thr, pc, size) #define COMMON_MALLOC_FREE(ptr) \ if (cur_thread()->in_symbolizer) return InternalFree(ptr); \ SCOPED_INTERCEPTOR_RAW(free, ptr); \ diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index f79dccddb..3f7a5e76c 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -149,11 +149,12 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { OutputReport(thr, rep); } -void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { +void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align, + bool signal) { if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) return Allocator::FailureHandler::OnBadRequest(); void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); - if (p == 0) + if (UNLIKELY(p == 0)) return 0; if (ctx && ctx->initialized) OnUserAlloc(thr, pc, (uptr)p, sz, true); @@ -162,15 +163,6 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { return p; } -void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { - if (CheckForCallocOverflow(size, n)) - return Allocator::FailureHandler::OnBadRequest(); - void *p = user_alloc(thr, pc, n * size); - if (p) - internal_memset(p, 0, n * size); - return p; -} - void user_free(ThreadState *thr, uptr pc, void *p, bool signal) { ScopedGlobalProcessor sgp; if (ctx && ctx->initialized) @@ -180,6 +172,19 @@ void user_free(ThreadState *thr, uptr pc, void *p, bool signal) { SignalUnsafeCall(thr, pc); } +void *user_alloc(ThreadState *thr, uptr pc, uptr sz) { + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, kDefaultAlignment)); +} + +void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { + if (UNLIKELY(CheckForCallocOverflow(size, n))) + return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); + void *p = user_alloc_internal(thr, pc, n * size); + if (p) + internal_memset(p, 0, n * size); + return SetErrnoOnNull(p); +} + void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) { DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p); ctx->metamap.AllocBlock(thr, pc, p, sz); @@ -200,15 +205,60 @@ void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) { void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { // FIXME: Handle "shrinking" more efficiently, // it seems that some software actually does this. - void *p2 = user_alloc(thr, pc, sz); - if (p2 == 0) - return 0; - if (p) { - uptr oldsz = user_alloc_usable_size(p); - internal_memcpy(p2, p, min(oldsz, sz)); + if (!p) + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz)); + if (!sz) { user_free(thr, pc, p); + return nullptr; } - return p2; + void *new_p = user_alloc_internal(thr, pc, sz); + if (new_p) { + uptr old_sz = user_alloc_usable_size(p); + internal_memcpy(new_p, p, min(old_sz, sz)); + user_free(thr, pc, p); + } + return SetErrnoOnNull(new_p); +} + +void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { + if (UNLIKELY(!IsPowerOfTwo(align))) { + errno = errno_EINVAL; + return Allocator::FailureHandler::OnBadRequest(); + } + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); +} + +int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, + uptr sz) { + if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { + Allocator::FailureHandler::OnBadRequest(); + return errno_EINVAL; + } + void *ptr = user_alloc_internal(thr, pc, sz, align); + if (UNLIKELY(!ptr)) + return errno_ENOMEM; + CHECK(IsAligned((uptr)ptr, align)); + *memptr = ptr; + return 0; +} + +void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) { + if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) { + errno = errno_EINVAL; + return Allocator::FailureHandler::OnBadRequest(); + } + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); +} + +void *user_valloc(ThreadState *thr, uptr pc, uptr sz) { + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, GetPageSizeCached())); +} + +void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) { + uptr PageSize = GetPageSizeCached(); + // pvalloc(0) should allocate one page. + sz = sz ? RoundUpTo(sz, PageSize) : PageSize; + return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize)); } uptr user_alloc_usable_size(const void *p) { diff --git a/lib/tsan/rtl/tsan_mman.h b/lib/tsan/rtl/tsan_mman.h index 8cdeeb35a..6042c5c5d 100644 --- a/lib/tsan/rtl/tsan_mman.h +++ b/lib/tsan/rtl/tsan_mman.h @@ -27,13 +27,20 @@ void AllocatorProcFinish(Processor *proc); void AllocatorPrintStats(); // For user allocations. -void *user_alloc(ThreadState *thr, uptr pc, uptr sz, - uptr align = kDefaultAlignment, bool signal = true); -void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n); +void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, + uptr align = kDefaultAlignment, bool signal = true); // Does not accept NULL. void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true); +// Interceptor implementations. +void *user_alloc(ThreadState *thr, uptr pc, uptr sz); +void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n); void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz); -void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align); +void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz); +int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, + uptr sz); +void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz); +void *user_valloc(ThreadState *thr, uptr pc, uptr sz); +void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz); uptr user_alloc_usable_size(const void *p); // Invoking malloc/free hooks that may be installed by the user. diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc index 60dea3d43..ed08247fa 100644 --- a/lib/tsan/tests/unit/tsan_mman_test.cc +++ b/lib/tsan/tests/unit/tsan_mman_test.cc @@ -56,6 +56,7 @@ TEST(Mman, UserRealloc) { // Realloc(NULL, N) is equivalent to malloc(N), thus must return // non-NULL pointer. EXPECT_NE(p, (void*)0); + user_free(thr, pc, p); } { void *p = user_realloc(thr, pc, 0, 100); @@ -67,8 +68,9 @@ TEST(Mman, UserRealloc) { void *p = user_alloc(thr, pc, 100); EXPECT_NE(p, (void*)0); memset(p, 0xde, 100); + // Realloc(P, 0) is equivalent to free(P) and returns NULL. void *p2 = user_realloc(thr, pc, p, 0); - EXPECT_NE(p2, (void*)0); + EXPECT_EQ(p2, (void*)0); } { void *p = user_realloc(thr, pc, 0, 100); @@ -135,12 +137,28 @@ TEST(Mman, Stats) { EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes()); } +TEST(Mman, Valloc) { + ThreadState *thr = cur_thread(); + + void *p = user_valloc(thr, 0, 100); + EXPECT_NE(p, (void*)0); + user_free(thr, 0, p); + + p = user_pvalloc(thr, 0, 100); + EXPECT_NE(p, (void*)0); + user_free(thr, 0, p); + + p = user_pvalloc(thr, 0, 0); + EXPECT_NE(p, (void*)0); + EXPECT_EQ(GetPageSizeCached(), __sanitizer_get_allocated_size(p)); + user_free(thr, 0, p); +} + +#if !SANITIZER_DEBUG +// EXPECT_DEATH clones a thread with 4K stack, +// which is overflown by tsan memory accesses functions in debug mode. + TEST(Mman, CallocOverflow) { -#if SANITIZER_DEBUG - // EXPECT_DEATH clones a thread with 4K stack, - // which is overflown by tsan memory accesses functions in debug mode. - return; -#endif ThreadState *thr = cur_thread(); uptr pc = 0; size_t kArraySize = 4096; @@ -152,4 +170,57 @@ TEST(Mman, CallocOverflow) { EXPECT_EQ(0L, p); } +TEST(Mman, Memalign) { + ThreadState *thr = cur_thread(); + + void *p = user_memalign(thr, 0, 8, 100); + EXPECT_NE(p, (void*)0); + user_free(thr, 0, p); + + p = NULL; + EXPECT_DEATH(p = user_memalign(thr, 0, 7, 100), + "allocator is terminating the process instead of returning 0"); + EXPECT_EQ(0L, p); +} + +TEST(Mman, PosixMemalign) { + ThreadState *thr = cur_thread(); + + void *p = NULL; + int res = user_posix_memalign(thr, 0, &p, 8, 100); + EXPECT_NE(p, (void*)0); + EXPECT_EQ(res, 0); + user_free(thr, 0, p); + + p = NULL; + // Alignment is not a power of two, although is a multiple of sizeof(void*). + EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 3 * sizeof(p), 100), + "allocator is terminating the process instead of returning 0"); + EXPECT_EQ(0L, p); + // Alignment is not a multiple of sizeof(void*), although is a power of 2. + EXPECT_DEATH(res = user_posix_memalign(thr, 0, &p, 2, 100), + "allocator is terminating the process instead of returning 0"); + EXPECT_EQ(0L, p); +} + +TEST(Mman, AlignedAlloc) { + ThreadState *thr = cur_thread(); + + void *p = user_aligned_alloc(thr, 0, 8, 64); + EXPECT_NE(p, (void*)0); + user_free(thr, 0, p); + + p = NULL; + // Alignement is not a power of 2. + EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 7, 100), + "allocator is terminating the process instead of returning 0"); + EXPECT_EQ(0L, p); + // Size is not a multiple of alignment. + EXPECT_DEATH(p = user_aligned_alloc(thr, 0, 8, 100), + "allocator is terminating the process instead of returning 0"); + EXPECT_EQ(0L, p); +} + +#endif + } // namespace __tsan diff --git a/test/tsan/allocator_returns_null.cc b/test/tsan/allocator_returns_null.cc index 852dda035..5e2e2e9a5 100644 --- a/test/tsan/allocator_returns_null.cc +++ b/test/tsan/allocator_returns_null.cc @@ -37,9 +37,10 @@ // RUN: | FileCheck %s --check-prefix=CHECK-nnNULL #include -#include +#include #include #include +#include #include #include @@ -51,6 +52,7 @@ int main(int argc, char **argv) { const char *action = argv[1]; fprintf(stderr, "%s:\n", action); + // The limit enforced in tsan_mman.cc, user_alloc_internal function. static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1; void *x = 0; @@ -78,10 +80,13 @@ int main(int argc, char **argv) { assert(0); } + fprintf(stderr, "errno: %d\n", errno); + // The NULL pointer is printed differently on different systems, while (long)0 // is always the same. fprintf(stderr, "x: %lx\n", (long)x); free(x); + return x != 0; } @@ -101,14 +106,19 @@ int main(int argc, char **argv) { // CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process // CHECK-mNULL: malloc: +// CHECK-mNULL: errno: 12 // CHECK-mNULL: x: 0 // CHECK-cNULL: calloc: +// CHECK-cNULL: errno: 12 // CHECK-cNULL: x: 0 // CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: errno: 12 // CHECK-coNULL: x: 0 // CHECK-rNULL: realloc: +// CHECK-rNULL: errno: 12 // CHECK-rNULL: x: 0 // CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: errno: 12 // CHECK-mrNULL: x: 0 // CHECK-nnNULL: new-nothrow: // CHECK-nnNULL: x: 0 -- cgit v1.2.1 From 3fba40218b918a973d76d4281d87d0dae75c40a9 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 24 Jul 2017 21:51:12 +0000 Subject: Add .pyc files to .gitignore to compiler-rt During testing .pyc temporary files appear, which may be annoying. Did not change SVN ignore, as it was heavily out of sync with GIT one. Differential Revision: D35815 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308931 91177308-0d34-0410-b5e6-96231b3b80d8 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2a7bdd6a8..f7d4697eb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ darwin_fat clang_darwin multi_arch *.sw? +*.pyc -- cgit v1.2.1 From 26aeaee1b40622ec7250f857078aebc765a39269 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 25 Jul 2017 15:27:32 +0000 Subject: Add address ranges for individual macho sections on darwin Summary: This is a re-upload of the reverted commit r308644. It has changed quite a bit to reflect post-commit comments by kcc, so I'm re-uploading as a new review. Reviewers: kubamracek, alekseyshl, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35799 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308977 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 15 ++++- lib/sanitizer_common/sanitizer_procmaps_common.cc | 7 ++- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 72 ++++++++++++++++++++--- 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 539a53bc3..20b93c1d2 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,9 +37,12 @@ static const uptr kProtectionWrite = 2; static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -struct MemoryMappedSegment { +struct MemoryMappedSegmentData; + +class MemoryMappedSegment { + public: MemoryMappedSegment(char *buff = nullptr, uptr size = 0) - : filename(buff), filename_size(size) {} + : filename(buff), filename_size(size), data_(nullptr) {} ~MemoryMappedSegment() {} bool IsReadable() const { return protection & kProtectionRead; } @@ -47,6 +50,8 @@ struct MemoryMappedSegment { bool IsExecutable() const { return protection & kProtectionExecute; } bool IsShared() const { return protection & kProtectionShared; } + void AddAddressRanges(LoadedModule *module); + uptr start; uptr end; uptr offset; @@ -55,6 +60,12 @@ struct MemoryMappedSegment { uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; + + private: + friend class MemoryMappingLayout; + + // This field is assigned and owned by MemoryMappingLayout if needed + MemoryMappedSegmentData *data_; }; class MemoryMappingLayout { diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index dac68ffe8..369b3ee1b 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -64,6 +64,10 @@ uptr ParseHex(const char **p) { return ParseNumber(p, 16); } +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); +} + MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { ReadProcMaps(&proc_self_maps_); if (cache_enabled) { @@ -139,8 +143,7 @@ void MemoryMappingLayout::DumpListOfModules( uptr base_address = (i ? segment.start : 0) - segment.offset; LoadedModule cur_module; cur_module.set(cur_name, base_address); - cur_module.addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(&cur_module); modules->push_back(cur_module); } } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 560451a16..4b26a1f2c 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -36,6 +36,48 @@ namespace __sanitizer { +// Contains information used to iterate through sections. +struct MemoryMappedSegmentData { + uptr nsects; + char *current_load_cmd_addr; + u32 lc_type; + uptr base_virt_addr; + uptr addr_mask; +}; + +template +static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, + bool isWritable) { + const Section *sc = (const Section *)data->current_load_cmd_addr; + data->current_load_cmd_addr += sizeof(Section); + + uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // Don't iterate over sections when the caller hasn't set up the + // data pointer, when there are no sections, or when the segment + // is executable. Avoid iterating over executable sections because + // it will confuse libignore, and because the extra granularity + // of information is not needed by any sanitizers. + if (!data_ || !data_->nsects || IsExecutable()) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); + return; + } + + do { + if (data_->lc_type == LC_SEGMENT) { + NextSectionLoad(module, data_, IsWritable()); +#ifdef MH_MAGIC_64 + } else if (data_->lc_type == LC_SEGMENT_64) { + NextSectionLoad(module, data_, IsWritable()); +#endif + } + } while (--data_->nsects); +} + MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); } @@ -144,19 +186,32 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; + uptr base_virt_addr, addr_mask; if (current_image_ == kDyldImageIdx) { + base_virt_addr = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); + addr_mask = 0xfffff; } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - segment->start = sc->vmaddr + dlloff; - segment->end = sc->vmaddr + sc->vmsize + dlloff; + base_virt_addr = (uptr)_dyld_get_image_vmaddr_slide(current_image_); + addr_mask = ~0; + } + segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; + segment->end = segment->start + sc->vmsize; + + // Most callers don't need section information, so only fill this struct + // when required. + if (segment->data_) { + segment->data_->nsects = sc->nsects; + segment->data_->current_load_cmd_addr = + (char *)lc + sizeof(SegmentCommand); + segment->data_->lc_type = kLCSegment; + segment->data_->base_virt_addr = base_virt_addr; + segment->data_->addr_mask = addr_mask; } // Return the initial protection. @@ -292,7 +347,9 @@ void MemoryMappingLayout::DumpListOfModules( Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - for (uptr i = 0; Next(&segment); i++) { + MemoryMappedSegmentData data; + segment.data_ = &data; + while (Next(&segment)) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -304,8 +361,7 @@ void MemoryMappingLayout::DumpListOfModules( cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - cur_module->addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(cur_module); } } -- cgit v1.2.1 From ad87a2bf27320d4026890d9ae58dc6a453928d44 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 25 Jul 2017 16:56:22 +0000 Subject: Revert "[compiler-rt] Include thread ID into sanitizers logs" This improvement introduce additional dependencies on sandboxed environments. This reverts commit r308637. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308984 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_printf.cc | 8 ++++---- test/sanitizer_common/TestCases/Linux/vreport.cc | 23 ----------------------- 2 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 test/sanitizer_common/TestCases/Linux/vreport.cc diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index f81e15357..520206441 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -257,15 +257,15 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, "Buffer in Report is too short!\n"); \ } if (append_pid) { + int pid = internal_getpid(); const char *exe_name = GetProcessName(); if (common_flags()->log_exe_name && exe_name) { needed_length += internal_snprintf(buffer, buffer_size, "==%s", exe_name); CHECK_NEEDED_LENGTH } - needed_length += - internal_snprintf(buffer + needed_length, buffer_size - needed_length, - "==%d:%d==", internal_getpid(), GetTid()); + needed_length += internal_snprintf( + buffer + needed_length, buffer_size - needed_length, "==%d==", pid); CHECK_NEEDED_LENGTH } needed_length += VSNPrintf(buffer + needed_length, @@ -307,7 +307,7 @@ void Printf(const char *format, ...) { va_end(args); } -// Like Printf, but prints the current PID:TID before the output string. +// Like Printf, but prints the current PID before the output string. FORMAT(1, 2) void Report(const char *format, ...) { va_list args; diff --git a/test/sanitizer_common/TestCases/Linux/vreport.cc b/test/sanitizer_common/TestCases/Linux/vreport.cc deleted file mode 100644 index 2357932ff..000000000 --- a/test/sanitizer_common/TestCases/Linux/vreport.cc +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clangxx -O0 %s -o %t && %env_tool_opts=verbosity=10 %run %t 2>&1 | FileCheck %s - -#include -#include -#include -#include - -void *thread(void *unused) { - printf("PID: %d\n", getpid()); - printf("TID: %ld\n", syscall(SYS_gettid)); - fflush(stdout); - return 0; -} - -int main() { - pthread_t t; - pthread_create(&t, 0, thread, 0); - pthread_join(t, 0); - return 0; -} -// CHECK: PID: [[PID:[0-9]+]] -// CHECK: TID: [[TID:[0-9]+]] -// CHECK: ==[[PID]]:[[TID]]== -- cgit v1.2.1 From 416f1839fc4ccdc0fcdeb5a5b3da1f9b421ecb41 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 25 Jul 2017 17:28:41 +0000 Subject: Fix unused variable warning with MemoryMappedSegment private data git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308992 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 369b3ee1b..c4daf0497 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -65,6 +65,8 @@ uptr ParseHex(const char **p) { } void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // data_ should be unused on this platform + CHECK(!data_); module->addAddressRange(start, end, IsExecutable(), IsWritable()); } -- cgit v1.2.1 From 5764cd92b929fefc1fef703c32e59516a0468d0b Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 25 Jul 2017 18:16:58 +0000 Subject: Only scan global sections containing data in LSan on darwin Summary: __DATA segments on Darwin contain a large number of separate sections, many of which cannot actually contain pointers, and contain const values or objc metadata. Not scanning sections which cannot contain pointers significantly improves performance. On a medium-sized (~4000 files) internal project, I saw a speedup of about 30% in standalone LSan's execution time (30% improvement in the time spent running LSan, not the total program time). Reviewers: kcc, kubamracek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35432 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308999 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common_mac.cc | 21 +++++++++++++++++++++ lib/sanitizer_common/sanitizer_common.cc | 5 +++-- lib/sanitizer_common/sanitizer_common.h | 12 +++++++++--- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 9 +++++++-- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index ade94340a..ac27c7af6 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -92,8 +92,25 @@ LoadedModule *GetLinker() { return nullptr; } // required on Darwin. void InitializePlatformSpecificModules() {} +// Sections which can't contain contain global pointers. This list errs on the +// side of caution to avoid false positives, at the expense of performance. +// +// Other potentially safe sections include: +// __all_image_info, __crash_info, __const, __got, __interpose, __objc_msg_break +// +// Sections which definitely cannot be included here are: +// __objc_data, __objc_const, __data, __bss, __common, __thread_data, +// __thread_bss, __thread_vars, __objc_opt_rw, __objc_opt_ptrs +static const char *kSkippedSecNames[] = { + "__cfstring", "__la_symbol_ptr", "__mod_init_func", + "__mod_term_func", "__nl_symbol_ptr", "__objc_classlist", + "__objc_classrefs", "__objc_imageinfo", "__objc_nlclslist", + "__objc_protolist", "__objc_selrefs", "__objc_superrefs"}; + // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { + for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName); + MemoryMappingLayout memory_mapping(false); InternalMmapVector modules(/*initial_capacity*/ 128); memory_mapping.DumpListOfModules(&modules); @@ -107,6 +124,10 @@ void ProcessGlobalRegions(Frontier *frontier) { // Sections storing global variables are writable and non-executable if (range.executable || !range.writable) continue; + for (auto name : kSkippedSecNames) { + if (!internal_strcmp(range.name, name)) continue; + } + ScanGlobalRange(range.beg, range.end, frontier); } } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 8d51e1ed1..87e04240a 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -183,9 +183,10 @@ void LoadedModule::clear() { } void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, - bool writable) { + bool writable, const char *name) { void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = new(mem) AddressRange(beg, end, executable, writable); + AddressRange *r = + new(mem) AddressRange(beg, end, executable, writable, name); ranges_.push_back(r); if (executable && end > max_executable_address_) max_executable_address_ = end; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9c801f151..9e65639b9 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -624,6 +624,7 @@ inline const char *ModuleArchToString(ModuleArch arch) { } const uptr kModuleUUIDSize = 16; +const uptr kMaxSegName = 16; // Represents a binary loaded into virtual memory (e.g. this can be an // executable or a shared object). @@ -642,7 +643,8 @@ class LoadedModule { void set(const char *module_name, uptr base_address, ModuleArch arch, u8 uuid[kModuleUUIDSize], bool instrumented); void clear(); - void addAddressRange(uptr beg, uptr end, bool executable, bool writable); + void addAddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name = nullptr); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } @@ -658,13 +660,17 @@ class LoadedModule { uptr end; bool executable; bool writable; + char name[kMaxSegName]; - AddressRange(uptr beg, uptr end, bool executable, bool writable) + AddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name) : next(nullptr), beg(beg), end(end), executable(executable), - writable(writable) {} + writable(writable) { + internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name)); + } }; const IntrusiveList &ranges() const { return ranges_; } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 4b26a1f2c..106294cac 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -38,6 +38,7 @@ namespace __sanitizer { // Contains information used to iterate through sections. struct MemoryMappedSegmentData { + char name[kMaxSegName]; uptr nsects; char *current_load_cmd_addr; u32 lc_type; @@ -53,7 +54,8 @@ static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable); + module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, + sc->sectname); } void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { @@ -63,7 +65,8 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { // it will confuse libignore, and because the extra granularity // of information is not needed by any sanitizers. if (!data_ || !data_->nsects || IsExecutable()) { - module->addAddressRange(start, end, IsExecutable(), IsWritable()); + module->addAddressRange(start, end, IsExecutable(), IsWritable(), + data_ ? data_->name : nullptr); return; } @@ -212,6 +215,8 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { segment->data_->lc_type = kLCSegment; segment->data_->base_virt_addr = base_virt_addr; segment->data_->addr_mask = addr_mask; + internal_strncpy(segment->data_->name, sc->segname, + ARRAY_SIZE(segment->data_->name)); } // Return the initial protection. -- cgit v1.2.1 From 2295a0eb5848c8fbdef829a1fb3fd4895aa5010f Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 25 Jul 2017 19:34:27 +0000 Subject: [ubsan] -fsanitize=vptr now requires -fsanitize=null, update tests See: https://bugs.llvm.org/show_bug.cgi?id=33881 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309008 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/PR33221.cpp | 2 +- .../TypeCheck/vptr-corrupted-vtable-itanium.cpp | 2 +- .../TestCases/TypeCheck/vptr-virtual-base.cpp | 2 +- test/ubsan/TestCases/TypeCheck/vptr.cpp | 23 +++++++++++++++------- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/test/ubsan/TestCases/TypeCheck/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/PR33221.cpp index c691e5fb2..71da06c09 100644 --- a/test/ubsan/TestCases/TypeCheck/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/PR33221.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=null,vptr -g %s -O3 -o %t // RUN: %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi diff --git a/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp index 37ffe5b70..898577d8e 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=vptr,null -fno-sanitize-recover=vptr,null -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-CORRUPTED-VTABLE --strict-whitespace // UNSUPPORTED: win32 diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp index 09deac143..f1fb11131 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=null,vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index 53a79c9fc..183c7b743 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false +// RUN: %clangxx -frtti -fsanitize=null,vptr -fno-sanitize-recover=null,vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false // RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT // RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU // RUN: %run %t rS && %run %t rV && %run %t oV @@ -9,7 +9,9 @@ // RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace // RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace // RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --check-prefix=CHECK-%os-OFFSET --strict-whitespace -// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace +// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace +// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace +// RUN: not %run %t nN 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMFUN --strict-whitespace // RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp // RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mS @@ -99,6 +101,9 @@ int main(int argc, char **argv) { case 'V': p = reinterpret_cast(new U); break; + case 'N': + p = 0; + break; } access_p(p, argv[1][0]); @@ -134,11 +139,11 @@ int access_p(T *p, char type) { // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]] return p->b; - // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' - // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr - // CHECK-NULL-MEMBER-NEXT: {{^ ?.. .. .. .. ?00 00 00 00 ?00 00 00 00 ?}} - // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} - // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}} + // CHECK-INVALID-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T' + // CHECK-INVALID-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr + // CHECK-INVALID-MEMBER-NEXT: {{^ ?.. .. .. .. ?00 00 00 00 ?00 00 00 00 ?}} + // CHECK-INVALID-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}} + // CHECK-INVALID-MEMBER-NEXT: {{^ invalid vptr}} // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]] case 'f': @@ -168,6 +173,10 @@ int access_p(T *p, char type) { // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]] (void)static_cast(reinterpret_cast(p)); return 0; + + case 'n': + // CHECK-NULL-MEMFUN: vptr.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T' + return p->g(); } return 0; } -- cgit v1.2.1 From 77afdbc0a07be926ec41110be6937aba4019165d Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 25 Jul 2017 21:18:02 +0000 Subject: [scudo] Check for pvalloc overflow Summary: Previously we were rounding up the size passed to `pvalloc` to the next multiple of page size no matter what. There is an overflow possibility that wasn't accounted for. So now, return null in the event of an overflow. The man page doesn't seem to indicate the errno to set in this particular situation, but the glibc unit tests go for ENOMEM (https://code.woboq.org/userspace/glibc/malloc/tst-pvalloc.c.html#54) so we'll do the same. Update the aligned allocation funtions tests to check for properly aligned returned pointers, and the `pvalloc` corner cases. @alekseyshl: do you want me to do the same in the other Sanitizers? Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: kubamracek, alekseyshl, llvm-commits Differential Revision: https://reviews.llvm.org/D35818 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309033 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_checks.h | 6 +++ lib/scudo/scudo_allocator.cpp | 4 ++ test/scudo/memalign.cpp | 14 ++--- test/scudo/valloc.cpp | 63 +++++++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 test/scudo/valloc.cpp diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index 202916eae..b72f541a4 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -59,6 +59,12 @@ INLINE bool CheckForCallocOverflow(uptr size, uptr n) { return (max / size) < n; } +// Returns true if the size passed to pvalloc overflows when rounded to the next +// multiple of page_size. +INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) { + return RoundUpTo(size, page_size) < size; +} + } // namespace __sanitizer #endif // SANITIZER_ALLOCATOR_CHECKS_H diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 38522de4d..e1758568b 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -665,6 +665,10 @@ void *scudoValloc(uptr Size) { void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) { + errno = errno_ENOMEM; + return ScudoAllocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. Size = Size ? RoundUpTo(Size, PageSize) : PageSize; return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign)); diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 82c54af8b..72aacffd2 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -8,17 +8,13 @@ #include #include #include +#include #include #include - -// Reduce the size of the quarantine, or the test can run out of aligned memory -// on 32-bit for the larger alignments. -extern "C" const char *__scudo_default_options() { - return "QuarantineSizeMb=1"; -} +#include // Sometimes the headers may not have this... -extern "C" void *aligned_alloc (size_t alignment, size_t size); +extern "C" void *aligned_alloc(size_t alignment, size_t size); int main(int argc, char **argv) { @@ -32,9 +28,11 @@ int main(int argc, char **argv) if (!strcmp(argv[1], "valid")) { posix_memalign(&p, alignment, size); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); p = aligned_alloc(alignment, size); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); // Tests various combinations of alignment and sizes for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { @@ -44,6 +42,7 @@ int main(int argc, char **argv) for (int k = 0; k < 3; k++) { p = memalign(alignment, size - (2 * sizeof(void *) * k)); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); } } @@ -54,6 +53,7 @@ int main(int argc, char **argv) for (int k = 0; k < 3; k++) { p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); free(p); } } diff --git a/test/scudo/valloc.cpp b/test/scudo/valloc.cpp new file mode 100644 index 000000000..010dac2a5 --- /dev/null +++ b/test/scudo/valloc.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t valid 2>&1 +// RUN: %run %t invalid 2>&1 + +// Tests that valloc and pvalloc work as intended. + +#include +#include +#include +#include +#include +#include + +size_t round_up_to(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +int main(int argc, char **argv) +{ + void *p = nullptr; + size_t size, page_size; + + assert(argc == 2); + + page_size = sysconf(_SC_PAGESIZE); + // Check that the page size is a power of two. + assert((page_size & (page_size - 1)) == 0); + + if (!strcmp(argv[1], "valid")) { + for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 21; i++) { + size = 1U << i; + p = valloc(size - (2 * sizeof(void *))); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + free(p); + p = pvalloc(size - (2 * sizeof(void *))); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + assert(malloc_usable_size(p) >= round_up_to(size, page_size)); + free(p); + p = valloc(size); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + free(p); + p = pvalloc(size); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + assert(malloc_usable_size(p) >= round_up_to(size, page_size)); + free(p); + } + } + if (!strcmp(argv[1], "invalid")) { + // Size passed to pvalloc overflows when rounded up. + p = pvalloc((size_t)-1); + assert(!p); + assert(errno == ENOMEM); + errno = 0; + p = pvalloc((size_t)-page_size); + assert(!p); + assert(errno == ENOMEM); + } + return 0; +} -- cgit v1.2.1 From 5d89c4be98863f7456a8c2c1936d768cc55f5c66 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 25 Jul 2017 22:33:28 +0000 Subject: [ubsan] Update a test missed in r309008, NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309042 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp index e026e8d05..b20ac73aa 100644 --- a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr -g %s -O3 -o %t +// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr,null -g %s -O3 -o %t // RUN: %run %t &> %t.log // RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0 -- cgit v1.2.1 From fd63314d6770e0da62572a3fea2c41c4cc0fc58a Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Tue, 25 Jul 2017 23:38:25 +0000 Subject: [sanitizer] Support compiler-rt builtins This change adds support for compiler-rt builtins as an alternative compiler runtime to libgcc. Differential Revision: https://reviews.llvm.org/D35165 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309060 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 16 ++++++++++++++++ cmake/Modules/HandleCompilerRT.cmake | 21 +++++++++++++++++++++ cmake/config-ix.cmake | 22 +++++++++++++++++++++- lib/asan/CMakeLists.txt | 5 +++-- lib/lsan/CMakeLists.txt | 5 ++++- lib/stats/CMakeLists.txt | 5 ++++- lib/tsan/CMakeLists.txt | 5 ++++- lib/tsan/dd/CMakeLists.txt | 5 ++++- lib/ubsan/CMakeLists.txt | 5 +++++ 9 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 cmake/Modules/HandleCompilerRT.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f997c5341..d2d829ae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ option(COMPILER_RT_EXTERNALIZE_DEBUGINFO # COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in. pythonize_bool(COMPILER_RT_DEBUG) +include(HandleCompilerRT) include(config-ix) if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") @@ -93,6 +94,8 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) +option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) + #================================ # Setup Compiler Flags #================================ @@ -228,6 +231,19 @@ append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS) +# Set common link flags. +append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS) + +if (SANITIZER_USE_COMPILER_RT) + list(APPEND SANITIZER_COMMON_LINK_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) + list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY}) +else() + append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS) +endif() + +append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) + # Warnings to turn off for all libraries, not just sanitizers. append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS) diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 000000000..cff5031ec --- /dev/null +++ b/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,21 @@ +function(find_compiler_rt_library name dest) + set(dest "" PARENT_SCOPE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${SANITIZER_COMMON_CFLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) + list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") + endif() + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") + message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}") + set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt ${name} library") + endif() +endfunction() diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index c329c6a97..64c1347c6 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -1,4 +1,5 @@ include(CMakePushCheckState) +include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) include(CheckLibraryExists) include(CheckSymbolExists) @@ -11,6 +12,26 @@ function(check_linker_flag flag out_var) cmake_pop_check_state() endfunction() +check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) +if (NOT SANITIZER_USE_COMPILER_RT) + check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB) +endif() + +check_c_compiler_flag(-nodefaultlibs COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) +if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + if (COMPILER_RT_HAS_LIBC) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (SANITIZER_USE_COMPILER_RT) + list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}") + elseif (COMPILER_RT_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () +endif () + # CodeGen options. check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG) @@ -73,7 +94,6 @@ check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG) check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL) # Libraries. -check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL) check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT) check_library_exists(m pow "" COMPILER_RT_HAS_LIBM) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 47afa79bd..f033010db 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -40,7 +40,7 @@ set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(OFF ASAN_CFLAGS) -set(ASAN_DYNAMIC_LINK_FLAGS) +set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) if(ANDROID) # On Android, -z global does not do what it is documented to do. @@ -65,7 +65,8 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS) -append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS) +set(ASAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index bd3a96f32..60da3e186 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -29,6 +29,8 @@ add_compiler_rt_object_libraries(RTLSanCommon if(COMPILER_RT_HAS_LSAN) add_compiler_rt_component(lsan) if(APPLE) + set(LSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -42,7 +44,8 @@ if(COMPILER_RT_HAS_LSAN) RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${LSAN_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${LSAN_LINK_LIBS} PARENT_TARGET lsan) else() foreach(arch ${LSAN_SUPPORTED_ARCH}) diff --git a/lib/stats/CMakeLists.txt b/lib/stats/CMakeLists.txt index 2b3d6474b..6be36a7cb 100644 --- a/lib/stats/CMakeLists.txt +++ b/lib/stats/CMakeLists.txt @@ -6,6 +6,8 @@ set_target_properties(stats PROPERTIES FOLDER "Compiler-RT Misc") if(APPLE) set(STATS_LIB_FLAVOR SHARED) + set(STATS_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -23,7 +25,8 @@ add_compiler_rt_runtime(clang_rt.stats OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${SANITIZER_COMMON_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${STATS_LINK_LIBS} PARENT_TARGET stats) add_compiler_rt_runtime(clang_rt.stats_client diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 193158c54..5e3bb102b 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -109,6 +109,8 @@ if(APPLE) set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES LANGUAGE C) endif() + set(TSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -122,7 +124,8 @@ if(APPLE) RTSanitizerCommonLibc RTUbsan CFLAGS ${TSAN_RTL_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${TSAN_LINK_LIBS} PARENT_TARGET tsan) add_compiler_rt_object_libraries(RTTsan_dynamic OS ${TSAN_SUPPORTED_OS} diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index bcff35f20..bd9515567 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -10,10 +10,12 @@ set(DD_SOURCES dd_interceptors.cc ) -set(DD_LINKLIBS) +set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. @@ -40,6 +42,7 @@ if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID) $ $ $ + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${DD_LINKLIBS} PARENT_TARGET dd) endif() diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 457a6b475..ab0e78073 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -34,9 +34,12 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) +set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) add_compiler_rt_component(ubsan) @@ -155,6 +158,7 @@ else() RTSanitizerCommonLibc RTUbsan CFLAGS ${UBSAN_CFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) @@ -166,6 +170,7 @@ else() RTUbsan RTUbsan_cxx CFLAGS ${UBSAN_CXXFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) -- cgit v1.2.1 From d1997bff31cf6b484eb59c2ee1fc3155442e338c Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 26 Jul 2017 01:43:02 +0000 Subject: [sanitizer] Support libc++abi in addition to libstdc++ This change adds sanitizer support for LLVM's libunwind and libc++abi as an alternative to libstdc++. This allows using the in tree version of libunwind and libc++abi which is useful when building a toolchain for different target. Differential Revision: https://reviews.llvm.org/D34501 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309074 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 34 ++++++++++++++++++++++++++++++++++ lib/asan/CMakeLists.txt | 3 ++- lib/tsan/dd/CMakeLists.txt | 3 ++- lib/ubsan/CMakeLists.txt | 3 ++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2d829ae0..0b4817457 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,40 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) +set(SANITIZER_CXX_ABI "default" CACHE STRING + "Specify C++ ABI library to use.") +set(CXXABIS none default libcxxabi libstdc++) +set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS}) + +if (SANITIZER_CXX_ABI STREQUAL "default") + if (HAVE_LIBCXXABI AND COMPILER_RT_DEFAULT_TARGET_ONLY) + set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") + set(SANITIZER_CXX_ABI_INTREE 1) + elseif (APPLE) + set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") + set(SANITIZER_CXX_ABI_SYSTEM 1) + else() + set(SANITIZER_CXX_ABI_LIBNAME "libstdc++") + endif() +elseif() + set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}") +endif() + +if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") + if (SANITIZER_CXX_ABI_INTREE) + if (TARGET unwind_shared OR HAVE_LIBUNWIND) + list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared) + endif() + if (TARGET cxxabi_shared OR HAVE_LIBCXXABI) + list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared) + endif() + else() + list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") + endif() +elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") + append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) +endif() + option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) #================================ diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index f033010db..6cb994aac 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -71,9 +71,10 @@ append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS) +list(APPEND ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) + # Compile ASan sources into an object library. add_compiler_rt_object_libraries(RTAsan_dynamic diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index bd9515567..4c9508183 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -15,7 +15,8 @@ set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) + +list(APPEND DD_LINKLIBS ${SANITIZER_CXX_ABI_LIBRARY}) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index ab0e78073..780072e2d 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -39,7 +39,8 @@ set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) + +list(APPEND UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) add_compiler_rt_component(ubsan) -- cgit v1.2.1 From 8e31fff29bcbd5148e222e11130671bfe46de849 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 26 Jul 2017 06:46:10 +0000 Subject: Revert "[sanitizer] Support libc++abi in addition to libstdc++" This reverts commit d1997bff31cf6b484eb59c2ee1fc3155442e338c. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309082 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 34 ---------------------------------- lib/asan/CMakeLists.txt | 3 +-- lib/tsan/dd/CMakeLists.txt | 3 +-- lib/ubsan/CMakeLists.txt | 3 +-- 4 files changed, 3 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b4817457..d2d829ae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,40 +94,6 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) -set(SANITIZER_CXX_ABI "default" CACHE STRING - "Specify C++ ABI library to use.") -set(CXXABIS none default libcxxabi libstdc++) -set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS}) - -if (SANITIZER_CXX_ABI STREQUAL "default") - if (HAVE_LIBCXXABI AND COMPILER_RT_DEFAULT_TARGET_ONLY) - set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") - set(SANITIZER_CXX_ABI_INTREE 1) - elseif (APPLE) - set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") - set(SANITIZER_CXX_ABI_SYSTEM 1) - else() - set(SANITIZER_CXX_ABI_LIBNAME "libstdc++") - endif() -elseif() - set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}") -endif() - -if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") - if (SANITIZER_CXX_ABI_INTREE) - if (TARGET unwind_shared OR HAVE_LIBUNWIND) - list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared) - endif() - if (TARGET cxxabi_shared OR HAVE_LIBCXXABI) - list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared) - endif() - else() - list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") - endif() -elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") - append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) -endif() - option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) #================================ diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 6cb994aac..f033010db 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -71,10 +71,9 @@ append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS) -list(APPEND ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) - # Compile ASan sources into an object library. add_compiler_rt_object_libraries(RTAsan_dynamic diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index 4c9508183..bd9515567 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -15,8 +15,7 @@ set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) - -list(APPEND DD_LINKLIBS ${SANITIZER_CXX_ABI_LIBRARY}) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 780072e2d..ab0e78073 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -39,8 +39,7 @@ set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) - -list(APPEND UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) add_compiler_rt_component(ubsan) -- cgit v1.2.1 From 99ae2fab3b53a1f0c17e17b2b045b488b52ae08a Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 26 Jul 2017 06:46:11 +0000 Subject: Revert "[sanitizer] Support compiler-rt builtins" This reverts commit fd63314d6770e0da62572a3fea2c41c4cc0fc58a. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309083 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 16 ---------------- cmake/Modules/HandleCompilerRT.cmake | 21 --------------------- cmake/config-ix.cmake | 22 +--------------------- lib/asan/CMakeLists.txt | 5 ++--- lib/lsan/CMakeLists.txt | 5 +---- lib/stats/CMakeLists.txt | 5 +---- lib/tsan/CMakeLists.txt | 5 +---- lib/tsan/dd/CMakeLists.txt | 5 +---- lib/ubsan/CMakeLists.txt | 5 ----- 9 files changed, 7 insertions(+), 82 deletions(-) delete mode 100644 cmake/Modules/HandleCompilerRT.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d2d829ae0..f997c5341 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,6 @@ option(COMPILER_RT_EXTERNALIZE_DEBUGINFO # COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in. pythonize_bool(COMPILER_RT_DEBUG) -include(HandleCompilerRT) include(config-ix) if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") @@ -94,8 +93,6 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) -option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) - #================================ # Setup Compiler Flags #================================ @@ -231,19 +228,6 @@ append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS) -# Set common link flags. -append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS) - -if (SANITIZER_USE_COMPILER_RT) - list(APPEND SANITIZER_COMMON_LINK_FLAGS -rtlib=compiler-rt) - find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) - list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY}) -else() - append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS) -endif() - -append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) - # Warnings to turn off for all libraries, not just sanitizers. append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS) diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake deleted file mode 100644 index cff5031ec..000000000 --- a/cmake/Modules/HandleCompilerRT.cmake +++ /dev/null @@ -1,21 +0,0 @@ -function(find_compiler_rt_library name dest) - set(dest "" PARENT_SCOPE) - set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${SANITIZER_COMMON_CFLAGS} - "--rtlib=compiler-rt" "--print-libgcc-file-name") - if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) - list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") - endif() - execute_process( - COMMAND ${CLANG_COMMAND} - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LIBRARY_FILE - ) - string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) - string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") - if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") - message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}") - set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) - else() - message(STATUS "Failed to find compiler-rt ${name} library") - endif() -endfunction() diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 64c1347c6..c329c6a97 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -1,5 +1,4 @@ include(CMakePushCheckState) -include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) include(CheckLibraryExists) include(CheckSymbolExists) @@ -12,26 +11,6 @@ function(check_linker_flag flag out_var) cmake_pop_check_state() endfunction() -check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) -if (NOT SANITIZER_USE_COMPILER_RT) - check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB) -endif() - -check_c_compiler_flag(-nodefaultlibs COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) -if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") - if (COMPILER_RT_HAS_LIBC) - list(APPEND CMAKE_REQUIRED_LIBRARIES c) - endif () - if (SANITIZER_USE_COMPILER_RT) - list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) - find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) - list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}") - elseif (COMPILER_RT_HAS_GCC_S_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) - endif () -endif () - # CodeGen options. check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG) @@ -94,6 +73,7 @@ check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG) check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL) # Libraries. +check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL) check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT) check_library_exists(m pow "" COMPILER_RT_HAS_LIBM) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index f033010db..47afa79bd 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -40,7 +40,7 @@ set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(OFF ASAN_CFLAGS) -set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) +set(ASAN_DYNAMIC_LINK_FLAGS) if(ANDROID) # On Android, -z global does not do what it is documented to do. @@ -65,8 +65,7 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS) -set(ASAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) - +append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index 60da3e186..bd3a96f32 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -29,8 +29,6 @@ add_compiler_rt_object_libraries(RTLSanCommon if(COMPILER_RT_HAS_LSAN) add_compiler_rt_component(lsan) if(APPLE) - set(LSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) - add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -44,8 +42,7 @@ if(COMPILER_RT_HAS_LSAN) RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${LSAN_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} - LINK_LIBS ${LSAN_LINK_LIBS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} PARENT_TARGET lsan) else() foreach(arch ${LSAN_SUPPORTED_ARCH}) diff --git a/lib/stats/CMakeLists.txt b/lib/stats/CMakeLists.txt index 6be36a7cb..2b3d6474b 100644 --- a/lib/stats/CMakeLists.txt +++ b/lib/stats/CMakeLists.txt @@ -6,8 +6,6 @@ set_target_properties(stats PROPERTIES FOLDER "Compiler-RT Misc") if(APPLE) set(STATS_LIB_FLAVOR SHARED) - set(STATS_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) - add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -25,8 +23,7 @@ add_compiler_rt_runtime(clang_rt.stats OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${SANITIZER_COMMON_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} - LINK_LIBS ${STATS_LINK_LIBS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} PARENT_TARGET stats) add_compiler_rt_runtime(clang_rt.stats_client diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 5e3bb102b..193158c54 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -109,8 +109,6 @@ if(APPLE) set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES LANGUAGE C) endif() - set(TSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) - add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -124,8 +122,7 @@ if(APPLE) RTSanitizerCommonLibc RTUbsan CFLAGS ${TSAN_RTL_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} - LINK_LIBS ${TSAN_LINK_LIBS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} PARENT_TARGET tsan) add_compiler_rt_object_libraries(RTTsan_dynamic OS ${TSAN_SUPPORTED_OS} diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index bd9515567..bcff35f20 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -10,12 +10,10 @@ set(DD_SOURCES dd_interceptors.cc ) -set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) - +set(DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. @@ -42,7 +40,6 @@ if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID) $ $ $ - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${DD_LINKLIBS} PARENT_TARGET dd) endif() diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index ab0e78073..457a6b475 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -34,12 +34,9 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) -set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) - append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) add_compiler_rt_component(ubsan) @@ -158,7 +155,6 @@ else() RTSanitizerCommonLibc RTUbsan CFLAGS ${UBSAN_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) @@ -170,7 +166,6 @@ else() RTUbsan RTUbsan_cxx CFLAGS ${UBSAN_CXXFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) -- cgit v1.2.1 From 01ebee35b138b3c3d1e850ac44d5aef681f3f57e Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 26 Jul 2017 20:40:25 +0000 Subject: [sanitizer-coverage] remove stale code git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309173 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_interface_internal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h index b28d8f08e..9c1f1ad33 100644 --- a/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/lib/sanitizer_common/sanitizer_interface_internal.h @@ -46,7 +46,6 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_report_error_summary(const char *error_summary); - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init(); SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( const __sanitizer::uptr *pcs, const __sanitizer::uptr len); -- cgit v1.2.1 From 861f5212c5583d72b48c528657bffc5aafe2a7c0 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Wed, 26 Jul 2017 21:16:15 +0000 Subject: Add liblog to ubsan `UBSAN_DYNAMIC_LIBS` Summary: liblog is still required to create ubsan runtimes on Android when __ANDROID_API__ < 21. Reviewers: eugenis, vsk Subscribers: kubamracek, mgorny, pirama, srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D35915 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309180 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 457a6b475..cf4b30bd3 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -35,6 +35,7 @@ append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) @@ -129,7 +130,7 @@ else() add_compiler_rt_object_libraries(RTUbsan_standalone ARCHS ${UBSAN_SUPPORTED_ARCH} SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS}) - + # Standalone UBSan runtimes. add_compiler_rt_runtime(clang_rt.ubsan_standalone STATIC @@ -140,7 +141,7 @@ else() RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} PARENT_TARGET ubsan) - + add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx STATIC ARCHS ${UBSAN_SUPPORTED_ARCH} -- cgit v1.2.1 From fa4969a72758e98246cb7ee4e8178bca5dd5250a Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Thu, 27 Jul 2017 18:40:38 +0000 Subject: [sanitizers] Sanitizer tests CMake clean up This patch addresses two issues: Most of the time, hacks with `if/else` in order to get support for multi-configuration builds are superfluous. The variable `CMAKE_CFG_INTDIR` was created precisely for this purpose: it expands to `.` on all single-configuration builds, and to a configuration name otherwise. The `if/else` hacks for the library name generation should also not be done, as CMake has `TARGET_FILE` generator expression precisely for this purpose, as it expands to the exact filename of the resulting target. Differential Revision: https://reviews.llvm.org/D35952 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309306 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 5 +---- lib/asan/tests/CMakeLists.txt | 34 ++++--------------------------- lib/interception/tests/CMakeLists.txt | 17 ++-------------- lib/sanitizer_common/tests/CMakeLists.txt | 17 ++-------------- 4 files changed, 9 insertions(+), 64 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index bc5fb9ff7..2366195ab 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -301,10 +301,7 @@ macro(add_compiler_rt_test test_suite test_name) if(TEST_SUBDIR) set(output_bin "${output_bin}/${TEST_SUBDIR}") endif() - if(CMAKE_CONFIGURATION_TYPES) - set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}") - endif() - set(output_bin "${output_bin}/${test_name}") + set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}/${test_name}") if(MSVC) set(output_bin "${output_bin}.exe") endif() diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 8089d51ef..e842c83de 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -129,11 +129,7 @@ append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) # options in ${ARGN}, and add it to the object list. macro(asan_compile obj_list source arch kind) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o") - else() - set(output_obj "${obj_list}.${basename}.${arch}${kind}.o") - endif() + set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o") get_target_flags_for_arch(${arch} TARGET_CFLAGS) set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -156,17 +152,7 @@ macro(add_asan_test test_suite test_name arch kind) endif() if(TEST_WITH_TEST_RUNTIME) list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME}) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(asan_test_runtime_path ${configuration_path}lib${ASAN_TEST_RUNTIME}.a) - else() - set(asan_test_runtime_path ${configuration_path}${ASAN_TEST_RUNTIME}.lib) - endif() - list(APPEND TEST_OBJECTS ${asan_test_runtime_path}) + list(APPEND TEST_OBJECTS $) endif() add_compiler_rt_test(${test_suite} ${test_name} SUBDIR ${TEST_SUBDIR} @@ -245,13 +231,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) endif() # Create the 'default' folder where ASAN tests are produced. - if(CMAKE_CONFIGURATION_TYPES) - foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${build_mode}") - endforeach() - else() - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default") - endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${CMAKE_CFG_INTDIR}") add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind} SUBDIR "default" @@ -259,13 +239,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) # Create the 'dynamic' folder where ASAN tests are produced. - if(CMAKE_CONFIGURATION_TYPES) - foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${build_mode}") - endforeach() - else() - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic") - endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${CMAKE_CFG_INTDIR}") add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind} SUBDIR "dynamic" diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index 5ea943f9a..15cba152d 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -74,16 +74,7 @@ function(get_interception_lib_for_arch arch lib lib_name) set(tgt_name "RTInterception.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) - else() - set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) - endif() + set(${lib_name} $ PARENT_SCOPE) endfunction() # Interception unit tests testsuite. @@ -103,11 +94,7 @@ macro(add_interception_tests_for_arch arch) set(INTERCEPTION_TEST_OBJECTS) foreach(source ${INTERCEPTION_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") - else() - set(output_obj "${basename}.${arch}.o") - endif() + set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") clang_compile(${output_obj} ${source} CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${INTERCEPTION_TEST_COMPILE_DEPS}) diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 2acedd0ef..5c107babe 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -127,16 +127,7 @@ function(get_sanitizer_common_lib_for_arch arch lib lib_name) set(tgt_name "RTSanitizerCommon.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) - else() - set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) - endif() + set(${lib_name} $ PARENT_SCOPE) endfunction() # Sanitizer_common unit tests testsuite. @@ -164,11 +155,7 @@ macro(add_sanitizer_tests_for_arch arch) set(SANITIZER_TEST_OBJECTS) foreach(source ${SANITIZER_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") - else() - set(output_obj "${basename}.${arch}.o") - endif() + set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") clang_compile(${output_obj} ${source} CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${SANITIZER_TEST_COMPILE_DEPS}) -- cgit v1.2.1 From 3d7f9b6425d5fed1fd084e5317ad5982201bf85d Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Thu, 27 Jul 2017 20:44:33 +0000 Subject: Revert "[sanitizers] Sanitizer tests CMake clean up" This reverts commit 0ab44db2aa1cd3710355ad79b04f954ce68c0b3a. Fails on some bots, reverting until I can fix it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309318 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 5 ++++- lib/asan/tests/CMakeLists.txt | 34 +++++++++++++++++++++++++++---- lib/interception/tests/CMakeLists.txt | 17 ++++++++++++++-- lib/sanitizer_common/tests/CMakeLists.txt | 17 ++++++++++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 2366195ab..bc5fb9ff7 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -301,7 +301,10 @@ macro(add_compiler_rt_test test_suite test_name) if(TEST_SUBDIR) set(output_bin "${output_bin}/${TEST_SUBDIR}") endif() - set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}/${test_name}") + if(CMAKE_CONFIGURATION_TYPES) + set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}") + endif() + set(output_bin "${output_bin}/${test_name}") if(MSVC) set(output_bin "${output_bin}.exe") endif() diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index e842c83de..8089d51ef 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -129,7 +129,11 @@ append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) # options in ${ARGN}, and add it to the object list. macro(asan_compile obj_list source arch kind) get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o") + if(CMAKE_CONFIGURATION_TYPES) + set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o") + else() + set(output_obj "${obj_list}.${basename}.${arch}${kind}.o") + endif() get_target_flags_for_arch(${arch} TARGET_CFLAGS) set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -152,7 +156,17 @@ macro(add_asan_test test_suite test_name arch kind) endif() if(TEST_WITH_TEST_RUNTIME) list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME}) - list(APPEND TEST_OBJECTS $) + if(CMAKE_CONFIGURATION_TYPES) + set(configuration_path "${CMAKE_CFG_INTDIR}/") + else() + set(configuration_path "") + endif() + if(NOT MSVC) + set(asan_test_runtime_path ${configuration_path}lib${ASAN_TEST_RUNTIME}.a) + else() + set(asan_test_runtime_path ${configuration_path}${ASAN_TEST_RUNTIME}.lib) + endif() + list(APPEND TEST_OBJECTS ${asan_test_runtime_path}) endif() add_compiler_rt_test(${test_suite} ${test_name} SUBDIR ${TEST_SUBDIR} @@ -231,7 +245,13 @@ macro(add_asan_tests_for_arch_and_kind arch kind) endif() # Create the 'default' folder where ASAN tests are produced. - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${CMAKE_CFG_INTDIR}") + if(CMAKE_CONFIGURATION_TYPES) + foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${build_mode}") + endforeach() + else() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default") + endif() add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind} SUBDIR "default" @@ -239,7 +259,13 @@ macro(add_asan_tests_for_arch_and_kind arch kind) LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) # Create the 'dynamic' folder where ASAN tests are produced. - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${CMAKE_CFG_INTDIR}") + if(CMAKE_CONFIGURATION_TYPES) + foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${build_mode}") + endforeach() + else() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic") + endif() add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind} SUBDIR "dynamic" diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index 15cba152d..5ea943f9a 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -74,7 +74,16 @@ function(get_interception_lib_for_arch arch lib lib_name) set(tgt_name "RTInterception.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - set(${lib_name} $ PARENT_SCOPE) + if(CMAKE_CONFIGURATION_TYPES) + set(configuration_path "${CMAKE_CFG_INTDIR}/") + else() + set(configuration_path "") + endif() + if(NOT MSVC) + set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) + else() + set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) + endif() endfunction() # Interception unit tests testsuite. @@ -94,7 +103,11 @@ macro(add_interception_tests_for_arch arch) set(INTERCEPTION_TEST_OBJECTS) foreach(source ${INTERCEPTION_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") + if(CMAKE_CONFIGURATION_TYPES) + set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") + else() + set(output_obj "${basename}.${arch}.o") + endif() clang_compile(${output_obj} ${source} CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${INTERCEPTION_TEST_COMPILE_DEPS}) diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 5c107babe..2acedd0ef 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -127,7 +127,16 @@ function(get_sanitizer_common_lib_for_arch arch lib lib_name) set(tgt_name "RTSanitizerCommon.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - set(${lib_name} $ PARENT_SCOPE) + if(CMAKE_CONFIGURATION_TYPES) + set(configuration_path "${CMAKE_CFG_INTDIR}/") + else() + set(configuration_path "") + endif() + if(NOT MSVC) + set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) + else() + set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) + endif() endfunction() # Sanitizer_common unit tests testsuite. @@ -155,7 +164,11 @@ macro(add_sanitizer_tests_for_arch arch) set(SANITIZER_TEST_OBJECTS) foreach(source ${SANITIZER_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") + if(CMAKE_CONFIGURATION_TYPES) + set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") + else() + set(output_obj "${basename}.${arch}.o") + endif() clang_compile(${output_obj} ${source} CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${SANITIZER_TEST_COMPILE_DEPS}) -- cgit v1.2.1 From bc1f9b219edc906f664dd16a6f3a7a7b51faad78 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 27 Jul 2017 23:22:37 +0000 Subject: [sancov] Implement __sanitizer_cov_reset. Summary: Clears all collected coverage. Reviewers: kcc Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D35958 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309333 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/coverage_interface.h | 7 ++- .../sanitizer_coverage_interface.inc | 1 + .../sanitizer_coverage_libcdep_new.cc | 15 ++++- test/asan/TestCases/Posix/coverage-reset.cc | 65 ++++++++++++++++++++++ 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 test/asan/TestCases/Posix/coverage-reset.cc diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index 637379d47..081033cec 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -22,8 +22,11 @@ extern "C" { // Record and dump coverage info. void __sanitizer_cov_dump(); - // Dump collected coverage info. Sorts pcs by module into individual - // .sancov files. + // Clear collected coverage info. + void __sanitizer_cov_reset(); + + // Dump collected coverage info. Sorts pcs by module into individual .sancov + // files. void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len); #ifdef __cplusplus diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index d4749000d..87ae9c038 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -9,6 +9,7 @@ // Sanitizer Coverage interface list. //===----------------------------------------------------------------------===// INTERFACE_FUNCTION(__sanitizer_cov_dump) +INTERFACE_FUNCTION(__sanitizer_cov_reset) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) INTERFACE_WEAK_FUNCTION(__sancov_default_options) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index ac9be2704..0614901aa 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -125,11 +125,17 @@ class TracePcGuardController { } void TracePcGuard(u32* guard, uptr pc) { - atomic_uint32_t* guard_ptr = reinterpret_cast(guard); - u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); + u32 idx = *guard; if (!idx) return; // we start indices from 1. - pc_vector[idx - 1] = pc; + atomic_uintptr_t* pc_ptr = + reinterpret_cast(&pc_vector[idx - 1]); + if (atomic_load(pc_ptr, memory_order_relaxed) == 0) + atomic_store(pc_ptr, pc, memory_order_relaxed); + } + + void Reset() { + internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); } void Dump() { @@ -181,6 +187,9 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { __sanitizer_dump_trace_pc_guard_coverage(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { + __sancov::pc_guard_controller.Reset(); +} // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} diff --git a/test/asan/TestCases/Posix/coverage-reset.cc b/test/asan/TestCases/Posix/coverage-reset.cc new file mode 100644 index 000000000..e9639b34d --- /dev/null +++ b/test/asan/TestCases/Posix/coverage-reset.cc @@ -0,0 +1,65 @@ +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so +// RUN: %clangxx_asan -fsanitize-coverage=func,trace-pc-guard %s %ld_flags_rpath_exe -o %t +// RUN: rm -rf %T/coverage-reset && mkdir -p %T/coverage-reset && cd %T/coverage-reset +// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s +// +// UNSUPPORTED: ios + +#include + +#include + +#ifdef SHARED +void bar1() { printf("bar1\n"); } +void bar2() { printf("bar2\n"); } +#else +__attribute__((noinline)) void foo1() { printf("foo1\n"); } +__attribute__((noinline)) void foo2() { printf("foo2\n"); } +void bar1(); +void bar2(); + +int main(int argc, char **argv) { + fprintf(stderr, "RESET"); + __sanitizer_cov_reset(); + foo1(); + foo2(); + bar1(); + bar2(); + __sanitizer_cov_dump(); +// CHECK: RESET +// CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written +// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written + + fprintf(stderr, "RESET"); + __sanitizer_cov_reset(); + foo1(); + bar1(); + __sanitizer_cov_dump(); +// CHECK: RESET +// CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 1 PCs written +// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 1 PCs written + + fprintf(stderr, "RESET"); + __sanitizer_cov_reset(); + foo1(); + foo2(); + __sanitizer_cov_dump(); +// CHECK: RESET +// CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written + + fprintf(stderr, "RESET"); + __sanitizer_cov_reset(); + bar1(); + bar2(); + __sanitizer_cov_dump(); +// CHECK: RESET +// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written + + fprintf(stderr, "RESET"); + __sanitizer_cov_reset(); +// CHECK: RESET + + bar2(); +// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 1 PCs written +} +#endif -- cgit v1.2.1 From 5215325996151915d06feb6917b9b9d54ea8dec9 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 28 Jul 2017 00:22:42 +0000 Subject: [sancov] Add missing line breaks in test. NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309339 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-reset.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Posix/coverage-reset.cc b/test/asan/TestCases/Posix/coverage-reset.cc index e9639b34d..89311c39f 100644 --- a/test/asan/TestCases/Posix/coverage-reset.cc +++ b/test/asan/TestCases/Posix/coverage-reset.cc @@ -19,7 +19,7 @@ void bar1(); void bar2(); int main(int argc, char **argv) { - fprintf(stderr, "RESET"); + fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); foo1(); foo2(); @@ -30,7 +30,7 @@ int main(int argc, char **argv) { // CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written // CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written - fprintf(stderr, "RESET"); + fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); foo1(); bar1(); @@ -39,7 +39,7 @@ int main(int argc, char **argv) { // CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 1 PCs written // CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 1 PCs written - fprintf(stderr, "RESET"); + fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); foo1(); foo2(); @@ -47,7 +47,7 @@ int main(int argc, char **argv) { // CHECK: RESET // CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written - fprintf(stderr, "RESET"); + fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); bar1(); bar2(); @@ -55,7 +55,7 @@ int main(int argc, char **argv) { // CHECK: RESET // CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written - fprintf(stderr, "RESET"); + fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); // CHECK: RESET -- cgit v1.2.1 From 33aba8c1c12302cd0e59995896a49338993022f6 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Fri, 28 Jul 2017 00:50:56 +0000 Subject: [sanitizers] Sanitizer tests CMake clean up: try #2 This patch addresses two issues: Most of the time, hacks with `if/else` in order to get support for multi-configuration builds are superfluous. The variable `CMAKE_CFG_INTDIR` was created precisely for this purpose: it expands to `.` on all single-configuration builds, and to a configuration name otherwise. The `if/else` hacks for the library name generation should also not be done, as CMake has `TARGET_FILE` generator expression precisely for this purpose, as it expands to the exact filename of the resulting target. Differential Revision: https://reviews.llvm.org/D35952 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309341 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 6 ++++++ cmake/Modules/AddCompilerRT.cmake | 5 +---- lib/asan/tests/CMakeLists.txt | 34 ++++--------------------------- lib/interception/tests/CMakeLists.txt | 17 ++-------------- lib/sanitizer_common/tests/CMakeLists.txt | 17 ++-------------- 5 files changed, 15 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f997c5341..6d176bc5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,12 @@ list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CFG_RESOLVED_INTDIR "${CMAKE_CFG_INTDIR}/") +else() + set(CMAKE_CFG_RESOLVED_INTDIR "") +endif() + include(base-config-ix) include(CompilerRTUtils) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index bc5fb9ff7..78663353c 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -301,10 +301,7 @@ macro(add_compiler_rt_test test_suite test_name) if(TEST_SUBDIR) set(output_bin "${output_bin}/${TEST_SUBDIR}") endif() - if(CMAKE_CONFIGURATION_TYPES) - set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}") - endif() - set(output_bin "${output_bin}/${test_name}") + set(output_bin "${output_bin}/${CMAKE_CFG_RESOLVED_INTDIR}${test_name}") if(MSVC) set(output_bin "${output_bin}.exe") endif() diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 8089d51ef..9342fa4f7 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -129,11 +129,7 @@ append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) # options in ${ARGN}, and add it to the object list. macro(asan_compile obj_list source arch kind) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o") - else() - set(output_obj "${obj_list}.${basename}.${arch}${kind}.o") - endif() + set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${obj_list}.${basename}.${arch}${kind}.o") get_target_flags_for_arch(${arch} TARGET_CFLAGS) set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -156,17 +152,7 @@ macro(add_asan_test test_suite test_name arch kind) endif() if(TEST_WITH_TEST_RUNTIME) list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME}) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(asan_test_runtime_path ${configuration_path}lib${ASAN_TEST_RUNTIME}.a) - else() - set(asan_test_runtime_path ${configuration_path}${ASAN_TEST_RUNTIME}.lib) - endif() - list(APPEND TEST_OBJECTS ${asan_test_runtime_path}) + list(APPEND TEST_OBJECTS $) endif() add_compiler_rt_test(${test_suite} ${test_name} SUBDIR ${TEST_SUBDIR} @@ -245,13 +231,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) endif() # Create the 'default' folder where ASAN tests are produced. - if(CMAKE_CONFIGURATION_TYPES) - foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${build_mode}") - endforeach() - else() - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default") - endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${CMAKE_CFG_RESOLVED_INTDIR}") add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind} SUBDIR "default" @@ -259,13 +239,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) # Create the 'dynamic' folder where ASAN tests are produced. - if(CMAKE_CONFIGURATION_TYPES) - foreach(build_mode ${CMAKE_CONFIGURATION_TYPES}) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${build_mode}") - endforeach() - else() - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic") - endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${CMAKE_CFG_RESOLVED_INTDIR}") add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind} SUBDIR "dynamic" diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index 5ea943f9a..5f4033104 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -74,16 +74,7 @@ function(get_interception_lib_for_arch arch lib lib_name) set(tgt_name "RTInterception.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) - else() - set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) - endif() + set(${lib_name} $ PARENT_SCOPE) endfunction() # Interception unit tests testsuite. @@ -103,11 +94,7 @@ macro(add_interception_tests_for_arch arch) set(INTERCEPTION_TEST_OBJECTS) foreach(source ${INTERCEPTION_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") - else() - set(output_obj "${basename}.${arch}.o") - endif() + set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${basename}.${arch}.o") clang_compile(${output_obj} ${source} CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${INTERCEPTION_TEST_COMPILE_DEPS}) diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 2acedd0ef..13c016314 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -127,16 +127,7 @@ function(get_sanitizer_common_lib_for_arch arch lib lib_name) set(tgt_name "RTSanitizerCommon.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - if(CMAKE_CONFIGURATION_TYPES) - set(configuration_path "${CMAKE_CFG_INTDIR}/") - else() - set(configuration_path "") - endif() - if(NOT MSVC) - set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) - else() - set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) - endif() + set(${lib_name} $ PARENT_SCOPE) endfunction() # Sanitizer_common unit tests testsuite. @@ -164,11 +155,7 @@ macro(add_sanitizer_tests_for_arch arch) set(SANITIZER_TEST_OBJECTS) foreach(source ${SANITIZER_TEST_SOURCES}) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") - else() - set(output_obj "${basename}.${arch}.o") - endif() + set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${basename}.${arch}.o") clang_compile(${output_obj} ${source} CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${SANITIZER_TEST_COMPILE_DEPS}) -- cgit v1.2.1 From ab3ad40db18c65299f5c4dbcd0cec54a774e50cf Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 28 Jul 2017 01:38:43 +0000 Subject: [sanitizer-coverage] add a run-time test for -fsanitize-coverage=inline-8bit-counters,pc-table git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309351 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/sanitizer_coverage_inline8bit_counter.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc index b7246ebf2..c071ba669 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -1,11 +1,12 @@ -// Tests -fsanitize-coverage=inline-8bit-counters +// Tests -fsanitize-coverage=inline-8bit-counters,pc-table // // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin // -// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters,pc-table 2>&1 #include +#include #include const char *first_counter; @@ -17,7 +18,19 @@ void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { first_counter = start; } +uintptr_t FirstPC; + +extern "C" void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, + const uint8_t *pcs_end) { + const uintptr_t *B = (const uintptr_t *)pcs_beg; + const uintptr_t *E = (const uintptr_t *)pcs_end; + assert(B < E); + FirstPC = *B; +} + + int main() { assert(first_counter); assert(*first_counter == 1); + assert(FirstPC == (uintptr_t)&main); } -- cgit v1.2.1 From d630c5dde1026eee0e5a1fb886791adf21ab95a6 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Fri, 28 Jul 2017 03:39:38 +0000 Subject: Support compiler-rt builtins This change adds support for compiler-rt builtins as an alternative compiler runtime to libgcc. Differential Revision: https://reviews.llvm.org/D35165 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309361 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 16 ++++++++++++++++ cmake/Modules/HandleCompilerRT.cmake | 21 +++++++++++++++++++++ cmake/config-ix.cmake | 22 +++++++++++++++++++++- lib/asan/CMakeLists.txt | 5 +++-- lib/lsan/CMakeLists.txt | 5 ++++- lib/stats/CMakeLists.txt | 5 ++++- lib/tsan/CMakeLists.txt | 5 ++++- lib/tsan/dd/CMakeLists.txt | 5 ++++- lib/ubsan/CMakeLists.txt | 5 +++++ 9 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 cmake/Modules/HandleCompilerRT.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d176bc5e..b8568dc53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ option(COMPILER_RT_EXTERNALIZE_DEBUGINFO # COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in. pythonize_bool(COMPILER_RT_DEBUG) +include(HandleCompilerRT) include(config-ix) if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") @@ -99,6 +100,8 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) +option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) + #================================ # Setup Compiler Flags #================================ @@ -234,6 +237,19 @@ append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS) append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS) +# Set common link flags. +append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS) + +if (SANITIZER_USE_COMPILER_RT) + list(APPEND SANITIZER_COMMON_LINK_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) + list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY}) +else() + append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS) +endif() + +append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) + # Warnings to turn off for all libraries, not just sanitizers. append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS) diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 000000000..cff5031ec --- /dev/null +++ b/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,21 @@ +function(find_compiler_rt_library name dest) + set(dest "" PARENT_SCOPE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${SANITIZER_COMMON_CFLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) + list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") + endif() + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") + message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}") + set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt ${name} library") + endif() +endfunction() diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index c329c6a97..64c1347c6 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -1,4 +1,5 @@ include(CMakePushCheckState) +include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) include(CheckLibraryExists) include(CheckSymbolExists) @@ -11,6 +12,26 @@ function(check_linker_flag flag out_var) cmake_pop_check_state() endfunction() +check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) +if (NOT SANITIZER_USE_COMPILER_RT) + check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB) +endif() + +check_c_compiler_flag(-nodefaultlibs COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) +if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + if (COMPILER_RT_HAS_LIBC) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (SANITIZER_USE_COMPILER_RT) + list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}") + elseif (COMPILER_RT_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () +endif () + # CodeGen options. check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG) @@ -73,7 +94,6 @@ check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG) check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL) # Libraries. -check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL) check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT) check_library_exists(m pow "" COMPILER_RT_HAS_LIBM) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 47afa79bd..f033010db 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -40,7 +40,7 @@ set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(OFF ASAN_CFLAGS) -set(ASAN_DYNAMIC_LINK_FLAGS) +set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) if(ANDROID) # On Android, -z global does not do what it is documented to do. @@ -65,7 +65,8 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS) -append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS) +set(ASAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt index bd3a96f32..60da3e186 100644 --- a/lib/lsan/CMakeLists.txt +++ b/lib/lsan/CMakeLists.txt @@ -29,6 +29,8 @@ add_compiler_rt_object_libraries(RTLSanCommon if(COMPILER_RT_HAS_LSAN) add_compiler_rt_component(lsan) if(APPLE) + set(LSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -42,7 +44,8 @@ if(COMPILER_RT_HAS_LSAN) RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${LSAN_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${LSAN_LINK_LIBS} PARENT_TARGET lsan) else() foreach(arch ${LSAN_SUPPORTED_ARCH}) diff --git a/lib/stats/CMakeLists.txt b/lib/stats/CMakeLists.txt index 2b3d6474b..6be36a7cb 100644 --- a/lib/stats/CMakeLists.txt +++ b/lib/stats/CMakeLists.txt @@ -6,6 +6,8 @@ set_target_properties(stats PROPERTIES FOLDER "Compiler-RT Misc") if(APPLE) set(STATS_LIB_FLAVOR SHARED) + set(STATS_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -23,7 +25,8 @@ add_compiler_rt_runtime(clang_rt.stats OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc CFLAGS ${SANITIZER_COMMON_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${STATS_LINK_LIBS} PARENT_TARGET stats) add_compiler_rt_runtime(clang_rt.stats_client diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 193158c54..5e3bb102b 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -109,6 +109,8 @@ if(APPLE) set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES LANGUAGE C) endif() + set(TSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) @@ -122,7 +124,8 @@ if(APPLE) RTSanitizerCommonLibc RTUbsan CFLAGS ${TSAN_RTL_CFLAGS} - LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${TSAN_LINK_LIBS} PARENT_TARGET tsan) add_compiler_rt_object_libraries(RTTsan_dynamic OS ${TSAN_SUPPORTED_OS} diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index bcff35f20..bd9515567 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -10,10 +10,12 @@ set(DD_SOURCES dd_interceptors.cc ) -set(DD_LINKLIBS) +set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. @@ -40,6 +42,7 @@ if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID) $ $ $ + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${DD_LINKLIBS} PARENT_TARGET dd) endif() diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index cf4b30bd3..c7473bbed 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -34,10 +34,13 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) +set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) add_compiler_rt_component(ubsan) @@ -156,6 +159,7 @@ else() RTSanitizerCommonLibc RTUbsan CFLAGS ${UBSAN_CFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) @@ -167,6 +171,7 @@ else() RTUbsan RTUbsan_cxx CFLAGS ${UBSAN_CXXFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) -- cgit v1.2.1 From d212208940208070463c1745da5411a3f08f271f Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Fri, 28 Jul 2017 03:39:39 +0000 Subject: Support libc++abi in addition to libstdc++ This change adds sanitizer support for LLVM's libunwind and libc++abi as an alternative to libstdc++. This allows using the in tree version of libunwind and libc++abi which is useful when building a toolchain for different target. Differential Revision: https://reviews.llvm.org/D34501 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309362 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 34 ++++++++++++++++++++++++++++++++++ lib/asan/CMakeLists.txt | 3 ++- lib/tsan/dd/CMakeLists.txt | 3 ++- lib/ubsan/CMakeLists.txt | 3 ++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8568dc53..ed3e01d23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,40 @@ endif() option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) pythonize_bool(SANITIZER_CAN_USE_CXXABI) +set(SANITIZER_CXX_ABI "default" CACHE STRING + "Specify C++ ABI library to use.") +set(CXXABIS none default libcxxabi libstdc++) +set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS}) + +if (SANITIZER_CXX_ABI STREQUAL "default") + if (HAVE_LIBCXXABI AND COMPILER_RT_DEFAULT_TARGET_ONLY) + set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") + set(SANITIZER_CXX_ABI_INTREE 1) + elseif (APPLE) + set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi") + set(SANITIZER_CXX_ABI_SYSTEM 1) + else() + set(SANITIZER_CXX_ABI_LIBNAME "libstdc++") + endif() +elseif() + set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}") +endif() + +if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") + if (SANITIZER_CXX_ABI_INTREE) + if (TARGET unwind_shared OR HAVE_LIBUNWIND) + list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared) + endif() + if (TARGET cxxabi_shared OR HAVE_LIBCXXABI) + list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared) + endif() + else() + list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") + endif() +elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") + append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) +endif() + option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF) #================================ diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index f033010db..6cb994aac 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -71,9 +71,10 @@ append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS) +list(APPEND ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) + # Compile ASan sources into an object library. add_compiler_rt_object_libraries(RTAsan_dynamic diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index bd9515567..4c9508183 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -15,7 +15,8 @@ set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ DD_LINKLIBS) + +list(APPEND DD_LINKLIBS ${SANITIZER_CXX_ABI_LIBRARY}) add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index c7473bbed..caa77c2a7 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -40,7 +40,8 @@ append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) -append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ UBSAN_DYNAMIC_LIBS) + +list(APPEND UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) add_compiler_rt_component(ubsan) -- cgit v1.2.1 From 540a1c9dd6a85ee76473f85b8865aff3bd1bb991 Mon Sep 17 00:00:00 2001 From: Dehao Chen Date: Fri, 28 Jul 2017 15:00:30 +0000 Subject: Change INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE from 8 to 16. Summary: In the current implementation, the defaul number of values per site tracked by value profiler is 8, which is too small and could introduce inaccuracies to profile. Changing it to 16 will be able to gain more accurate value profiler. Reviewers: davidxl, tejohnson Reviewed By: tejohnson Subscribers: sanjoy, llvm-commits Differential Revision: https://reviews.llvm.org/D35964 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309388 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingValue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profile/InstrProfilingValue.c b/lib/profile/InstrProfilingValue.c index 44263da80..4bc7bb601 100644 --- a/lib/profile/InstrProfilingValue.c +++ b/lib/profile/InstrProfilingValue.c @@ -22,7 +22,7 @@ static int hasStaticCounters = 1; static int OutOfNodesWarnings = 0; static int hasNonDefaultValsPerSite = 0; #define INSTR_PROF_MAX_VP_WARNS 10 -#define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 8 +#define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 16 #define INSTR_PROF_VNODE_POOL_SIZE 1024 #ifndef _MSC_VER -- cgit v1.2.1 From b8f4c3386545a540eebf0d64473e8827373fcdf2 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Fri, 28 Jul 2017 17:32:37 +0000 Subject: [sanitizer tests CMake] Factor out CMake logic for compiling sanitizer tests Currently there's a large amount of CMake logic duplication for compiling sanitizer tests. If we add more sanitizers, the duplication will get even worse. This change factors out common compilation commands into a macro available to all sanitizers. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309405 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 35 +++++++++++++++++++++++++++++++++ lib/asan/tests/CMakeLists.txt | 36 ++++++++++++++-------------------- lib/msan/tests/CMakeLists.txt | 37 ++++++++++++++--------------------- lib/tsan/tests/CMakeLists.txt | 22 ++++++--------------- lib/xray/tests/CMakeLists.txt | 17 +++------------- 5 files changed, 74 insertions(+), 73 deletions(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index 30663b695..b39ca4ef8 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -24,6 +24,41 @@ function(translate_msvc_cflags out_flags msvc_flags) set(${out_flags} "${clang_flags}" PARENT_SCOPE) endfunction() +# Compile a sanitizer test with a freshly built clang +# for a given architecture, adding the result to the object list. +# - obj_list: output list of objects, populated by path +# of the generated object file. +# - source: source file of a test. +# - arch: architecture to compile for. +# sanitizer_test_compile( +# KIND +# COMPILE_DEPS +# DEPS +# CFLAGS +# ) +macro(sanitizer_test_compile obj_list source arch) + cmake_parse_arguments(TEST + "" "" "KIND;COMPILE_DEPS;DEPS;CFLAGS" ${ARGN}) + get_filename_component(basename ${source} NAME) + if(CMAKE_CONFIGURATION_TYPES) + set(output_obj + "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${TEST_KIND}.o") + else() + set(output_obj "${obj_list}.${basename}.${arch}${TEST_KIND}.o") + endif() + + # Write out architecture-specific flags into TARGET_CFLAGS variable. + get_target_flags_for_arch(${arch} TARGET_CFLAGS) + set(COMPILE_DEPS ${TEST_COMPILE_DEPS}) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND COMPILE_DEPS ${TEST_DEPS}) + endif() + clang_compile(${output_obj} ${source} + CFLAGS ${TEST_CFLAGS} ${TARGET_CFLAGS} + DEPS ${TEST_COMPILE_DEPS}) + list(APPEND ${obj_list} ${output_obj}) +endmacro() + # Compile a source into an object file with COMPILER_RT_TEST_COMPILER using # a provided compile flags and dependenices. # clang_compile( diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 9342fa4f7..e08346ade 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -125,20 +125,14 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS) # NDK r10 requires -latomic almost always. append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) -# Compile source for the given architecture, using compiler -# options in ${ARGN}, and add it to the object list. macro(asan_compile obj_list source arch kind) - get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${obj_list}.${basename}.${arch}${kind}.o") - get_target_flags_for_arch(${arch} TARGET_CFLAGS) - set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND COMPILE_DEPS gtest asan) - endif() - clang_compile(${output_obj} ${source} - CFLAGS ${ARGN} ${TARGET_CFLAGS} - DEPS ${COMPILE_DEPS}) - list(APPEND ${obj_list} ${output_obj}) + cmake_parse_arguments(ASAN_TEST "" "" "CFLAGS" ${ARGN}) + sanitizer_test_compile(${obj_list} ${source} ${arch} + KIND ${kind} + COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE} + DEPS gtest asan + CFLAGS ${ASAN_TEST_CFLAGS} + ) endmacro() # Link ASan unit test for a given architecture from a set @@ -200,17 +194,17 @@ set(ASAN_BENCHMARKS_SOURCES asan_benchmarks_test.cc) # Adds ASan unit tests and benchmarks for architecture. -macro(add_asan_tests_for_arch_and_kind arch kind) +macro(add_asan_tests_for_arch_and_kind arch kind cflags) # Instrumented tests. set(ASAN_INST_TEST_OBJECTS) foreach(src ${ASAN_INST_TEST_SOURCES}) asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN}) + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}) endforeach() if (APPLE) # Add Mac-specific helper. asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN}) + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${cflags}) endif() if (MSVC) @@ -219,7 +213,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) set(ASAN_INST_DYNAMIC_TEST_OBJECTS) foreach(src ${ASAN_INST_TEST_SOURCES}) asan_compile(ASAN_INST_DYNAMIC_TEST_OBJECTS ${src} ${arch} ${kind} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL ${ARGN}) + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL ${cflags}) endforeach() # Clang links the static CRT by default. Override that to use the dynamic # CRT. @@ -276,7 +270,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) set(ASAN_NOINST_TEST_OBJECTS) foreach(src ${ASAN_NOINST_TEST_SOURCES}) asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind} - ${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN}) + CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS} ${cflags}) endforeach() add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test" ${arch} ${kind} SUBDIR "default" @@ -288,7 +282,7 @@ macro(add_asan_tests_for_arch_and_kind arch kind) set(ASAN_BENCHMARKS_OBJECTS) foreach(src ${ASAN_BENCHMARKS_SOURCES}) asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN}) + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}) endforeach() add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark" ${arch} ${kind} SUBDIR "default" @@ -302,9 +296,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH) endif() foreach(arch ${ASAN_TEST_ARCH}) - add_asan_tests_for_arch_and_kind(${arch} "-inline") + add_asan_tests_for_arch_and_kind(${arch} "-inline" "") add_asan_tests_for_arch_and_kind(${arch} "-with-calls" - -mllvm -asan-instrumentation-with-call-threshold=0) + "-mllvm;-asan-instrumentation-with-call-threshold=0") endforeach() endif() diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index 65fbc732d..9d130bb3b 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -53,20 +53,14 @@ set(MSAN_UNITTEST_LINK_FLAGS append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS) -# Compile source for the given architecture, using compiler -# options in ${ARGN}, and add it to the object list. -macro(msan_compile obj_list source arch kind) - get_filename_component(basename ${source} NAME) - set(output_obj "${basename}.${arch}${kind}.o") - get_target_flags_for_arch(${arch} TARGET_CFLAGS) - set(COMPILE_DEPS ${MSAN_UNITTEST_HEADERS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND COMPILE_DEPS gtest msan) - endif() - clang_compile(${output_obj} ${source} - CFLAGS ${ARGN} ${TARGET_CFLAGS} - DEPS ${COMPILE_DEPS}) - list(APPEND ${obj_list} ${output_obj}) +macro(msan_compile obj_list source arch kind cflags) + sanitizer_test_compile( + ${obj_list} ${source} ${arch} + KIND ${kind} + COMPILE_DEPS ${MSAN_UNITTEST_HEADERS} + DEPS gtest msan + CFLAGS ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags} + ) endmacro() macro(msan_link_shared so_list so_name arch kind) @@ -88,23 +82,22 @@ add_custom_target(MsanUnitTests) set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests") # Adds MSan unit tests and benchmarks for architecture. -macro(add_msan_tests_for_arch arch kind) +macro(add_msan_tests_for_arch arch kind cflags) # Build gtest instrumented with MSan. set(MSAN_INST_GTEST) - msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}" - ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN}) + msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} ${kind} + "${cflags}") # Instrumented tests. set(MSAN_INST_TEST_OBJECTS) foreach (SOURCE ${MSAN_UNITTEST_SOURCES}) - msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}" - ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN}) + msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}" "${cflags}") endforeach(SOURCE) # Instrumented loadable module objects. set(MSAN_INST_LOADABLE_OBJECTS) msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}" - ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} "-fPIC" ${ARGN}) + "-fPIC;${cflags}") # Instrumented loadable library tests. set(MSAN_LOADABLE_SO) @@ -138,8 +131,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES) CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS}) set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so) - add_msan_tests_for_arch(${arch} "") + add_msan_tests_for_arch(${arch} "" "") add_msan_tests_for_arch(${arch} "-with-call" - -mllvm -msan-instrumentation-with-call-threshold=0) + "-mllvm;-msan-instrumentation-with-call-threshold=0") endforeach() endif() diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index f8aec6854..a8a322113 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -23,21 +23,6 @@ foreach (header ${TSAN_HEADERS}) list(APPEND TSAN_RTL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header}) endforeach() -# tsan_compile(obj_list, source, arch, {headers}) -macro(tsan_compile obj_list source arch) - get_filename_component(basename ${source} NAME) - set(output_obj "${basename}.${arch}.o") - get_target_flags_for_arch(${arch} TARGET_CFLAGS) - set(COMPILE_DEPS ${TSAN_RTL_HEADERS} ${ARGN}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND COMPILE_DEPS gtest tsan) - endif() - clang_compile(${output_obj} ${source} - CFLAGS ${TSAN_UNITTEST_CFLAGS} ${TARGET_CFLAGS} - DEPS ${COMPILE_DEPS}) - list(APPEND ${obj_list} ${output_obj}) -endmacro() - macro(add_tsan_unittest testname) set(TSAN_TEST_ARCH ${TSAN_SUPPORTED_ARCH}) if(APPLE) @@ -48,7 +33,12 @@ macro(add_tsan_unittest testname) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) set(TEST_OBJECTS) foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - tsan_compile(TEST_OBJECTS ${SOURCE} ${arch} ${TEST_HEADERS}) + sanitizer_test_compile( + TEST_OBJECTS ${SOURCE} ${arch} + COMPILE_DEPS ${TSAN_RTL_HEADERS} ${TEST_HEADERS} + DEPS gtest tsan + CFLAGS ${TSAN_UNITTEST_CFLAGS} + ) endforeach() get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) set(TEST_DEPS ${TEST_OBJECTS}) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index a1eb4a030..151fa4c10 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -11,19 +11,6 @@ set(XRAY_UNITTEST_CFLAGS -I${COMPILER_RT_SOURCE_DIR}/lib/xray -I${COMPILER_RT_SOURCE_DIR}/lib) -macro(xray_compile obj_list source arch) - get_filename_component(basename ${source} NAME) - set(output_obj "${basename}.${arch}.o") - get_target_flags_for_arch(${arch} TARGET_CFLAGS) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND COMPILE_DEPS gtest_main xray) - endif() - clang_compile(${output_obj} ${source} - CFLAGS ${XRAY_UNITTEST_CFLAGS} ${TARGET_CFLAGS} - DEPS ${COMPILE_DEPS}) - list(APPEND ${obj_list} ${output_obj}) -endmacro() - macro(add_xray_unittest testname) set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) if (APPLE) @@ -34,7 +21,9 @@ macro(add_xray_unittest testname) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) set(TEST_OBJECTS) foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - xray_compile(TEST_OBJECTS ${SOURCE} ${arch} ${TEST_HEADERS}) + sanitizer_test_compile(TEST_OBJECTS ${SOURCE} ${arch} + DEPS gtest_main xray + CFLAGS ${XRAY_UNITTEST_CFLAGS}) endforeach() get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) set(TEST_DEPS ${TEST_OBJECTS}) -- cgit v1.2.1 From 581f796e9ff2526223fa0aec434632bef5f09348 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Fri, 28 Jul 2017 17:38:44 +0000 Subject: [sanitizers test CMake] further refactor testing CMake for tsan TSan tests on Darwin first link all libraries into a static archive file. With this change, the linking is done once per all architecture, and previously the linking step was repeated per each architecture per each add_tsan_test call. Furthermore, the code is cleared up. Differential Revision: https://reviews.llvm.org/D35913 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309406 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/tests/CMakeLists.txt | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index a8a322113..4b9bc6ae9 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -13,9 +13,22 @@ set(TSAN_UNITTEST_CFLAGS -I${COMPILER_RT_SOURCE_DIR}/lib/tsan/rtl -DGTEST_HAS_RTTI=0) +set(TSAN_TEST_ARCH ${TSAN_SUPPORTED_ARCH}) if(APPLE) + darwin_filter_host_archs(TSAN_SUPPORTED_ARCH TSAN_TEST_ARCH) list(APPEND TSAN_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS}) - list(APPEND TSAN_UNITTEST_LINKFLAGS ${DARWIN_osx_LINKFLAGS}) + + # Create a static library for test dependencies. + set(TSAN_TEST_RUNTIME_OBJECTS + $ + $ + $ + $ + $) + set(TSAN_TEST_RUNTIME RTTsanTest) + add_library(${TSAN_TEST_RUNTIME} STATIC ${TSAN_TEST_RUNTIME_OBJECTS}) + set_target_properties(${TSAN_TEST_RUNTIME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() set(TSAN_RTL_HEADERS) @@ -23,14 +36,13 @@ foreach (header ${TSAN_HEADERS}) list(APPEND TSAN_RTL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header}) endforeach() +# add_tsan_unittest( +# SOURCES +# HEADERS ) macro(add_tsan_unittest testname) - set(TSAN_TEST_ARCH ${TSAN_SUPPORTED_ARCH}) - if(APPLE) - darwin_filter_host_archs(TSAN_SUPPORTED_ARCH TSAN_TEST_ARCH) - endif() + cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) if(UNIX) foreach(arch ${TSAN_TEST_ARCH}) - cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) set(TEST_OBJECTS) foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) sanitizer_test_compile( @@ -42,9 +54,6 @@ macro(add_tsan_unittest testname) endforeach() get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) set(TEST_DEPS ${TEST_OBJECTS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND TEST_DEPS tsan) - endif() if(NOT APPLE) # FIXME: Looks like we should link TSan with just-built runtime, # and not rely on -fsanitize=thread, as these tests are essentially @@ -56,17 +65,7 @@ macro(add_tsan_unittest testname) -fsanitize=thread -lstdc++ -lm) else() - set(TSAN_TEST_RUNTIME_OBJECTS - $ - $ - $ - $ - $) - set(TSAN_TEST_RUNTIME RTTsanTest.${testname}.${arch}) - add_library(${TSAN_TEST_RUNTIME} STATIC ${TSAN_TEST_RUNTIME_OBJECTS}) - set_target_properties(${TSAN_TEST_RUNTIME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - list(APPEND TEST_OBJECTS lib${TSAN_TEST_RUNTIME}.a) + list(APPEND TEST_OBJECTS $) list(APPEND TEST_DEPS ${TSAN_TEST_RUNTIME}) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) -- cgit v1.2.1 From 99e39e2aaeaa41130b4ef5061ad8cfd58ae1b0e9 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 28 Jul 2017 19:11:16 +0000 Subject: Revert r308677. Incorrect directories were created by the patch. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309420 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../test/asan/TestCases/pass-object-byval.cc | 36 -------------------- .../test/asan/TestCases/pass-struct-byval-uar.cc | 38 ---------------------- .../test/asan/TestCases/pass-struct-byval.cc | 23 ------------- 3 files changed, 97 deletions(-) delete mode 100644 compiler-rt/test/asan/TestCases/pass-object-byval.cc delete mode 100644 compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc delete mode 100644 compiler-rt/test/asan/TestCases/pass-struct-byval.cc diff --git a/compiler-rt/test/asan/TestCases/pass-object-byval.cc b/compiler-rt/test/asan/TestCases/pass-object-byval.cc deleted file mode 100644 index 189fcbeb2..000000000 --- a/compiler-rt/test/asan/TestCases/pass-object-byval.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Verify that objects passed by value get red zones and that the copy -// constructor is called. -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ -// RUN: Assertion{{.*}}failed -#include - -class A { - public: - A() : me(this) {} - A(const A &other) : me(this) { - for (int i = 0; i < 8; ++i) a[i] = other.a[i]; - } - - int a[8]; - A *me; -}; - -int bar(A *a) { - int *volatile ptr = &a->a[0]; - return *(ptr - 1); -} - -void foo(A a) { - assert(a.me == &a); - bar(&a); -} - -int main() { - A a; - foo(a); -} - -// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow -// CHECK: READ of size 4 at -// CHECK: is located in stack of thread diff --git a/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc b/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc deleted file mode 100644 index 3f2fd09c6..000000000 --- a/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Test that use-after-return works with arguments passed by value. -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK-NO-UAR %s -// RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK-UAR %s -// -// On several architectures, the IR does not use byval arguments for foo() and -// instead creates a copy in main() and gives foo() a pointer to the copy. In -// that case, ASAN has nothing to poison on return from foo() and will not -// detect the UAR. -// REQUIRES: x86_64-target-arch, linux, not-android - -#include - -struct A { - int a[8]; -}; - -A *foo(A a) { - return &a; -} - -int main() { - A *a = foo(A()); - a->a[0] = 7; - std::fprintf(stderr, "\n"); // Ensures some output is generated for FileCheck - // to verify in the case where UAR is not - // detected. -} - -// CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return -// CHECK-NO-UAR-NOT: WRITE of size 4 at -// CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable -// -// CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return -// CHECK-UAR: WRITE of size 4 at -// CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable diff --git a/compiler-rt/test/asan/TestCases/pass-struct-byval.cc b/compiler-rt/test/asan/TestCases/pass-struct-byval.cc deleted file mode 100644 index ba49eccf4..000000000 --- a/compiler-rt/test/asan/TestCases/pass-struct-byval.cc +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s - -struct A { - int a[8]; -}; - -int bar(A *a) { - int *volatile ptr = &a->a[0]; - return *(ptr - 1); -} - -void foo(A a) { - bar(&a); -} - -int main() { - foo(A()); -} - -// CHECK: ERROR: AddressSanitizer: stack-buffer-underflow -// CHECK: READ of size 4 at -// CHECK: is located in stack of thread -- cgit v1.2.1 From b340d2cc8cfa5f26019be4e14a03873d41341e32 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Fri, 28 Jul 2017 19:49:22 +0000 Subject: Add clear_cache implementation for ppc64. Fix buffer to meet ppc64 alignment. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309423 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 16 +++++++++++++++- test/builtins/Unit/clear_cache_test.c | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index af4ca619a..3c6570db6 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -165,6 +165,21 @@ void __clear_cache(void *start, void *end) { for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); +#elif defined (__powerpc64__) && defined(__LITTLE_ENDIAN__) + const size_t line_size = 32; + const size_t len = (uintptr_t)end - (uintptr_t)start; + + const uintptr_t mask = ~(line_size - 1); + const uintptr_t start_line = ((uintptr_t)start) & mask; + const uintptr_t end_line = ((uintptr_t)start + len + line_size - 1) & mask; + + for (uintptr_t line = start_line; line < end_line; line += line_size) + __asm__ volatile("dcbf 0, %0" : : "r"(line)); + __asm__ volatile("sync"); + + for (uintptr_t line = start_line; line < end_line; line += line_size) + __asm__ volatile("icbi 0, %0" : : "r"(line)); + __asm__ volatile("isync"); #else #if __APPLE__ /* On Darwin, sys_icache_invalidate() provides this functionality */ @@ -174,4 +189,3 @@ void __clear_cache(void *start, void *end) { #endif #endif } - diff --git a/test/builtins/Unit/clear_cache_test.c b/test/builtins/Unit/clear_cache_test.c index 58960ce3c..e50e66f5e 100644 --- a/test/builtins/Unit/clear_cache_test.c +++ b/test/builtins/Unit/clear_cache_test.c @@ -52,7 +52,7 @@ memcpy_f(void *dst, const void *src, size_t n) { #endif } -unsigned char execution_buffer[128]; +unsigned char execution_buffer[128] __attribute__((aligned(8))); int main() { -- cgit v1.2.1 From 7810a905a4c21031e7a5e8b8a8fde70ec40b5fa5 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 28 Jul 2017 19:52:31 +0000 Subject: Add end-to-end tests for overflows of byval arguments. Summary: Included is one test for passing structs by value and one test for passing C++ objects by value. Reviewers: eugenis, vitalybuka Reviewed By: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34827 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309424 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/pass-object-byval.cc | 36 ++++++++++++++++++++++++++ test/asan/TestCases/pass-struct-byval-uar.cc | 38 ++++++++++++++++++++++++++++ test/asan/TestCases/pass-struct-byval.cc | 23 +++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 test/asan/TestCases/pass-object-byval.cc create mode 100644 test/asan/TestCases/pass-struct-byval-uar.cc create mode 100644 test/asan/TestCases/pass-struct-byval.cc diff --git a/test/asan/TestCases/pass-object-byval.cc b/test/asan/TestCases/pass-object-byval.cc new file mode 100644 index 000000000..189fcbeb2 --- /dev/null +++ b/test/asan/TestCases/pass-object-byval.cc @@ -0,0 +1,36 @@ +// Verify that objects passed by value get red zones and that the copy +// constructor is called. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ +// RUN: Assertion{{.*}}failed +#include + +class A { + public: + A() : me(this) {} + A(const A &other) : me(this) { + for (int i = 0; i < 8; ++i) a[i] = other.a[i]; + } + + int a[8]; + A *me; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + assert(a.me == &a); + bar(&a); +} + +int main() { + A a; + foo(a); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread diff --git a/test/asan/TestCases/pass-struct-byval-uar.cc b/test/asan/TestCases/pass-struct-byval-uar.cc new file mode 100644 index 000000000..3f2fd09c6 --- /dev/null +++ b/test/asan/TestCases/pass-struct-byval-uar.cc @@ -0,0 +1,38 @@ +// Test that use-after-return works with arguments passed by value. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-NO-UAR %s +// RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-UAR %s +// +// On several architectures, the IR does not use byval arguments for foo() and +// instead creates a copy in main() and gives foo() a pointer to the copy. In +// that case, ASAN has nothing to poison on return from foo() and will not +// detect the UAR. +// REQUIRES: x86_64-target-arch, linux, not-android + +#include + +struct A { + int a[8]; +}; + +A *foo(A a) { + return &a; +} + +int main() { + A *a = foo(A()); + a->a[0] = 7; + std::fprintf(stderr, "\n"); // Ensures some output is generated for FileCheck + // to verify in the case where UAR is not + // detected. +} + +// CHECK-NO-UAR-NOT: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-NO-UAR-NOT: WRITE of size 4 at +// CHECK-NO-UAR-NOT: Memory access at offset {{[0-9]+}} is inside this variable +// +// CHECK-UAR: ERROR: AddressSanitizer: stack-use-after-return +// CHECK-UAR: WRITE of size 4 at +// CHECK-UAR: Memory access at offset {{[0-9]+}} is inside this variable diff --git a/test/asan/TestCases/pass-struct-byval.cc b/test/asan/TestCases/pass-struct-byval.cc new file mode 100644 index 000000000..ba49eccf4 --- /dev/null +++ b/test/asan/TestCases/pass-struct-byval.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +struct A { + int a[8]; +}; + +int bar(A *a) { + int *volatile ptr = &a->a[0]; + return *(ptr - 1); +} + +void foo(A a) { + bar(&a); +} + +int main() { + foo(A()); +} + +// CHECK: ERROR: AddressSanitizer: stack-buffer-underflow +// CHECK: READ of size 4 at +// CHECK: is located in stack of thread -- cgit v1.2.1 From 64531a13cdf81d045c934b7235f0d54861c245ea Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Fri, 28 Jul 2017 20:29:29 +0000 Subject: [compiler-rt] Add missing quotation marks to msan_compile invocation git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309430 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index 9d130bb3b..04428958e 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -85,7 +85,7 @@ set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests") macro(add_msan_tests_for_arch arch kind cflags) # Build gtest instrumented with MSan. set(MSAN_INST_GTEST) - msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} ${kind} + msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}" "${cflags}") # Instrumented tests. -- cgit v1.2.1 From de4bce9053a9eef9c3ed3e5fb0157c7da6261a44 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 28 Jul 2017 21:43:23 +0000 Subject: Try to fix asan test on sanitizer-windows git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309440 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/pass-object-byval.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/asan/TestCases/pass-object-byval.cc b/test/asan/TestCases/pass-object-byval.cc index 189fcbeb2..b99360fa7 100644 --- a/test/asan/TestCases/pass-object-byval.cc +++ b/test/asan/TestCases/pass-object-byval.cc @@ -3,6 +3,10 @@ // RUN: %clangxx_asan -O0 %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s --implicit-check-not \ // RUN: Assertion{{.*}}failed + +// ASan instrumentation can't insert red-zones around inalloca parameters. +// XFAIL: win32 && asan-32-bits + #include class A { -- cgit v1.2.1 From 1c338cbe701cacb8136b58b0a62766b8ffe51fb5 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 29 Jul 2017 00:20:02 +0000 Subject: [ubsan] Diagnose invalid uses of builtins (compiler-rt) Differential Revision: https://reviews.llvm.org/D34591 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309461 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_checks.inc | 1 + lib/ubsan/ubsan_handlers.cc | 24 +++++++++++++++++++++++ lib/ubsan/ubsan_handlers.h | 15 +++++++++++++++ lib/ubsan/ubsan_interface.inc | 2 ++ test/ubsan/TestCases/Misc/builtins.cpp | 35 ++++++++++++++++++++++++++++++++++ test/ubsan/lit.common.cfg | 2 ++ 6 files changed, 79 insertions(+) create mode 100644 test/ubsan/TestCases/Misc/builtins.cpp diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc index 0a87e6e8e..73c693632 100644 --- a/lib/ubsan/ubsan_checks.inc +++ b/lib/ubsan/ubsan_checks.inc @@ -29,6 +29,7 @@ UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow", 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(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_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 75a4490a1..06438a5d3 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -437,6 +437,30 @@ void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, Die(); } +static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + ErrorType ET = ErrorType::InvalidBuiltin; + + if (ignoreReport(Loc, Opts, ET)) + return; + + ScopedReport R(Opts, Loc, ET); + + Diag(Loc, DL_Error, + "passing zero to %0, which is not a valid argument") + << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()"); +} + +void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) { + GET_REPORT_OPTIONS(true); + handleInvalidBuiltin(Data, Opts); +} +void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { + GET_REPORT_OPTIONS(true); + handleInvalidBuiltin(Data, Opts); + Die(); +} + static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, ValueHandle Function, ReportOptions Opts) { diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 796321b81..5a9e902ce 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -122,6 +122,21 @@ struct InvalidValueData { /// \brief Handle a load of an invalid value for the type. RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val) +/// Known builtin check kinds. +/// Keep in sync with the enum of the same name in CodeGenFunction.h +enum BuiltinCheckKind : unsigned char { + BCK_CTZPassedZero, + BCK_CLZPassedZero, +}; + +struct InvalidBuiltinData { + SourceLocation Loc; + unsigned char Kind; +}; + +/// Handle a builtin called in an invalid way. +RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data) + struct FunctionTypeMismatchData { SourceLocation Loc; const TypeDescriptor &Type; diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index a69ca57cd..4c8f92e4f 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -19,6 +19,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_invalid_builtin) +INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort) INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value) INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value_abort) INTERFACE_FUNCTION(__ubsan_handle_missing_return) diff --git a/test/ubsan/TestCases/Misc/builtins.cpp b/test/ubsan/TestCases/Misc/builtins.cpp new file mode 100644 index 000000000..18c68b591 --- /dev/null +++ b/test/ubsan/TestCases/Misc/builtins.cpp @@ -0,0 +1,35 @@ +// REQUIRES: arch=x86_64 +// +// RUN: %clangxx -fsanitize=builtin -w %s -O3 -o %t +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER +// RUN: %clangxx -fsanitize=builtin -fno-sanitize-recover=builtin -w %s -O3 -o %t.abort +// RUN: not %run %t.abort 2>&1 | FileCheck %s --check-prefix=ABORT + +void check_ctz(int n) { + // ABORT: builtins.cpp:[[@LINE+2]]:17: runtime error: passing zero to ctz(), which is not a valid argument + // RECOVER: builtins.cpp:[[@LINE+1]]:17: runtime error: passing zero to ctz(), which is not a valid argument + __builtin_ctz(n); + + // RECOVER: builtins.cpp:[[@LINE+1]]:18: runtime error: passing zero to ctz(), which is not a valid argument + __builtin_ctzl(n); + + // RECOVER: builtins.cpp:[[@LINE+1]]:19: runtime error: passing zero to ctz(), which is not a valid argument + __builtin_ctzll(n); +} + +void check_clz(int n) { + // RECOVER: builtins.cpp:[[@LINE+1]]:17: runtime error: passing zero to clz(), which is not a valid argument + __builtin_clz(n); + + // RECOVER: builtins.cpp:[[@LINE+1]]:18: runtime error: passing zero to clz(), which is not a valid argument + __builtin_clzl(n); + + // RECOVER: builtins.cpp:[[@LINE+1]]:19: runtime error: passing zero to clz(), which is not a valid argument + __builtin_clzll(n); +} + +int main() { + check_ctz(0); + check_clz(0); + return 0; +} diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index e3a1367e7..b55fb5f6e 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -77,3 +77,5 @@ if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']: # because the test hangs or fails on one configuration and not the other. if config.target_arch.startswith('arm') == False and config.target_arch != 'aarch64': config.available_features.add('stable-runtime') + +config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 87f217d20bb24fa92a5882c2a565e1f14ad41e85 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 31 Jul 2017 05:16:20 +0000 Subject: [XRay][compiler-rt] Do not print the warning when the binary is not XRay instrumented. Summary: Currently when the XRay runtime is linked into a binary that doesn't have the instrumentation map, we print a warning unconditionally. This change attempts to make this behaviour more quiet. Reviewers: kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35789 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309534 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_init.cc | 3 ++- test/xray/TestCases/Linux/quiet-start.cc | 22 ++++++++++++++++++++++ test/xray/lit.cfg | 5 +++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/xray/TestCases/Linux/quiet-start.cc diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index aa660baa9..b46fa9880 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -49,7 +49,8 @@ XRaySledMap XRayInstrMap; void __xray_init() XRAY_NEVER_INSTRUMENT { initializeFlags(); if (__start_xray_instr_map == nullptr) { - Report("XRay instrumentation map missing. Not initializing XRay.\n"); + if (Verbosity()) + Report("XRay instrumentation map missing. Not initializing XRay.\n"); return; } diff --git a/test/xray/TestCases/Linux/quiet-start.cc b/test/xray/TestCases/Linux/quiet-start.cc new file mode 100644 index 000000000..08d3a8acc --- /dev/null +++ b/test/xray/TestCases/Linux/quiet-start.cc @@ -0,0 +1,22 @@ +// Ensure that we have a quiet startup when we don't have the XRay +// instrumentation sleds. +// +// RUN: %clangxx -std=c++11 %s -o %t %xraylib +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1" %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix NOISY +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=0" %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix QUIET +// RUN: XRAY_OPTIONS="" %run %t 2>&1 | FileCheck %s --check-prefix DEFAULT +#include + +using namespace std; + +int main(int, char**) { + // NOISY: {{.*}}XRay instrumentation map missing. Not initializing XRay. + // QUIET-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. + // DEFAULT-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. + cout << "Hello, XRay!" << endl; + // NOISY-NEXT: Hello, XRay! + // QUIET: Hello, XRay! + // DEFAULT: Hello, XRay! +} diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg index b07dcbd79..2852bdb74 100644 --- a/test/xray/lit.cfg +++ b/test/xray/lit.cfg @@ -31,6 +31,11 @@ config.substitutions.append( ('%clangxx_xray', build_invocation(clang_xray_cxxflags))) config.substitutions.append( ('%llvm_xray', llvm_xray)) +config.substitutions.append( + ('%xraylib', + ('-lm -lpthread -ldl -lrt -L%s ' + '-Wl,-whole-archive -lclang_rt.xray-%s -Wl,-no-whole-archive') + % (config.compiler_rt_libdir, config.host_arch))) # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -- cgit v1.2.1 From 9b7feef3201de0c6b551747085c3a1be8d64f80e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 31 Jul 2017 05:58:15 +0000 Subject: [sanitizer_common] Rename SI_NOT_WINDOWS to SI_POSIX Summary: New systems might be neither Windows nor POSIX. The SI_NOT_WINDOWS macro in sanitizer_platform_interceptors.h was already effectively the same as SI_POSIX, so just use SI_POSIX instead. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: phosek, filcab, llvm-commits, kubamracek Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36038 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309536 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_common_interceptors.inc | 6 +- .../sanitizer_platform_interceptors.h | 173 +++++++++++---------- 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 8607bf449..e6f0f1129 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -258,7 +258,7 @@ typedef AddrHashMap MetadataHashMap; static MetadataHashMap *interceptor_metadata_map; -#if SI_NOT_WINDOWS +#if SI_POSIX UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr, const FileMetadata &file) { MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr); @@ -285,7 +285,7 @@ UNUSED static void DeleteInterceptorMetadata(void *addr) { MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true); CHECK(h.exists()); } -#endif // SI_NOT_WINDOWS +#endif // SI_POSIX #if SANITIZER_INTERCEPT_STRLEN INTERCEPTOR(SIZE_T, strlen, const char *s) { @@ -886,7 +886,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) { #define INIT_FREXPF_FREXPL #endif // SANITIZER_INTERCEPT_FREXPF_FREXPL -#if SI_NOT_WINDOWS +#if SI_POSIX static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec, SIZE_T iovlen, SIZE_T maxlen) { for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 0380cee92..84cc9eb7f 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -16,19 +16,24 @@ #include "sanitizer_internal_defs.h" +#if SANITIZER_POSIX +# define SI_POSIX 1 +#else +# define SI_POSIX 0 +#endif + #if !SANITIZER_WINDOWS # define SI_WINDOWS 0 -# define SI_NOT_WINDOWS 1 -# include "sanitizer_platform_limits_posix.h" #else # define SI_WINDOWS 1 -# define SI_NOT_WINDOWS 0 #endif -#if SANITIZER_POSIX -# define SI_POSIX 1 -#else -# define SI_POSIX 0 +#if (SI_POSIX != 0) == (SI_WINDOWS != 0) +# error "Windows is not POSIX!" +#endif + +#if SI_POSIX +# include "sanitizer_platform_limits_posix.h" #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -75,10 +80,10 @@ # define SI_IOS 0 #endif -#if !SANITIZER_WINDOWS && !SANITIZER_MAC -# define SI_UNIX_NOT_MAC 1 +#if SANITIZER_POSIX && !SANITIZER_MAC +# define SI_POSIX_NOT_MAC 1 #else -# define SI_UNIX_NOT_MAC 0 +# define SI_POSIX_NOT_MAC 0 #endif #if SANITIZER_LINUX && !SANITIZER_FREEBSD @@ -91,7 +96,7 @@ #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 #define SANITIZER_INTERCEPT_STRSTR 1 -#define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX #define SANITIZER_INTERCEPT_STRTOK 1 #define SANITIZER_INTERCEPT_STRCHR 1 #define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC @@ -99,7 +104,7 @@ #define SANITIZER_INTERCEPT_STRSPN 1 #define SANITIZER_INTERCEPT_STRPBRK 1 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX #define SANITIZER_INTERCEPT_MEMSET 1 #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 @@ -114,24 +119,23 @@ #endif // memmem on Darwin doesn't exist on 10.6 // FIXME: enable memmem on Windows. -#define SANITIZER_INTERCEPT_MEMMEM \ - (SI_NOT_WINDOWS && !SI_MAC_DEPLOYMENT_BELOW_10_7) +#define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7) #define SANITIZER_INTERCEPT_MEMCHR 1 #define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) -#define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_READ SI_POSIX +#define SANITIZER_INTERCEPT_PREAD SI_POSIX +#define SANITIZER_INTERCEPT_WRITE SI_POSIX +#define SANITIZER_INTERCEPT_PWRITE SI_POSIX -#define SANITIZER_INTERCEPT_FREAD SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_FWRITE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FREAD SI_POSIX +#define SANITIZER_INTERCEPT_FWRITE SI_POSIX #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_READV SI_POSIX +#define SANITIZER_INTERCEPT_WRITEV SI_POSIX #define SANITIZER_INTERCEPT_PREADV \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) @@ -141,22 +145,22 @@ #define SANITIZER_INTERCEPT_PRCTL SI_LINUX -#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX +#define SANITIZER_INTERCEPT_STRPTIME SI_POSIX -#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SCANF SI_POSIX #define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID #ifndef SANITIZER_INTERCEPT_PRINTF -# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS +# define SANITIZER_INTERCEPT_PRINTF SI_POSIX # define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif #define SANITIZER_INTERCEPT_FREXP 1 -#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX -#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETPWENT \ @@ -166,32 +170,32 @@ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SETPWENT (SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_CLOCK_GETTIME (SI_FREEBSD || SI_NETBSD || SI_LINUX) -#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_GETITIMER SI_POSIX +#define SANITIZER_INTERCEPT_TIME SI_POSIX #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_WAIT SI_POSIX +#define SANITIZER_INTERCEPT_INET SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX +#define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX +#define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX +#define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX +#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_POSIX #define SANITIZER_INTERCEPT_GETHOSTBYNAME_R (SI_FREEBSD || SI_LINUX) #define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R \ (SI_FREEBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX +#define SANITIZER_INTERCEPT_ACCEPT SI_POSIX #define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_SENDMSG SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_MODF SI_POSIX +#define SANITIZER_INTERCEPT_RECVMSG SI_POSIX +#define SANITIZER_INTERCEPT_SENDMSG SI_POSIX +#define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX +#define SANITIZER_INTERCEPT_IOCTL SI_POSIX +#define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX -#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_READDIR SI_POSIX #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID #if SI_LINUX_NOT_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ @@ -201,42 +205,42 @@ #else #define SANITIZER_INTERCEPT_PTRACE 0 #endif -#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SETLOCALE SI_POSIX +#define SANITIZER_INTERCEPT_GETCWD SI_POSIX #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRTOIMAX SI_POSIX +#define SANITIZER_INTERCEPT_MBSTOWCS SI_POSIX #define SANITIZER_INTERCEPT_MBSNRTOWCS (SI_MAC || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX #define SANITIZER_INTERCEPT_WCSNRTOMBS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_WCRTOMB \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_REALPATH SI_POSIX #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CONFSTR \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STRERROR SI_POSIX +#define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX +#define SANITIZER_INTERCEPT_POLL SI_POSIX #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WORDEXP \ (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGSETOPS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX +#define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX #define SANITIZER_INTERCEPT_BACKTRACE \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX @@ -248,8 +252,8 @@ #define SANITIZER_INTERCEPT_STATVFS \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX +#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX #define SANITIZER_INTERCEPT_ETHER_HOST \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) @@ -257,30 +261,30 @@ (SI_NETBSD || ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ SANITIZER_WORDSIZE == 64)) // NOLINT #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_TMPNAM SI_POSIX #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_TTYNAME_R SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX +#define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX #define SANITIZER_INTERCEPT_SINCOS SI_LINUX -#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_REMQUO SI_POSIX +#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX) #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID @@ -288,7 +292,7 @@ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ICONV \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_TIMES SI_POSIX // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE \ @@ -297,7 +301,7 @@ #define SANITIZER_INTERCEPT__EXIT \ (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC) -#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) @@ -318,17 +322,17 @@ #define SANITIZER_INTERCEPT_AEABI_MEM 0 #endif #define SANITIZER_INTERCEPT___BZERO SI_MAC -#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_NOT_WINDOWS) +#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX) #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TSEARCH \ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FOPEN SI_POSIX #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM (SI_LINUX_NOT_ANDROID || SI_NETBSD) #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FFLUSH SI_POSIX +#define SANITIZER_INTERCEPT_FCLOSE SI_POSIX #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE #define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ @@ -339,10 +343,10 @@ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_MLOCKX SI_POSIX #define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SEM (SI_LINUX || SI_FREEBSD || SI_NETBSD) -#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX #define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD) #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX #define SANITIZER_INTERCEPT_CTERMID \ @@ -350,19 +354,18 @@ #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD) #define SANITIZER_INTERCEPTOR_HOOKS (SI_LINUX || SI_MAC || SI_WINDOWS) -#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_SEND_SENDTO SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX +#define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX #define SANITIZER_INTERCEPT_STAT \ (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD) -#define SANITIZER_INTERCEPT___XSTAT \ - (!SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS) +#define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX) #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT #define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_UTMP (SI_NOT_WINDOWS && !SI_MAC && !SI_FREEBSD) +#define SANITIZER_INTERCEPT_UTMP (SI_POSIX && !SI_MAC && !SI_FREEBSD) #define SANITIZER_INTERCEPT_UTMPX (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD) #define SANITIZER_INTERCEPT_GETLOADAVG \ @@ -376,6 +379,6 @@ #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_WCSCAT SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H -- cgit v1.2.1 From 1421294197a63a343207b96347efa718962752cd Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Mon, 31 Jul 2017 06:01:39 +0000 Subject: [builtins] Fix mingw-w64 cross compilation Lowercase the Windows.h include in enable_execute_stack.c, just as in emutls.c in SVN r302340. Differential Revision: https://reviews.llvm.org/D36066 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309537 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/enable_execute_stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/enable_execute_stack.c b/lib/builtins/enable_execute_stack.c index 0dc3482c4..327d460b4 100644 --- a/lib/builtins/enable_execute_stack.c +++ b/lib/builtins/enable_execute_stack.c @@ -22,7 +22,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN -#include +#include #else #ifndef __APPLE__ #include -- cgit v1.2.1 From da26635ad1bd32f654102730632ed70dbbe36ecd Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 31 Jul 2017 06:09:57 +0000 Subject: [XRay][compiler-rt] Require build-in-tree and x86_64-linux. The quiet-start.cc test currently fails for arm (and potentially other platforms). This change limits it to x86_64-linux. Follow-up to D35789. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309538 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/quiet-start.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/xray/TestCases/Linux/quiet-start.cc b/test/xray/TestCases/Linux/quiet-start.cc index 08d3a8acc..42d9f8847 100644 --- a/test/xray/TestCases/Linux/quiet-start.cc +++ b/test/xray/TestCases/Linux/quiet-start.cc @@ -7,6 +7,10 @@ // RUN: XRAY_OPTIONS="patch_premain=true verbosity=0" %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix QUIET // RUN: XRAY_OPTIONS="" %run %t 2>&1 | FileCheck %s --check-prefix DEFAULT +// +// FIXME: Understand how to make this work on other platforms +// REQUIRES: built-in-llvm-tree +// REQRUIES: x86_64-linux #include using namespace std; -- cgit v1.2.1 From b5c7208211b31e7f38caf52f3de1eebb66370320 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 31 Jul 2017 06:21:13 +0000 Subject: [sanitizer_common] Add SANITIZER_FUCHSIA Summary: More changes to follow will add the Fuchsia port. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits, phosek, filcab Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36027 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309539 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 396f7c934..e65671533 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -14,7 +14,7 @@ #define SANITIZER_PLATFORM_H #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ - !defined(__APPLE__) && !defined(_WIN32) + !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) # error "This operating system is not supported" #endif @@ -85,6 +85,12 @@ # define SANITIZER_ANDROID 0 #endif +#if defined(__Fuchsia__) +# define SANITIZER_FUCHSIA 1 +#else +# define SANITIZER_FUCHSIA 0 +#endif + #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD) -- cgit v1.2.1 From 30f6f020ab010db825f79a0dcaca0be18cd12d9d Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 31 Jul 2017 06:21:38 +0000 Subject: [XRay][compiler-rt] Fix typo for REQUIRES. Follow-up on D35789. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309540 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/quiet-start.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/xray/TestCases/Linux/quiet-start.cc b/test/xray/TestCases/Linux/quiet-start.cc index 42d9f8847..409e1788f 100644 --- a/test/xray/TestCases/Linux/quiet-start.cc +++ b/test/xray/TestCases/Linux/quiet-start.cc @@ -10,7 +10,7 @@ // // FIXME: Understand how to make this work on other platforms // REQUIRES: built-in-llvm-tree -// REQRUIES: x86_64-linux +// REQUIRES: x86_64-linux #include using namespace std; -- cgit v1.2.1 From 73b1687daa69da4a9364a440f3f95b97932140d3 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 31 Jul 2017 06:48:34 +0000 Subject: [asan] Move shadow memory setup into its own file Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Subscribers: kubamracek, mgorny, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36037 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309542 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/CMakeLists.txt | 1 + lib/asan/asan_internal.h | 4 ++ lib/asan/asan_rtl.cc | 126 +----------------------------------- lib/asan/asan_shadow_setup.cc | 144 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 125 deletions(-) create mode 100644 lib/asan/asan_shadow_setup.cc diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 6cb994aac..57c34051b 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -22,6 +22,7 @@ set(ASAN_SOURCES asan_posix.cc asan_report.cc asan_rtl.cc + asan_shadow_setup.cc asan_stack.cc asan_stats.cc asan_suppressions.cc diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index f09bbd83a..3cfd75f49 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -69,8 +69,12 @@ void InitializePlatformExceptionHandlers(); bool IsSystemHeapAddress(uptr addr); // asan_rtl.cc +void PrintAddressSpaceLayout(); void NORETURN ShowStatsAndAbort(); +// asan_shadow_setup.cc +void InitializeShadowMemory(); + // asan_malloc_linux.cc / asan_malloc_mac.cc void ReplaceSystemMalloc(); diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 5ae3568ae..376c50b58 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -84,26 +84,6 @@ void ShowStatsAndAbort() { Die(); } -// ---------------------- mmap -------------------- {{{1 -// Reserve memory range [beg, end]. -// We need to use inclusive range because end+1 may not be representable. -void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { - CHECK_EQ((beg % GetMmapGranularity()), 0); - CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); - uptr size = end - beg + 1; - DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - void *res = MmapFixedNoReserve(beg, size, name); - if (res != (void*)beg) { - Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " - "Perhaps you're using ulimit -v\n", size); - Abort(); - } - if (common_flags()->no_huge_pages_for_shadow) - NoHugePagesInRegion(beg, size); - if (common_flags()->use_madv_dontdump) - DontDumpShadowMemory(beg, size); -} - // --------------- LowLevelAllocateCallbac ---------- {{{1 static void OnLowLevelAllocate(uptr ptr, uptr size) { PoisonShadow(ptr, size, kAsanInternalHeapMagic); @@ -335,46 +315,7 @@ static void InitializeHighMemEnd() { CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); } -static void ProtectGap(uptr addr, uptr size) { - if (!flags()->protect_shadow_gap) { - // The shadow gap is unprotected, so there is a chance that someone - // is actually using this memory. Which means it needs a shadow... - uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); - uptr GapShadowEnd = - RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; - if (Verbosity()) - Printf("protect_shadow_gap=0:" - " not protecting shadow gap, allocating gap's shadow\n" - "|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg, - GapShadowEnd); - ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, - "unprotected gap shadow"); - return; - } - void *res = MmapFixedNoAccess(addr, size, "shadow gap"); - if (addr == (uptr)res) - return; - // A few pages at the start of the address space can not be protected. - // But we really want to protect as much as possible, to prevent this memory - // being returned as a result of a non-FIXED mmap(). - if (addr == kZeroBaseShadowStart) { - uptr step = GetMmapGranularity(); - while (size > step && addr < kZeroBaseMaxShadowStart) { - addr += step; - size -= step; - void *res = MmapFixedNoAccess(addr, size, "shadow gap"); - if (addr == (uptr)res) - return; - } - } - - Report("ERROR: Failed to protect the shadow gap. " - "ASan cannot proceed correctly. ABORTING.\n"); - DumpProcessMap(); - Die(); -} - -static void PrintAddressSpaceLayout() { +void PrintAddressSpaceLayout() { Printf("|| `[%p, %p]` || HighMem ||\n", (void*)kHighMemBeg, (void*)kHighMemEnd); Printf("|| `[%p, %p]` || HighShadow ||\n", @@ -426,71 +367,6 @@ static void PrintAddressSpaceLayout() { kHighShadowBeg > kMidMemEnd); } -static void InitializeShadowMemory() { - // Set the shadow memory address to uninitialized. - __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; - - uptr shadow_start = kLowShadowBeg; - // Detect if a dynamic shadow address must used and find a available location - // when necessary. When dynamic address is used, the macro |kLowShadowBeg| - // expands to |__asan_shadow_memory_dynamic_address| which is - // |kDefaultShadowSentinel|. - if (shadow_start == kDefaultShadowSentinel) { - __asan_shadow_memory_dynamic_address = 0; - CHECK_EQ(0, kLowShadowBeg); - shadow_start = FindDynamicShadowStart(); - } - // Update the shadow memory address (potentially) used by instrumentation. - __asan_shadow_memory_dynamic_address = shadow_start; - - if (kLowShadowBeg) - shadow_start -= GetMmapGranularity(); - bool full_shadow_is_available = - MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); - -#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ - !ASAN_FIXED_MAPPING - if (!full_shadow_is_available) { - kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; - kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; - } -#endif - - if (Verbosity()) PrintAddressSpaceLayout(); - - if (full_shadow_is_available) { - // mmap the low shadow plus at least one page at the left. - if (kLowShadowBeg) - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); - // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); - // protect the gap. - ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); - CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); - } else if (kMidMemBeg && - MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && - MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { - CHECK(kLowShadowBeg != kLowShadowEnd); - // mmap the low shadow plus at least one page at the left. - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); - // mmap the mid shadow. - ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); - // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); - // protect the gaps. - ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); - ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); - ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); - } else { - Report("Shadow memory range interleaves with an existing memory mapping. " - "ASan cannot proceed correctly. ABORTING.\n"); - Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", - shadow_start, kHighShadowEnd); - DumpProcessMap(); - Die(); - } -} - static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc new file mode 100644 index 000000000..b36e35780 --- /dev/null +++ b/lib/asan/asan_shadow_setup.cc @@ -0,0 +1,144 @@ +//===-- asan_shadow_setup.cc ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Set up the shadow memory. +//===----------------------------------------------------------------------===// + +#include "asan_internal.h" +#include "asan_mapping.h" + +namespace __asan { + +// ---------------------- mmap -------------------- {{{1 +// Reserve memory range [beg, end]. +// We need to use inclusive range because end+1 may not be representable. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { + CHECK_EQ((beg % GetMmapGranularity()), 0); + CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); + uptr size = end - beg + 1; + DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. + void *res = MmapFixedNoReserve(beg, size, name); + if (res != (void *)beg) { + Report( + "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " + "Perhaps you're using ulimit -v\n", + size); + Abort(); + } + if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size); + if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); +} + +static void ProtectGap(uptr addr, uptr size) { + if (!flags()->protect_shadow_gap) { + // The shadow gap is unprotected, so there is a chance that someone + // is actually using this memory. Which means it needs a shadow... + uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); + uptr GapShadowEnd = + RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; + if (Verbosity()) + Printf( + "protect_shadow_gap=0:" + " not protecting shadow gap, allocating gap's shadow\n" + "|| `[%p, %p]` || ShadowGap's shadow ||\n", + GapShadowBeg, GapShadowEnd); + ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, + "unprotected gap shadow"); + return; + } + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) return; + // A few pages at the start of the address space can not be protected. + // But we really want to protect as much as possible, to prevent this memory + // being returned as a result of a non-FIXED mmap(). + if (addr == kZeroBaseShadowStart) { + uptr step = GetMmapGranularity(); + while (size > step && addr < kZeroBaseMaxShadowStart) { + addr += step; + size -= step; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) return; + } + } + + Report( + "ERROR: Failed to protect the shadow gap. " + "ASan cannot proceed correctly. ABORTING.\n"); + DumpProcessMap(); + Die(); +} + +void InitializeShadowMemory() { + // Set the shadow memory address to uninitialized. + __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; + + uptr shadow_start = kLowShadowBeg; + // Detect if a dynamic shadow address must used and find a available location + // when necessary. When dynamic address is used, the macro |kLowShadowBeg| + // expands to |__asan_shadow_memory_dynamic_address| which is + // |kDefaultShadowSentinel|. + if (shadow_start == kDefaultShadowSentinel) { + __asan_shadow_memory_dynamic_address = 0; + CHECK_EQ(0, kLowShadowBeg); + shadow_start = FindDynamicShadowStart(); + } + // Update the shadow memory address (potentially) used by instrumentation. + __asan_shadow_memory_dynamic_address = shadow_start; + + if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); + bool full_shadow_is_available = + MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); + +#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ + !ASAN_FIXED_MAPPING + if (!full_shadow_is_available) { + kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; + kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; + } +#endif + + if (Verbosity()) PrintAddressSpaceLayout(); + + if (full_shadow_is_available) { + // mmap the low shadow plus at least one page at the left. + if (kLowShadowBeg) + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); + // mmap the high shadow. + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); + // protect the gap. + ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); + CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); + } else if (kMidMemBeg && + MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && + MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { + CHECK(kLowShadowBeg != kLowShadowEnd); + // mmap the low shadow plus at least one page at the left. + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); + // mmap the mid shadow. + ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); + // mmap the high shadow. + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); + // protect the gaps. + ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); + ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); + ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); + } else { + Report( + "Shadow memory range interleaves with an existing memory mapping. " + "ASan cannot proceed correctly. ABORTING.\n"); + Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", + shadow_start, kHighShadowEnd); + DumpProcessMap(); + Die(); + } +} + +} // namespace __asan -- cgit v1.2.1 From f0878f1e7f4e67ed9c574ccd8b82093a201928e9 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 31 Jul 2017 06:58:09 +0000 Subject: [XRay][compiler-rt] Fix test to not be too strict with output order. Follow-up to D35789. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309543 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/quiet-start.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/xray/TestCases/Linux/quiet-start.cc b/test/xray/TestCases/Linux/quiet-start.cc index 409e1788f..e26fa63aa 100644 --- a/test/xray/TestCases/Linux/quiet-start.cc +++ b/test/xray/TestCases/Linux/quiet-start.cc @@ -20,7 +20,7 @@ int main(int, char**) { // QUIET-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. // DEFAULT-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. cout << "Hello, XRay!" << endl; - // NOISY-NEXT: Hello, XRay! + // NOISY: Hello, XRay! // QUIET: Hello, XRay! // DEFAULT: Hello, XRay! } -- cgit v1.2.1 From 84b9dd08af3cabe2c588ea9775c42575da45fd40 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 31 Jul 2017 18:45:17 +0000 Subject: [msan] Check for pvalloc overflow Summary: `CheckForPvallocOverflow` was introduced with D35818 to detect when pvalloc would wrap when rounding up to the next multiple of the page size. Add this check to MSan's pvalloc implementation. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36093 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309601 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_allocator.cc | 6 +++++- lib/msan/tests/msan_test.cc | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 1034dbdf9..1b134e15a 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -255,8 +255,12 @@ void *msan_valloc(uptr size, StackTrace *stack) { void *msan_pvalloc(uptr size, StackTrace *stack) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { + errno = errno_ENOMEM; + return Allocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. - size = size == 0 ? PageSize : RoundUpTo(size, PageSize); + size = size ? RoundUpTo(size, PageSize) : PageSize; return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); } diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index b2d5f7c60..b4cc8493a 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3449,6 +3449,17 @@ TEST(MemorySanitizer, pvalloc) { EXPECT_EQ(0U, (uintptr_t)p % PageSize); EXPECT_EQ(PageSize, __sanitizer_get_allocated_size(p)); free(p); + + // Overflows in pvalloc should be caught. + errno = 0; + p = pvalloc((uintptr_t)-PageSize); + EXPECT_EQ(p, nullptr); + EXPECT_EQ(errno, ENOMEM); + + errno = 0; + p = pvalloc((uintptr_t)-1); + EXPECT_EQ(p, nullptr); + EXPECT_EQ(errno, ENOMEM); } #endif -- cgit v1.2.1 From 8d6193b01a9e7cda1a4b46a8211804b8a804f457 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 31 Jul 2017 20:39:32 +0000 Subject: Remove STL/microsoft-specific CFI blacklist entries Patch by Vlad Tsyrklevich! Differential Revision: https://reviews.llvm.org/D35855 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309617 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi_blacklist.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index cc111be81..2006d0b86 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -1,12 +1,3 @@ -# Standard library types. -type:std::* - -# The stdext namespace contains Microsoft standard library extensions. -type:stdext::* - -# Types with a uuid attribute, i.e. COM types. -type:attr:uuid - # STL allocators (T *allocator::allocate(size_type, const void*)). # The type signature mandates a cast from uninitialized void* to T*. # size_type can either be unsigned int (j) or unsigned long (m). -- cgit v1.2.1 From 0be3d11da345e02fcb1fe9dd5832377d68d46253 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Mon, 31 Jul 2017 22:23:17 +0000 Subject: Add powerpc64 to compiler-rt build infrastructure. Summary: Add powerpc64 to compiler-rt build infrastructure. Reviewers: timshen Reviewed By: timshen Subscribers: nemanjai, dberris, mgorny, aheejin, cfe-commits Differential Revision: https://reviews.llvm.org/D36108 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309634 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 6 ++++++ cmake/builtin-config-ix.cmake | 2 +- lib/builtins/CMakeLists.txt | 14 ++++++++++++++ lib/builtins/clear_cache.c | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 3b3a0c153..a04352440 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -167,6 +167,8 @@ macro(detect_target_arch) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) + check_symbol_exists(__powerpc64__ "" __PPC64) + check_symbol_exists(__powerpc64le__ "" __PPC64LE) check_symbol_exists(__s390x__ "" __S390X) check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32) check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64) @@ -184,6 +186,10 @@ macro(detect_target_arch) add_default_target_arch(mips64) elseif(__MIPS) add_default_target_arch(mips) + elseif(__PPC64) + add_default_target_arch(powerpc64) + elseif(__PPC64LE) + add_default_target_arch(powerpc64le) elseif(__S390X) add_default_target_arch(s390x) elseif(__WEBASSEMBLY32) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 20bc68476..23ec500e4 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -40,7 +40,7 @@ if(APPLE) endif() set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} - ${MIPS32} ${MIPS64} ${WASM32} ${WASM64}) + ${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64}) include(CompilerRTUtils) include(CompilerRTDarwinUtils) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index f0d3f5071..840042715 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -458,6 +458,20 @@ set(mips64_SOURCES ${GENERIC_TF_SOURCES} set(mips64el_SOURCES ${GENERIC_TF_SOURCES} ${mips_SOURCES}) +set(powerpc64_SOURCES + ppc/divtc3.c + ppc/fixtfdi.c + ppc/fixunstfdi.c + ppc/floatditf.c + ppc/floatunditf.c + ppc/gcc_qadd.c + ppc/gcc_qdiv.c + ppc/gcc_qmul.c + ppc/gcc_qsub.c + ppc/multc3.c + ${GENERIC_SOURCES}) +set(powerpc64le_SOURCES ${powerpc64_SOURCES}) + set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 3c6570db6..e21ac08f8 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -165,7 +165,7 @@ void __clear_cache(void *start, void *end) { for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); -#elif defined (__powerpc64__) && defined(__LITTLE_ENDIAN__) +#elif defined (__powerpc64__) const size_t line_size = 32; const size_t len = (uintptr_t)end - (uintptr_t)start; -- cgit v1.2.1 From 42a455c34ed860066b92b8957fa9dd786026939d Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 31 Jul 2017 22:46:01 +0000 Subject: [msan] Reverting D36093 Summary: Reverting D36093 until I can figure out how to launch the correct tests :/ My apologies. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36120 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309637 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_allocator.cc | 4 ---- lib/msan/tests/msan_test.cc | 11 ----------- 2 files changed, 15 deletions(-) diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 1b134e15a..8e9d4d397 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -255,10 +255,6 @@ void *msan_valloc(uptr size, StackTrace *stack) { void *msan_pvalloc(uptr size, StackTrace *stack) { uptr PageSize = GetPageSizeCached(); - if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { - errno = errno_ENOMEM; - return Allocator::FailureHandler::OnBadRequest(); - } // pvalloc(0) should allocate one page. size = size ? RoundUpTo(size, PageSize) : PageSize; return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index b4cc8493a..b2d5f7c60 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3449,17 +3449,6 @@ TEST(MemorySanitizer, pvalloc) { EXPECT_EQ(0U, (uintptr_t)p % PageSize); EXPECT_EQ(PageSize, __sanitizer_get_allocated_size(p)); free(p); - - // Overflows in pvalloc should be caught. - errno = 0; - p = pvalloc((uintptr_t)-PageSize); - EXPECT_EQ(p, nullptr); - EXPECT_EQ(errno, ENOMEM); - - errno = 0; - p = pvalloc((uintptr_t)-1); - EXPECT_EQ(p, nullptr); - EXPECT_EQ(errno, ENOMEM); } #endif -- cgit v1.2.1 From add8c7766a630d6a21adb1cb26304563f1c728a6 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 31 Jul 2017 22:46:43 +0000 Subject: [sanitizer] Fix the sanitizer build on Android Android uses libgcc name even for shared library unlike other platforms which use libgcc_s. Furthemore, Android libstdc++ has a dependency on libdl. These need to be handled while performing CMake checks. Differential Revision: https://reviews.llvm.org/D36035 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309638 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 6 +++++- cmake/config-ix.cmake | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed3e01d23..294904b50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,7 +279,11 @@ if (SANITIZER_USE_COMPILER_RT) find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY) list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY}) else() - append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS) + if (ANDROID) + append_list_if(COMPILER_RT_HAS_GCC_LIB gcc SANITIZER_COMMON_LINK_LIBS) + else() + append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS) + endif() endif() append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 64c1347c6..192c9b052 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -14,7 +14,11 @@ endfunction() check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC) if (NOT SANITIZER_USE_COMPILER_RT) - check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB) + if (ANDROID) + check_library_exists(gcc __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_LIB) + else() + check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB) + endif() endif() check_c_compiler_flag(-nodefaultlibs COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) @@ -29,6 +33,8 @@ if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG) list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}") elseif (COMPILER_RT_HAS_GCC_S_LIB) list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + elseif (COMPILER_RT_HAS_GCC_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc) endif () endif () @@ -98,6 +104,10 @@ check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL) check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT) check_library_exists(m pow "" COMPILER_RT_HAS_LIBM) check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD) +if (ANDROID AND COMPILER_RT_HAS_LIBDL) + # Android's libstdc++ has a dependency on libdl. + list(APPEND CMAKE_REQUIRED_LIBRARIES dl) +endif() check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX) # Linker flags. -- cgit v1.2.1 From 1549687ffb2e74eb1b9689827b5fa109934a6273 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 31 Jul 2017 23:08:27 +0000 Subject: [sancov] Fix coverage-reset test on Android/i686. DSO coverage may be dumped in any order. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309639 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/coverage-reset.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/asan/TestCases/Posix/coverage-reset.cc b/test/asan/TestCases/Posix/coverage-reset.cc index 89311c39f..201bf8e53 100644 --- a/test/asan/TestCases/Posix/coverage-reset.cc +++ b/test/asan/TestCases/Posix/coverage-reset.cc @@ -27,8 +27,8 @@ int main(int argc, char **argv) { bar2(); __sanitizer_cov_dump(); // CHECK: RESET -// CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written -// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written +// CHECK-DAG: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 2 PCs written +// CHECK-DAG: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 2 PCs written fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); @@ -36,8 +36,8 @@ int main(int argc, char **argv) { bar1(); __sanitizer_cov_dump(); // CHECK: RESET -// CHECK: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 1 PCs written -// CHECK: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 1 PCs written +// CHECK-DAG: SanitizerCoverage: ./coverage-reset.cc{{.*}}.sancov: 1 PCs written +// CHECK-DAG: SanitizerCoverage: ./libcoverage-reset.cc{{.*}}.sancov: 1 PCs written fprintf(stderr, "RESET\n"); __sanitizer_cov_reset(); -- cgit v1.2.1 From fd528d76eb64da7db6274685209f62063184e106 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 1 Aug 2017 04:24:05 +0000 Subject: [sanitizer-coverage] dummy definitions for __sanitizer_cov_8bit_counters_init and __sanitizer_cov_pcs_init git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309655 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_interface.inc | 2 ++ lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 87ae9c038..0ed113f59 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -25,3 +25,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 0614901aa..56cfd1c1f 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -201,4 +201,6 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" -- cgit v1.2.1 From a0c6823f72d3ac2d9768c1bef21f0c327de5c612 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 07:45:46 +0000 Subject: [sanitizer-coverage] Fix Windows build broken by r309655 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309665 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_interface_internal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h index 9c1f1ad33..043c73eed 100644 --- a/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/lib/sanitizer_common/sanitizer_interface_internal.h @@ -94,6 +94,10 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_trace_pc_guard_init(__sanitizer::u32*, __sanitizer::u32*); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_8bit_counters_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_pcs_init(); } // extern "C" #endif // SANITIZER_INTERFACE_INTERNAL_H -- cgit v1.2.1 From 1a764aafc6f0c5a78c77e5125bc40507db8ed5f7 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Tue, 1 Aug 2017 17:16:05 +0000 Subject: Revert rL309634 until upstream buildbots have upgraded libc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309704 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 6 ------ cmake/builtin-config-ix.cmake | 2 +- lib/builtins/CMakeLists.txt | 14 -------------- lib/builtins/clear_cache.c | 2 +- 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index a04352440..3b3a0c153 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -167,8 +167,6 @@ macro(detect_target_arch) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) - check_symbol_exists(__powerpc64__ "" __PPC64) - check_symbol_exists(__powerpc64le__ "" __PPC64LE) check_symbol_exists(__s390x__ "" __S390X) check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32) check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64) @@ -186,10 +184,6 @@ macro(detect_target_arch) add_default_target_arch(mips64) elseif(__MIPS) add_default_target_arch(mips) - elseif(__PPC64) - add_default_target_arch(powerpc64) - elseif(__PPC64LE) - add_default_target_arch(powerpc64le) elseif(__S390X) add_default_target_arch(s390x) elseif(__WEBASSEMBLY32) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 23ec500e4..20bc68476 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -40,7 +40,7 @@ if(APPLE) endif() set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} - ${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64}) + ${MIPS32} ${MIPS64} ${WASM32} ${WASM64}) include(CompilerRTUtils) include(CompilerRTDarwinUtils) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 840042715..f0d3f5071 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -458,20 +458,6 @@ set(mips64_SOURCES ${GENERIC_TF_SOURCES} set(mips64el_SOURCES ${GENERIC_TF_SOURCES} ${mips_SOURCES}) -set(powerpc64_SOURCES - ppc/divtc3.c - ppc/fixtfdi.c - ppc/fixunstfdi.c - ppc/floatditf.c - ppc/floatunditf.c - ppc/gcc_qadd.c - ppc/gcc_qdiv.c - ppc/gcc_qmul.c - ppc/gcc_qsub.c - ppc/multc3.c - ${GENERIC_SOURCES}) -set(powerpc64le_SOURCES ${powerpc64_SOURCES}) - set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index e21ac08f8..3c6570db6 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -165,7 +165,7 @@ void __clear_cache(void *start, void *end) { for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); -#elif defined (__powerpc64__) +#elif defined (__powerpc64__) && defined(__LITTLE_ENDIAN__) const size_t line_size = 32; const size_t len = (uintptr_t)end - (uintptr_t)start; -- cgit v1.2.1 From ba0e4f947e27ade26d7c572e04daca89f3f309fc Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 20:48:36 +0000 Subject: [ubsan] Enable UBSan build for Fuchsia Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: srhines, kubamracek, mgorny, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36033 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309742 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/ubsan/ubsan_platform.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 192c9b052..5ab9f0264 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -533,7 +533,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia") set(COMPILER_RT_HAS_UBSAN TRUE) else() set(COMPILER_RT_HAS_UBSAN FALSE) diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h index 1a3bfd6af..26e89f8c9 100644 --- a/lib/ubsan/ubsan_platform.h +++ b/lib/ubsan/ubsan_platform.h @@ -19,7 +19,7 @@ defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \ defined(__s390__)) # define CAN_SANITIZE_UB 1 -#elif defined(_WIN32) +#elif defined(_WIN32) || defined(__Fuchsia__) # define CAN_SANITIZE_UB 1 #else # define CAN_SANITIZE_UB 0 -- cgit v1.2.1 From c6c5f9c9c5579d6b5f38c0aa03cf5f135bf1ec1a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 21:15:19 +0000 Subject: [sanitizer_common] Fuchsia support for interceptors Summary: Actually Fuchsia non-support for interceptors. Fuchsia doesn't use interceptors in the common sense at all. Almost all system library functions don't need interception at all, because the system libraries are just themselves compiled with sanitizers enabled and have specific hook interfaces where needed to inform the sanitizer runtime about thread lifetimes and the like. For the few functions that do get intercepted, they don't use a generic mechanism like dlsym with RTLD_NEXT to find the underlying system library function. Instead, they use specific extra symbol names published by the system library (e.g. __unsanitized_memcpy). Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc, filcab Reviewed By: filcab Subscribers: kubamracek, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36028 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309745 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception.h | 37 +++++++++++++++---- .../sanitizer_platform_interceptors.h | 42 +++++++++++++--------- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/lib/interception/interception.h b/lib/interception/interception.h index d79fa67ba..2d280731e 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -15,8 +15,8 @@ #ifndef INTERCEPTION_H #define INTERCEPTION_H -#if !defined(__linux__) && !defined(__FreeBSD__) && \ - !defined(__APPLE__) && !defined(_WIN32) +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) && \ + !defined(_WIN32) && !defined(__Fuchsia__) # error "Interception doesn't work on this operating system." #endif @@ -139,7 +139,7 @@ const interpose_substitution substitution_##func_name[] \ # define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__) \ __attribute__((alias("__interceptor_" #func), visibility("default"))); -#else +#elif !defined(__Fuchsia__) # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) @@ -148,7 +148,15 @@ const interpose_substitution substitution_##func_name[] \ __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); #endif -#if !defined(__APPLE__) +#if defined(__Fuchsia__) +// There is no general interception at all on Fuchsia. +// Sanitizer runtimes just define functions directly to preempt them, +// and have bespoke ways to access the underlying libc functions. +# include +# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) +# define REAL(x) __unsanitized_##x +# define DECLARE_REAL(ret_type, func, ...) +#elif !defined(__APPLE__) # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) # define FUNC_TYPE(x) x##_f @@ -166,15 +174,19 @@ const interpose_substitution substitution_##func_name[] \ # define ASSIGN_REAL(x, y) #endif // __APPLE__ +#if !defined(__Fuchsia__) #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ DECLARE_REAL(ret_type, func, __VA_ARGS__) \ extern "C" ret_type WRAP(func)(__VA_ARGS__); +#else +#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) +#endif // Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR // macros does its job. In exceptional cases you may need to call REAL(foo) // without defining INTERCEPTOR(..., foo, ...). For example, if you override // foo with an interceptor for other function. -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__Fuchsia__) # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -184,7 +196,18 @@ const interpose_substitution substitution_##func_name[] \ # define DEFINE_REAL(ret_type, func, ...) #endif -#if !defined(__APPLE__) +#if defined(__Fuchsia__) + +// We need to define the __interceptor_func name just to get +// sanitizer_common/scripts/gen_dynamic_list.py to export func. +// But we don't need to export __interceptor_func to get that. +#define INTERCEPTOR(ret_type, func, ...) \ + extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \ + __interceptor_##func(__VA_ARGS__); \ + extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__) + +#elif !defined(__APPLE__) + #define INTERCEPTOR(ret_type, func, ...) \ DEFINE_REAL(ret_type, func, __VA_ARGS__) \ DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ @@ -251,7 +274,7 @@ typedef unsigned long uptr; // NOLINT # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ INTERCEPT_FUNCTION_VER_MAC(func, symver) -#else // defined(_WIN32) +#elif defined(_WIN32) # include "interception_win.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 84cc9eb7f..276b5c490 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -28,7 +28,7 @@ # define SI_WINDOWS 1 #endif -#if (SI_POSIX != 0) == (SI_WINDOWS != 0) +#if (SI_POSIX != 0) == (SI_WINDOWS != 0) && !SANITIZER_FUCHSIA # error "Windows is not POSIX!" #endif @@ -80,6 +80,12 @@ # define SI_IOS 0 #endif +#if SANITIZER_FUCHSIA +# define SI_NOT_FUCHSIA 0 +#else +# define SI_NOT_FUCHSIA 1 +#endif + #if SANITIZER_POSIX && !SANITIZER_MAC # define SI_POSIX_NOT_MAC 1 #else @@ -92,23 +98,23 @@ # define SI_LINUX_NOT_FREEBSD 0 #endif -#define SANITIZER_INTERCEPT_STRLEN 1 -#define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC -#define SANITIZER_INTERCEPT_STRCMP 1 -#define SANITIZER_INTERCEPT_STRSTR 1 +#define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) +#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX -#define SANITIZER_INTERCEPT_STRTOK 1 -#define SANITIZER_INTERCEPT_STRCHR 1 -#define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC -#define SANITIZER_INTERCEPT_STRRCHR 1 -#define SANITIZER_INTERCEPT_STRSPN 1 -#define SANITIZER_INTERCEPT_STRPBRK 1 +#define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC +#define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX #define SANITIZER_INTERCEPT_MEMSET 1 #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 -#define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX #define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ @@ -120,7 +126,7 @@ // memmem on Darwin doesn't exist on 10.6 // FIXME: enable memmem on Windows. #define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7) -#define SANITIZER_INTERCEPT_MEMCHR 1 +#define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) #define SANITIZER_INTERCEPT_READ SI_POSIX @@ -157,7 +163,7 @@ # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif -#define SANITIZER_INTERCEPT_FREXP 1 +#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX @@ -372,10 +378,12 @@ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) -#define SANITIZER_INTERCEPT_PVALLOC (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) -#define SANITIZER_INTERCEPT_CFREE (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PVALLOC \ + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) +#define SANITIZER_INTERCEPT_CFREE \ + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID -- cgit v1.2.1 From 3982c2153bab743e9677dc4ef2d085c11a6594c4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 21:28:39 +0000 Subject: [sanitizer_common] Disable filesystem-related code for Fuchsia Summary: Fuchsia doesn't support filesystem access per se at low level. So it won't use any of the filesystem-oriented code in sanitizer_common. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: kubamracek, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36029 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309749 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_libcdep.cc | 15 ++++++++++++++- lib/sanitizer_common/sanitizer_file.cc | 6 ++++++ lib/sanitizer_common/sanitizer_suppressions.cc | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 82d223a29..b54503a6d 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -26,12 +26,25 @@ namespace __sanitizer { +#if !SANITIZER_FUCHSIA + bool ReportFile::SupportsColors() { SpinMutexLock l(mu); ReopenIfNecessary(); return SupportsColoredOutput(fd); } +static INLINE bool ReportSupportsColors() { + return report_file.SupportsColors(); +} + +#else // SANITIZER_FUCHSIA + +// Fuchsia's logs always go through post-processing that handles colorization. +static INLINE bool ReportSupportsColors() { return true; } + +#endif // !SANITIZER_FUCHSIA + bool ColorizeReports() { // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color // printing on Windows. @@ -40,7 +53,7 @@ bool ColorizeReports() { const char *flag = common_flags()->color; return internal_strcmp(flag, "always") == 0 || - (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors()); + (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); } static void (*sandboxing_callback)(); diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc index dfbe99c56..cde54bfde 100644 --- a/lib/sanitizer_common/sanitizer_file.cc +++ b/lib/sanitizer_common/sanitizer_file.cc @@ -14,6 +14,10 @@ // //===---------------------------------------------------------------------===// +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA + #include "sanitizer_common.h" #include "sanitizer_file.h" @@ -169,3 +173,5 @@ void __sanitizer_set_report_fd(void *fd) { report_file.fd_pid = internal_getpid(); } } // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index d9e26b8fc..89ddfddd1 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -51,6 +51,7 @@ void SuppressionContext::ParseFromFile(const char *filename) { if (filename[0] == '\0') return; +#if !SANITIZER_FUCHSIA // If we cannot find the file, check if its location is relative to // the location of the executable. InternalScopedString new_file_path(kMaxPathLength); @@ -59,6 +60,7 @@ void SuppressionContext::ParseFromFile(const char *filename) { new_file_path.size())) { filename = new_file_path.data(); } +#endif // !SANITIZER_FUCHSIA // Read the file. VPrintf(1, "%s: reading suppressions file at %s\n", -- cgit v1.2.1 From 55414c1d124546b452292fdf28dc9ef5bf326085 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 22:22:25 +0000 Subject: [sanitizer_common] Fuchsia OS support code Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: cryptoad, srhines, kubamracek, mgorny, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36031 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309756 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 5 + cmake/config-ix.cmake | 2 +- lib/sanitizer_common/CMakeLists.txt | 2 + lib/sanitizer_common/sanitizer_fuchsia.cc | 504 ++++++++++++++++++++++++++++++ lib/sanitizer_common/sanitizer_fuchsia.h | 31 ++ lib/sanitizer_common/sanitizer_printf.cc | 4 +- 6 files changed, 546 insertions(+), 2 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_fuchsia.cc create mode 100644 lib/sanitizer_common/sanitizer_fuchsia.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 294904b50..5fbc8554c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,6 +288,11 @@ endif() append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia") + list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs,-z,now,-z,relro) + list(APPEND SANITIZER_COMMON_LINK_LIBS magenta) +endif() + # Warnings to turn off for all libraries, not just sanitizers. append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 5ab9f0264..68c00db08 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -470,7 +470,7 @@ set(COMPILER_RT_SANITIZERS_TO_BUILD ${ALL_SANITIZERS} CACHE STRING list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD" OR + (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|Fuchsia" OR (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN)))) set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE) else() diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index a0831e80e..36134999a 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -10,6 +10,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_file.cc sanitizer_flags.cc sanitizer_flag_parser.cc + sanitizer_fuchsia.cc sanitizer_libc.cc sanitizer_libignore.cc sanitizer_linux.cc @@ -101,6 +102,7 @@ set(SANITIZER_HEADERS sanitizer_flag_parser.h sanitizer_flags.h sanitizer_flags.inc + sanitizer_fuchsia.h sanitizer_interface_internal.h sanitizer_internal_defs.h sanitizer_lfstack.h diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc new file mode 100644 index 000000000..e45a28418 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -0,0 +1,504 @@ +//===-- sanitizer_fuchsia.cc ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and other sanitizer +// run-time libraries and implements Fuchsia-specific functions from +// sanitizer_common.h. +//===---------------------------------------------------------------------===// + +#include "sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_stacktrace.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace __sanitizer { + +void NORETURN internal__exit(int exitcode) { _mx_process_exit(exitcode); } + +uptr internal_sched_yield() { + mx_status_t status = _mx_nanosleep(0); + CHECK_EQ(status, MX_OK); + return 0; // Why doesn't this return void? +} + +static void internal_nanosleep(mx_time_t ns) { + mx_status_t status = _mx_nanosleep(_mx_deadline_after(ns)); + CHECK_EQ(status, MX_OK); +} + +unsigned int internal_sleep(unsigned int seconds) { + internal_nanosleep(MX_SEC(seconds)); + return 0; +} + +u64 NanoTime() { return _mx_time_get(MX_CLOCK_UTC); } + +uptr internal_getpid() { + mx_info_handle_basic_t info; + mx_status_t status = + _mx_object_get_info(_mx_process_self(), MX_INFO_HANDLE_BASIC, &info, + sizeof(info), NULL, NULL); + CHECK_EQ(status, MX_OK); + uptr pid = static_cast(info.koid); + CHECK_EQ(pid, info.koid); + return pid; +} + +uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } + +uptr GetTid() { return GetThreadSelf(); } + +void Abort() { abort(); } + +int Atexit(void (*function)(void)) { return atexit(function); } + +void SleepForSeconds(int seconds) { internal_sleep(seconds); } + +void SleepForMillis(int millis) { internal_nanosleep(MX_MSEC(millis)); } + +void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { + pthread_attr_t attr; + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + void *base; + size_t size; + CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); + CHECK_EQ(pthread_attr_destroy(&attr), 0); + + *stack_bottom = reinterpret_cast(base); + *stack_top = *stack_bottom + size; +} + +void MaybeReexec() {} +void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} +void DisableCoreDumperIfNecessary() {} +void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void SetAlternateSignalStack() {} +void UnsetAlternateSignalStack() {} +void InitTlsSize() {} + +void PrintModuleMap() {} + +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = static_cast(param); + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = _Unwind_GetIP(ctx); + if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP + : _URC_NO_REASON); +} + +void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + CHECK_GT(size, 0); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + PopStackFrames(Min(to_pop, static_cast(1))); + trace_buffer[0] = pc; +} + +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, + u32 max_depth) { + CHECK_NE(context, nullptr); + UNREACHABLE("signal context doesn't exist"); +} + +enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; + +BlockingMutex::BlockingMutex() { + // NOTE! It's important that this use internal_memset, because plain + // memset might be intercepted (e.g., actually be __asan_memset). + // Defining this so the compiler initializes each field, e.g.: + // BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {} + // might result in the compiler generating a call to memset, which would + // have the same problem. + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + CHECK_EQ(owner_, 0); + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) + return; + while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { + mx_status_t status = _mx_futex_wait(reinterpret_cast(m), + MtxSleeping, MX_TIME_INFINITE); + if (status != MX_ERR_BAD_STATE) // Normal race. + CHECK_EQ(status, MX_OK); + } +} + +void BlockingMutex::Unlock() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); + CHECK_NE(v, MtxUnlocked); + if (v == MtxSleeping) { + mx_status_t status = _mx_futex_wake(reinterpret_cast(m), 1); + CHECK_EQ(status, MX_OK); + } +} + +void BlockingMutex::CheckLocked() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); +} + +uptr GetPageSize() { return PAGE_SIZE; } + +uptr GetMmapGranularity() { return PAGE_SIZE; } + +sanitizer_shadow_bounds_t ShadowBounds; + +uptr GetMaxVirtualAddress() { + ShadowBounds = __sanitizer_shadow_bounds(); + return ShadowBounds.memory_limit - 1; +} + +static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, + bool raw_report, bool die_for_nomem) { + size = RoundUpTo(size, PAGE_SIZE); + + mx_handle_t vmo; + mx_status_t status = _mx_vmo_create(size, 0, &vmo); + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "mx_vmo_create", status, + raw_report); + return nullptr; + } + _mx_object_set_property(vmo, MX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + uintptr_t addr; + status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, size, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &addr); + _mx_handle_close(vmo); + + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "mx_vmar_map", status, + raw_report); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast(addr); +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + return DoAnonymousMmapOrDie(size, mem_type, raw_report, true); +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + return DoAnonymousMmapOrDie(size, mem_type, false, false); +} + +// MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. +// Instead of doing exactly what they say, we make MmapNoAccess actually +// just allocate a VMAR to reserve the address space. Then MmapFixedOrDie +// uses that VMAR instead of the root. + +mx_handle_t allocator_vmar = MX_HANDLE_INVALID; +uintptr_t allocator_vmar_base; +size_t allocator_vmar_size; + +void *MmapNoAccess(uptr size) { + size = RoundUpTo(size, PAGE_SIZE); + CHECK_EQ(allocator_vmar, MX_HANDLE_INVALID); + uintptr_t base; + mx_status_t status = + _mx_vmar_allocate(_mx_vmar_root_self(), 0, size, + MX_VM_FLAG_CAN_MAP_READ | MX_VM_FLAG_CAN_MAP_WRITE | + MX_VM_FLAG_CAN_MAP_SPECIFIC, + &allocator_vmar, &base); + if (status != MX_OK) + ReportMmapFailureAndDie(size, "sanitizer allocator address space", + "mx_vmar_allocate", status); + + allocator_vmar_base = base; + allocator_vmar_size = size; + return reinterpret_cast(base); +} + +constexpr const char kAllocatorVmoName[] = "sanitizer_allocator"; + +static void *DoMmapFixedOrDie(uptr fixed_addr, uptr size, bool die_for_nomem) { + size = RoundUpTo(size, PAGE_SIZE); + + mx_handle_t vmo; + mx_status_t status = _mx_vmo_create(size, 0, &vmo); + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, kAllocatorVmoName, "mx_vmo_create", status); + return nullptr; + } + _mx_object_set_property(vmo, MX_PROP_NAME, kAllocatorVmoName, + sizeof(kAllocatorVmoName) - 1); + + DCHECK_GE(fixed_addr, allocator_vmar_base); + uintptr_t offset = fixed_addr - allocator_vmar_base; + DCHECK_LE(size, allocator_vmar_size); + DCHECK_GE(allocator_vmar_size - offset, size); + + uintptr_t addr; + status = _mx_vmar_map( + allocator_vmar, offset, vmo, 0, size, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE | MX_VM_FLAG_SPECIFIC, + &addr); + _mx_handle_close(vmo); + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, kAllocatorVmoName, "mx_vmar_map", status); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast(addr); +} + +void *MmapFixedOrDie(uptr fixed_addr, uptr size) { + return DoMmapFixedOrDie(fixed_addr, size, true); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { + return DoMmapFixedOrDie(fixed_addr, size, false); +} + +// This should never be called. +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + UNIMPLEMENTED(); +} + +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK_GE(size, PAGE_SIZE); + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + + mx_handle_t vmo; + mx_status_t status = _mx_vmo_create(size, 0, &vmo); + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "mx_vmo_create", status, false); + return nullptr; + } + _mx_object_set_property(vmo, MX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + + // Map a larger size to get a chunk of address space big enough that + // it surely contains an aligned region of the requested size. Then + // overwrite the aligned middle portion with a mapping from the + // beginning of the VMO, and unmap the excess before and after. + size_t map_size = size + alignment; + uintptr_t addr; + status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, map_size, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &addr); + if (status == MX_OK) { + uintptr_t map_addr = addr; + uintptr_t map_end = map_addr + map_size; + addr = RoundUpTo(map_addr, alignment); + uintptr_t end = addr + size; + if (addr != map_addr) { + mx_info_vmar_t info; + status = _mx_object_get_info(_mx_vmar_root_self(), MX_INFO_VMAR, &info, + sizeof(info), NULL, NULL); + if (status == MX_OK) { + uintptr_t new_addr; + status = + _mx_vmar_map(_mx_vmar_root_self(), addr - info.base, vmo, 0, size, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE | + MX_VM_FLAG_SPECIFIC_OVERWRITE, + &new_addr); + if (status == MX_OK) CHECK_EQ(new_addr, addr); + } + } + if (status == MX_OK && addr != map_addr) + status = _mx_vmar_unmap(_mx_vmar_root_self(), map_addr, addr - map_addr); + if (status == MX_OK && end != map_end) + status = _mx_vmar_unmap(_mx_vmar_root_self(), end, map_end - end); + } + _mx_handle_close(vmo); + + if (status != MX_OK) { + if (status != MX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "mx_vmar_map", status, false); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast(addr); +} + +void UnmapOrDie(void *addr, uptr size) { + if (!addr || !size) return; + size = RoundUpTo(size, PAGE_SIZE); + + mx_status_t status = _mx_vmar_unmap(_mx_vmar_root_self(), + reinterpret_cast(addr), size); + if (status != MX_OK) { + Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, size, size, addr); + CHECK("unable to unmap" && 0); + } + + DecreaseTotalMmap(size); +} + +// This is used on the shadow mapping, which cannot be changed. +// Magenta doesn't have anything like MADV_DONTNEED. +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} + +void DumpProcessMap() { + UNIMPLEMENTED(); // TODO(mcgrathr): write it +} + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + // TODO(mcgrathr): Figure out a better way. + mx_handle_t vmo; + mx_status_t status = _mx_vmo_create(size, 0, &vmo); + if (status == MX_OK) { + while (size > 0) { + size_t wrote; + status = _mx_vmo_write(vmo, reinterpret_cast(beg), 0, size, + &wrote); + if (status != MX_OK) break; + CHECK_GT(wrote, 0); + CHECK_LE(wrote, size); + beg += wrote; + size -= wrote; + } + _mx_handle_close(vmo); + } + return status == MX_OK; +} + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + mx_handle_t vmo; + mx_status_t status = __sanitizer_get_configuration(file_name, &vmo); + if (status == MX_OK) { + uint64_t vmo_size; + status = _mx_vmo_get_size(vmo, &vmo_size); + if (status == MX_OK) { + if (vmo_size < max_len) max_len = vmo_size; + size_t map_size = RoundUpTo(max_len, PAGE_SIZE); + uintptr_t addr; + status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, map_size, + MX_VM_FLAG_PERM_READ, &addr); + if (status == MX_OK) { + *buff = reinterpret_cast(addr); + *buff_size = map_size; + *read_len = max_len; + } + } + _mx_handle_close(vmo); + } + if (status != MX_OK && errno_p) *errno_p = status; + return status == MX_OK; +} + +void RawWrite(const char *buffer) { + __sanitizer_log_write(buffer, internal_strlen(buffer)); +} + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + __sanitizer_log_write(buffer, length); +} + +char **StoredArgv; +char **StoredEnviron; + +char **GetArgv() { return StoredArgv; } + +const char *GetEnv(const char *name) { + if (StoredEnviron) { + uptr NameLen = internal_strlen(name); + for (char **Env = StoredEnviron; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return nullptr; +} + +uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { + const char *argv0 = StoredArgv[0]; + if (!argv0) argv0 = ""; + internal_strncpy(buf, argv0, buf_len); + return internal_strlen(buf); +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +uptr MainThreadStackBase, MainThreadStackSize; + +} // namespace __sanitizer + +using namespace __sanitizer; // NOLINT + +extern "C" { +void __sanitizer_startup_hook(int argc, char **argv, char **envp, + void *stack_base, size_t stack_size) { + __sanitizer::StoredArgv = argv; + __sanitizer::StoredEnviron = envp; + __sanitizer::MainThreadStackBase = reinterpret_cast(stack_base); + __sanitizer::MainThreadStackSize = stack_size; +} + +void __sanitizer_set_report_path(const char *path) { + // Handle the initialization code in each sanitizer, but no other calls. + // This setting is never consulted on Fuchsia. + DCHECK_EQ(path, common_flags()->log_path); +} + +void __sanitizer_set_report_fd(void *fd) { + UNREACHABLE("not available on Fuchsia"); +} +} // extern "C" + +#endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_fuchsia.h b/lib/sanitizer_common/sanitizer_fuchsia.h new file mode 100644 index 000000000..455eadf6f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_fuchsia.h @@ -0,0 +1,31 @@ +//===-- sanitizer_fuchsia.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// Fuchsia-specific sanitizer support. +// +//===---------------------------------------------------------------------===// +#ifndef SANITIZER_FUCHSIA_H +#define SANITIZER_FUCHSIA_H + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA + +#include "sanitizer_common.h" + +#include + +namespace __sanitizer { + +extern uptr MainThreadStackBase, MainThreadStackSize; +extern sanitizer_shadow_bounds_t ShadowBounds; + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA +#endif // SANITIZER_FUCHSIA_H diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index 520206441..a44cfae40 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -256,7 +256,9 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, RAW_CHECK_MSG(needed_length < kLen, \ "Buffer in Report is too short!\n"); \ } - if (append_pid) { + // Fuchsia's logging infrastructure always keeps track of the logging + // process, thread, and timestamp, so never prepend such information. + if (!SANITIZER_FUCHSIA && append_pid) { int pid = internal_getpid(); const char *exe_name = GetProcessName(); if (common_flags()->log_exe_name && exe_name) { -- cgit v1.2.1 From 73ea55e16c3724f1ea0caa30a34aad7427dd36f7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 1 Aug 2017 22:54:51 +0000 Subject: [sanitizer_common] Fuchsia-specific symbolizer Summary: Fuchsia doesn't support built-in symbolization per se at all. Instead, it always emits a Fuchsia-standard "symbolizer markup" format that makes it possible for a post-processing filter to massage the logs into symbolized format. Hence, it does not support user-specified formatting options for backtraces or other symbolization. Reviewers: vitalybuka, alekseyshl, kcc Subscribers: kubamracek, mgorny, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36032 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309760 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 1 + .../sanitizer_stacktrace_printer.cc | 6 ++ .../sanitizer_symbolizer_fuchsia.cc | 109 +++++++++++++++++++++ .../sanitizer_symbolizer_libcdep.cc | 23 +++-- 4 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 36134999a..0c16c6332 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -31,6 +31,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_stoptheworld_mac.cc sanitizer_suppressions.cc sanitizer_symbolizer.cc + sanitizer_symbolizer_fuchsia.cc sanitizer_symbolizer_libbacktrace.cc sanitizer_symbolizer_mac.cc sanitizer_symbolizer_win.cc diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index 587817f8e..78f07448a 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -13,9 +13,13 @@ #include "sanitizer_stacktrace_printer.h" #include "sanitizer_file.h" +#include "sanitizer_fuchsia.h" namespace __sanitizer { +// sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia. +#if !SANITIZER_FUCHSIA + static const char *StripFunctionName(const char *function, const char *prefix) { if (!function) return nullptr; if (!prefix) return function; @@ -147,6 +151,8 @@ void RenderData(InternalScopedString *buffer, const char *format, } } +#endif // !SANITIZER_FUCHSIA + void RenderSourceLocation(InternalScopedString *buffer, const char *file, int line, int column, bool vs_style, const char *strip_path_prefix) { diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc new file mode 100644 index 000000000..8e383dd8f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc @@ -0,0 +1,109 @@ +//===-- sanitizer_symbolizer_fuchsia.cc -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of Fuchsia-specific symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA + +#include "sanitizer_fuchsia.h" +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +// For Fuchsia we don't do any actual symbolization per se. +// Instead, we emit text containing raw addresses and raw linkage +// symbol names, embedded in Fuchsia's symbolization markup format. +// Fuchsia's logging infrastructure emits enough information about +// process memory layout that a post-processing filter can do the +// symbolization and pretty-print the markup. +// TODO(mcgrathr): URL to markup format document + +// This is used by UBSan for type names, and by ASan for global variable names. +constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; +constexpr uptr kFormatDemangleMax = 1024; // Arbitrary. + +// Function name or equivalent from PC location. +constexpr const char *kFormatFunction = "{{{pc:%p}}}"; +constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. + +// Global variable name or equivalent from data memory address. +constexpr const char *kFormatData = "{{{data:%p}}}"; + +// One frame in a backtrace (printed on a line by itself). +constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}"; + +// This is used by UBSan for type names, and by ASan for global variable names. +// It's expected to return a static buffer that will be reused on each call. +const char *Symbolizer::Demangle(const char *name) { + static char buffer[kFormatDemangleMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); + return buffer; +} + +// This is used mostly for suppression matching. Making it work +// would enable "interceptor_via_lib" suppressions. It's also used +// once in UBSan to say "in module ..." in a message that also +// includes an address in the module, so post-processing can already +// pretty-print that so as to indicate the module. +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + return false; +} + +// This is used in some places for suppression checking, which we +// don't really support for Fuchsia. It's also used in UBSan to +// identify a PC location to a function name, so we always fill in +// the function member with a string containing markup around the PC +// value. +// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan +// to render stack frames, but that should be changed to use +// RenderStackFrame. +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + SymbolizedStack *s = SymbolizedStack::New(addr); + char buffer[kFormatFunctionMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); + s->info.function = internal_strdup(buffer); + return s; +} + +// Always claim we succeeded, so that RenderDataInfo will be called. +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + info->Clear(); + info->start = addr; + return true; +} + +// We ignore the format argument to __sanitizer_symbolize_global. +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix) { + buffer->append(kFormatData, DI->start); +} + +// We don't support the stack_trace_format flag at all. +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + const AddressInfo &info, bool vs_style, + const char *strip_path_prefix, const char *strip_func_prefix) { + buffer->append(kFormatFrame, frame_no, info.address); +} + +Symbolizer *Symbolizer::PlatformInit() { + return new(symbolizer_allocator_) Symbolizer({}); +} + +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit(); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 614470a63..ba226e84c 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -17,6 +17,18 @@ namespace __sanitizer { +Symbolizer *Symbolizer::GetOrInit() { + SpinMutexLock l(&init_mu_); + if (symbolizer_) + return symbolizer_; + symbolizer_ = PlatformInit(); + CHECK(symbolizer_); + return symbolizer_; +} + +// See sanitizer_symbolizer_fuchsia.cc. +#if !SANITIZER_FUCHSIA + const char *ExtractToken(const char *str, const char *delims, char **result) { uptr prefix_len = internal_strcspn(str, delims); *result = (char*)InternalAlloc(prefix_len + 1); @@ -175,15 +187,6 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { return 0; } -Symbolizer *Symbolizer::GetOrInit() { - SpinMutexLock l(&init_mu_); - if (symbolizer_) - return symbolizer_; - symbolizer_ = PlatformInit(); - CHECK(symbolizer_); - return symbolizer_; -} - // For now we assume the following protocol: // For each request of the form // @@ -472,4 +475,6 @@ bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { return true; } +#endif // !SANITIZER_FUCHSIA + } // namespace __sanitizer -- cgit v1.2.1 From cd6d69c22ec4b19475b51fa7a677954b9da1ddb3 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 2 Aug 2017 04:51:40 +0000 Subject: [XRay][compiler-rt] Remove use of std::mutex and std::shared_ptr from global scope. Summary: This change attempts to remove all the dependencies we have on std::mutex and any std::shared_ptr construction in global variables. We instead use raw pointers to these objects, and construct them on the heap. In cases where it's possible, we lazily initialize these pointers. While we do not have a replacement for std::shared_ptr yet in compiler-rt, we use this work-around to avoid having to statically initialize the objects as globals. Subsequent changes should allow us to completely remove our dependency on std::shared_ptr and instead have our own implementation of the std::shared_ptr and std::weak_ptr semantics (or completely rewrite the implementaton to not need these standard-library provided abstractions). Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36078 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309792 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_records.h | 2 ++ lib/xray/xray_fdr_logging.cc | 20 +++++++++++++------- lib/xray/xray_fdr_logging_impl.h | 35 ++++++++++++++++++----------------- lib/xray/xray_inmemory_log.cc | 10 +++++----- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/include/xray/xray_records.h b/include/xray/xray_records.h index feb8d228b..506755dbd 100644 --- a/include/xray/xray_records.h +++ b/include/xray/xray_records.h @@ -17,6 +17,8 @@ #ifndef XRAY_XRAY_RECORDS_H #define XRAY_XRAY_RECORDS_H +#include + namespace __xray { enum FileTypes { diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index a7e1382c3..21a09bf12 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -39,7 +39,10 @@ namespace __xray { // Global BufferQueue. -std::shared_ptr BQ; +// NOTE: This is a pointer to avoid having to do atomic operations at +// initialization time. This is OK to leak as there will only be one bufferqueue +// for the runtime, initialized once through the fdrInit(...) sequence. +std::shared_ptr* BQ = nullptr; __sanitizer::atomic_sint32_t LogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; @@ -64,7 +67,7 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { // Make a copy of the BufferQueue pointer to prevent other threads that may be // resetting it from blowing away the queue prematurely while we're dealing // with it. - auto LocalBQ = BQ; + auto LocalBQ = *BQ; // We write out the file in the following format: // @@ -129,7 +132,7 @@ XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT { // Do special things to make the log finalize itself, and not allow any more // operations to be performed until re-initialized. - BQ->finalize(); + (*BQ)->finalize(); __sanitizer::atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_FINALIZED, @@ -146,7 +149,7 @@ XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { return static_cast(CurrentStatus); // Release the in-memory buffer queue. - BQ.reset(); + BQ->reset(); // Spin until the flushing status is flushed. s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; @@ -195,7 +198,7 @@ void fdrLoggingHandleArg0(int32_t FuncId, auto TSC_CPU = getTimestamp(); __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), std::get<1>(TSC_CPU), clock_gettime, - LoggingStatus, BQ); + LoggingStatus, *BQ); } void fdrLoggingHandleCustomEvent(void *Event, @@ -220,7 +223,7 @@ void fdrLoggingHandleCustomEvent(void *Event, (void)Once; } int32_t ReducedEventSize = static_cast(EventSize); - if (!isLogInitializedAndReady(LocalBQ, TSC, CPU, clock_gettime)) + if (!isLogInitializedAndReady(*LocalBQ, TSC, CPU, clock_gettime)) return; // Here we need to prepare the log to handle: @@ -268,7 +271,10 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, } bool Success = false; - BQ = std::make_shared(BufferSize, BufferMax, Success); + if (BQ == nullptr) + BQ = new std::shared_ptr(); + + *BQ = std::make_shared(BufferSize, BufferMax, Success); if (!Success) { Report("BufferQueue init failed.\n"); return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 4a1d80fd0..ce4f6cd53 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -169,8 +169,9 @@ public: // Make sure a thread that's ever called handleArg0 has a thread-local // live reference to the buffer queue for this particular instance of // FDRLogging, and that we're going to clean it up when the thread exits. -thread_local std::shared_ptr LocalBQ = nullptr; -thread_local ThreadExitBufferCleanup Cleanup(LocalBQ, Buffer); +thread_local std::shared_ptr* LocalBQ = + new std::shared_ptr(); +thread_local ThreadExitBufferCleanup Cleanup(*LocalBQ, Buffer); class RecursionGuard { bool &Running; @@ -451,8 +452,8 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, } } -inline bool releaseThreadLocalBuffer(BufferQueue *BQ) { - auto EC = BQ->releaseBuffer(Buffer); +inline bool releaseThreadLocalBuffer(BufferQueue &BQArg) { + auto EC = BQArg.releaseBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, BufferQueue::getErrorString(EC)); @@ -467,9 +468,9 @@ inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, char *BufferStart = static_cast(Buffer.Buffer); if ((RecordPtr + MaxSize) > (BufferStart + Buffer.Size - MetadataRecSize)) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) + if (!releaseThreadLocalBuffer(**LocalBQ)) return false; - auto EC = LocalBQ->getBuffer(Buffer); + auto EC = (*LocalBQ)->getBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to acquire a buffer; error=%s\n", BufferQueue::getErrorString(EC)); @@ -481,7 +482,7 @@ inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, } inline bool isLogInitializedAndReady( - std::shared_ptr &LocalBQ, uint64_t TSC, unsigned char CPU, + std::shared_ptr &LBQ, uint64_t TSC, unsigned char CPU, int (*wall_clock_reader)(clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { // Bail out right away if logging is not initialized yet. @@ -493,24 +494,24 @@ inline bool isLogInitializedAndReady( (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) + if (!releaseThreadLocalBuffer(*LBQ)) return false; RecordPtr = nullptr; - LocalBQ = nullptr; + LBQ = nullptr; return false; } return false; } - if (!loggingInitialized(LoggingStatus) || LocalBQ->finalizing()) { + if (!loggingInitialized(LoggingStatus) || LBQ->finalizing()) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) + if (!releaseThreadLocalBuffer(*LBQ)) return false; RecordPtr = nullptr; } if (Buffer.Buffer == nullptr) { - auto EC = LocalBQ->getBuffer(Buffer); + auto EC = LBQ->getBuffer(Buffer); if (EC != BufferQueue::ErrorCode::Ok) { auto LS = __sanitizer::atomic_load(&LoggingStatus, __sanitizer::memory_order_acquire); @@ -538,7 +539,7 @@ inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { auto BufferStart = static_cast(Buffer.Buffer); if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(LocalBQ.get())) + if (!releaseThreadLocalBuffer(**LocalBQ)) return; RecordPtr = nullptr; } @@ -563,10 +564,10 @@ inline void processFunctionHook( // In case the reference has been cleaned up before, we make sure we // initialize it to the provided BufferQueue. - if (LocalBQ == nullptr) - LocalBQ = BQ; + if ((*LocalBQ) == nullptr) + *LocalBQ = BQ; - if (!isLogInitializedAndReady(LocalBQ, TSC, CPU, wall_clock_reader)) + if (!isLogInitializedAndReady(*LocalBQ, TSC, CPU, wall_clock_reader)) return; // Before we go setting up writing new function entries, we need to be really @@ -606,7 +607,7 @@ inline void processFunctionHook( // Buffer, set it up properly before doing any further writing. // if (!prepareBuffer(wall_clock_reader, FunctionRecSize + MetadataRecSize)) { - LocalBQ = nullptr; + *LocalBQ = nullptr; return; } diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc index 83aecfaf7..2f407e2a3 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_inmemory_log.cc @@ -16,12 +16,12 @@ //===----------------------------------------------------------------------===// #include +#include #include -#include #include #include #include -#include +#include #include #include "sanitizer_common/sanitizer_libc.h" @@ -43,7 +43,7 @@ void __xray_InMemoryRawLog(int32_t FuncId, namespace __xray { -std::mutex LogMutex; +__sanitizer::SpinMutex LogMutex; class ThreadExitFlusher { int Fd; @@ -58,7 +58,7 @@ public: Offset(Offset) {} ~ThreadExitFlusher() XRAY_NEVER_INSTRUMENT { - std::lock_guard L(LogMutex); + __sanitizer::SpinMutexLock L(&LogMutex); if (Fd > 0 && Start != nullptr) { retryingWriteAll(Fd, reinterpret_cast(Start), reinterpret_cast(Start + Offset)); @@ -127,7 +127,7 @@ void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, R.FuncId = FuncId; ++Offset; if (Offset == BuffLen) { - std::lock_guard L(LogMutex); + __sanitizer::SpinMutexLock L(&LogMutex); auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); retryingWriteAll(Fd, reinterpret_cast(RecordBuffer), reinterpret_cast(RecordBuffer + Offset)); -- cgit v1.2.1 From 25f76046195f63958505de577a20416d529928f8 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 2 Aug 2017 07:51:38 +0000 Subject: [sanitizer_common] Fuchsia-specific implementation of SanitizerCoverage Submitted on behalf of Roland McGrath. Reviewers: kcc, eugenis, alekseyshl, vitalybuka Reviewed By: kcc Subscribers: filcab, vitalybuka, phosek, llvm-commits, kubamracek, mgorny Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35866 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309797 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 1 + lib/sanitizer_common/sanitizer_coverage_fuchsia.cc | 233 +++++++++++++++++++++ .../sanitizer_coverage_libcdep_new.cc | 5 + 3 files changed, 239 insertions(+) create mode 100644 lib/sanitizer_common/sanitizer_coverage_fuchsia.cc diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 0c16c6332..eb053929a 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -58,6 +58,7 @@ set(SANITIZER_NOLIBC_SOURCES set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc sancov_flags.cc + sanitizer_coverage_fuchsia.cc sanitizer_coverage_libcdep_new.cc sanitizer_coverage_win_sections.cc sanitizer_linux_libcdep.cc diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc new file mode 100644 index 000000000..9e5ff4bb9 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -0,0 +1,233 @@ +//===-- sanitizer_coverage_fuchsia.cc ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version. +// +// This Fuchsia-specific implementation uses the same basic scheme and the +// same simple '.sancov' file format as the generic implementation. The +// difference is that we just produce a single blob of output for the whole +// program, not a separate one per DSO. We do not sort the PC table and do +// not prune the zeros, so the resulting file is always as large as it +// would be to report 100% coverage. Implicit tracing information about +// the address ranges of DSOs allows offline tools to split the one big +// blob into separate files that the 'sancov' tool can understand. +// +// Unlike the traditional implementation that uses an atexit hook to write +// out data files at the end, the results on Fuchsia do not go into a file +// per se. The 'coverage_dir' option is ignored. Instead, they are stored +// directly into a shared memory object (a Magenta VMO). At exit, that VMO +// is handed over to a system service that's responsible for getting the +// data out to somewhere that it can be fed into the sancov tool (where and +// how is not our problem). + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" + +#include +#include +#include + +using namespace __sanitizer; // NOLINT + +namespace __sancov { +namespace { + +// TODO(mcgrathr): Move the constant into a header shared with other impls. +constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64"); + +constexpr const char kSancovSinkName[] = "sancov"; + +// Collects trace-pc guard coverage. +// This class relies on zero-initialization. +class TracePcGuardController { + public: + // For each PC location being tracked, there is a u32 reserved in global + // data called the "guard". At startup, we assign each guard slot a + // unique index into the big results array. Later during runtime, the + // first call to TracePcGuard (below) will store the corresponding PC at + // that index in the array. (Each later call with the same guard slot is + // presumed to be from the same PC.) Then it clears the guard slot back + // to zero, which tells the compiler not to bother calling in again. At + // the end of the run, we have a big array where each element is either + // zero or is a tracked PC location that was hit in the trace. + + // This is called from global constructors. Each translation unit has a + // contiguous array of guard slots, and a constructor that calls here + // with the bounds of its array. Those constructors are allowed to call + // here more than once for the same array. Usually all of these + // constructors run in the initial thread, but it's possible that a + // dlopen call on a secondary thread will run constructors that get here. + void InitTracePcGuard(u32 *start, u32 *end) { + if (end > start && *start == 0 && common_flags()->coverage) { + // Complete the setup before filling in any guards with indices. + // This avoids the possibility of code called from Setup reentering + // TracePcGuard. + u32 idx = Setup(end - start); + for (u32 *p = start; p < end; ++p) { + *p = idx++; + } + } + } + + void TracePcGuard(u32 *guard, uptr pc) { + atomic_uint32_t *guard_ptr = reinterpret_cast(guard); + u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); + if (idx > 0) array_[idx] = pc; + } + + void Dump() { + BlockingMutexLock locked(&setup_lock_); + if (array_) { + CHECK_NE(vmo_, MX_HANDLE_INVALID); + + // Publish the VMO to the system, where it can be collected and + // analyzed after this process exits. This always consumes the VMO + // handle. Any failure is just logged and not indicated to us. + __sanitizer_publish_data(kSancovSinkName, vmo_); + vmo_ = MX_HANDLE_INVALID; + + // This will route to __sanitizer_log_write, which will ensure + // that information about shared libraries is written out. + Printf("SanitizerCoverage: published '%s' with up to %u PCs\n", vmo_name_, + next_index_ - 1); + } + } + + private: + // We map in the largest possible view into the VMO: one word + // for every possible 32-bit index value. This avoids the need + // to change the mapping when increasing the size of the VMO. + // We can always spare the 32G of address space. + static constexpr size_t MappingSize = sizeof(uptr) << 32; + + BlockingMutex setup_lock_; + uptr *array_; + u32 next_index_; + mx_handle_t vmo_; + char vmo_name_[MX_MAX_NAME_LEN]; + + size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } + + u32 Setup(u32 num_guards) { + BlockingMutexLock locked(&setup_lock_); + DCHECK(common_flags()->coverage); + + if (next_index_ == 0) { + CHECK_EQ(vmo_, MX_HANDLE_INVALID); + CHECK_EQ(array_, nullptr); + + // The first sample goes at [1] to reserve [0] for the magic number. + next_index_ = 1 + num_guards; + + mx_status_t status = _mx_vmo_create(DataSize(), 0, &vmo_); + CHECK_EQ(status, MX_OK); + + // Give the VMO a name including our process KOID so it's easy to spot. + internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName, + internal_getpid()); + _mx_object_set_property(vmo_, MX_PROP_NAME, vmo_name_, + internal_strlen(vmo_name_)); + + // Map the largest possible view we might need into the VMO. Later + // we might need to increase the VMO's size before we can use larger + // indices, but we'll never move the mapping address so we don't have + // any multi-thread synchronization issues with that. + uintptr_t mapping; + status = + _mx_vmar_map(_mx_vmar_root_self(), 0, vmo_, 0, MappingSize, + MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &mapping); + CHECK_EQ(status, MX_OK); + + // Hereafter other threads are free to start storing into + // elements [1, next_index_) of the big array. + array_ = reinterpret_cast(mapping); + + // Store the magic number. + // Hereafter, the VMO serves as the contents of the '.sancov' file. + array_[0] = Magic64; + + return 1; + } else { + // The VMO is already mapped in, but it's not big enough to use the + // new indices. So increase the size to cover the new maximum index. + + CHECK_NE(vmo_, MX_HANDLE_INVALID); + CHECK_NE(array_, nullptr); + + uint32_t first_index = next_index_; + next_index_ += num_guards; + + mx_status_t status = _mx_vmo_set_size(vmo_, DataSize()); + CHECK_EQ(status, MX_OK); + + return first_index; + } + } +}; + +static TracePcGuardController pc_guard_controller; + +} // namespace +} // namespace __sancov + +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + CHECK_EQ(enabled, common_flags()->coverage); + CHECK_EQ(dir, common_flags()->coverage_dir); + + static bool coverage_enabled = false; + if (!coverage_enabled) { + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); + } +} +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT + const uptr *pcs, uptr len) { + UNIMPLEMENTED(); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { + if (!*guard) return; + __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, + u32 *start, u32 *end) { + if (start == end || *start) return; + __sancov::pc_guard_controller.InitTracePcGuard(start, end); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { + __sancov::pc_guard_controller.Dump(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +} // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 56cfd1c1f..1b61c95c7 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// // Sanitizer Coverage Controller for Trace PC Guard. +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA #include "sancov_flags.h" #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" @@ -204,3 +207,5 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" + +#endif // !SANITIZER_FUCHSIA -- cgit v1.2.1 From e18e52ff1c30d465661ecbd4bd873762ca70688a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 2 Aug 2017 07:59:30 +0000 Subject: [asan] Interceptors for Fuchsia Summary: Fuchsia uses the "memintrinsics" interceptors, though not via any generalized interception mechanism. It doesn't use any other interceptors. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: vitalybuka Subscribers: kubamracek, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36189 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309798 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 7 ++++++ lib/asan/asan_interceptors.h | 34 ++++++++++++++++++----------- lib/asan/asan_interceptors_memintrinsics.cc | 12 ++++++++++ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 999c799fe..1d68a2c0e 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -24,6 +24,11 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" +// There is no general interception at all on Fuchsia. +// Only the functions in asan_interceptors_memintrinsics.cc are +// really defined to replace libc functions. +#if !SANITIZER_FUCHSIA + #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" #endif @@ -654,3 +659,5 @@ void InitializeAsanInterceptors() { } } // namespace __asan + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 5bc621724..650e0869c 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -19,6 +19,26 @@ #include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" +namespace __asan { + +void InitializeAsanInterceptors(); +void InitializePlatformInterceptors(); + +#define ENSURE_ASAN_INITED() \ + do { \ + CHECK(!asan_init_is_running); \ + if (UNLIKELY(!asan_inited)) { \ + AsanInitFromRtl(); \ + } \ + } while (0) + +} // namespace __asan + +// There is no general interception at all on Fuchsia. +// Only the functions in asan_interceptors_memintrinsics.h are +// really defined to replace libc functions. +#if !SANITIZER_FUCHSIA + // Use macro to describe if specific function should be // intercepted on a given platform. #if !SANITIZER_WINDOWS @@ -112,18 +132,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, #define ASAN_INTERCEPT_FUNC(name) #endif // SANITIZER_MAC -namespace __asan { - -void InitializeAsanInterceptors(); -void InitializePlatformInterceptors(); - -#define ENSURE_ASAN_INITED() do { \ - CHECK(!asan_init_is_running); \ - if (UNLIKELY(!asan_inited)) { \ - AsanInitFromRtl(); \ - } \ -} while (0) - -} // namespace __asan +#endif // !SANITIZER_FUCHSIA #endif // ASAN_INTERCEPTORS_H diff --git a/lib/asan/asan_interceptors_memintrinsics.cc b/lib/asan/asan_interceptors_memintrinsics.cc index 7a59e7c5f..c89cb0114 100644 --- a/lib/asan/asan_interceptors_memintrinsics.cc +++ b/lib/asan/asan_interceptors_memintrinsics.cc @@ -30,3 +30,15 @@ void *__asan_memset(void *block, int c, uptr size) { void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } + +#if SANITIZER_FUCHSIA + +// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only +// things there it wants are these three. Just define them as aliases +// here rather than repeating the contents. + +decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; +decltype(memmove) memmove[[gnu::alias("__asan_memmove")]]; +decltype(memset) memset[[gnu::alias("__asan_memset")]]; + +#endif // SANITIZER_FUCHSIA -- cgit v1.2.1 From 62abea7849ec96360b0c45e82d92c2a206200d5b Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 2 Aug 2017 18:10:36 +0000 Subject: [ubsan] Test -fsanitize=vptr without -fsanitize=null This reverts commit r309042, thereby adding a test for -fsanitize=vptr functionality without -fsanitize=null. It also removes -fsanitize=null from another -fsanitize=vptr test. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309847 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp | 2 +- test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp index b20ac73aa..e026e8d05 100644 --- a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr,null -g %s -O3 -o %t +// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr -g %s -O3 -o %t // RUN: %run %t &> %t.log // RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0 diff --git a/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp index 898577d8e..f0659f439 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr,null -fno-sanitize-recover=vptr,null -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr,null -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-CORRUPTED-VTABLE --strict-whitespace // UNSUPPORTED: win32 -- cgit v1.2.1 From e4760795708443dbbdb724bdcdc24a828fef1aa1 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Wed, 2 Aug 2017 18:13:59 +0000 Subject: This ppc64 implementation of clear_cache works for both big and little endian. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309848 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 3c6570db6..e21ac08f8 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -165,7 +165,7 @@ void __clear_cache(void *start, void *end) { for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); -#elif defined (__powerpc64__) && defined(__LITTLE_ENDIAN__) +#elif defined (__powerpc64__) const size_t line_size = 32; const size_t len = (uintptr_t)end - (uintptr_t)start; -- cgit v1.2.1 From f6f49c0e05d1847dfd55d87a683140d991c9c6c1 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 2 Aug 2017 18:48:45 +0000 Subject: Add new ASAN_OPTION: sleep_after_init. Summary: As mentioned in https://github.com/google/sanitizers/issues/834, suggested option can be handy for debugging. Reviewers: kcc Reviewed By: kcc Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D35409 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309854 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.inc | 4 ++++ lib/asan/asan_rtl.cc | 5 +++++ test/asan/TestCases/sleep_after_init.c | 10 ++++++++++ 3 files changed, 19 insertions(+) create mode 100644 test/asan/TestCases/sleep_after_init.c diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index f2216c2e9..19ebc696e 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -79,6 +79,10 @@ ASAN_FLAG( "Number of seconds to sleep between printing an error report and " "terminating the program. Useful for debugging purposes (e.g. when one " "needs to attach gdb).") +ASAN_FLAG( + int, sleep_after_init, 0, + "Number of seconds to sleep after AddressSanitizer is initialized. " + "Useful for debugging purposes (e.g. when one needs to attach gdb).") ASAN_FLAG(bool, check_malloc_usable_size, true, "Allows the users to work around the bug in Nvidia drivers prior to " "295.*.") diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 376c50b58..c75a46399 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -484,6 +484,11 @@ static void AsanInitInternal() { } VReport(1, "AddressSanitizer Init done\n"); + + if (flags()->sleep_after_init) { + Report("Sleeping for %d second(s)\n", flags()->sleep_after_init); + SleepForSeconds(flags()->sleep_after_init); + } } // Initialize as requested from some part of ASan runtime library (interceptors, diff --git a/test/asan/TestCases/sleep_after_init.c b/test/asan/TestCases/sleep_after_init.c new file mode 100644 index 000000000..147af67c7 --- /dev/null +++ b/test/asan/TestCases/sleep_after_init.c @@ -0,0 +1,10 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: %env_asan_opts=sleep_after_init=1 not %run %t 2>&1 | FileCheck %s + +#include +int main() { + // CHECK: Sleeping for 1 second + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; +} -- cgit v1.2.1 From d20ebd10fdafaae026ac550e17d17daff39608e7 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 2 Aug 2017 20:32:12 +0000 Subject: [msan] Check for pvalloc overflow Summary: CheckForPvallocOverflow was introduced with D35818 to detect when pvalloc would wrap when rounding up to the next multiple of the page size. Add this check to MSan's pvalloc implementation. This time I made sure I was actually running (and writing) the correct tests, and that they are passing... Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36164 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309883 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_allocator.cc | 4 ++++ lib/msan/tests/msan_test.cc | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc index 8e9d4d397..1b134e15a 100644 --- a/lib/msan/msan_allocator.cc +++ b/lib/msan/msan_allocator.cc @@ -255,6 +255,10 @@ void *msan_valloc(uptr size, StackTrace *stack) { void *msan_pvalloc(uptr size, StackTrace *stack) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { + errno = errno_ENOMEM; + return Allocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. size = size ? RoundUpTo(size, PageSize) : PageSize; return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index b2d5f7c60..0310656d1 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3449,6 +3449,12 @@ TEST(MemorySanitizer, pvalloc) { EXPECT_EQ(0U, (uintptr_t)p % PageSize); EXPECT_EQ(PageSize, __sanitizer_get_allocated_size(p)); free(p); + + // Overflows should be caught. + EXPECT_DEATH(p = pvalloc((uintptr_t)-1), + "allocator is terminating the process instead of returning 0"); + EXPECT_DEATH(p = pvalloc((uintptr_t)-(PageSize - 1)), + "allocator is terminating the process instead of returning 0"); } #endif -- cgit v1.2.1 From ac2979953f5a661ebb67eb8f4a36d63ae0db19c3 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Wed, 2 Aug 2017 21:52:23 +0000 Subject: Use a more standard method to mark these tests as unsupported on powerpc64. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309892 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/divxc3_test.c | 1 + test/builtins/Unit/mulxc3_test.c | 1 + test/builtins/Unit/powixf2_test.c | 1 + 3 files changed, 3 insertions(+) diff --git a/test/builtins/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c index 6517ef124..9974dfb80 100644 --- a/test/builtins/Unit/divxc3_test.c +++ b/test/builtins/Unit/divxc3_test.c @@ -1,4 +1,5 @@ // RUN: %clang_builtins %s %librt -lm -o %t && %run %t +// UNSUPPORTED: powerpc64 //===-- divxc3_test.c - Test __divxc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c index c48b0da50..9b8e058df 100644 --- a/test/builtins/Unit/mulxc3_test.c +++ b/test/builtins/Unit/mulxc3_test.c @@ -1,4 +1,5 @@ // RUN: %clang_builtins %s %librt -lm -o %t && %run %t +// UNSUPPORTED: powerpc64 //===-- mulxc3_test.c - Test __mulxc3 -------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/powixf2_test.c b/test/builtins/Unit/powixf2_test.c index bf5a812fa..0d2734ae4 100644 --- a/test/builtins/Unit/powixf2_test.c +++ b/test/builtins/Unit/powixf2_test.c @@ -1,4 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t +// UNSUPPORTED: powerpc64 //===-- powixf2_test.cpp - Test __powixf2 ---------------------------------===// // // The LLVM Compiler Infrastructure -- cgit v1.2.1 From 5dea2733b9b133262190ffec6f967e81d0e8b27b Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 2 Aug 2017 22:47:54 +0000 Subject: [tsan] Check for pvalloc overlow Summary: `CheckForPvallocOverflow` was introduced with D35818 to detect when pvalloc would wrap when rounding up to the next multiple of the page size. Add this check to TSan's pvalloc implementation. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D36245 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309897 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_mman.cc | 4 ++++ lib/tsan/tests/unit/tsan_mman_test.cc | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 3f7a5e76c..8ef031646 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -256,6 +256,10 @@ void *user_valloc(ThreadState *thr, uptr pc, uptr sz) { void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) { + errno = errno_ENOMEM; + return Allocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. sz = sz ? RoundUpTo(sz, PageSize) : PageSize; return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize)); diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc index ed08247fa..05ae42867 100644 --- a/lib/tsan/tests/unit/tsan_mman_test.cc +++ b/lib/tsan/tests/unit/tsan_mman_test.cc @@ -139,6 +139,7 @@ TEST(Mman, Stats) { TEST(Mman, Valloc) { ThreadState *thr = cur_thread(); + uptr page_size = GetPageSizeCached(); void *p = user_valloc(thr, 0, 100); EXPECT_NE(p, (void*)0); @@ -150,8 +151,13 @@ TEST(Mman, Valloc) { p = user_pvalloc(thr, 0, 0); EXPECT_NE(p, (void*)0); - EXPECT_EQ(GetPageSizeCached(), __sanitizer_get_allocated_size(p)); + EXPECT_EQ(page_size, __sanitizer_get_allocated_size(p)); user_free(thr, 0, p); + + EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-(page_size - 1)), + "allocator is terminating the process instead of returning 0"); + EXPECT_DEATH(p = user_pvalloc(thr, 0, (uptr)-1), + "allocator is terminating the process instead of returning 0"); } #if !SANITIZER_DEBUG -- cgit v1.2.1 From 9f25f183953ef11dd7c2c02a1b73e7d10b598b7e Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 3 Aug 2017 00:58:45 +0000 Subject: [XRay][compiler-rt] Allow for building the XRay runtime without PREINIT initialization. Summary: Define a build-time configuration option for the XRay runtime to determine whether the archive will add an entry to the `.preinit_array` section of the binary. We also allow for initializing the XRay data structures with an explicit call to __xray_init(). This allows us to give users the capability to initialize the XRay data structures on demand. This can allow us to start porting XRay to platforms where `.preinit_array` isn't a supported section. It also allows us to limit the effects of XRay in the initialization sequence for applications that are sensitive to this kind of interference (i.e. large binaries) or those that want to package XRay control in libraries. Future changes should allow us to build two different library archives for the XRay runtime, and allow clang users to determine which version to link. Reviewers: dblaikie, kpw, pelikan Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D36080 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309909 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 ++ include/xray/xray_interface.h | 8 ++++++++ lib/xray/CMakeLists.txt | 2 ++ lib/xray/xray_init.cc | 24 +++++++++++++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fbc8554c..5f277e0db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,8 @@ option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON) mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS) option(COMPILER_RT_BUILD_XRAY "Build xray" ON) mark_as_advanced(COMPILER_RT_BUILD_XRAY) +option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF) +mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT) set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN "Build for a bare-metal target.") diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index 564613417..d08039a67 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -106,6 +106,14 @@ extern uintptr_t __xray_function_address(int32_t FuncId); /// encounter errors (when there are no instrumented functions, etc.). extern size_t __xray_max_function_id(); +/// Initialize the required XRay data structures. This is useful in cases where +/// users want to control precisely when the XRay instrumentation data +/// structures are initialized, for example when the XRay library is built with +/// the XRAY_NO_PREINIT preprocessor definition. +/// +/// Calling __xray_init() more than once is safe across multiple threads. +extern void __xray_init(); + } // end extern "C" #endif // XRAY_XRAY_INTERFACE_H diff --git a/lib/xray/CMakeLists.txt b/lib/xray/CMakeLists.txt index 72caa9fac..6d24ba8bf 100644 --- a/lib/xray/CMakeLists.txt +++ b/lib/xray/CMakeLists.txt @@ -62,6 +62,8 @@ set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS}) set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1) append_list_if( COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS) +append_list_if( + COMPILER_RT_BUILD_XRAY_NO_PREINIT XRAY_NO_PREINIT XRAY_COMMON_DEFINITIONS) add_compiler_rt_object_libraries(RTXray ARCHS ${XRAY_SUPPORTED_ARCH} diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index b46fa9880..07f692431 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -44,10 +44,28 @@ __sanitizer::atomic_uint8_t XRayInitialized{0}; __sanitizer::SpinMutex XRayInstrMapMutex; XRaySledMap XRayInstrMap; +// Global flag to determine whether the flags have been initialized. +__sanitizer::atomic_uint8_t XRayFlagsInitialized{0}; + +// A mutex to allow only one thread to initialize the XRay data structures. +__sanitizer::SpinMutex XRayInitMutex; + // __xray_init() will do the actual loading of the current process' memory map // and then proceed to look for the .xray_instr_map section/segment. void __xray_init() XRAY_NEVER_INSTRUMENT { - initializeFlags(); + __sanitizer::SpinMutexLock Guard(&XRayInitMutex); + // Short-circuit if we've already initialized XRay before. + if (__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) + return; + + if (!__sanitizer::atomic_load(&XRayFlagsInitialized, + __sanitizer::memory_order_acquire)) { + initializeFlags(); + __sanitizer::atomic_store(&XRayFlagsInitialized, true, + __sanitizer::memory_order_release); + } + if (__start_xray_instr_map == nullptr) { if (Verbosity()) Report("XRay instrumentation map missing. Not initializing XRay.\n"); @@ -64,9 +82,13 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { __sanitizer::atomic_store(&XRayInitialized, true, __sanitizer::memory_order_release); +#ifndef XRAY_NO_PREINIT if (flags()->patch_premain) __xray_patch(); +#endif } +#ifndef XRAY_NO_PREINIT __attribute__((section(".preinit_array"), used)) void (*__local_xray_preinit)(void) = __xray_init; +#endif -- cgit v1.2.1 From 78017f6ef468a40da739e298b81243bdf103c4ab Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 3 Aug 2017 02:22:11 +0000 Subject: [asan] Allocator support for Fuchsia Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: alekseyshl Subscribers: srhines, cryptoad, kubamracek, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36190 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309914 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.h | 6 +++- lib/asan/asan_malloc_linux.cc | 50 ++++++++++++++++++------------- lib/sanitizer_common/sanitizer_platform.h | 2 +- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index ad1aeb58a..615e34fa6 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -119,7 +119,11 @@ struct AsanMapUnmapCallback { }; #if SANITIZER_CAN_USE_ALLOCATOR64 -# if defined(__powerpc64__) +# if SANITIZER_FUCHSIA +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +typedef DefaultSizeClassMap SizeClassMap; +# elif defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index fd40f47db..a094d6eec 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -15,7 +15,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "asan_allocator.h" @@ -30,9 +30,9 @@ static uptr allocated_for_dlsym; static const uptr kDlsymAllocPoolSize = 1024; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; -static bool IsInDlsymAllocPool(const void *ptr) { +static INLINE bool IsInDlsymAllocPool(const void *ptr) { uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < sizeof(alloc_memory_for_dlsym); + return off < allocated_for_dlsym; } static void *AllocateFromLocalPool(uptr size_in_bytes) { @@ -43,6 +43,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { return mem; } +static INLINE bool MaybeInDlsym() { + // Fuchsia doesn't use dlsym-based interceptors. + return !SANITIZER_FUCHSIA && asan_init_is_running; +} + +static void *ReallocFromLocalPool(void *ptr, uptr size) { + const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); + void *new_ptr; + if (UNLIKELY(MaybeInDlsym())) { + new_ptr = AllocateFromLocalPool(size); + } else { + ENSURE_ASAN_INITED(); + GET_STACK_TRACE_MALLOC; + new_ptr = asan_malloc(size, &stack); + } + internal_memcpy(new_ptr, ptr, copy_size); + return new_ptr; +} + INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) @@ -60,7 +80,7 @@ INTERCEPTOR(void, cfree, void *ptr) { #endif // SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void*, malloc, uptr size) { - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(MaybeInDlsym())) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); @@ -69,7 +89,7 @@ INTERCEPTOR(void*, malloc, uptr size) { } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(MaybeInDlsym())) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); ENSURE_ASAN_INITED(); @@ -78,21 +98,9 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(asan_init_is_running)) { - new_ptr = AllocateFromLocalPool(size); - } else { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - new_ptr = asan_malloc(size, &stack); - } - internal_memcpy(new_ptr, ptr, copy_size); - return new_ptr; - } - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(IsInDlsymAllocPool(ptr))) + return ReallocFromLocalPool(ptr, size); + if (UNLIKELY(MaybeInDlsym())) return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; @@ -226,4 +234,4 @@ void ReplaceSystemMalloc() { } // namespace __asan #endif // SANITIZER_ANDROID -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index e65671533..81d9164c3 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -187,7 +187,7 @@ // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here. #ifndef SANITIZER_CAN_USE_ALLOCATOR64 -# if SANITIZER_ANDROID && defined(__aarch64__) +# if (SANITIZER_ANDROID && defined(__aarch64__)) || SANITIZER_FUCHSIA # define SANITIZER_CAN_USE_ALLOCATOR64 1 # elif defined(__mips64) || defined(__aarch64__) # define SANITIZER_CAN_USE_ALLOCATOR64 0 -- cgit v1.2.1 From 6b85e16e8efc13254b113ab4c6087000b21f3e56 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Thu, 3 Aug 2017 18:56:54 +0000 Subject: These tests use 80-bit long doubles, which are x86 only. Mark them so. This avoids having each new target need to mark them as unsupported. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309973 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/fixunsxfti_test.c | 5 +---- test/builtins/Unit/fixxfti_test.c | 5 +---- test/builtins/Unit/floattixf_test.c | 5 +---- test/builtins/Unit/floatuntixf_test.c | 5 +---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/test/builtins/Unit/fixunsxfti_test.c b/test/builtins/Unit/fixunsxfti_test.c index 0a48a7332..256ba0cf4 100644 --- a/test/builtins/Unit/fixunsxfti_test.c +++ b/test/builtins/Unit/fixunsxfti_test.c @@ -1,8 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: aarch64 -// test fails for aarch64 (see pr32260) - -// UNSUPPORTED: mips +// REQUIRES: x86-target-arch //===-- fixunsxfti_test.c - Test __fixunsxfti -----------------------------===// // diff --git a/test/builtins/Unit/fixxfti_test.c b/test/builtins/Unit/fixxfti_test.c index e5e15ab78..518ef44fb 100644 --- a/test/builtins/Unit/fixxfti_test.c +++ b/test/builtins/Unit/fixxfti_test.c @@ -1,8 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: aarch64 -// test fails for aarch64 (see pr32260) - -// UNSUPPORTED: mips +// REQUIRES: x86-target-arch //===-- fixxfti_test.c - Test __fixxfti -----------------------------------===// // diff --git a/test/builtins/Unit/floattixf_test.c b/test/builtins/Unit/floattixf_test.c index 3de472934..77a6f7dbf 100644 --- a/test/builtins/Unit/floattixf_test.c +++ b/test/builtins/Unit/floattixf_test.c @@ -1,8 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: aarch64 -// test fails for aarch64 (see pr32260) - -// UNSUPPORTED: mips +// REQUIRES: x86-target-arch //===-- floattixf.c - Test __floattixf ------------------------------------===// // diff --git a/test/builtins/Unit/floatuntixf_test.c b/test/builtins/Unit/floatuntixf_test.c index 2d71f0f88..0f7ad4634 100644 --- a/test/builtins/Unit/floatuntixf_test.c +++ b/test/builtins/Unit/floatuntixf_test.c @@ -1,8 +1,5 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t -// XFAIL: aarch64 -// test fails for aarch64 (see pr32260) - -// UNSUPPORTED: mips +// REQUIRES: x86-target-arch //===-- floatuntixf.c - Test __floatuntixf --------------------------------===// // -- cgit v1.2.1 From 8293838e866814d904640f6359954d00852f2421 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Thu, 3 Aug 2017 19:04:28 +0000 Subject: [builtins] Use Interlocked* intrinsics for atomics on MSVC Tested on MSVC 2013, 2015 and 2017 targeting X86, X64 and ARM. This fixes building emutls.c for Windows for ARM (both with clang which don't need these atomics fallbacks at all, but just failed due to the immintrin.h include before, and with MSVC). Differential Revision: https://reviews.llvm.org/D36071 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309974 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/emutls.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index 12aad3a42..5dd8dd154 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -102,7 +102,6 @@ static __inline emutls_address_array* emutls_getspecific() { #include #include #include -#include static LPCRITICAL_SECTION emutls_mutex; static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES; @@ -203,25 +202,24 @@ static __inline emutls_address_array* emutls_getspecific() { /* Provide atomic load/store functions for emutls_get_index if built with MSVC. */ #if !defined(__ATOMIC_RELEASE) +#include enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 }; static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) { assert(type == __ATOMIC_ACQUIRE); + // These return the previous value - but since we do an OR with 0, + // it's equivalent to a plain load. #ifdef _WIN64 - return (uintptr_t) _load_be_u64(ptr); + return InterlockedOr64(ptr, 0); #else - return (uintptr_t) _load_be_u32(ptr); + return InterlockedOr(ptr, 0); #endif } static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) { assert(type == __ATOMIC_RELEASE); -#ifdef _WIN64 - _store_be_u64(ptr, val); -#else - _store_be_u32(ptr, val); -#endif + InterlockedExchangePointer((void *volatile *)ptr, (void *)val); } #endif -- cgit v1.2.1 From d4151aa47c598a5d1f1ec1a167fc4f3f5797de7a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 4 Aug 2017 01:22:19 +0000 Subject: coverage: Update tests to reflect changes from r310012 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310015 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Inputs/extern_template.h | 2 +- test/profile/Linux/coverage_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/profile/Inputs/extern_template.h b/test/profile/Inputs/extern_template.h index aa59f6c1e..d08592da0 100644 --- a/test/profile/Inputs/extern_template.h +++ b/test/profile/Inputs/extern_template.h @@ -3,7 +3,7 @@ template struct Test { void doIt(int N) { // CHECK: [[@LINE]]| 2| void doIt if (N > 10) { // CHECK: [[@LINE]]| 2| if (N > 10) { M += 2; // CHECK: [[@LINE]]| 1| M += 2; - } else // CHECK: [[@LINE]]| 1| } else + } else // CHECK: [[@LINE]]| 2| } else M -= 2; // CHECK: [[@LINE]]| 1| M -= 2; } T M; diff --git a/test/profile/Linux/coverage_test.cpp b/test/profile/Linux/coverage_test.cpp index db9a14e26..439c6382f 100644 --- a/test/profile/Linux/coverage_test.cpp +++ b/test/profile/Linux/coverage_test.cpp @@ -19,7 +19,7 @@ void foo(bool cond) { // CHECK: [[@LINE]]| 1|void foo( if (cond) { // CHECK: [[@LINE]]| 1| if (cond) { - } // CHECK: [[@LINE]]| 0| } + } // CHECK: [[@LINE]]| 1| } } // CHECK: [[@LINE]]| 1|} void bar() { // CHECK: [[@LINE]]| 1|void bar() { } // CHECK: [[@LINE]]| 1|} -- cgit v1.2.1 From b78dceb242dc3f37b19687b2ce7b60b10b9f7969 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Fri, 4 Aug 2017 07:32:10 +0000 Subject: [msan] Switch the pvalloc overflow test to a lit test The test was not passing on targets where allocator_may_return_null defaults to true. Change the test to a lit test so that we can test both situations. Patch by Kostya Kortchinsky! Differential Revision: https://reviews.llvm.org/D36302 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310033 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/tests/msan_test.cc | 6 ------ test/msan/pvalloc.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 test/msan/pvalloc.cc diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index 0310656d1..b2d5f7c60 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -3449,12 +3449,6 @@ TEST(MemorySanitizer, pvalloc) { EXPECT_EQ(0U, (uintptr_t)p % PageSize); EXPECT_EQ(PageSize, __sanitizer_get_allocated_size(p)); free(p); - - // Overflows should be caught. - EXPECT_DEATH(p = pvalloc((uintptr_t)-1), - "allocator is terminating the process instead of returning 0"); - EXPECT_DEATH(p = pvalloc((uintptr_t)-(PageSize - 1)), - "allocator is terminating the process instead of returning 0"); } #endif diff --git a/test/msan/pvalloc.cc b/test/msan/pvalloc.cc new file mode 100644 index 000000000..21b2300b5 --- /dev/null +++ b/test/msan/pvalloc.cc @@ -0,0 +1,43 @@ +// RUN: %clangxx_msan -O0 %s -o %t +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t m1 2>&1 +// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s +// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t psm1 2>&1 + +// UNSUPPORTED: win32, freebsd + +// Checks that pvalloc overflows are caught. If the allocator is allowed to +// return null, the errno should be set to ENOMEM. + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + void *p; + size_t page_size; + + assert(argc == 2); + + page_size = sysconf(_SC_PAGESIZE); + // Check that the page size is a power of two. + assert((page_size & (page_size - 1)) == 0); + + if (!strcmp(argv[1], "m1")) { + p = pvalloc((uintptr_t)-1); + assert(!p); + assert(errno == ENOMEM); + } + if (!strcmp(argv[1], "psm1")) { + p = pvalloc((uintptr_t)-(page_size - 1)); + assert(!p); + assert(errno == ENOMEM); + } + + return 0; +} + +// CHECK: MemorySanitizer's allocator is terminating the process -- cgit v1.2.1 From 4f66f8ee20575ad5d67877114347024aff90317b Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 4 Aug 2017 18:39:36 +0000 Subject: [compiler-rt] Check for empty buffer in Addr2LineProcess::ReadFromSymbolizer This fixes a bug in the ReadFromSymbolizer method of the Addr2LineProcess class; if the input is too large, the returned buffer will be null and will consequently fail the CHECK. The proposed fix is to simply check if the buffer consists of only a null-terminator and return if so (in effect skipping that frame). I tested by running one of the unit tests both before and after my change. Submitted on behalf of david-y-lam. Reviewers: eugenis, alekseyshl, kcc Reviewed By: alekseyshl Differential Revision: https://reviews.llvm.org/D36207 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310089 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 2 +- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index ba226e84c..12369d709 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -454,7 +454,7 @@ bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { if (ReachedEndOfOutput(buffer, read_len)) break; if (read_len + 1 == max_length) { - Report("WARNING: Symbolizer buffer too small"); + Report("WARNING: Symbolizer buffer too small\n"); read_len = 0; break; } diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 5ef91c7cf..60f22bfd7 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -272,6 +272,10 @@ class Addr2LineProcess : public SymbolizerProcess { bool ReadFromSymbolizer(char *buffer, uptr max_length) override { if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) return false; + // The returned buffer is empty when output is valid, but exceeds + // max_length. + if (*buffer == '\0') + return true; // We should cut out output_terminator_ at the end of given buffer, // appended by addr2line to mark the end of its meaningful output. // We cannot scan buffer from it's beginning, because it is legal for it -- cgit v1.2.1 From 18c47b4afe28c8afd93ab1bfe0e151a1906702dc Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Fri, 4 Aug 2017 20:04:01 +0000 Subject: CFI: Move STL allocator blacklist to clang Summary: The regular expression to match STL allocators can't easily account for C++ mangling compression and fails to match some valid instances of STL allocators. Perform this logic in clang instead. Motivated by crbug.com/751385. Reviewers: pcc, kcc, llvm-commits Reviewed By: pcc Differential Revision: https://reviews.llvm.org/D36291 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310109 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi_blacklist.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index 2006d0b86..5b10b13de 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -1,9 +1,3 @@ -# STL allocators (T *allocator::allocate(size_type, const void*)). -# The type signature mandates a cast from uninitialized void* to T*. -# size_type can either be unsigned int (j) or unsigned long (m). -fun:*8allocateEjPKv -fun:*8allocateEmPKv - # std::get_temporary_buffer, likewise (libstdc++, libc++). fun:_ZSt20get_temporary_buffer* fun:_ZNSt3__120get_temporary_buffer* -- cgit v1.2.1 From 9b65d5838ade28aed2ba4caf9704d4b9608d47b9 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 4 Aug 2017 20:17:24 +0000 Subject: Add NetBSD support in sanitizer_procmaps_freebsd.cc Summary: This adds NetBSD specific: - ReadProcMaps() - MemoryMappingLayout::Next() This code is largely shared with FreeBSD. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: kcc, joerg, filcab, vitalybuka, fjricci Reviewed By: fjricci Subscribers: emaste, kubamracek, mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35551 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310116 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps_freebsd.cc | 34 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc index f0cdbeb44..3c7b98d6b 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc @@ -7,18 +7,22 @@ // //===----------------------------------------------------------------------===// // -// Information about the process mappings (FreeBSD-specific parts). +// Information about the process mappings (FreeBSD and NetBSD-specific parts). //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD #include "sanitizer_common.h" +#if SANITIZER_FREEBSD #include "sanitizer_freebsd.h" +#endif #include "sanitizer_procmaps.h" #include #include +#if SANITIZER_FREEBSD #include +#endif // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) @@ -31,16 +35,30 @@ namespace __sanitizer { void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() }; + const int Mib[] = { +#if SANITIZER_FREEBSD + CTL_KERN, + KERN_PROC, + KERN_PROC_VMMAP, + getpid() +#else + CTL_VM, + VM_PROC, + VM_PROC_MAP, + getpid(), + sizeof(struct kinfo_vmentry) +#endif + }; + size_t Size = 0; - int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0); + int Err = sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); CHECK_EQ(Err, 0); CHECK_GT(Size, 0); size_t MmapedSize = Size * 4 / 3; void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); Size = MmapedSize; - Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0); + Err = sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); CHECK_EQ(Err, 0); proc_maps->data = (char*)VmMap; @@ -71,11 +89,15 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { VmEntry->kve_path); } +#if SANITIZER_FREEBSD current_ += VmEntry->kve_structsize; +#else + current_ += sizeof(*VmEntry); +#endif return true; } } // namespace __sanitizer -#endif // SANITIZER_FREEBSD +#endif // SANITIZER_FREEBSD || SANITIZER_NETBSD -- cgit v1.2.1 From 0cbd2ad9eda21a6ed5024acb4cff8eceb250c6d3 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 4 Aug 2017 20:28:59 +0000 Subject: [asan] Check for pvalloc overlow Summary: Last one of the `pvalloc` overflow checks! `CheckForPvallocOverflow` was introduced with D35818 to detect when `pvalloc` would wrap when rounding up to the next multiple of the page size. Add this check to ASan's `pvalloc` implementation. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D36257 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310119 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 4 +++ test/asan/TestCases/Linux/pvalloc-overflow.cc | 41 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/asan/TestCases/Linux/pvalloc-overflow.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 92963ddfc..c98f9a89c 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -839,6 +839,10 @@ void *asan_valloc(uptr size, BufferedStackTrace *stack) { void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { + errno = errno_ENOMEM; + return AsanAllocator::FailureHandler::OnBadRequest(); + } // pvalloc(0) should allocate one page. size = size ? RoundUpTo(size, PageSize) : PageSize; return SetErrnoOnNull( diff --git a/test/asan/TestCases/Linux/pvalloc-overflow.cc b/test/asan/TestCases/Linux/pvalloc-overflow.cc new file mode 100644 index 000000000..80a2b9ce8 --- /dev/null +++ b/test/asan/TestCases/Linux/pvalloc-overflow.cc @@ -0,0 +1,41 @@ +// RUN: %clangxx_asan %s -o %t +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %run %t m1 2>&1 +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %run %t psm1 2>&1 + +// UNSUPPORTED: freebsd + +// Checks that pvalloc overflows are caught. If the allocator is allowed to +// return null, the errno should be set to ENOMEM. + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + void *p; + size_t page_size; + + assert(argc == 2); + + page_size = sysconf(_SC_PAGESIZE); + + if (!strcmp(argv[1], "m1")) { + p = pvalloc((uintptr_t)-1); + assert(!p); + assert(errno == ENOMEM); + } + if (!strcmp(argv[1], "psm1")) { + p = pvalloc((uintptr_t)-(page_size - 1)); + assert(!p); + assert(errno == ENOMEM); + } + + return 0; +} + +// CHECK: AddressSanitizer's allocator is terminating the process -- cgit v1.2.1 From fc2d319eaa67535ca9470cecc9db7863ac185883 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 4 Aug 2017 21:26:20 +0000 Subject: [asan] Fix unsupported test on Android Summary: `pvalloc` appears to not be available on Android. Mark the failing test as unsupported on that platform. Reviewers: alekseyshl, vitalybuka Reviewed By: alekseyshl, vitalybuka Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D36339 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310133 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/pvalloc-overflow.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Linux/pvalloc-overflow.cc b/test/asan/TestCases/Linux/pvalloc-overflow.cc index 80a2b9ce8..b47c6266b 100644 --- a/test/asan/TestCases/Linux/pvalloc-overflow.cc +++ b/test/asan/TestCases/Linux/pvalloc-overflow.cc @@ -4,7 +4,7 @@ // RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s // RUN: ASAN_OPTIONS=allocator_may_return_null=1 %run %t psm1 2>&1 -// UNSUPPORTED: freebsd +// UNSUPPORTED: freebsd, android // Checks that pvalloc overflows are caught. If the allocator is allowed to // return null, the errno should be set to ENOMEM. -- cgit v1.2.1 From 62ccbaa636912dc96859f08dccbd849f3108200a Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 4 Aug 2017 22:23:52 +0000 Subject: Add NetBSD support in sanitizer_syscall_generic.inc Summary: This adds: - NetBSD specific aliases for renamed syscalls, - differentiate internal_syscall, internal_syscall64, internal_syscall_ptr as there are various types of syscalls on NetBSD. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36316 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310139 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_syscall_generic.inc | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc index 15cf05f06..b1a5941a5 100644 --- a/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -7,17 +7,41 @@ // //===----------------------------------------------------------------------===// // -// Generic implementations of internal_syscall and internal_iserror. +// Generic implementations of internal_syscall* and internal_iserror. // //===----------------------------------------------------------------------===// -#if SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name #endif -#if (SANITIZER_FREEBSD || SANITIZER_MAC) && defined(__x86_64__) +#if SANITIZER_NETBSD +// We use 3 kinds of internal_syscall's for different types of retval in order +// to address differences in calling conventions (e.g. registers to place the +// return value in). +// - internal_syscall for 32-bit length (int, pid_t) +// - internal_syscall64 for 64-bit length (off_t) +// - internal_syscall_ptr for pointer and (s)size_t +# define internal_syscall syscall +# define internal_syscall64 __syscall +// Handle syscall renames manually +# define SYS_stat SYS___stat50 +# define SYS_lstat SYS___lstat50 +# define SYS_fstat SYS___fstat50 +# define SYS_gettimeofday SYS___gettimeofday50 +# define SYS_wait4 SYS___wait450 +# define SYS_getdents SYS___getdents30 +# define SYS_sigaltstack SYS___sigaltstack14 +# define SYS_sigprocmask SYS___sigprocmask14 +# define SYS_nanosleep SYS___nanosleep50 +# if SANITIZER_WORDSIZE == 64 +# define internal_syscall_ptr __syscall +# else +# define internal_syscall_ptr syscall +# endif +#elif defined(__x86_64__) && (SANITIZER_FREEBSD || SANITIZER_MAC) # define internal_syscall __syscall # else # define internal_syscall syscall -- cgit v1.2.1 From a9ea11a357a8408e758dbaf6f8b98c7e77846fec Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 4 Aug 2017 22:27:01 +0000 Subject: Add NetBSD support in interception.h Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, filcab, vitalybuka Reviewed By: vitalybuka Subscribers: llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36323 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310140 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/interception/interception.h b/lib/interception/interception.h index 2d280731e..9e65ffa8e 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -16,7 +16,7 @@ #define INTERCEPTION_H #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) && \ - !defined(_WIN32) && !defined(__Fuchsia__) + !defined(__NetBSD__) && !defined(_WIN32) && !defined(__Fuchsia__) # error "Interception doesn't work on this operating system." #endif @@ -129,7 +129,7 @@ const interpose_substitution substitution_##func_name[] \ extern "C" ret_type func(__VA_ARGS__); # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__NetBSD__) # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) @@ -264,7 +264,7 @@ typedef unsigned long uptr; // NOLINT #define INCLUDED_FROM_INTERCEPTION_LIB -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ -- cgit v1.2.1 From 6906724697e9c56ad605dc70a64cae6cbb0d8901 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 4 Aug 2017 22:32:46 +0000 Subject: Add NetBSD support in sanitizer_linux_libcdep.cc Summary: When possible reuse FreeBSD and Linux code. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab Reviewed By: vitalybuka Subscribers: srhines, emaste, kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36320 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310143 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 3a159078a..858e4e32c 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" @@ -149,7 +149,8 @@ bool SanitizerGetThreadName(char *name, int max_len) { #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ + !SANITIZER_NETBSD static uptr g_tls_size; #ifdef __i386__ @@ -177,7 +178,8 @@ void InitTlsSize() { } #else void InitTlsSize() { } -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO +#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && + // !SANITIZER_NETBSD #if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \ @@ -332,7 +334,9 @@ static void **ThreadSelfSegbase() { uptr ThreadSelf() { return (uptr)ThreadSelfSegbase()[2]; } -#endif // SANITIZER_FREEBSD +#elif SANITIZER_NETBSD +uptr ThreadSelf() { return (uptr)pthread_self(); } +#endif // SANITIZER_NETBSD #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { @@ -363,7 +367,7 @@ static void GetTls(uptr *addr, uptr *size) { *addr = (uptr) dtv[2]; *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); } -#elif SANITIZER_ANDROID +#elif SANITIZER_ANDROID || SANITIZER_NETBSD *addr = 0; *size = 0; #else @@ -374,7 +378,7 @@ static void GetTls(uptr *addr, uptr *size) { #if !SANITIZER_GO uptr GetTlsSize() { -#if SANITIZER_FREEBSD || SANITIZER_ANDROID +#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD uptr addr, size; GetTls(&addr, &size); return size; -- cgit v1.2.1 From e0a4b2e12bbbc4f49bb8c6abdc87a07ab503611f Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 5 Aug 2017 13:36:49 +0000 Subject: Add NetBSD support in sanitizer_unwind_linux_libcdep.cc Summary: NetBSD is a POSIX-like and BSD-family system. Reuse FreeBSD and Linux code. NetBSD uses DWARF ExceptionHandler. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, filcab, vitalybuka Reviewed By: vitalybuka Subscribers: srhines, emaste, llvm-commits, kubamracek, aprantl, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36314 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310179 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc index 5943125c8..59b71842b 100644 --- a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc @@ -8,11 +8,11 @@ //===----------------------------------------------------------------------===// // // This file contains the unwind.h-based (aka "slow") stack unwinding routines -// available to the tools on Linux, Android, and FreeBSD. +// available to the tools on Linux, Android, NetBSD and FreeBSD. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_common.h" #include "sanitizer_stacktrace.h" @@ -78,7 +78,8 @@ void SanitizerInitializeUnwinder() { } #endif -#ifdef __arm__ +#if defined(__arm__) && !SANITIZER_NETBSD +// NetBSD uses dwarf EH #define UNWIND_STOP _URC_END_OF_STACK #define UNWIND_CONTINUE _URC_NO_REASON #else @@ -165,4 +166,4 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -- cgit v1.2.1 From 41d1b5e1df6c57b85e21d94c59f711f1d6a573ce Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 5 Aug 2017 18:10:51 +0000 Subject: Add NetBSD support in sanitizer_errno.h Summary: NetBSD ships with __errno (value for __errno_location) like Android. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, vitalybuka, fjricci, kcc, filcab Reviewed By: vitalybuka Subscribers: llvm-commits, srhines, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36360 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310182 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_errno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_errno.h b/lib/sanitizer_common/sanitizer_errno.h index 7872b89c2..6cbbace9f 100644 --- a/lib/sanitizer_common/sanitizer_errno.h +++ b/lib/sanitizer_common/sanitizer_errno.h @@ -24,7 +24,7 @@ #if SANITIZER_FREEBSD || SANITIZER_MAC # define __errno_location __error -#elif SANITIZER_ANDROID +#elif SANITIZER_ANDROID || SANITIZER_NETBSD # define __errno_location __errno #elif SANITIZER_WINDOWS # define __errno_location _errno -- cgit v1.2.1 From 285e20603ef2a5d5bd617723e6066d8869054e04 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 7 Aug 2017 09:08:44 +0000 Subject: [asan] Return sizeof missed by r309914 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310244 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index a094d6eec..8222c6d70 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -32,7 +32,7 @@ static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; static INLINE bool IsInDlsymAllocPool(const void *ptr) { uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < allocated_for_dlsym; + return off < sizeof(alloc_memory_for_dlsym); } static void *AllocateFromLocalPool(uptr size_in_bytes) { -- cgit v1.2.1 From 36deaa181e4635ab140d75aac4a15ef5bfef2bc1 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 7 Aug 2017 10:57:58 +0000 Subject: Add NetBSD support in asan_interceptors.h Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, filcab, kcc, fjricci, vitalybuka Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36375 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310246 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 650e0869c..1422b159d 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -55,7 +55,7 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_FORK 0 #endif -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1 #else # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 -- cgit v1.2.1 From 6f115effabc63ed12b3b597b6e9abfdc1384f6b4 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 7 Aug 2017 10:58:48 +0000 Subject: Add NetBSD support in asan_errors.cc Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, fjricci, vitalybuka, filcab, kcc Reviewed By: vitalybuka Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36374 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310247 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index b7a38eb7c..4bc47600c 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -59,7 +59,7 @@ static void MaybeDumpRegisters(void *context) { } static void MaybeReportNonExecRegion(uptr pc) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { -- cgit v1.2.1 From acb113dd88f5bdca20e42d611981fb133d40d292 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 7 Aug 2017 10:59:44 +0000 Subject: Add NetBSD support in sanitizer_test_utils.h Summary: NetBSD ships with printf_l(3) like FreeBSD. NetBSD does not ship with memalign, pvalloc, malloc with "usable size" and is the same here as Darwin, Android, FreeBSD and Windows. Sponsored by Reviewers: joerg, vitalybuka, kcc, fjricci, filcab Reviewed By: vitalybuka Subscribers: srhines, llvm-commits, emaste, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36373 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310248 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index b7728d9ea..f8821a15d 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -101,8 +101,8 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0 #endif -#if !defined(__APPLE__) && !defined(__FreeBSD__) && \ - !defined(__ANDROID__) && !defined(_WIN32) +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__ANDROID__) && \ + !defined(__NetBSD__) && !defined(_WIN32) # define SANITIZER_TEST_HAS_MEMALIGN 1 # define SANITIZER_TEST_HAS_PVALLOC 1 # define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1 @@ -118,7 +118,7 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_STRNLEN 0 #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) # define SANITIZER_TEST_HAS_PRINTF_L 1 #else # define SANITIZER_TEST_HAS_PRINTF_L 0 -- cgit v1.2.1 From 06f7854c1d782fe072c1442dbaa4d9bf75b1bfd7 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 7 Aug 2017 18:07:20 +0000 Subject: [sanitizer] Remove use of task_for_pid from sanitizer_stoptheworld_mac.cc Using task_for_pid to get the "self" task is not necessary, and it can fail (e.g. for sandboxed processes). Let's just use mach_task_self(). Differential Revision: https://reviews.llvm.org/D36284 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310271 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc index 0c27c472f..d84ebef3b 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -55,17 +55,9 @@ void RunThread(void *arg) { struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; SuspendedThreadsListMac suspended_threads_list; - mach_port_t task; - kern_return_t err = task_for_pid(mach_task_self(), internal_getpid(), &task); - if (err != KERN_SUCCESS) { - VReport(1, "Getting task from pid failed (errno %d).\n", err); - return; - } - thread_array_t threads; mach_msg_type_number_t num_threads; - - err = task_threads(task, &threads, &num_threads); + kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); if (err != KERN_SUCCESS) { VReport(1, "Failed to get threads for task (errno %d).\n", err); return; -- cgit v1.2.1 From 3f62c21007d9222fb869ea7ae52ff11e89b2ec79 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 7 Aug 2017 18:12:01 +0000 Subject: [asan] Make dump_registers.cc more stable Differential Revision: https://reviews.llvm.org/D36231 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310273 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/dump_registers.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/asan/TestCases/Darwin/dump_registers.cc b/test/asan/TestCases/Darwin/dump_registers.cc index 42db446ff..cc2710f06 100644 --- a/test/asan/TestCases/Darwin/dump_registers.cc +++ b/test/asan/TestCases/Darwin/dump_registers.cc @@ -5,22 +5,22 @@ #include #include +#include int main() { fprintf(stderr, "Hello\n"); char *ptr; - if (sizeof(void *) == 8) - ptr = (char *)0x6666666666666666; - else if (sizeof(void *) == 4) - ptr = (char *)0x55555555; - else - assert(0 && "Your computer is weird."); + ptr = (char *)mmap(NULL, 0x10000, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + assert(ptr && "failed to mmap"); + + fprintf(stderr, sizeof(uintptr_t) == 8 ? "p = 0x%016lx\n" : "p = 0x%08lx\n", (uintptr_t)ptr); + // CHECK: p = [[ADDR:0x[0-9]+]] char c = *ptr; // BOOM // CHECK: ERROR: AddressSanitizer: {{SEGV|BUS}} // CHECK: Register values: - // CHECK: {{0x55555555|0x6666666666666666}} + // CHECK: [[ADDR]] fprintf(stderr, "World\n"); return c; } -- cgit v1.2.1 From b6103e6638e0c9551c5a75f39252ac7b9692c22b Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 7 Aug 2017 18:12:59 +0000 Subject: [tsan] Fix format string in WriteMemoryProfile The current format string is broken and fails to parse. Differential Revision: https://reviews.llvm.org/D36192 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310276 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform_mac.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index 73a656ffc..4570286b1 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -167,8 +167,8 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) { #else // !SANITIZER_GO "app (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n" #endif - "stacks: %ld unique IDs, %ld kB allocated\n" - "threads: %ld total, %ld live\n" + "stacks: %zd unique IDs, %zd kB allocated\n" + "threads: %zd total, %zd live\n" "------------------------------\n", ShadowBeg(), ShadowEnd(), shadow_res / 1024, shadow_dirty / 1024, MetaShadowBeg(), MetaShadowEnd(), meta_res / 1024, meta_dirty / 1024, -- cgit v1.2.1 From c1c4d6655443998352adcfeb89e593c07f7be243 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 7 Aug 2017 23:34:45 +0000 Subject: Add NetBSD support in asan_stack.h Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab, fjricci Reviewed By: vitalybuka Subscribers: davide, kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36377 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310322 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_stack.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h index cc95e0f30..324cd3ddd 100644 --- a/lib/asan/asan_stack.h +++ b/lib/asan/asan_stack.h @@ -44,7 +44,8 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() // yields the call stack of the signal's handler and not of the code // that raised the signal (as it does on Linux). - if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true; + if ((SANITIZER_FREEBSD || SANITIZER_NETBSD) && t->isInDeadlySignal()) + fast = true; uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); -- cgit v1.2.1 From 0f9a6a534e6e1d44676a06c37061522a75edab38 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 7 Aug 2017 23:38:14 +0000 Subject: Fix asan_test.cc build on NetBSD Summary: Include for variable argument list macros (va_list, va_start etc). Add fallback definition of _LIBCPP_GET_C_LOCALE, this is required for GNU libstdc++ compatibility. Define new macro SANITIZER_GET_C_LOCALE. This value is currently required for FreeBSD and NetBSD for printf_l(3) tests. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab, fjricci Reviewed By: vitalybuka Subscribers: llvm-commits, emaste, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36406 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310323 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test.cc | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 7e9cf3bab..ed000327f 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -13,6 +13,17 @@ #include "asan_test_utils.h" #include +#include + +#ifdef _LIBCPP_GET_C_LOCALE +#define SANITIZER_GET_C_LOCALE _LIBCPP_GET_C_LOCALE +#else +#if defined(__FreeBSD__) +#define SANITIZER_GET_C_LOCALE 0 +#elif defined(__NetBSD__) +#define SANITIZER_GET_C_LOCALE LC_C_LOCALE +#endif +#endif NOINLINE void *malloc_fff(size_t size) { void *res = malloc/**/(size); break_optimization(0); return res;} @@ -1328,19 +1339,18 @@ static int vsnprintf_l_wrapper(char *s, size_t n, TEST(AddressSanitizer, snprintf_l) { char buff[5]; // Check that snprintf_l() works fine with Asan. - int res = snprintf_l(buff, 5, - _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"); + int res = snprintf_l(buff, 5, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"); EXPECT_EQ(12, res); // Check that vsnprintf_l() works fine with Asan. - res = vsnprintf_l_wrapper(buff, 5, - _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"); + res = vsnprintf_l_wrapper(buff, 5, SANITIZER_GET_C_LOCALE, "%s", + "vsnprintf_l()"); EXPECT_EQ(13, res); - EXPECT_DEATH(snprintf_l(buff, 10, - _LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"), - "AddressSanitizer: stack-buffer-overflow"); - EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, - _LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"), - "AddressSanitizer: stack-buffer-overflow"); + EXPECT_DEATH( + snprintf_l(buff, 10, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"), + "AddressSanitizer: stack-buffer-overflow"); + EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, SANITIZER_GET_C_LOCALE, "%s", + "vsnprintf_l()"), + "AddressSanitizer: stack-buffer-overflow"); } #endif -- cgit v1.2.1 From b07ae8ba81c69f8b1ad896536585c66295fde4f3 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 8 Aug 2017 01:01:59 +0000 Subject: [asan] Restore dead-code-elimination optimization for Fuchsia Summary: r310244 fixed a bug introduced by r309914 for non-Fuchsia builds. In doing so it also reversed the intended effect of the change for Fuchsia builds, which was to allow all the AllocateFromLocalPool code and its variables to be optimized away entirely. This change restores that optimization for Fuchsia builds, but doesn't have the original change's bug because the comparison arithmetic now takes into account the size of the elements. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36430 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310330 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 8222c6d70..beef81896 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -32,7 +32,7 @@ static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; static INLINE bool IsInDlsymAllocPool(const void *ptr) { uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < sizeof(alloc_memory_for_dlsym); + return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]); } static void *AllocateFromLocalPool(uptr size_in_bytes) { -- cgit v1.2.1 From b7816a65e2b4352aa2296d1551b6e68aa84ad2ea Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 11:40:15 +0000 Subject: Define OFF_T as 64-bit integer on NetBSD Summary: All 32 and 64 bit NetBSD platforms define off_t as 64-bit integer. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, filcab, kcc, vitalybuka Reviewed By: vitalybuka Subscribers: emaste, kubamracek, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35553 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310349 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_internal_defs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index f35b095ee..4b780917f 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -132,9 +132,9 @@ typedef int pid_t; // WARNING: OFF_T may be different from OS type off_t, depending on the value of // _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls // like pread and mmap, as opposed to pread64 and mmap64. -// FreeBSD, Mac and Linux/x86-64 are special. -#if SANITIZER_FREEBSD || SANITIZER_MAC || \ - (SANITIZER_LINUX && defined(__x86_64__)) +// FreeBSD, NetBSD, Mac and Linux/x86-64 are special. +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \ + (SANITIZER_LINUX && defined(__x86_64__)) typedef u64 OFF_T; #else typedef uptr OFF_T; -- cgit v1.2.1 From 4347a8988f22c675cc42eee25db3483f530982ce Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 12:10:08 +0000 Subject: Reuse interception_linux for NetBSD Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab Reviewed By: vitalybuka Subscribers: llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36321 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310351 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception_linux.cc | 13 ++++++++++--- lib/interception/interception_linux.h | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/interception/interception_linux.cc b/lib/interception/interception_linux.cc index 6e908ac01..23780429d 100644 --- a/lib/interception/interception_linux.cc +++ b/lib/interception/interception_linux.cc @@ -12,14 +12,22 @@ // Linux-specific interception methods. //===----------------------------------------------------------------------===// -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) #include "interception.h" #include // for dlsym() and dlvsym() +#ifdef __NetBSD__ +#include "sanitizer_common/sanitizer_libc.h" +#endif + namespace __interception { bool GetRealFunctionAddress(const char *func_name, uptr *func_addr, uptr real, uptr wrapper) { +#ifdef __NetBSD__ + // XXX: Find a better way to handle renames + if (internal_strcmp(func_name, "sigaction") == 0) func_name = "__sigaction14"; +#endif *func_addr = (uptr)dlsym(RTLD_NEXT, func_name); return real == wrapper; } @@ -32,5 +40,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) { } // namespace __interception - -#endif // __linux__ || __FreeBSD__ +#endif // __linux__ || __FreeBSD__ || __NetBSD__ diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h index 27a66c882..0e15bd8e1 100644 --- a/lib/interception/interception_linux.h +++ b/lib/interception/interception_linux.h @@ -12,7 +12,7 @@ // Linux-specific interception methods. //===----------------------------------------------------------------------===// -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_linux.h should be included from interception library only" @@ -44,4 +44,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver); #endif // !defined(__ANDROID__) #endif // INTERCEPTION_LINUX_H -#endif // __linux__ || __FreeBSD__ +#endif // __linux__ || __FreeBSD__ || __NetBSD__ -- cgit v1.2.1 From 1445db94879de2a68c37a606acb6abfff17a6027 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 15:25:26 +0000 Subject: Enable COMPILER_RT_HAS_SANITIZER_COMMON on NetBSD Summary: Temporarily keep disabled COMPILER_RT_HAS_ASAN on NetBSD. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, filcab, kcc, vitalybuka Reviewed By: vitalybuka Subscribers: srhines, mgorny, #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36312 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310370 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 68c00db08..4a63674af 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -470,7 +470,7 @@ set(COMPILER_RT_SANITIZERS_TO_BUILD ${ALL_SANITIZERS} CACHE STRING list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|Fuchsia" OR + (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia" OR (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN)))) set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE) else() @@ -483,7 +483,8 @@ else() set(COMPILER_RT_HAS_INTERCEPTION FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH) +if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND + (NOT OS_NAME MATCHES "NetBSD")) set(COMPILER_RT_HAS_ASAN TRUE) else() set(COMPILER_RT_HAS_ASAN FALSE) -- cgit v1.2.1 From 195d1722cd1be21717ee261c5b31a4fa602d961b Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 18:16:35 +0000 Subject: NetBSD compatibility nit in asan_test_utils.h Summary: Do not include on NetBSD, as this header serves on this OS backward compatibility with K&R alias for . Sponsored by Reviewers: vitalybuka, kcc, joerg, filcab, fjricci Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36469 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310391 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_test_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h index c29246722..d7b6f82e2 100644 --- a/lib/asan/tests/asan_test_utils.h +++ b/lib/asan/tests/asan_test_utils.h @@ -45,7 +45,7 @@ #include #endif -#if !defined(__APPLE__) && !defined(__FreeBSD__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) #include #endif -- cgit v1.2.1 From 00e8d2ff30476d0d4825d9f16881c64416d3416f Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 19:09:48 +0000 Subject: Add NetBSD support in asan_interceptors.cc Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab, fjricci Reviewed By: vitalybuka Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36470 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310400 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 1d68a2c0e..b43f12948 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -314,6 +314,11 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, } #endif // ASAN_INTERCEPT_SWAPCONTEXT +#if SANITIZER_NETBSD +#define longjmp __longjmp14 +#define siglongjmp __siglongjmp14 +#endif + INTERCEPTOR(void, longjmp, void *env, int val) { __asan_handle_no_return(); REAL(longjmp)(env, val); -- cgit v1.2.1 From 8b950ead2228ba5b170432c35bfea27ac62a8994 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 20:36:10 +0000 Subject: Reuse sanitizer_linux for NetBSD Summary: Follow FreeBSD and reuse sanitizer_linux for NetBSD. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, filcab, vitalybuka, fjricci, dvyukov Reviewed By: fjricci Subscribers: dvyukov, emaste, kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36325 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310411 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 124 +++++++++++++++++++++++++++----- lib/sanitizer_common/sanitizer_linux.h | 4 +- 2 files changed, 110 insertions(+), 18 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 8c3c1e5d6..3ca762782 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -27,10 +27,14 @@ #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" -#if !SANITIZER_FREEBSD +#if SANITIZER_LINUX #include #endif +#if SANITIZER_NETBSD +#include +#endif + // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To // access stat from asm/stat.h, without conflicting with definition in @@ -79,6 +83,12 @@ extern "C" { extern char **environ; // provided by crt1 #endif // SANITIZER_FREEBSD +#if SANITIZER_NETBSD +#include // For NAME_MAX +#include +extern char **environ; // provided by crt1 +#endif // SANITIZER_NETBSD + #if !SANITIZER_ANDROID #include #endif @@ -139,7 +149,10 @@ namespace __sanitizer { #if !SANITIZER_S390 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, OFF_T offset) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_NETBSD + return internal_syscall_ptr(SYSCALL(mmap), addr, length, prot, flags, fd, + (long)0, offset); +#elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, offset); #else @@ -182,26 +195,38 @@ uptr internal_open(const char *filename, int flags, u32 mode) { uptr internal_read(fd_t fd, void *buf, uptr count) { sptr res; +#if SANITIZER_NETBSD + HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(read), fd, buf, count)); +#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); +#endif return res; } uptr internal_write(fd_t fd, const void *buf, uptr count) { sptr res; +#if SANITIZER_NETBSD + HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(write), fd, buf, count)); +#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); +#endif return res; } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; +#if SANITIZER_NETBSD + HANDLE_EINTR(res, internal_syscall(SYSCALL(ftruncate), fd, 0, (s64)size)); +#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); +#endif return res; } -#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; @@ -240,7 +265,7 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { #endif uptr internal_stat(const char *path, void *buf) { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS @@ -265,7 +290,9 @@ uptr internal_stat(const char *path, void *buf) { } uptr internal_lstat(const char *path, void *buf) { -#if SANITIZER_FREEBSD +#if SANITIZER_NETBSD + return internal_syscall(SYSCALL(lstat), path, buf); +#elif SANITIZER_FREEBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS @@ -290,7 +317,7 @@ uptr internal_lstat(const char *path, void *buf) { } uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_NETBSD # if SANITIZER_MIPS64 // For mips64, fstat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; @@ -324,7 +351,9 @@ uptr internal_dup2(int oldfd, int newfd) { } uptr internal_readlink(const char *path, char *buf, uptr bufsize) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_NETBSD + return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, bufsize); #else @@ -354,7 +383,7 @@ uptr internal_sched_yield() { } void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD internal_syscall(SYSCALL(exit), exitcode); #else internal_syscall(SYSCALL(exit_group), exitcode); @@ -393,19 +422,25 @@ bool FileExists(const char *filename) { tid_t GetTid() { #if SANITIZER_FREEBSD return (uptr)pthread_self(); +#elif SANITIZER_NETBSD + return _lwp_self(); #else return internal_syscall(SYSCALL(gettid)); #endif } u64 NanoTime() { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD timeval tv; #else kernel_timeval tv; #endif internal_memset(&tv, 0, sizeof(tv)); +#if SANITIZER_NETBSD + internal_syscall_ptr(SYSCALL(gettimeofday), &tv, NULL); +#else internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0); +#endif return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } @@ -413,7 +448,7 @@ u64 NanoTime() { // 'environ' array (on FreeBSD) and does not use libc. This function should be // called first inside __asan_init. const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -547,6 +582,8 @@ void BlockingMutex::Lock() { while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { #if SANITIZER_FREEBSD _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); +#elif SANITIZER_NETBSD + sched_yield(); /* No userspace futex-like synchromization */ #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0); #endif @@ -560,6 +597,8 @@ void BlockingMutex::Unlock() { if (v == MtxSleeping) { #if SANITIZER_FREEBSD _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); +#elif SANITIZER_NETBSD + /* No userspace futex-like synchromization */ #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0); #endif @@ -575,6 +614,17 @@ void BlockingMutex::CheckLocked() { // The actual size of this structure is specified by d_reclen. // Note that getdents64 uses a different structure format. We only provide the // 32-bit syscall here. +#if SANITIZER_NETBSD +// struct dirent is different for Linux and us. At this moment, we use only +// d_fileno (Linux call this d_ino), d_reclen, and d_name. +struct linux_dirent { + u64 d_ino; // d_fileno + u16 d_reclen; + u16 d_namlen; // not used + u8 d_type; // not used + char d_name[NAME_MAX + 1]; +}; +#else struct linux_dirent { #if SANITIZER_X32 || defined(__aarch64__) u64 d_ino; @@ -589,16 +639,34 @@ struct linux_dirent { #endif char d_name[256]; }; +#endif // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { +#if SANITIZER_NETBSD + // XXX We need additional work for ptrace: + // - for request, we use PT_FOO whereas Linux uses PTRACE_FOO + // - data is int for us, but void * for Linux + // - Linux sometimes uses data in the case where we use addr instead + // At this moment, this function is used only within + // "#if SANITIZER_LINUX && defined(__x86_64__)" block in + // sanitizer_stoptheworld_linux_libcdep.cc. + return internal_syscall_ptr(SYSCALL(ptrace), request, pid, (uptr)addr, + (uptr)data); +#else return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); +#endif } uptr internal_waitpid(int pid, int *status, int options) { +#if SANITIZER_NETBSD + return internal_syscall(SYSCALL(wait4), pid, status, options, + NULL /* rusage */); +#else return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, 0 /* rusage */); +#endif } uptr internal_getpid() { @@ -610,7 +678,9 @@ uptr internal_getppid() { } uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { -#if SANITIZER_FREEBSD +#if SANITIZER_NETBSD + return internal_syscall(SYSCALL(getdents), fd, dirp, (uptr)count); +#elif SANITIZER_FREEBSD return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); @@ -620,7 +690,11 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { +#if SANITIZER_NETBSD + return internal_syscall64(SYSCALL(lseek), fd, 0, offset, whence); +#else return internal_syscall(SYSCALL(lseek), fd, offset, whence); +#endif } #if SANITIZER_LINUX @@ -711,7 +785,7 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) { uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; @@ -856,7 +930,9 @@ static uptr GetKernelAreaSize() { #endif // SANITIZER_WORDSIZE == 32 uptr GetMaxVirtualAddress() { -#if SANITIZER_WORDSIZE == 64 +#if SANITIZER_NETBSD && defined(__x86_64__) + return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) +#elif SANITIZER_WORDSIZE == 64 # if defined(__powerpc64__) || defined(__aarch64__) // On PowerPC64 we have two different address space layouts: 44- and 46-bit. // We somehow need to figure out which one we are using now and choose @@ -900,8 +976,12 @@ uptr GetPageSize() { } uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD #if SANITIZER_FREEBSD - const int Mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +#else + const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif const char *default_module_name = "kern.proc.pathname"; size_t Size = buf_len; bool IsErr = (sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); @@ -1545,6 +1625,8 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) { static const uptr PF_WRITE = 1U << 1; #if SANITIZER_FREEBSD uptr err = ucontext->uc_mcontext.mc_err; +#elif SANITIZER_NETBSD + uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; #else uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; #endif @@ -1591,6 +1673,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_rip; *bp = ucontext->uc_mcontext.mc_rbp; *sp = ucontext->uc_mcontext.mc_rsp; +#elif SANITIZER_NETBSD + ucontext_t *ucontext = (ucontext_t *)context; + *pc = ucontext->uc_mcontext.__gregs[_REG_RIP]; + *bp = ucontext->uc_mcontext.__gregs[_REG_RBP]; + *sp = ucontext->uc_mcontext.__gregs[_REG_RSP]; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; @@ -1603,6 +1690,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_eip; *bp = ucontext->uc_mcontext.mc_ebp; *sp = ucontext->uc_mcontext.mc_esp; +#elif SANITIZER_NETBSD + ucontext_t *ucontext = (ucontext_t *)context; + *pc = ucontext->uc_mcontext.__gregs[_REG_EIP]; + *bp = ucontext->uc_mcontext.__gregs[_REG_EBP]; + *sp = ucontext->uc_mcontext.__gregs[_REG_ESP]; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_EIP]; @@ -1704,4 +1796,4 @@ bool GetRandom(void *buffer, uptr length) { } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 11cad6b80..2d15525ee 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -14,7 +14,7 @@ #define SANITIZER_LINUX_H #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_posix.h" @@ -128,5 +128,5 @@ ALWAYS_INLINE uptr *get_android_tls_ptr() { } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #endif // SANITIZER_LINUX_H -- cgit v1.2.1 From d1348d80663566a292d1955b37f33ed4066ff201 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 20:49:20 +0000 Subject: Enable ubsan on NetBSD Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, vitalybuka, kcc, filcab, fjricci Reviewed By: fjricci Subscribers: srhines, kubamracek, mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36483 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310412 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/ubsan/ubsan_platform.h | 7 ++++--- test/ubsan/TestCases/Float/cast-overflow.cpp | 14 ++++++++++---- test/ubsan/lit.common.cfg | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 4a63674af..84ffa3904 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -534,7 +534,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia") set(COMPILER_RT_HAS_UBSAN TRUE) else() set(COMPILER_RT_HAS_UBSAN FALSE) diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h index 26e89f8c9..a26c37557 100644 --- a/lib/ubsan/ubsan_platform.h +++ b/lib/ubsan/ubsan_platform.h @@ -14,9 +14,10 @@ #define UBSAN_PLATFORM_H // Other platforms should be easy to add, and probably work as-is. -#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \ - (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \ - defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \ +#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(__NetBSD__)) && \ + (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \ + defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \ defined(__s390__)) # define CAN_SANITIZE_UB 1 #elif defined(_WIN32) || defined(__Fuchsia__) diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp index 85c5049b4..a53c663b1 100644 --- a/test/ubsan/TestCases/Float/cast-overflow.cpp +++ b/test/ubsan/TestCases/Float/cast-overflow.cpp @@ -18,11 +18,17 @@ # define BYTE_ORDER __DARWIN_BYTE_ORDER # define BIG_ENDIAN __DARWIN_BIG_ENDIAN # define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__NetBSD__) # include -# define BYTE_ORDER _BYTE_ORDER -# define BIG_ENDIAN _BIG_ENDIAN -# define LITTLE_ENDIAN _LITTLE_ENDIAN +# ifndef BYTE_ORDER +# define BYTE_ORDER _BYTE_ORDER +# endif +# ifndef BIG_ENDIAN +# define BIG_ENDIAN _BIG_ENDIAN +# endif +# ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN _LITTLE_ENDIAN +# endif #elif defined(_WIN32) # define BYTE_ORDER 0 # define BIG_ENDIAN 1 diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index b55fb5f6e..e165e72ed 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -70,7 +70,7 @@ config.substitutions.append( ("%gmlt ", " ".join(config.debug_info_flags) + " ") config.suffixes = ['.c', '.cc', '.cpp'] # Check that the host supports UndefinedBehaviorSanitizer tests -if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']: +if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows', 'NetBSD']: config.unsupported = True # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -- cgit v1.2.1 From 082c31c97841cad6165c0975301c419ee45ad6a7 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 20:50:07 +0000 Subject: Add NetBSD support in asan_symbolize.py Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, filcab, vitalybuka, kcc, fjricci Reviewed By: fjricci Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36484 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310413 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_symbolize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index 1a56e4412..d53ec3571 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -280,7 +280,7 @@ def BreakpadSymbolizerFactory(binary): def SystemSymbolizerFactory(system, addr, binary, arch): if system == 'Darwin': return DarwinSymbolizer(addr, binary, arch) - elif system == 'Linux' or system == 'FreeBSD': + elif system == 'Linux' or system == 'FreeBSD' or system == 'NetBSD': return Addr2LineSymbolizer(binary) @@ -370,7 +370,7 @@ class SymbolizationLoop(object): self.binary_name_filter = binary_name_filter self.dsym_hint_producer = dsym_hint_producer self.system = os.uname()[0] - if self.system not in ['Linux', 'Darwin', 'FreeBSD']: + if self.system not in ['Linux', 'Darwin', 'FreeBSD', 'NetBSD']: raise Exception('Unknown system') self.llvm_symbolizers = {} self.last_llvm_symbolizer = None -- cgit v1.2.1 From 43c12c39b55ee6dfabb909526e3626c694958744 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 20:52:54 +0000 Subject: Add NetBSD support in asan_malloc_linux.cc Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, fjricci, vitalybuka, filcab Reviewed By: fjricci Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36376 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310414 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_linux.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index beef81896..775142e6d 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -15,7 +15,8 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ + SANITIZER_NETBSD #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "asan_allocator.h" @@ -234,4 +235,5 @@ void ReplaceSystemMalloc() { } // namespace __asan #endif // SANITIZER_ANDROID -#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX \ + || SANITIZER_NETBSD -- cgit v1.2.1 From dc85b2098319fb97cbedca276199188d211b6b45 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 8 Aug 2017 21:18:36 +0000 Subject: [winasan] Fix hotpatching ntdll!strcpy for Win10 creators edition The 9 byte nop is a suffix of the 10 byte nop, and we need at most 6 bytes. ntdll's version of strcpy is written in assembly and is very clever. strcat tail calls strcpy but with a slightly different arrangement of argument registers at an alternate entry point. It looks like this: ntdll!strcpy: 00007ffd`64e8a7a0 4c8bd9 mov r11,rcx ntdll!__entry_from_strcat_in_strcpy: 00007ffd`64e8a7a3 482bca sub rcx,rdx 00007ffd`64e8a7a6 f6c207 test dl,7 If we overwrite more than two bytes in our interceptor, that label will no longer be a valid instruction boundary. By recognizing the 9 byte nop, we use the two byte backwards branch to start our trampoline, avoiding this issue. Fixes https://github.com/google/sanitizers/issues/829 Patch by David Major git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310419 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception_win.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index b2902d57f..3e593c98f 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -223,9 +223,8 @@ static bool IsMemoryPadding(uptr address, uptr size) { return true; } -static const u8 kHintNop10Bytes[] = { - 0x66, 0x66, 0x0F, 0x1F, 0x84, - 0x00, 0x00, 0x00, 0x00, 0x00 +static const u8 kHintNop9Bytes[] = { + 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; template @@ -240,8 +239,8 @@ static bool FunctionHasPrefix(uptr address, const T &pattern) { static bool FunctionHasPadding(uptr address, uptr size) { if (IsMemoryPadding(address - size, size)) return true; - if (size <= sizeof(kHintNop10Bytes) && - FunctionHasPrefix(address, kHintNop10Bytes)) + if (size <= sizeof(kHintNop9Bytes) && + FunctionHasPrefix(address, kHintNop9Bytes)) return true; return false; } -- cgit v1.2.1 From f9bc4d2adcfeaf4bfecdad20f83c811af6ffd138 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 8 Aug 2017 23:31:21 +0000 Subject: Try to appease compiler and break multiline comment. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310428 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_malloc_linux.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 775142e6d..118da9ca7 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -235,5 +235,5 @@ void ReplaceSystemMalloc() { } // namespace __asan #endif // SANITIZER_ANDROID -#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX \ - || SANITIZER_NETBSD +#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || + // SANITIZER_NETBSD -- cgit v1.2.1 From f569d19ea0c83ee6e59b64135727b0a2cd8434f8 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 9 Aug 2017 00:21:45 +0000 Subject: [asan] Complete the Fuchsia port Submitted on behalf of Roland McGrath. Reviewers: kcc, eugenis, alekseyshl, vitalybuka Reviewed By: vitalybuka Subscribers: filcab, vitalybuka, srhines, kubamracek, mgorny, phosek, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D35865 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310431 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/CMakeLists.txt | 1 + lib/asan/asan_fake_stack.cc | 4 +- lib/asan/asan_fuchsia.cc | 218 ++++++++++++++++++++++ lib/asan/asan_mapping.h | 5 +- lib/asan/asan_poisoning.h | 7 +- lib/asan/asan_rtl.cc | 1 + lib/asan/asan_shadow_setup.cc | 7 + lib/asan/asan_thread.cc | 6 + lib/sanitizer_common/sanitizer_fuchsia.cc | 3 + lib/sanitizer_common/sanitizer_thread_registry.cc | 3 +- 10 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 lib/asan/asan_fuchsia.cc diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 57c34051b..355466f8c 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -8,6 +8,7 @@ set(ASAN_SOURCES asan_errors.cc asan_fake_stack.cc asan_flags.cc + asan_fuchsia.cc asan_globals.cc asan_globals_win.cc asan_interceptors.cc diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc index 017b7d2af..6a064aaa1 100644 --- a/lib/asan/asan_fake_stack.cc +++ b/lib/asan/asan_fake_stack.cc @@ -171,7 +171,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { } } -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA static THREADLOCAL FakeStack *fake_stack_tls; FakeStack *GetTLSFakeStack() { @@ -183,7 +183,7 @@ void SetTLSFakeStack(FakeStack *fs) { #else FakeStack *GetTLSFakeStack() { return 0; } void SetTLSFakeStack(FakeStack *fs) { } -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA static FakeStack *GetFakeStack() { AsanThread *t = GetCurrentThread(); diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc new file mode 100644 index 000000000..f41fabdba --- /dev/null +++ b/lib/asan/asan_fuchsia.cc @@ -0,0 +1,218 @@ +//===-- asan_fuchsia.cc --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Fuchsia-specific details. +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include "asan_interceptors.h" +#include "asan_internal.h" +#include "asan_stack.h" +#include "asan_thread.h" + +#include +#include +#include +#include + +namespace __asan { + +// The system already set up the shadow memory for us. +// __sanitizer::GetMaxVirtualAddress has already been called by +// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc). +// Just do some additional sanity checks here. +void InitializeShadowMemory() { + if (Verbosity()) PrintAddressSpaceLayout(); + + // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address. + __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; + DCHECK(kLowShadowBeg != kDefaultShadowSentinel); + __asan_shadow_memory_dynamic_address = kLowShadowBeg; + + CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); + CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1); + CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit); + CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base); + CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1); + CHECK_EQ(kLowShadowEnd, 0); + CHECK_EQ(kLowShadowBeg, 0); +} + +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + +void AsanCheckDynamicRTPrereqs() {} +void AsanCheckIncompatibleRT() {} +void InitializeAsanInterceptors() {} + +void *AsanDoesNotSupportStaticLinkage() { return nullptr; } + +void InitializePlatformExceptionHandlers() {} +void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { + UNIMPLEMENTED(); +} + +// We can use a plain thread_local variable for TSD. +static thread_local void *per_thread; + +void *AsanTSDGet() { return per_thread; } + +void AsanTSDSet(void *tsd) { per_thread = tsd; } + +// There's no initialization needed, and the passed-in destructor +// will never be called. Instead, our own thread destruction hook +// (below) will call AsanThread::TSDDtor directly. +void AsanTSDInit(void (*destructor)(void *tsd)) { + DCHECK(destructor == &PlatformTSDDtor); +} + +void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } + +static inline size_t AsanThreadMmapSize() { + return RoundUpTo(sizeof(AsanThread), PAGE_SIZE); +} + +struct AsanThread::InitOptions { + uptr stack_bottom, stack_size; +}; + +// Shared setup between thread creation and startup for the initial thread. +static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, + uptr user_id, bool detached, + const char *name, uptr stack_bottom, + uptr stack_size) { + // In lieu of AsanThread::Create. + AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); + + AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; + u32 tid = + asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); + asanThreadRegistry().SetThreadName(tid, name); + + // On other systems, AsanThread::Init() is called from the new + // thread itself. But on Fuchsia we already know the stack address + // range beforehand, so we can do most of the setup right now. + const AsanThread::InitOptions options = {stack_bottom, stack_size}; + thread->Init(&options); + + return thread; +} + +// This gets the same arguments passed to Init by CreateAsanThread, above. +// We're in the creator thread before the new thread is actually started, +// but its stack address range is already known. We don't bother tracking +// the static TLS address range because the system itself already uses an +// ASan-aware allocator for that. +void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { + DCHECK_NE(GetCurrentThread(), this); + DCHECK_NE(GetCurrentThread(), nullptr); + CHECK_NE(options->stack_bottom, 0); + CHECK_NE(options->stack_size, 0); + stack_bottom_ = options->stack_bottom; + stack_top_ = options->stack_bottom + options->stack_size; +} + +// Called by __asan::AsanInitInternal (asan_rtl.c). +AsanThread *CreateMainThread() { + thrd_t self = thrd_current(); + char name[MX_MAX_NAME_LEN]; + CHECK_NE(__sanitizer::MainThreadStackBase, 0); + CHECK_GT(__sanitizer::MainThreadStackSize, 0); + AsanThread *t = CreateAsanThread( + nullptr, 0, reinterpret_cast(self), true, + _mx_object_get_property(thrd_get_mx_handle(self), MX_PROP_NAME, name, + sizeof(name)) == MX_OK + ? name + : nullptr, + __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); + SetCurrentThread(t); + return t; +} + +// This is called before each thread creation is attempted. So, in +// its first call, the calling thread is the initial and sole thread. +static void *BeforeThreadCreateHook(uptr user_id, bool detached, + const char *name, uptr stack_bottom, + uptr stack_size) { + EnsureMainThreadIDIsCorrect(); + // Strict init-order checking is thread-hostile. + if (flags()->strict_init_order) StopInitOrderChecking(); + + GET_STACK_TRACE_THREAD; + u32 parent_tid = GetCurrentTidOrInvalid(); + + return CreateAsanThread(&stack, parent_tid, user_id, detached, name, + stack_bottom, stack_size); +} + +// This is called after creating a new thread (in the creating thread), +// with the pointer returned by BeforeThreadCreateHook (above). +static void ThreadCreateHook(void *hook, bool aborted) { + AsanThread *thread = static_cast(hook); + if (!aborted) { + // The thread was created successfully. + // ThreadStartHook is already running in the new thread. + } else { + // The thread wasn't created after all. + // Clean up everything we set up in BeforeThreadCreateHook. + asanThreadRegistry().FinishThread(thread->tid()); + UnmapOrDie(thread, AsanThreadMmapSize()); + } +} + +// This is called in the newly-created thread before it runs anything else, +// with the pointer returned by BeforeThreadCreateHook (above). +// cf. asan_interceptors.cc:asan_thread_start +static void ThreadStartHook(void *hook, uptr os_id) { + AsanThread *thread = static_cast(hook); + SetCurrentThread(thread); + + // In lieu of AsanThread::ThreadStart. + asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false, + nullptr); +} + +// Each thread runs this just before it exits, +// with the pointer returned by BeforeThreadCreateHook (above). +// All per-thread destructors have already been called. +static void ThreadExitHook(void *hook, uptr os_id) { + AsanThread::TSDDtor(per_thread); +} + +} // namespace __asan + +// These are declared (in extern "C") by . +// The system runtime will call our definitions directly. + +void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, + const char *name, void *stack_base, + size_t stack_size) { + return __asan::BeforeThreadCreateHook( + reinterpret_cast(thread), detached, name, + reinterpret_cast(stack_base), stack_size); +} + +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { + __asan::ThreadCreateHook(hook, error != thrd_success); +} + +void __sanitizer_thread_start_hook(void *hook, thrd_t self) { + __asan::ThreadStartHook(hook, reinterpret_cast(self)); +} + +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { + __asan::ThreadExitHook(hook, reinterpret_cast(self)); +} + +#endif // SANITIZER_FUCHSIA diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index 695740cd9..408b3427a 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -144,8 +144,9 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #define SHADOW_SCALE kDefaultShadowScale - -#if SANITIZER_WORDSIZE == 32 +#if SANITIZER_FUCHSIA +# define SHADOW_OFFSET (0) +#elif SANITIZER_WORDSIZE == 32 # if SANITIZER_ANDROID # define SHADOW_OFFSET (0) # elif defined(__mips__) diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h index cc3281e08..1e00070bc 100644 --- a/lib/asan/asan_poisoning.h +++ b/lib/asan/asan_poisoning.h @@ -46,8 +46,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, // for mapping shadow and zeroing out pages doesn't "just work", so we should // probably provide higher-level interface for these operations. // For now, just memset on Windows. - if (value || - SANITIZER_WINDOWS == 1 || + if (value || SANITIZER_WINDOWS == 1 || + // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be + // changed at all. It doesn't currently have an efficient means + // to zero a bunch of pages, but maybe we should add one. + SANITIZER_FUCHSIA == 1 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index c75a46399..e32872452 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -528,6 +528,7 @@ void NOINLINE __asan_handle_no_return() { top = curr_thread->stack_top(); bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); } else { + CHECK(!SANITIZER_FUCHSIA); // If we haven't seen this thread, try asking the OS for stack bounds. uptr tls_addr, tls_size, stack_size; GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index b36e35780..33b4102b6 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -12,6 +12,11 @@ // Set up the shadow memory. //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_platform.h" + +// asan_fuchsia.cc has its own InitializeShadowMemory implementation. +#if !SANITIZER_FUCHSIA + #include "asan_internal.h" #include "asan_mapping.h" @@ -142,3 +147,5 @@ void InitializeShadowMemory() { } } // namespace __asan + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index b1a0d9a3b..74426f675 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -239,6 +239,10 @@ void AsanThread::Init() { &local); } +// Fuchsia doesn't use ThreadStart. +// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls. +#if !SANITIZER_FUCHSIA + thread_return_t AsanThread::ThreadStart( tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { Init(); @@ -283,6 +287,8 @@ void AsanThread::SetThreadStackAndTls() { CHECK(AddrIsInStack((uptr)&local)); } +#endif // !SANITIZER_FUCHSIA + void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); if (tls_begin_ != tls_end_) diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index e45a28418..75924536a 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -97,6 +97,9 @@ void InitTlsSize() {} void PrintModuleMap() {} +void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } +const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } + struct UnwindTraceArg { BufferedStackTrace *stack; u32 max_depth; diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc index 439e33a08..84c55fc81 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.cc +++ b/lib/sanitizer_common/sanitizer_thread_registry.cc @@ -204,7 +204,8 @@ void ThreadRegistry::SetThreadName(u32 tid, const char *name) { CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); - CHECK_EQ(ThreadStatusRunning, tctx->status); + CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, + tctx->status); tctx->SetName(name); } -- cgit v1.2.1 From 5f5d782f41c4db73d704a0d1d15dceb8f3f8e3e7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 9 Aug 2017 00:38:57 +0000 Subject: [asan] Refactor thread creation bookkeeping Summary: This is a pure refactoring change. It paves the way for OS-specific implementations, such as Fuchsia's, that can do most of the per-thread bookkeeping work in the creator thread before the new thread actually starts. This model is simpler and cleaner, avoiding some race issues that the interceptor code for thread creation has to do for the existing OS-specific implementations. Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Reviewed By: alekseyshl Subscribers: phosek, filcab, llvm-commits, kubamracek Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36385 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310432 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_internal.h | 3 +++ lib/asan/asan_rtl.cc | 7 +----- lib/asan/asan_thread.cc | 27 +++++++++++++++-------- lib/asan/asan_thread.h | 13 +++++++++-- lib/sanitizer_common/sanitizer_thread_registry.cc | 26 +++++++++++++++++----- 5 files changed, 53 insertions(+), 23 deletions(-) diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 3cfd75f49..19133e529 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -84,6 +84,9 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); +// asan_thread.cc +AsanThread *CreateMainThread(); + // Support function for __asan_(un)register_image_globals. Searches for the // loaded image containing `needle' and then enumerates all global metadata // structures declared in that image, applying `op' (e.g., diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index e32872452..6e83671ab 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -451,13 +451,8 @@ static void AsanInitInternal() { InitTlsSize(); // Create main thread. - AsanThread *main_thread = AsanThread::Create( - /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, - /* stack */ nullptr, /* detached */ true); + AsanThread *main_thread = CreateMainThread(); CHECK_EQ(0, main_thread->tid()); - SetCurrentThread(main_thread); - main_thread->ThreadStart(internal_getpid(), - /* signal_thread_is_registered */ nullptr); force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index 74426f675..c41d3ba94 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -27,11 +27,6 @@ namespace __asan { // AsanThreadContext implementation. -struct CreateThreadContextArgs { - AsanThread *thread; - StackTrace *stack; -}; - void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast(arg); if (args->stack) @@ -88,7 +83,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); thread->start_routine_ = start_routine; thread->arg_ = arg; - CreateThreadContextArgs args = { thread, stack }; + AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; asanThreadRegistry().CreateThread(*reinterpret_cast(thread), detached, parent_tid, &args); @@ -223,12 +218,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { return nullptr; } -void AsanThread::Init() { +void AsanThread::Init(const InitOptions *options) { next_stack_top_ = next_stack_bottom_ = 0; atomic_store(&stack_switching_, false, memory_order_release); fake_stack_ = nullptr; // Will be initialized lazily if needed. CHECK_EQ(this->stack_size(), 0U); - SetThreadStackAndTls(); + SetThreadStackAndTls(options); CHECK_GT(this->stack_size(), 0U); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); @@ -274,7 +269,21 @@ thread_return_t AsanThread::ThreadStart( return res; } -void AsanThread::SetThreadStackAndTls() { +AsanThread *CreateMainThread() { + AsanThread *main_thread = AsanThread::Create( + /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, + /* stack */ nullptr, /* detached */ true); + SetCurrentThread(main_thread); + main_thread->ThreadStart(internal_getpid(), + /* signal_thread_is_registered */ nullptr); + return main_thread; +} + +// This implementation doesn't use the argument, which is just passed down +// from the caller of Init (which see, above). It's only there to support +// OS-specific implementations that need more information passed through. +void AsanThread::SetThreadStackAndTls(const InitOptions *options) { + DCHECK_EQ(options, nullptr); uptr tls_size = 0; uptr stack_size = 0; GetThreadStackAndTls(tid() == 0, const_cast(&stack_bottom_), diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index 424f9e68d..d34942492 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -49,6 +49,11 @@ class AsanThreadContext : public ThreadContextBase { void OnCreated(void *arg) override; void OnFinished() override; + + struct CreateThreadContextArgs { + AsanThread *thread; + StackTrace *stack; + }; }; // AsanThreadContext objects are never freed, so we need many of them. @@ -62,7 +67,9 @@ class AsanThread { static void TSDDtor(void *tsd); void Destroy(); - void Init(); // Should be called from the thread itself. + struct InitOptions; + void Init(const InitOptions *options = nullptr); + thread_return_t ThreadStart(tid_t os_id, atomic_uintptr_t *signal_thread_is_registered); @@ -128,7 +135,9 @@ class AsanThread { private: // NOTE: There is no AsanThread constructor. It is allocated // via mmap() and *must* be valid in zero-initialized state. - void SetThreadStackAndTls(); + + void SetThreadStackAndTls(const InitOptions *options); + void ClearShadowForThreadStackAndTLS(); FakeStack *AsyncSignalSafeLazyInitFakeStack(); diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc index 84c55fc81..79f3caad2 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.cc +++ b/lib/sanitizer_common/sanitizer_thread_registry.cc @@ -54,8 +54,11 @@ void ThreadContextBase::SetJoined(void *arg) { } void ThreadContextBase::SetFinished() { - if (!detached) - status = ThreadStatusFinished; + // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state + // for a thread that never actually started. In that case the thread + // should go to ThreadStatusFinished regardless of whether it was created + // as detached. + if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; OnFinished(); } @@ -252,18 +255,29 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) { QuarantinePush(tctx); } +// Normally this is called when the thread is about to exit. If +// called in ThreadStatusCreated state, then this thread was never +// really started. We just did CreateThread for a prospective new +// thread before trying to create it, and then failed to actually +// create it, and so never called StartThread. void ThreadRegistry::FinishThread(u32 tid) { BlockingMutexLock l(&mtx_); CHECK_GT(alive_threads_, 0); alive_threads_--; - CHECK_GT(running_threads_, 0); - running_threads_--; CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); - CHECK_EQ(ThreadStatusRunning, tctx->status); + bool dead = tctx->detached; + if (tctx->status == ThreadStatusRunning) { + CHECK_GT(running_threads_, 0); + running_threads_--; + } else { + // The thread never really existed. + CHECK_EQ(tctx->status, ThreadStatusCreated); + dead = true; + } tctx->SetFinished(); - if (tctx->detached) { + if (dead) { tctx->SetDead(); QuarantinePush(tctx); } -- cgit v1.2.1 From 5ea17034a673941f369a46763891150e671f8c1a Mon Sep 17 00:00:00 2001 From: Oleg Ranevskyy Date: Thu, 10 Aug 2017 13:27:29 +0000 Subject: [compiler-rt][ARM] Fix filtering of ARM targets Summary: Similarly to i686, the ARM build target has multiple names, such as armhf, armv7 and so on. Currently we get duplicated symbol definitions for these targets while compiling the library. Each duplicated definition has its generic version from `lib/builtins` and an ARM-specialized version from `lib/builtins/arm`. This patch fixes filtering for ARM to ignore the generic definitions if they have their ARM specializations. Reviewers: compnerd Reviewed By: compnerd Subscribers: aemerson, dberris, llvm-commits, mgorny, asl, kristof.beyls Differential Revision: https://reviews.llvm.org/D35336 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310588 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index f0d3f5071..6b25c96ce 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -492,9 +492,13 @@ else () if (CAN_TARGET_${arch}) # NOTE: some architectures (e.g. i386) have multiple names. Ensure that # we catch them all. - set(_arch ${arch}) - if("${arch}" STREQUAL "i686") + set(_arch ${arch}) + if("${arch}" STREQUAL "i686") set(_arch "i386|i686") + elseif("${arch}" STREQUAL "armv6m") + set(_arch "arm|armv6m") + elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$") + set(_arch "arm") endif() # Filter out generic versions of routines that are re-implemented in -- cgit v1.2.1 From e3829d0bee44db530d5f542b5e49c078b0449ba6 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Thu, 10 Aug 2017 14:22:57 +0000 Subject: [sanitizer_common] Update sanitizers w.r.t. the new comparisons instrumentation API Added declarations of __sanitizer_cov_trace_const_cmp[1248] callbacks. For more details, please see https://reviews.llvm.org/D36465. Patch by Victor Chibotaru. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310596 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_fuchsia.cc | 4 ++++ lib/sanitizer_common/sanitizer_coverage_interface.inc | 4 ++++ lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 4 ++++ lib/sanitizer_common/sanitizer_interface_internal.h | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc index 9e5ff4bb9..491d5a215 100644 --- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -223,6 +223,10 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 0ed113f59..f909b74c9 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -18,6 +18,10 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 1b61c95c7..469656766 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -199,6 +199,10 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h index 043c73eed..942f0b1cb 100644 --- a/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/lib/sanitizer_common/sanitizer_interface_internal.h @@ -80,6 +80,14 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_trace_cmp8(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp1(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp2(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp4(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp8(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_trace_switch(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_trace_div4(); -- cgit v1.2.1 From 259aa6a72652545279711d06f5d86057e2303575 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 10 Aug 2017 18:40:09 +0000 Subject: Enable SafeStack on NetBSD Summary: make check-safestack: -- Testing: 8 tests, 8 threads -- Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. Testing Time: 0.44s Expected Passes : 7 Unsupported Tests : 1 Sponsored by Reviewers: joerg, vitalybuka, kcc, fjricci, filcab Reviewed By: vitalybuka Subscribers: mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36542 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310646 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/safestack/safestack.cc | 2 ++ test/safestack/lit.cfg | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 84ffa3904..078a62e49 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -541,7 +541,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD") set(COMPILER_RT_HAS_SAFESTACK TRUE) else() set(COMPILER_RT_HAS_SAFESTACK FALSE) diff --git a/lib/safestack/safestack.cc b/lib/safestack/safestack.cc index b194b6cfa..d783cd5a9 100644 --- a/lib/safestack/safestack.cc +++ b/lib/safestack/safestack.cc @@ -21,7 +21,9 @@ #include #include #include +#if !defined(__NetBSD__) #include +#endif #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" diff --git a/test/safestack/lit.cfg b/test/safestack/lit.cfg index fb5672936..87b678320 100644 --- a/test/safestack/lit.cfg +++ b/test/safestack/lit.cfg @@ -18,8 +18,7 @@ config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsaniti if config.lto_supported: config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=safe-stack ']))) -# SafeStack tests are currently supported on Linux, FreeBSD and Darwin only. -if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']: +if config.host_os not in ['Linux', 'FreeBSD', 'Darwin', 'NetBSD']: config.unsupported = True # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -- cgit v1.2.1 From 15c612158931f4ccad2d84f405356708c5ff4d5a Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 10 Aug 2017 18:51:51 +0000 Subject: Add NetBSD support in asan_linux.cc Summary: Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: fjricci, vitalybuka, joerg, kcc, filcab Reviewed By: vitalybuka Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36488 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310647 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_linux.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 6d47ba432..9ebfea254 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "asan_interceptors.h" #include "asan_internal.h" @@ -42,6 +42,10 @@ #if SANITIZER_ANDROID || SANITIZER_FREEBSD #include extern "C" void* _DYNAMIC; +#elif SANITIZER_NETBSD +#include +#include +extern Elf_Dyn _DYNAMIC; #else #include #include @@ -101,6 +105,15 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) return 0; +#if SANITIZER_NETBSD + // Ignore first entry (the main program) + char **p = (char **)data; + if (!(*p)) { + *p = (char *)-1; + return 0; + } +#endif + *(const char **)data = info->dlpi_name; return 1; } @@ -179,4 +192,4 @@ void *AsanDlSymNext(const char *sym) { } // namespace __asan -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -- cgit v1.2.1 From 53b30a2888f3da7d8912546e27978e8758fa5c81 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 10 Aug 2017 19:08:39 +0000 Subject: Enable ASAN on NetBSD Summary: This enables also static runtime option. Sponsored by Reviewers: joerg, vitalybuka, filcab, kcc, fjricci Reviewed By: vitalybuka Subscribers: mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36490 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310651 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 078a62e49..092d98dd1 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -483,14 +483,13 @@ else() set(COMPILER_RT_HAS_INTERCEPTION FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND - (NOT OS_NAME MATCHES "NetBSD")) +if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH) set(COMPILER_RT_HAS_ASAN TRUE) else() set(COMPILER_RT_HAS_ASAN FALSE) endif() -if (OS_NAME MATCHES "Linux|FreeBSD|Windows") +if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD") set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE) else() set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE) -- cgit v1.2.1 From 83dafd31d45ad9648dfde40206ebc33cd71af735 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 11 Aug 2017 22:28:02 +0000 Subject: [compiler-rt] Add SANITIZER_CXX_ABI_LIBNAME=libc++ option. Summary: This is to support Android where libc++abi is part of libc++. Reviewers: srhines, EricWF Subscribers: dberris, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D36640 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310769 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f277e0db..1db04f3a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,8 @@ if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi") else() list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi") endif() +elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++") + list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++") elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++") append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY) endif() -- cgit v1.2.1 From 7c74cefba29dbdda2d9328ce2db68a153103de45 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sun, 13 Aug 2017 20:18:15 +0000 Subject: Enable profile on NetBSD Summary: make check-profile: Failing Tests (2): Profile-i386 :: instrprof-dlopen.test Profile-x86_64 :: instrprof-dlopen.test Expected Passes : 64 Unsupported Tests : 42 Unexpected Failures: 2 Sponsored by Reviewers: joerg, vitalybuka, kcc, filcab, fjricci Reviewed By: vitalybuka Subscribers: vsk, llvm-commits, srhines, mgorny, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36603 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310800 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/profile/lit.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 092d98dd1..29a9e6863 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -519,7 +519,7 @@ else() endif() if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|NetBSD") set(COMPILER_RT_HAS_PROFILE TRUE) else() set(COMPILER_RT_HAS_PROFILE FALSE) diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 9ca394212..143752088 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -78,7 +78,7 @@ config.substitutions.append( ("%clangxx_profuse=", build_invocation(clang_cxxfla config.substitutions.append( ("%clang_lto_profgen=", build_invocation(clang_cflags, True) + " -fprofile-instr-generate=") ) -if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: +if config.host_os not in ['Darwin', 'FreeBSD', 'Linux', 'NetBSD']: config.unsupported = True if config.target_arch in ['armv7l']: -- cgit v1.2.1 From 1c85aaf50b80c5e1233ca176b13359d39b040c02 Mon Sep 17 00:00:00 2001 From: Sean Eveson Date: Mon, 14 Aug 2017 12:43:05 +0000 Subject: [llvm-cov] Fix compiler-rt tests failing in build bots after rL310827. The compiler-rt tests used llvm-cov with -filename-equivelence, which was replaced with the new option -path-equivalence in rL310827. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310836 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Linux/coverage_ctors.cpp | 2 +- test/profile/Linux/coverage_dtor.cpp | 2 +- test/profile/Linux/coverage_test.cpp | 6 +++--- test/profile/Linux/instrprof-comdat.test | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/profile/Linux/coverage_ctors.cpp b/test/profile/Linux/coverage_ctors.cpp index 021d9df5e..adf078e56 100644 --- a/test/profile/Linux/coverage_ctors.cpp +++ b/test/profile/Linux/coverage_ctors.cpp @@ -1,7 +1,7 @@ // RUN: %clangxx_profgen -std=c++11 -fuse-ld=gold -fcoverage-mapping -o %t %s // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw -// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s +// RUN: llvm-cov show %t -instr-profile %t.profdata -path-equivalence=/tmp,%S 2>&1 | FileCheck %s struct Base { int B; diff --git a/test/profile/Linux/coverage_dtor.cpp b/test/profile/Linux/coverage_dtor.cpp index 164151220..c91dd42d2 100644 --- a/test/profile/Linux/coverage_dtor.cpp +++ b/test/profile/Linux/coverage_dtor.cpp @@ -1,7 +1,7 @@ // RUN: %clang_profgen -x c++ -fno-exceptions -std=c++11 -fuse-ld=gold -fcoverage-mapping -o %t %s // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw -// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s +// RUN: llvm-cov show %t -instr-profile %t.profdata -path-equivalence=/tmp,%S 2>&1 | FileCheck %s int g = 100; struct Base { diff --git a/test/profile/Linux/coverage_test.cpp b/test/profile/Linux/coverage_test.cpp index 439c6382f..e636e5559 100644 --- a/test/profile/Linux/coverage_test.cpp +++ b/test/profile/Linux/coverage_test.cpp @@ -1,12 +1,12 @@ // RUN: %clang_profgen -fuse-ld=gold -O2 -fdata-sections -ffunction-sections -fcoverage-mapping -Wl,--gc-sections -o %t %s // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw -// RUN: llvm-cov show %t -instr-profile %t.profdata -filename-equivalence 2>&1 | FileCheck %s +// RUN: llvm-cov show %t -instr-profile %t.profdata -path-equivalence=/tmp,%S 2>&1 | FileCheck %s // BFD linker older than 2.26 has a bug that per-func profile data will be wrongly garbage collected when GC is turned on. We only do end-to-end test here without GC: // RUN: %clang_profgen -O2 -fcoverage-mapping -o %t.2 %s // RUN: env LLVM_PROFILE_FILE=%t.2.profraw %run %t.2 // RUN: llvm-profdata merge -o %t.2.profdata %t.2.profraw -// RUN: llvm-cov show %t.2 -instr-profile %t.2.profdata -filename-equivalence 2>&1 | FileCheck %s +// RUN: llvm-cov show %t.2 -instr-profile %t.2.profdata -path-equivalence=/tmp,%S 2>&1 | FileCheck %s // Check covmap is not garbage collected when GC is turned on with BFD linker. Due to the bug mentioned above, we can only // do the check with objdump: // RUN: %clang_profgen -O2 -fcoverage-mapping -Wl,--gc-sections -o %t.3 %s @@ -15,7 +15,7 @@ // RUN: %clang_profgen -fuse-ld=gold -O2 -fdata-sections -ffunction-sections -fPIE -pie -fcoverage-mapping -Wl,--gc-sections -o %t.pie %s // RUN: env LLVM_PROFILE_FILE=%t.pie.profraw %run %t.pie // RUN: llvm-profdata merge -o %t.pie.profdata %t.pie.profraw -// RUN: llvm-cov show %t.pie -instr-profile %t.pie.profdata -filename-equivalence 2>&1 | FileCheck %s +// RUN: llvm-cov show %t.pie -instr-profile %t.pie.profdata -path-equivalence=/tmp,%S 2>&1 | FileCheck %s void foo(bool cond) { // CHECK: [[@LINE]]| 1|void foo( if (cond) { // CHECK: [[@LINE]]| 1| if (cond) { diff --git a/test/profile/Linux/instrprof-comdat.test b/test/profile/Linux/instrprof-comdat.test index 5a11a241a..1490ea7f0 100644 --- a/test/profile/Linux/instrprof-comdat.test +++ b/test/profile/Linux/instrprof-comdat.test @@ -2,5 +2,5 @@ RUN: mkdir -p %t.d RUN: %clangxx_profgen -o %t.d/comdat -fcoverage-mapping -fuse-ld=gold %S/../Inputs/instrprof-comdat-1.cpp %S/../Inputs/instrprof-comdat-2.cpp RUN: LLVM_PROFILE_FILE=%t-comdat.profraw %run %t.d/comdat RUN: llvm-profdata merge -o %t.d/comdat.prof %t-comdat.profraw -RUN: llvm-cov show --filename-equivalence --instr-profile=%t.d/comdat.prof %t.d/comdat | FileCheck --check-prefix=HEADER %S/../Inputs/instrprof-comdat.h +RUN: llvm-cov show --path-equivalence=/tmp,%S --instr-profile=%t.d/comdat.prof %t.d/comdat | FileCheck --check-prefix=HEADER %S/../Inputs/instrprof-comdat.h -- cgit v1.2.1 From 83db677110a0953642661a2e526521e30c358c53 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 14 Aug 2017 14:53:47 +0000 Subject: [sanitizers] Add a blocking boolean to GetRandom prototype Summary: On platforms with `getrandom`, the system call defaults to blocking. This becomes an issue in the very early stage of the boot for Scudo, when the RNG source is not set-up yet: the syscall will block and we'll stall. Introduce a parameter to specify that the function should not block, defaulting to blocking as the underlying syscall does. Update Scudo to use the non-blocking version. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D36399 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310839 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 4 ++-- lib/sanitizer_common/sanitizer_linux.cc | 21 ++++++++++++++++----- lib/sanitizer_common/sanitizer_mac.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 2 +- lib/sanitizer_common/tests/sanitizer_common_test.cc | 20 +++++++++++--------- lib/scudo/scudo_utils.h | 13 ++++++++----- 6 files changed, 39 insertions(+), 23 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9e65639b9..048101295 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -857,8 +857,8 @@ const s32 kReleaseToOSIntervalNever = -1; void CheckNoDeepBind(const char *filename, int flag); // Returns the requested amount of random data (up to 256 bytes) that can then -// be used to seed a PRNG. -bool GetRandom(void *buffer, uptr length); +// be used to seed a PRNG. Defaults to blocking like the underlying syscall. +bool GetRandom(void *buffer, uptr length, bool blocking = true); } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 3ca762782..7923078a6 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -135,6 +135,15 @@ extern void internal_sigreturn(); } #endif +#if SANITIZER_LINUX && defined(__NR_getrandom) +# if !defined(GRND_NONBLOCK) +# define GRND_NONBLOCK 1 +# endif +# define SANITIZER_USE_GETRANDOM 1 +#else +# define SANITIZER_USE_GETRANDOM 0 +#endif // SANITIZER_LINUX && defined(__NR_getrandom) + namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) @@ -1768,25 +1777,27 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, return 0; } -bool GetRandom(void *buffer, uptr length) { +bool GetRandom(void *buffer, uptr length, bool blocking) { if (!buffer || !length || length > 256) return false; -#if defined(__NR_getrandom) +#if SANITIZER_USE_GETRANDOM static atomic_uint8_t skip_getrandom_syscall; if (!atomic_load_relaxed(&skip_getrandom_syscall)) { // Up to 256 bytes, getrandom will not be interrupted. - uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, 0); + uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, + blocking ? 0 : GRND_NONBLOCK); int rverrno = 0; if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) atomic_store_relaxed(&skip_getrandom_syscall, 1); else if (res == length) return true; } -#endif +#endif // SANITIZER_USE_GETRANDOM + // Up to 256 bytes, a read off /dev/urandom will not be interrupted. + // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. uptr fd = internal_open("/dev/urandom", O_RDONLY); if (internal_iserror(fd)) return false; - // internal_read deals with EINTR. uptr res = internal_read(fd, buffer, length); if (internal_iserror(res)) return false; diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 38b418314..6cb75266b 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -992,7 +992,7 @@ void CheckNoDeepBind(const char *filename, int flag) { } // FIXME: implement on this platform. -bool GetRandom(void *buffer, uptr length) { +bool GetRandom(void *buffer, uptr length, bool blocking) { UNIMPLEMENTED(); } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index c7772213a..a13a4c5a5 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -1022,7 +1022,7 @@ void CheckNoDeepBind(const char *filename, int flag) { } // FIXME: implement on this platform. -bool GetRandom(void *buffer, uptr length) { +bool GetRandom(void *buffer, uptr length, bool blocking) { UNIMPLEMENTED(); } diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index d92c9d9c3..9c62b4593 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -304,15 +304,17 @@ TEST(SanitizerCommon, InternalScopedString) { #if SANITIZER_LINUX TEST(SanitizerCommon, GetRandom) { u8 buffer_1[32], buffer_2[32]; - EXPECT_FALSE(GetRandom(nullptr, 32)); - EXPECT_FALSE(GetRandom(buffer_1, 0)); - EXPECT_FALSE(GetRandom(buffer_1, 512)); - EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2)); - for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) { - for (uptr i = 0; i < 100; i++) { - EXPECT_TRUE(GetRandom(buffer_1, size)); - EXPECT_TRUE(GetRandom(buffer_2, size)); - EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0); + for (bool blocking : { false, true }) { + EXPECT_FALSE(GetRandom(nullptr, 32, blocking)); + EXPECT_FALSE(GetRandom(buffer_1, 0, blocking)); + EXPECT_FALSE(GetRandom(buffer_1, 512, blocking)); + EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2)); + for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) { + for (uptr i = 0; i < 100; i++) { + EXPECT_TRUE(GetRandom(buffer_1, size, blocking)); + EXPECT_TRUE(GetRandom(buffer_2, size, blocking)); + EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0); + } } } } diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index 6c6c9d893..13269195b 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -44,11 +44,14 @@ INLINE u64 rotl(const u64 X, int K) { struct XoRoShiRo128Plus { public: void init() { - if (UNLIKELY(!GetRandom(reinterpret_cast(State), sizeof(State)))) { - // Early processes (eg: init) do not have /dev/urandom yet, but we still - // have to provide them with some degree of entropy. Not having a secure - // seed is not as problematic for them, as they are less likely to be - // the target of heap based vulnerabilities exploitation attempts. + if (UNLIKELY(!GetRandom(reinterpret_cast(State), sizeof(State), + /*blocking=*/false))) { + // On some platforms, early processes like `init` do not have an + // initialized random pool (getrandom blocks and /dev/urandom doesn't + // exist yet), but we still have to provide them with some degree of + // entropy. Not having a secure seed is not as problematic for them, as + // they are less likely to be the target of heap based vulnerabilities + // exploitation attempts. State[0] = NanoTime(); State[1] = 0; } -- cgit v1.2.1 From 3caa058f838394a73e896a500784a21915f209ef Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Mon, 14 Aug 2017 16:51:05 +0000 Subject: [PGO] Add support for relocate profile dumping directory Differential Revsion: http://reviews.llvm.org/D36648 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310857 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingFile.c | 28 +++++++++++++++++----------- lib/profile/InstrProfilingUtil.c | 3 ++- test/profile/instrprof-path.c | 18 +++++++++++++++++- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index d038bb9cb..ddfa39225 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -513,23 +513,29 @@ const char *__llvm_profile_get_path_prefix(void) { COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { const char *EnvFilenamePat; - const char *SelectedPat = NULL; - ProfileNameSpecifier PNS = PNS_unknown; int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); EnvFilenamePat = getFilenamePatFromEnv(); - if (EnvFilenamePat) { - SelectedPat = EnvFilenamePat; - PNS = PNS_environment; - } else if (hasCommandLineOverrider) { - SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; - PNS = PNS_command_line; + if (EnvFilenamePat) + parseAndSetFilename(EnvFilenamePat, PNS_environment, 0); + else if (hasCommandLineOverrider) { + const char *SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; + + size_t PrefixLen; + int StripLen; + const char *Prefix = lprofGetPathPrefix(&StripLen, &PrefixLen); + if (Prefix != NULL) { + char *StripPat = + COMPILER_RT_ALLOCA(PrefixLen + 1 + strlen(SelectedPat) + 1); + lprofApplyPathPrefix(StripPat, SelectedPat, Prefix, PrefixLen, StripLen); + SelectedPat = StripPat; + } + + parseAndSetFilename(SelectedPat, PNS_command_line, Prefix ? 1 : 0); } else { - SelectedPat = NULL; - PNS = PNS_default; + parseAndSetFilename(NULL, PNS_default, 0); } - parseAndSetFilename(SelectedPat, PNS, 0); } /* This API is directly called by the user application code. It has the diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index fb68f30a5..bed97e526 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -196,7 +196,8 @@ lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix, memcpy(Dest, Prefix, PrefixLen); - if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1])) + if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]) && + !IS_DIR_SEPARATOR(StrippedPathStr[0])) Dest[PrefixLen++] = DIR_SEPARATOR; memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1); diff --git a/test/profile/instrprof-path.c b/test/profile/instrprof-path.c index 28ee8ad0a..ff0586b8d 100644 --- a/test/profile/instrprof-path.c +++ b/test/profile/instrprof-path.c @@ -1,6 +1,8 @@ // RUN: %clang_pgogen -O2 -o %t.0 %s // RUN: %clang_pgogen=%t.d1 -O2 -o %t.1 %s // RUN: %clang_pgogen=%t.d1/%t.d2 -O2 -o %t.2 %s +// RUN: %clang_pgogen=a/b/c/d -O2 -o %t.3 %s +// RUN: %clang_pgogen=/a/b/c/d -O2 -o %t.4 %s // // RUN: %run %t.0 "" // RUN: env LLVM_PROFILE_FILE=%t.d1/default.profraw %run %t.0 %t.d1/ @@ -9,6 +11,17 @@ // RUN: %run %t.2 %t.d1/%t.d2/ // RUN: %run %t.2 %t.d1/%t.d2/ %t.d1/%t.d2/%t.d3/blah.profraw %t.d1/%t.d2/%t.d3/ +// RUN: env GCOV_PREFIX=%t.prefix %run %t.3 %t.prefix/a/b/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=1 %run %t.3 %t.prefix/b/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=2 %run %t.3 %t.prefix/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=3 %run %t.3 %t.prefix/d/ + +// RUN: env GCOV_PREFIX=%t.prefix %run %t.4 %t.prefix/a/b/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=1 %run %t.4 %t.prefix/b/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=2 %run %t.4 %t.prefix/c/d/ +// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=3 %run %t.4 %t.prefix/d/ + +#include #include const char *__llvm_profile_get_path_prefix(); @@ -24,8 +37,11 @@ int main(int argc, const char *argv[]) { expected = argv[1]; prefix = __llvm_profile_get_path_prefix(); - if (strcmp(prefix, expected)) + if (strcmp(prefix, expected)) { + fprintf(stderr, "Expected = %s\n", expected); + fprintf(stderr, " Actual = %s\n", prefix); return 1; + } if (argc == 4) { __llvm_profile_set_filename(argv[2]); -- cgit v1.2.1 From 435b4b3eb8f094a9ccb434b23aa87b1e56055dac Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 14 Aug 2017 20:42:43 +0000 Subject: Fix a cmake typo. Also add "libc++" to list of property values (AFAIK that only affects the cmake gui). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310883 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db04f3a4..e3e5627e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ pythonize_bool(SANITIZER_CAN_USE_CXXABI) set(SANITIZER_CXX_ABI "default" CACHE STRING "Specify C++ ABI library to use.") -set(CXXABIS none default libcxxabi libstdc++) +set(CXXABIS none default libcxxabi libstdc++ libc++) set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS}) if (SANITIZER_CXX_ABI STREQUAL "default") @@ -117,7 +117,7 @@ if (SANITIZER_CXX_ABI STREQUAL "default") else() set(SANITIZER_CXX_ABI_LIBNAME "libstdc++") endif() -elseif() +else() set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}") endif() -- cgit v1.2.1 From 4ae44f4ac154fc0bb0458f33c4c6bef0837d9fa8 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Mon, 14 Aug 2017 20:48:47 +0000 Subject: [builtins][ARM] Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation mode (-mthumb, -marm), it reflect's capability of given CPU. Due to this: •use tbumb and thumb2 insteand of __ARM_ARCH_ISA_THUMB •use '.thumb' directive consistently in all affected files •decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION() (This is based off Michal's patch https://reviews.llvm.org/D30938) Reviewers: dim, rengolin, compnerd, strejda Reviewed By: compnerd Subscribers: peter.smith, kubamracek, mgorny, javed.absar, kristof.beyls, jamesduley, aemerson, llvm-commits Differential Revision: https://reviews.llvm.org/D31220 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310884 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_cdcmp.S | 4 ++-- lib/builtins/arm/aeabi_cfcmp.S | 4 ++-- lib/builtins/arm/aeabi_idivmod.S | 8 ++++--- lib/builtins/arm/aeabi_uidivmod.S | 6 +++-- lib/builtins/arm/bswapdi2.S | 8 +------ lib/builtins/arm/bswapsi2.S | 8 +------ lib/builtins/arm/clzdi2.S | 9 +------ lib/builtins/arm/clzsi2.S | 8 +------ lib/builtins/arm/comparesf2.S | 28 +++++++++++----------- lib/builtins/arm/divmodsi4.S | 8 +------ lib/builtins/arm/divsi3.S | 18 +++++--------- lib/builtins/arm/modsi3.S | 8 +------ lib/builtins/arm/udivmodsi4.S | 13 +++-------- lib/builtins/arm/udivsi3.S | 32 +++++++++++-------------- lib/builtins/arm/umodsi3.S | 12 +++------- lib/builtins/assembly.h | 49 +++++++++++++++++++++++++++++---------- 16 files changed, 95 insertions(+), 128 deletions(-) diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S index 3e7a8b86b..b06f294e2 100644 --- a/lib/builtins/arm/aeabi_cdcmp.S +++ b/lib/builtins/arm/aeabi_cdcmp.S @@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq) push {r0-r3, lr} bl __aeabi_cdcmpeq_check_nan cmp r0, #1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) beq 1f // NaN has been ruled out, so __aeabi_cdcmple can't trap mov r0, sp @@ -78,7 +78,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple) bl __aeabi_dcmplt cmp r0, #1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bne 1f // Z = 0, C = 0 movs r0, #1 diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S index 1f304ffd9..7bc84073f 100644 --- a/lib/builtins/arm/aeabi_cfcmp.S +++ b/lib/builtins/arm/aeabi_cfcmp.S @@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq) push {r0-r3, lr} bl __aeabi_cfcmpeq_check_nan cmp r0, #1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) beq 1f // NaN has been ruled out, so __aeabi_cfcmple can't trap mov r0, sp @@ -78,7 +78,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple) bl __aeabi_fcmplt cmp r0, #1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bne 1f // Z = 0, C = 0 movs r0, #1 diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S index 0164b15dc..9c9c80ab5 100644 --- a/lib/builtins/arm/aeabi_idivmod.S +++ b/lib/builtins/arm/aeabi_idivmod.S @@ -20,16 +20,18 @@ #endif .syntax unified + .text + DEFINE_CODE_STATE .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) push {r0, r1, lr} bl SYMBOL_NAME(__divsi3) pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom muls r2, r0, r2 // r2 = quot * denom subs r1, r1, r2 JMP (r3) -#else +#else // defined(USE_THUMB_1) push { lr } sub sp, sp, #4 mov r2, sp @@ -42,7 +44,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) ldr r1, [sp] add sp, sp, #4 pop { pc } -#endif // __ARM_ARCH_ISA_THUMB == 1 +#endif // defined(USE_THUMB_1) END_COMPILERRT_FUNCTION(__aeabi_idivmod) NO_EXEC_STACK_DIRECTIVE diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S index a627fc740..88a4a6d8b 100644 --- a/lib/builtins/arm/aeabi_uidivmod.S +++ b/lib/builtins/arm/aeabi_uidivmod.S @@ -21,9 +21,11 @@ #endif .syntax unified + .text + DEFINE_CODE_STATE .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) cmp r0, r1 bcc LOCAL_LABEL(case_denom_larger) push {r0, r1, lr} @@ -36,7 +38,7 @@ LOCAL_LABEL(case_denom_larger): movs r1, r0 movs r0, #0 JMP (lr) -#else +#else // defined(USE_THUMB_1) push { lr } sub sp, sp, #4 mov r2, sp diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S index fb226cea2..e9db8bac7 100644 --- a/lib/builtins/arm/bswapdi2.S +++ b/lib/builtins/arm/bswapdi2.S @@ -11,9 +11,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE // // extern uint64_t __bswapdi2(uint64_t); @@ -21,11 +19,7 @@ // Reverse all the bytes in a 64-bit integer. // .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2) -#else DEFINE_COMPILERRT_FUNCTION(__bswapdi2) -#endif #if __ARM_ARCH < 6 // before armv6 does not have "rev" instruction // r2 = rev(r0) diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S index 553c3c2e3..1f6eed5c1 100644 --- a/lib/builtins/arm/bswapsi2.S +++ b/lib/builtins/arm/bswapsi2.S @@ -11,9 +11,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE // // extern uint32_t __bswapsi2(uint32_t); @@ -21,11 +19,7 @@ // Reverse all the bytes in a 32-bit integer. // .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2) -#else DEFINE_COMPILERRT_FUNCTION(__bswapsi2) -#endif #if __ARM_ARCH < 6 // before armv6 does not have "rev" instruction eor r1, r0, r0, ror #16 diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S index 6068c176f..fc03b385c 100644 --- a/lib/builtins/arm/clzdi2.S +++ b/lib/builtins/arm/clzdi2.S @@ -15,17 +15,10 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif - + DEFINE_CODE_STATE .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2) -#else DEFINE_COMPILERRT_FUNCTION(__clzdi2) -#endif #ifdef __ARM_FEATURE_CLZ #ifdef __ARMEB__ cmp r0, 0 diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S index c2ba3a8cf..f2ce59c90 100644 --- a/lib/builtins/arm/clzsi2.S +++ b/lib/builtins/arm/clzsi2.S @@ -15,16 +15,10 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2) -#else DEFINE_COMPILERRT_FUNCTION(__clzsi2) -#endif #ifdef __ARM_FEATURE_CLZ clz r0, r0 JMP(lr) diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S index ef7091bf3..c6c4cc067 100644 --- a/lib/builtins/arm/comparesf2.S +++ b/lib/builtins/arm/comparesf2.S @@ -38,10 +38,9 @@ //===----------------------------------------------------------------------===// #include "../assembly.h" -.syntax unified -#if __ARM_ARCH_ISA_THUMB == 2 -.thumb -#endif + .syntax unified + .text + DEFINE_CODE_STATE @ int __eqsf2(float a, float b) @@ -53,7 +52,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) #endif // Make copies of a and b with the sign bit shifted off the top. These will // be used to detect zeros and NaNs. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 @@ -67,7 +66,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // flag if both a and b are zero (of either sign). The shift of r3 doesn't // effect this at all, but it *does* make sure that the C flag is clear for // the subsequent operations. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) lsrs r6, r3, #1 orrs r6, r2 #else @@ -75,7 +74,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) #endif // Next, we check if a and b have the same or different signs. If they have // opposite signs, this eor will set the N flag. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) beq 1f movs r6, r0 eors r6, r1 @@ -89,7 +88,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // ignoring NaNs for now), this subtract will zero out r0. If they have the // same sign, the flags are updated as they would be for a comparison of the // absolute values of a and b. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bmi 1f subs r0, r2, r3 1: @@ -108,7 +107,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // still clear from the shift argument in orrs; if a is positive and b // negative, this places 0 in r0; if a is negative and b positive, -1 is // placed in r0. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bhs 1f // Here if a and b have the same sign and absA < absB, the result is thus // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan). @@ -127,7 +126,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed // in r0, which is the desired result. Conversely, if both are positive // and a > b, zero is placed in r0. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bls 1f // Here both have the same sign and absA > absB. movs r0, #1 @@ -145,14 +144,14 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2) // If a == b, then the Z flag is set, so we can get the correct final value // into r0 by simply or'ing with 1 if Z is clear. // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b. -#if __ARM_ARCH_ISA_THUMB != 1 +#if !defined(USE_THUMB_1) it ne orrne r0, r0, #1 #endif // Finally, we need to deal with NaNs. If either argument is NaN, replace // the value in r0 with 1. -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) LOCAL_LABEL(CHECK_NAN): movs r6, #0xff lsls r6, #24 @@ -189,7 +188,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2) vmov r0, s0 vmov r1, s1 #endif -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 @@ -255,6 +254,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) .p2align 2 DEFINE_COMPILERRT_FUNCTION(__unordsf2) + #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 @@ -263,7 +263,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2) lsls r2, r0, #1 lsls r3, r1, #1 movs r0, #0 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) movs r1, #0xff lsls r1, #24 cmp r2, r1 diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S index 999c310ec..8a027b741 100644 --- a/lib/builtins/arm/divmodsi4.S +++ b/lib/builtins/arm/divmodsi4.S @@ -23,20 +23,14 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE @ int __divmodsi4(int divident, int divisor, int *remainder) @ Calculate the quotient and remainder of the (signed) division. The return @ value is the quotient, the remainder is placed in the variable. .p2align 3 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4) -#else DEFINE_COMPILERRT_FUNCTION(__divmodsi4) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divzero) diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S index f066f60ad..19757af17 100644 --- a/lib/builtins/arm/divsi3.S +++ b/lib/builtins/arm/divsi3.S @@ -20,11 +20,9 @@ #define CLEAR_FRAME_AND_RETURN \ pop {r4, r7, pc} - .syntax unified - .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + .syntax unified + .text + DEFINE_CODE_STATE .p2align 3 // Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine. @@ -33,11 +31,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3) @ int __divsi3(int divident, int divisor) @ Calculate and return the quotient of the (signed) division. -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3) -#else DEFINE_COMPILERRT_FUNCTION(__divsi3) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1,r1 beq LOCAL_LABEL(divzero) @@ -49,14 +43,14 @@ LOCAL_LABEL(divzero): #else ESTABLISH_FRAME // Set aside the sign of the quotient. -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) movs r4, r0 eors r4, r1 # else eor r4, r0, r1 # endif // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) asrs r2, r0, #31 asrs r3, r1, #31 eors r0, r2 @@ -72,7 +66,7 @@ ESTABLISH_FRAME // abs(a) / abs(b) bl SYMBOL_NAME(__udivsi3) // Apply sign of quotient to result and return. -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) asrs r4, #31 eors r0, r4 subs r0, r0, r4 diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S index 1d302edc6..be263834d 100644 --- a/lib/builtins/arm/modsi3.S +++ b/lib/builtins/arm/modsi3.S @@ -22,19 +22,13 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE @ int __modsi3(int divident, int divisor) @ Calculate and return the remainder of the (signed) division. .p2align 3 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3) -#else DEFINE_COMPILERRT_FUNCTION(__modsi3) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divzero) diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S index 1ad8ee34b..ee3950c9b 100644 --- a/lib/builtins/arm/udivmodsi4.S +++ b/lib/builtins/arm/udivmodsi4.S @@ -16,10 +16,7 @@ .syntax unified .text - -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor, @ unsigned int *remainder) @@ -27,11 +24,7 @@ @ value is the quotient, the remainder is placed in the variable. .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4) -#else DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divby0) @@ -67,7 +60,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -78,7 +71,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) mov r3, #0 bx ip # else -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif str r4, [sp, #-8]! diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S index b97b3080b..6dea27d40 100644 --- a/lib/builtins/arm/udivsi3.S +++ b/lib/builtins/arm/udivsi3.S @@ -17,9 +17,7 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif +DEFINE_CODE_STATE .p2align 2 DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) @@ -27,11 +25,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) @ unsigned int __udivsi3(unsigned int divident, unsigned int divisor) @ Calculate and return the quotient of the (unsigned) division. -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3) -#else DEFINE_COMPILERRT_FUNCTION(__udivsi3) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divby0) @@ -49,7 +43,7 @@ LOCAL_LABEL(divby0): #else /* ! __ARM_ARCH_EXT_IDIV__ */ cmp r1, #1 bcc LOCAL_LABEL(divby0) -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bne LOCAL_LABEL(num_neq_denom) JMP(lr) LOCAL_LABEL(num_neq_denom): @@ -58,7 +52,7 @@ LOCAL_LABEL(num_neq_denom): JMPc(lr, eq) #endif cmp r0, r1 -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) bhs LOCAL_LABEL(num_ge_denom) movs r0, #0 JMP(lr) @@ -90,7 +84,7 @@ LOCAL_LABEL(num_ge_denom): clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -101,17 +95,17 @@ LOCAL_LABEL(num_ge_denom): mov r3, #0 bx ip # else /* No CLZ Feature */ -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) # define BLOCK_SIZE 10 # else # define BLOCK_SIZE 12 # endif mov r2, r0 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) mov ip, r0 adr r0, LOCAL_LABEL(div0block) adds r0, #1 @@ -120,7 +114,7 @@ LOCAL_LABEL(num_ge_denom): # endif lsrs r3, r2, #16 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_16) movs r2, r3 subs r0, r0, #(16 * BLOCK_SIZE) @@ -132,7 +126,7 @@ LOCAL_LABEL(skip_16): lsrs r3, r2, #8 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_8) movs r2, r3 subs r0, r0, #(8 * BLOCK_SIZE) @@ -144,7 +138,7 @@ LOCAL_LABEL(skip_8): lsrs r3, r2, #4 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_4) movs r2, r3 subs r0, r0, #(4 * BLOCK_SIZE) @@ -156,7 +150,7 @@ LOCAL_LABEL(skip_4): lsrs r3, r2, #2 cmp r3, r1 -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) blo LOCAL_LABEL(skip_2) movs r2, r3 subs r0, r0, #(2 * BLOCK_SIZE) @@ -167,7 +161,7 @@ LOCAL_LABEL(skip_2): # endif /* Last block, no need to update r2 or r3. */ -# if __ARM_ARCH_ISA_THUMB == 1 +# if defined(USE_THUMB_1) lsrs r3, r2, #1 cmp r3, r1 blo LOCAL_LABEL(skip_1) @@ -203,7 +197,7 @@ LOCAL_LABEL(divby0): # endif -#if __ARM_ARCH_ISA_THUMB == 1 +#if defined(USE_THUMB_1) #define block(shift) \ lsls r2, r1, IMM shift; \ cmp r0, r2; \ diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S index 672487e81..069fad34c 100644 --- a/lib/builtins/arm/umodsi3.S +++ b/lib/builtins/arm/umodsi3.S @@ -16,19 +16,13 @@ .syntax unified .text -#if __ARM_ARCH_ISA_THUMB == 2 - .thumb -#endif + DEFINE_CODE_STATE @ unsigned int __umodsi3(unsigned int divident, unsigned int divisor) @ Calculate and return the remainder of the (unsigned) division. .p2align 2 -#if __ARM_ARCH_ISA_THUMB == 2 -DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3) -#else DEFINE_COMPILERRT_FUNCTION(__umodsi3) -#endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divby0) @@ -65,7 +59,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else @@ -74,7 +68,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3) sub ip, ip, r3, lsl #3 bx ip # else -# if __ARM_ARCH_ISA_THUMB == 2 +# if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif mov r2, r0 diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index b15da5234..825fe29f6 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -68,10 +68,42 @@ #endif #if defined(__arm__) + +/* + * Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros: + * - for '-mthumb -march=armv6' compiler defines '__thumb__' + * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' + */ +#if defined(__thumb2__) || defined(__thumb__) +#define DEFINE_CODE_STATE .thumb +#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR +#if defined(__thumb2__) +#define USE_THUMB_2 +#define IT(cond) it cond +#define ITT(cond) itt cond +#define ITE(cond) ite cond +#else +#define USE_THUMB_1 +#define IT(cond) +#define ITT(cond) +#define ITE(cond) +#endif // defined(__thumb__2) +#else // !defined(__thumb2__) && !defined(__thumb__) +#define DEFINE_CODE_STATE .arm +#define DECLARE_FUNC_ENCODING +#define IT(cond) +#define ITT(cond) +#define ITE(cond) +#endif + +#if defined(USE_THUMB_1) && defined(USE_THUMB_2) +#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together." +#endif + #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 #define ARM_HAS_BX #endif -#if !defined(__ARM_FEATURE_CLZ) && __ARM_ARCH_ISA_THUMB != 1 && \ +#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) #define __ARM_FEATURE_CLZ #endif @@ -93,17 +125,7 @@ JMP(ip) #endif -#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 +#if defined(USE_THUMB_2) #define WIDE(op) op.w #else #define WIDE(op) op @@ -126,6 +148,7 @@ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) \ + DECLARE_FUNC_ENCODING \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ @@ -141,12 +164,14 @@ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_FUNC_ENCODING \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ + DECLARE_FUNC_ENCODING \ name: #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ -- cgit v1.2.1 From 6a52c89fd901ed4e70aa567e99488f380afbbc67 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Mon, 14 Aug 2017 21:44:33 +0000 Subject: [builtins] fix build error on non-ARM for r310884 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310890 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 825fe29f6..58116114a 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -130,6 +130,8 @@ #else #define WIDE(op) op #endif +#else // !defined(__arm) +#define DECLARE_FUNC_ENCODING #endif #define GLUE2(a, b) a##b -- cgit v1.2.1 From 237a4de6d7bb4234853740591cea82f8d2d603ff Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 15 Aug 2017 03:13:01 +0000 Subject: Revert r310857 due to internal test failure git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310907 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingFile.c | 28 +++++++++++----------------- lib/profile/InstrProfilingUtil.c | 3 +-- test/profile/instrprof-path.c | 18 +----------------- 3 files changed, 13 insertions(+), 36 deletions(-) diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index ddfa39225..d038bb9cb 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -513,29 +513,23 @@ const char *__llvm_profile_get_path_prefix(void) { COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { const char *EnvFilenamePat; + const char *SelectedPat = NULL; + ProfileNameSpecifier PNS = PNS_unknown; int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); EnvFilenamePat = getFilenamePatFromEnv(); - if (EnvFilenamePat) - parseAndSetFilename(EnvFilenamePat, PNS_environment, 0); - else if (hasCommandLineOverrider) { - const char *SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; - - size_t PrefixLen; - int StripLen; - const char *Prefix = lprofGetPathPrefix(&StripLen, &PrefixLen); - if (Prefix != NULL) { - char *StripPat = - COMPILER_RT_ALLOCA(PrefixLen + 1 + strlen(SelectedPat) + 1); - lprofApplyPathPrefix(StripPat, SelectedPat, Prefix, PrefixLen, StripLen); - SelectedPat = StripPat; - } - - parseAndSetFilename(SelectedPat, PNS_command_line, Prefix ? 1 : 0); + if (EnvFilenamePat) { + SelectedPat = EnvFilenamePat; + PNS = PNS_environment; + } else if (hasCommandLineOverrider) { + SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; + PNS = PNS_command_line; } else { - parseAndSetFilename(NULL, PNS_default, 0); + SelectedPat = NULL; + PNS = PNS_default; } + parseAndSetFilename(SelectedPat, PNS, 0); } /* This API is directly called by the user application code. It has the diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index bed97e526..fb68f30a5 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -196,8 +196,7 @@ lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix, memcpy(Dest, Prefix, PrefixLen); - if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]) && - !IS_DIR_SEPARATOR(StrippedPathStr[0])) + if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1])) Dest[PrefixLen++] = DIR_SEPARATOR; memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1); diff --git a/test/profile/instrprof-path.c b/test/profile/instrprof-path.c index ff0586b8d..28ee8ad0a 100644 --- a/test/profile/instrprof-path.c +++ b/test/profile/instrprof-path.c @@ -1,8 +1,6 @@ // RUN: %clang_pgogen -O2 -o %t.0 %s // RUN: %clang_pgogen=%t.d1 -O2 -o %t.1 %s // RUN: %clang_pgogen=%t.d1/%t.d2 -O2 -o %t.2 %s -// RUN: %clang_pgogen=a/b/c/d -O2 -o %t.3 %s -// RUN: %clang_pgogen=/a/b/c/d -O2 -o %t.4 %s // // RUN: %run %t.0 "" // RUN: env LLVM_PROFILE_FILE=%t.d1/default.profraw %run %t.0 %t.d1/ @@ -11,17 +9,6 @@ // RUN: %run %t.2 %t.d1/%t.d2/ // RUN: %run %t.2 %t.d1/%t.d2/ %t.d1/%t.d2/%t.d3/blah.profraw %t.d1/%t.d2/%t.d3/ -// RUN: env GCOV_PREFIX=%t.prefix %run %t.3 %t.prefix/a/b/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=1 %run %t.3 %t.prefix/b/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=2 %run %t.3 %t.prefix/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=3 %run %t.3 %t.prefix/d/ - -// RUN: env GCOV_PREFIX=%t.prefix %run %t.4 %t.prefix/a/b/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=1 %run %t.4 %t.prefix/b/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=2 %run %t.4 %t.prefix/c/d/ -// RUN: env GCOV_PREFIX=%t.prefix env GCOV_PREFIX_STRIP=3 %run %t.4 %t.prefix/d/ - -#include #include const char *__llvm_profile_get_path_prefix(); @@ -37,11 +24,8 @@ int main(int argc, const char *argv[]) { expected = argv[1]; prefix = __llvm_profile_get_path_prefix(); - if (strcmp(prefix, expected)) { - fprintf(stderr, "Expected = %s\n", expected); - fprintf(stderr, " Actual = %s\n", prefix); + if (strcmp(prefix, expected)) return 1; - } if (argc == 4) { __llvm_profile_set_filename(argv[2]); -- cgit v1.2.1 From 5761b5b90a374f6a69664ac504c8f765d2acb680 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 15 Aug 2017 09:56:47 +0000 Subject: Revert: Enable profile on NetBSD Requested by V.Kumar. Not all tests pass. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310912 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/profile/lit.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 29a9e6863..092d98dd1 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -519,7 +519,7 @@ else() endif() if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|NetBSD") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android") set(COMPILER_RT_HAS_PROFILE TRUE) else() set(COMPILER_RT_HAS_PROFILE FALSE) diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 143752088..9ca394212 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -78,7 +78,7 @@ config.substitutions.append( ("%clangxx_profuse=", build_invocation(clang_cxxfla config.substitutions.append( ("%clang_lto_profgen=", build_invocation(clang_cflags, True) + " -fprofile-instr-generate=") ) -if config.host_os not in ['Darwin', 'FreeBSD', 'Linux', 'NetBSD']: +if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: config.unsupported = True if config.target_arch in ['armv7l']: -- cgit v1.2.1 From 8ffc41adbd409d8e5c2211cf93b8db79158d7a9d Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 15 Aug 2017 18:32:28 +0000 Subject: [compiler-rt CMake] CMake refactoring: create directories in helper func. Change macro to a function, move creating test directory into `add_compiler_rt_test`. Differential Revision: https://reviews.llvm.org/D36724 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310943 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 12 +++++++----- lib/asan/tests/CMakeLists.txt | 5 ----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 78663353c..34afc10a4 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -295,13 +295,15 @@ endif() # OBJECTS # DEPS # LINK_FLAGS ) -macro(add_compiler_rt_test test_suite test_name) +function(add_compiler_rt_test test_suite test_name) cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN}) - set(output_bin ${CMAKE_CURRENT_BINARY_DIR}) + set(output_dir ${CMAKE_CURRENT_BINARY_DIR}) if(TEST_SUBDIR) - set(output_bin "${output_bin}/${TEST_SUBDIR}") + set(output_dir "${output_dir}/${TEST_SUBDIR}") endif() - set(output_bin "${output_bin}/${CMAKE_CFG_RESOLVED_INTDIR}${test_name}") + set(output_dir "${output_dir}/${CMAKE_CFG_INTDIR}") + file(MAKE_DIRECTORY "${output_dir}") + set(output_bin "${output_dir}/${test_name}") if(MSVC) set(output_bin "${output_bin}.exe") endif() @@ -329,7 +331,7 @@ macro(add_compiler_rt_test test_suite test_name) # Make the test suite depend on the binary. add_dependencies(${test_suite} ${test_name}) -endmacro() +endfunction() macro(add_compiler_rt_resource_file target_name file_name component) set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}") diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index e08346ade..a690ed42b 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -224,16 +224,11 @@ macro(add_asan_tests_for_arch_and_kind arch kind cflags) set(ASAN_INST_DYNAMIC_TEST_OBJECTS ${ASAN_INST_TEST_OBJECTS}) endif() - # Create the 'default' folder where ASAN tests are produced. - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${CMAKE_CFG_RESOLVED_INTDIR}") - add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" ${arch} ${kind} SUBDIR "default" OBJECTS ${ASAN_INST_TEST_OBJECTS} LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) - # Create the 'dynamic' folder where ASAN tests are produced. - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${CMAKE_CFG_RESOLVED_INTDIR}") add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test" ${arch} ${kind} SUBDIR "dynamic" -- cgit v1.2.1 From 0ea082ef441a219374b785aa0a1a3e290015d852 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 15 Aug 2017 18:35:02 +0000 Subject: [compiler-rt CMake] NFC: Minor CMake refactoring. Change macro to a function, and use a generic variable instead of branching for handling multi-output build with CMAKE_CONFIGURATION_TYPES. Differential Revision: https://reviews.llvm.org/D36725 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310944 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index b39ca4ef8..8727f5bb3 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -27,7 +27,7 @@ endfunction() # Compile a sanitizer test with a freshly built clang # for a given architecture, adding the result to the object list. # - obj_list: output list of objects, populated by path -# of the generated object file. +# of a generated object file. # - source: source file of a test. # - arch: architecture to compile for. # sanitizer_test_compile( @@ -36,16 +36,12 @@ endfunction() # DEPS # CFLAGS # ) -macro(sanitizer_test_compile obj_list source arch) +function(sanitizer_test_compile obj_list source arch) cmake_parse_arguments(TEST "" "" "KIND;COMPILE_DEPS;DEPS;CFLAGS" ${ARGN}) get_filename_component(basename ${source} NAME) - if(CMAKE_CONFIGURATION_TYPES) - set(output_obj - "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${TEST_KIND}.o") - else() - set(output_obj "${obj_list}.${basename}.${arch}${TEST_KIND}.o") - endif() + set(output_obj + "${CMAKE_CFG_RESOLVED_INTDIR}${obj_list}.${basename}.${arch}${TEST_KIND}.o") # Write out architecture-specific flags into TARGET_CFLAGS variable. get_target_flags_for_arch(${arch} TARGET_CFLAGS) @@ -57,7 +53,8 @@ macro(sanitizer_test_compile obj_list source arch) CFLAGS ${TEST_CFLAGS} ${TARGET_CFLAGS} DEPS ${TEST_COMPILE_DEPS}) list(APPEND ${obj_list} ${output_obj}) -endmacro() + set("${obj_list}" "${${obj_list}}" PARENT_SCOPE) +endfunction() # Compile a source into an object file with COMPILER_RT_TEST_COMPILER using # a provided compile flags and dependenices. -- cgit v1.2.1 From 7de198abb3557fb8b6c5bca2beaeb7910d687d89 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 15 Aug 2017 18:38:14 +0000 Subject: [CMake compiler-rt] NFC: Minor CMake refactoring. Detect ObjC files in `clang_compile` and pass an appropriate flag to a compiler, also change `clang_compile` to a function. Differential Revision: https://reviews.llvm.org/D36727 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310945 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 8 ++++++-- lib/asan/tests/CMakeLists.txt | 7 +------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index 8727f5bb3..4c6568167 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -61,7 +61,7 @@ endfunction() # clang_compile( # CFLAGS # DEPS ) -macro(clang_compile object_file source) +function(clang_compile object_file source) cmake_parse_arguments(SOURCE "" "" "CFLAGS;DEPS" ${ARGN}) get_filename_component(source_rpath ${source} REALPATH) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -71,6 +71,7 @@ macro(clang_compile object_file source) list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx) endif() string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath}) + string(REGEX MATCH "[.](m|mm)$" is_objc ${source_rpath}) if(is_cxx) string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}") else() @@ -84,6 +85,9 @@ macro(clang_compile object_file source) if (APPLE) set(global_flags ${OSX_SYSROOT_FLAG} ${global_flags}) endif() + if (is_objc) + list(APPEND global_flags -ObjC) + endif() # Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options # which are not supported by Clang. @@ -96,7 +100,7 @@ macro(clang_compile object_file source) ${source_rpath} MAIN_DEPENDENCY ${source} DEPENDS ${SOURCE_DEPS}) -endmacro() +endfunction() # On Darwin, there are no system-wide C++ headers and the just-built clang is # therefore not able to compile C++ files unless they are copied/symlinked into diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index a690ed42b..4fbda265e 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -186,7 +186,7 @@ set(ASAN_INST_TEST_SOURCES asan_str_test.cc asan_test_main.cc) if(APPLE) - list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc) + list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc asan_mac_test_helpers.mm) endif() set(ASAN_BENCHMARKS_SOURCES @@ -201,11 +201,6 @@ macro(add_asan_tests_for_arch_and_kind arch kind cflags) asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind} CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}) endforeach() - if (APPLE) - # Add Mac-specific helper. - asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind} - CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${cflags}) - endif() if (MSVC) # With the MSVC CRT, the choice between static and dynamic CRT is made at -- cgit v1.2.1 From 38e269e523b107d0d0adee1dd61fa9db554a6bac Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 15 Aug 2017 22:56:10 +0000 Subject: [sanitizers CMake] NFC Refactor the logic for compiling and generating tests into a function. Most CMake configuration under compiler-rt/lib/*/tests have almost-the-same-but-not-quite functions of the form add_X_[unit]tests for compiling and running the tests. Much of the logic is duplicated with minor variations across different sub-folders. This can harm productivity for multiple reasons: For newcomers, resulting CMake files are very large, hard to understand, and hide the intention of the code. Changes for enabling certain architectures end up being unnecessarily large, as they get duplicated across multiple folders. Adding new sub-projects requires more effort than it should, as a developer has to again copy-n-paste the configuration, and it's not even clear from which sub-project it should be copy-n-pasted. With this change the logic of compile-and-generate-a-set-of-tests is extracted into a function, which hopefully makes writing and reading CMake much easier. Differential Revision: https://reviews.llvm.org/D36116 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310971 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 50 +++++++- lib/asan/tests/CMakeLists.txt | 204 +++++++++++++----------------- lib/interception/tests/CMakeLists.txt | 37 ++---- lib/sanitizer_common/tests/CMakeLists.txt | 48 ++----- lib/tsan/tests/CMakeLists.txt | 57 +++------ lib/xray/tests/CMakeLists.txt | 33 ++--- 6 files changed, 190 insertions(+), 239 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 34afc10a4..3cb55db13 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -287,15 +287,57 @@ if(MSVC) list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations) endif() +# Compile and register compiler-rt tests. +# generate_compiler_rt_tests( +# +# KIND +# SUBDIR +# SOURCES +# RUNTIME +# CFLAGS +# COMPILE_DEPS +# DEPS +# LINK_FLAGS +# ) +function(generate_compiler_rt_tests test_objects test_suite testname arch) + cmake_parse_arguments(TEST "" "KIND;RUNTIME;SUBDIR" + "SOURCES;COMPILE_DEPS;DEPS;CFLAGS;LINK_FLAGS" ${ARGN}) + + foreach(source ${TEST_SOURCES}) + sanitizer_test_compile( + "${test_objects}" "${source}" "${arch}" + KIND ${TEST_KIND} + COMPILE_DEPS ${TEST_COMPILE_DEPS} + DEPS ${TEST_DEPS} + CFLAGS ${TEST_CFLAGS} + ) + endforeach() + + set(TEST_DEPS ${${test_objects}}) + + if(NOT "${TEST_RUNTIME}" STREQUAL "") + list(APPEND TEST_DEPS ${TEST_RUNTIME}) + list(APPEND "${test_objects}" $) + endif() + + add_compiler_rt_test(${test_suite} "${testname}" "${arch}" + SUBDIR ${TEST_SUBDIR} + OBJECTS ${${test_objects}} + DEPS ${TEST_DEPS} + LINK_FLAGS ${TARGET_LINK_FLAGS} + ) + set("${test_objects}" "${${test_objects}}" PARENT_SCOPE) +endfunction() + # Link objects into a single executable with COMPILER_RT_TEST_COMPILER, # using specified link flags. Make executable a part of provided # test_suite. -# add_compiler_rt_test( +# add_compiler_rt_test( # SUBDIR # OBJECTS # DEPS # LINK_FLAGS ) -function(add_compiler_rt_test test_suite test_name) +function(add_compiler_rt_test test_suite test_name arch) cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN}) set(output_dir ${CMAKE_CURRENT_BINARY_DIR}) if(TEST_SUBDIR) @@ -312,6 +354,10 @@ function(add_compiler_rt_test test_suite test_name) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND TEST_DEPS clang) endif() + + get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) + list(APPEND TEST_LINK_FLAGS ${TARGET_LINK_FLAGS}) + # If we're not on MSVC, include the linker flags from CMAKE but override them # with the provided link flags. This ensures that flags which are required to # link programs at all are included, but the changes needed for the test diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 4fbda265e..983cf9f90 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -125,37 +125,6 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS) # NDK r10 requires -latomic almost always. append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS) -macro(asan_compile obj_list source arch kind) - cmake_parse_arguments(ASAN_TEST "" "" "CFLAGS" ${ARGN}) - sanitizer_test_compile(${obj_list} ${source} ${arch} - KIND ${kind} - COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE} - DEPS gtest asan - CFLAGS ${ASAN_TEST_CFLAGS} - ) -endmacro() - -# Link ASan unit test for a given architecture from a set -# of objects in with given linker flags. -macro(add_asan_test test_suite test_name arch kind) - cmake_parse_arguments(TEST "WITH_TEST_RUNTIME" "" "OBJECTS;LINK_FLAGS;SUBDIR" ${ARGN}) - get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) - set(TEST_DEPS ${TEST_OBJECTS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND TEST_DEPS asan) - endif() - if(TEST_WITH_TEST_RUNTIME) - list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME}) - list(APPEND TEST_OBJECTS $) - endif() - add_compiler_rt_test(${test_suite} ${test_name} - SUBDIR ${TEST_SUBDIR} - OBJECTS ${TEST_OBJECTS} - DEPS ${TEST_DEPS} - LINK_FLAGS ${TEST_LINK_FLAGS} - ${TARGET_LINK_FLAGS}) -endmacro() - # Main AddressSanitizer unit tests. add_custom_target(AsanUnitTests) set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests") @@ -193,102 +162,111 @@ set(ASAN_BENCHMARKS_SOURCES ${COMPILER_RT_GTEST_SOURCE} asan_benchmarks_test.cc) -# Adds ASan unit tests and benchmarks for architecture. -macro(add_asan_tests_for_arch_and_kind arch kind cflags) - # Instrumented tests. - set(ASAN_INST_TEST_OBJECTS) - foreach(src ${ASAN_INST_TEST_SOURCES}) - asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind} - CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}) - endforeach() +function(add_asan_tests arch test_runtime) + cmake_parse_arguments(TEST "" "KIND" "CFLAGS" ${ARGN}) - if (MSVC) - # With the MSVC CRT, the choice between static and dynamic CRT is made at - # compile time with a macro. Simulate the effect of passing /MD to clang-cl. - set(ASAN_INST_DYNAMIC_TEST_OBJECTS) - foreach(src ${ASAN_INST_TEST_SOURCES}) - asan_compile(ASAN_INST_DYNAMIC_TEST_OBJECTS ${src} ${arch} ${kind} - CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL ${cflags}) - endforeach() - # Clang links the static CRT by default. Override that to use the dynamic - # CRT. - set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS - ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS} - -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames) - else() - set(ASAN_INST_DYNAMIC_TEST_OBJECTS ${ASAN_INST_TEST_OBJECTS}) - endif() + # Closure to keep the values. + function(generate_asan_tests test_objects test_suite testname) + generate_compiler_rt_tests(${test_objects} ${test_suite} ${testname} ${arch} + COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE} + DEPS gtest asan + KIND ${TEST_KIND} + ${ARGN} + ) + set("${test_objects}" "${${test_objects}}" PARENT_SCOPE) + endfunction() - add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test" - ${arch} ${kind} SUBDIR "default" - OBJECTS ${ASAN_INST_TEST_OBJECTS} - LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) - if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + set(ASAN_INST_TEST_OBJECTS) + generate_asan_tests(ASAN_INST_TEST_OBJECTS AsanUnitTests + "Asan-${arch}${TEST_KIND}-Test" + SUBDIR "default" + LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS} + SOURCES ${ASAN_INST_TEST_SOURCES} + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${TEST_CFLAGS}) - add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test" - ${arch} ${kind} SUBDIR "dynamic" - OBJECTS ${ASAN_INST_DYNAMIC_TEST_OBJECTS} - LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}) + if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + set(dynamic_test_name "Asan-${arch}${TEST_KIND}-Dynamic-Test") + if(MSVC) + + # With the MSVC CRT, the choice between static and dynamic CRT is made at + # compile time with a macro. Simulate the effect of passing /MD to clang-cl. + set(ASAN_DYNAMIC_TEST_OBJECTS) + generate_asan_tests(ASAN_DYNAMIC_TEST_OBJECTS + AsanDynamicUnitTests "${dynamic_test_name}" + SUBDIR "dynamic" + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL + SOURCES ${ASAN_INST_TEST_SOURCES} + LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS} + -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames + ) + else() + + # Otherwise, reuse ASAN_INST_TEST_OBJECTS. + add_compiler_rt_test(AsanDynamicUnitTests "${dynamic_test_name}" "${arch}" + SUBDIR "dynamic" + OBJECTS ${ASAN_INST_TEST_OBJECTS} + DEPS gtest asan ${ASAN_INST_TEST_OBJECTS} + LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS} + ) + endif() endif() - # Add static ASan runtime that will be linked with uninstrumented tests. - set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind}) - if(APPLE) - set(ASAN_TEST_RUNTIME_OBJECTS - $ - $ - $ - $ - $ - $) - else() - set(ASAN_TEST_RUNTIME_OBJECTS - $ - $ - $ - $ - $ - $ - $ - $) - endif() - add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS}) - set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT Runtime tests") # Uninstrumented tests. set(ASAN_NOINST_TEST_OBJECTS) - foreach(src ${ASAN_NOINST_TEST_SOURCES}) - asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind} - CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS} ${cflags}) - endforeach() - add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test" - ${arch} ${kind} SUBDIR "default" - OBJECTS ${ASAN_NOINST_TEST_OBJECTS} - LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS} - WITH_TEST_RUNTIME) - - # Benchmarks. - set(ASAN_BENCHMARKS_OBJECTS) - foreach(src ${ASAN_BENCHMARKS_SOURCES}) - asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind} - CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}) - endforeach() - add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark" - ${arch} ${kind} SUBDIR "default" - OBJECTS ${ASAN_BENCHMARKS_OBJECTS} - LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) -endmacro() + generate_asan_tests(ASAN_NOINST_TEST_OBJECTS + AsanUnitTests "Asan-${arch}${TEST_KIND}-Noinst-Test" + SUBDIR "default" + CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS} + LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS} + SOURCES ${ASAN_NOINST_TEST_SOURCES} + RUNTIME ${test_runtime}) + + set(ASAN_BENCHMARK_OBJECTS) + generate_asan_tests(ASAN_BENCHMARK_OBJECTS + AsanBenchmarks "Asan-${arch}${TEST_KIND}-Benchmark" + SUBDIR "default" + CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} + SOURCES ${ASAN_BENCHMARKS_SOURCES} + LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}) +endfunction() if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH}) if(APPLE) darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH) endif() + foreach(arch ${ASAN_TEST_ARCH}) - add_asan_tests_for_arch_and_kind(${arch} "-inline" "") - add_asan_tests_for_arch_and_kind(${arch} "-with-calls" - "-mllvm;-asan-instrumentation-with-call-threshold=0") + + # Add static ASan runtime that will be linked with uninstrumented tests. + set(ASAN_TEST_RUNTIME RTAsanTest.${arch}) + if(APPLE) + set(ASAN_TEST_RUNTIME_OBJECTS + $ + $ + $ + $ + $ + $) + else() + set(ASAN_TEST_RUNTIME_OBJECTS + $ + $ + $ + $ + $ + $ + $ + $) + endif() + add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS}) + set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + FOLDER "Compiler-RT Runtime tests") + + add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-inline") + add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-with-calls" + CFLAGS -mllvm -asan-instrumentation-with-call-threshold=0) endforeach() endif() diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index 5f4033104..782066753 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -67,14 +67,13 @@ macro(add_interceptor_lib library) FOLDER "Compiler-RT Runtime tests") endmacro() -function(get_interception_lib_for_arch arch lib lib_name) +function(get_interception_lib_for_arch arch lib) if(APPLE) set(tgt_name "RTInterception.test.osx") else() set(tgt_name "RTInterception.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - set(${lib_name} $ PARENT_SCOPE) endfunction() # Interception unit tests testsuite. @@ -84,32 +83,16 @@ set_target_properties(InterceptionUnitTests PROPERTIES # Adds interception tests for architecture. macro(add_interception_tests_for_arch arch) - get_target_flags_for_arch(${arch} TARGET_FLAGS) - set(INTERCEPTION_TEST_SOURCES ${INTERCEPTION_UNITTESTS} - ${COMPILER_RT_GTEST_SOURCE}) - set(INTERCEPTION_TEST_COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND INTERCEPTION_TEST_COMPILE_DEPS gtest) - endif() set(INTERCEPTION_TEST_OBJECTS) - foreach(source ${INTERCEPTION_TEST_SOURCES}) - get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${basename}.${arch}.o") - clang_compile(${output_obj} ${source} - CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} - DEPS ${INTERCEPTION_TEST_COMPILE_DEPS}) - list(APPEND INTERCEPTION_TEST_OBJECTS ${output_obj}) - endforeach() - get_interception_lib_for_arch(${arch} INTERCEPTION_COMMON_LIB - INTERCEPTION_COMMON_LIB_NAME) - # Add unittest target. - set(INTERCEPTION_TEST_NAME "Interception-${arch}-Test") - add_compiler_rt_test(InterceptionUnitTests ${INTERCEPTION_TEST_NAME} - OBJECTS ${INTERCEPTION_TEST_OBJECTS} - ${INTERCEPTION_COMMON_LIB_NAME} - DEPS ${INTERCEPTION_TEST_OBJECTS} ${INTERCEPTION_COMMON_LIB} - LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON} - ${TARGET_FLAGS}) + get_interception_lib_for_arch(${arch} INTERCEPTION_COMMON_LIB) + generate_compiler_rt_tests(INTERCEPTION_TEST_OBJECTS + InterceptionUnitTests "Interception-${arch}-Test" ${arch} + RUNTIME ${INTERCEPTION_COMMON_LIB} + SOURCES ${INTERCEPTION_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} + COMPILE_DEPS gtest ${INTERCEPTION_TEST_HEADERS} + DEPS gtest + CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} + LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON}) endmacro() if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID AND NOT APPLE) diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 13c016314..2e55257da 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -120,14 +120,13 @@ macro(add_sanitizer_common_lib library) FOLDER "Compiler-RT Runtime tests") endmacro() -function(get_sanitizer_common_lib_for_arch arch lib lib_name) +function(get_sanitizer_common_lib_for_arch arch lib) if(APPLE) set(tgt_name "RTSanitizerCommon.test.osx") else() set(tgt_name "RTSanitizerCommon.test.${arch}") endif() set(${lib} "${tgt_name}" PARENT_SCOPE) - set(${lib_name} $ PARENT_SCOPE) endfunction() # Sanitizer_common unit tests testsuite. @@ -136,41 +135,22 @@ set_target_properties(SanitizerUnitTests PROPERTIES FOLDER "Compiler-RT Tests") # Adds sanitizer tests for architecture. macro(add_sanitizer_tests_for_arch arch) - get_target_flags_for_arch(${arch} TARGET_FLAGS) - - # If the sanitizer library was built with _FILE_OFFSET_BITS=64 we need - # to ensure that the library and tests agree on the layout of certain - # structures such as 'struct stat'. + set(extra_flags) if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) - list(APPEND TARGET_FLAGS "-D_LARGEFILE_SOURCE") - list(APPEND TARGET_FLAGS "-D_FILE_OFFSET_BITS=64") + list(APPEND extra_flags "-D_LARGEFILE_SOURCE") + list(APPEND extra_flags "-D_FILE_OFFSET_BITS=64") endif() + get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB) - set(SANITIZER_TEST_SOURCES ${SANITIZER_UNITTESTS} - ${COMPILER_RT_GTEST_SOURCE}) - set(SANITIZER_TEST_COMPILE_DEPS ${SANITIZER_TEST_HEADERS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND SANITIZER_TEST_COMPILE_DEPS gtest) - endif() set(SANITIZER_TEST_OBJECTS) - foreach(source ${SANITIZER_TEST_SOURCES}) - get_filename_component(basename ${source} NAME) - set(output_obj "${CMAKE_CFG_RESOLVED_INTDIR}${basename}.${arch}.o") - clang_compile(${output_obj} ${source} - CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} - DEPS ${SANITIZER_TEST_COMPILE_DEPS}) - list(APPEND SANITIZER_TEST_OBJECTS ${output_obj}) - endforeach() - get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB - SANITIZER_COMMON_LIB_NAME) - # Add unittest target. - set(SANITIZER_TEST_NAME "Sanitizer-${arch}-Test") - add_compiler_rt_test(SanitizerUnitTests ${SANITIZER_TEST_NAME} - OBJECTS ${SANITIZER_TEST_OBJECTS} - ${SANITIZER_COMMON_LIB_NAME} - DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB} - LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON} - ${TARGET_FLAGS}) + generate_compiler_rt_tests(SANITIZER_TEST_OBJECTS SanitizerUnitTests + "Sanitizer-${arch}-Test" ${arch} + RUNTIME "${SANITIZER_COMMON_LIB}" + SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} + COMPILE_DEPS ${SANITIZER_TEST_HEADERS} + DEPS gtest + CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${extra_flags} + LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON} ${extra_flags}) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64") # Test that the libc-independent part of sanitizer_common is indeed @@ -180,7 +160,7 @@ macro(add_sanitizer_tests_for_arch arch) sanitizer_nolibc_test_main.cc CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} DEPS ${SANITIZER_TEST_COMPILE_DEPS}) - add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc" + add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc" ${arch} OBJECTS sanitizer_nolibc_test_main.${arch}.o -Wl,-whole-archive libRTSanitizerCommon.test.nolibc.${arch}.a diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index 4b9bc6ae9..324b70c94 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -15,8 +15,6 @@ set(TSAN_UNITTEST_CFLAGS set(TSAN_TEST_ARCH ${TSAN_SUPPORTED_ARCH}) if(APPLE) - darwin_filter_host_archs(TSAN_SUPPORTED_ARCH TSAN_TEST_ARCH) - list(APPEND TSAN_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS}) # Create a static library for test dependencies. set(TSAN_TEST_RUNTIME_OBJECTS @@ -29,6 +27,15 @@ if(APPLE) add_library(${TSAN_TEST_RUNTIME} STATIC ${TSAN_TEST_RUNTIME_OBJECTS}) set_target_properties(${TSAN_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + darwin_filter_host_archs(TSAN_SUPPORTED_ARCH TSAN_TEST_ARCH) + list(APPEND TSAN_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS}) + + set(LINK_FLAGS "-lc++") + add_weak_symbols("ubsan" LINK_FLAGS) + add_weak_symbols("sanitizer_common" LINK_FLAGS) +else() + set(LINK_FLAGS "-fsanitize=thread;-lstdc++;-lm") endif() set(TSAN_RTL_HEADERS) @@ -42,44 +49,14 @@ endforeach() macro(add_tsan_unittest testname) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) if(UNIX) - foreach(arch ${TSAN_TEST_ARCH}) - set(TEST_OBJECTS) - foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - sanitizer_test_compile( - TEST_OBJECTS ${SOURCE} ${arch} - COMPILE_DEPS ${TSAN_RTL_HEADERS} ${TEST_HEADERS} - DEPS gtest tsan - CFLAGS ${TSAN_UNITTEST_CFLAGS} - ) - endforeach() - get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) - set(TEST_DEPS ${TEST_OBJECTS}) - if(NOT APPLE) - # FIXME: Looks like we should link TSan with just-built runtime, - # and not rely on -fsanitize=thread, as these tests are essentially - # unit tests. - add_compiler_rt_test(TsanUnitTests ${testname} - OBJECTS ${TEST_OBJECTS} - DEPS ${TEST_DEPS} - LINK_FLAGS ${TARGET_LINK_FLAGS} - -fsanitize=thread - -lstdc++ -lm) - else() - list(APPEND TEST_OBJECTS $) - list(APPEND TEST_DEPS ${TSAN_TEST_RUNTIME}) - - add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) - add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) - - # Intentionally do *not* link with `-fsanitize=thread`. We already link - # against a static version of the runtime, and we don't want the dynamic - # one. - add_compiler_rt_test(TsanUnitTests "${testname}-${arch}-Test" - OBJECTS ${TEST_OBJECTS} - DEPS ${TEST_DEPS} - LINK_FLAGS ${TARGET_LINK_FLAGS} ${DARWIN_osx_LINK_FLAGS} - ${WEAK_SYMBOL_LINK_FLAGS} -lc++) - endif() + foreach(arch ${ASAN_TEST_ARCH}) + generate_compiler_rt_tests(TsanUnitTests ${testname} ${arch} + SOURCES ${TEST_SOURCES} + RUNTIME ${TSAN_TEST_RUNTIME} + COMPILE_DEPS ${TEST_HEADERS} ${TSAN_RTL_HEADERS} + DEPS gtest tsan + CFLAGS ${TSAN_UNITTEST_CFLAGS} + LINK_FLAGS ${LINK_FLAGS}) endforeach() endif() endmacro() diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index 151fa4c10..b140671c2 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -13,34 +13,21 @@ set(XRAY_UNITTEST_CFLAGS macro(add_xray_unittest testname) set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) - if (APPLE) - darwin_filter_host_archs(XRAY_SUPPORTED_ARCH) - endif() - if(UNIX) + cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) + set(TEST_OBJECTS) + # FIXME: Figure out how to run even just the unit tests on APPLE. + if(UNIX AND NOT APPLE) foreach(arch ${XRAY_TEST_ARCH}) - cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) - set(TEST_OBJECTS) - foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - sanitizer_test_compile(TEST_OBJECTS ${SOURCE} ${arch} - DEPS gtest_main xray - CFLAGS ${XRAY_UNITTEST_CFLAGS}) - endforeach() - get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) - set(TEST_DEPS ${TEST_OBJECTS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND TEST_DEPS gtest_main xray) - endif() - if(NOT APPLE) - add_compiler_rt_test(XRayUnitTests ${testname}-${arch} - OBJECTS ${TEST_OBJECTS} - DEPS ${TEST_DEPS} - LINK_FLAGS ${TARGET_LINK_FLAGS} + generate_compiler_rt_tests(TEST_OBJECTS + XRayUnitTests "${testname}-${arch}" "${arch}" + SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} + DEPS gtest_main xray + CFLAGS ${XRAY_UNITTEST_CFLAGS} + LINK_FLAGS -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} -lpthread -L${COMPILER_RT_LIBRARY_OUTPUT_DIR} -lclang_rt.xray-${arch} -ldl -lrt) - endif() - # FIXME: Figure out how to run even just the unit tests on APPLE. endforeach() endif() endmacro() -- cgit v1.2.1 From bcb584b2636e6acc02aba4c8a8d8b07fac4c537c Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 15 Aug 2017 23:22:52 +0000 Subject: Quickfix to the refactoring commit: typo in the link flags variable name. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310973 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 3cb55db13..aa6b4a30d 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -324,7 +324,7 @@ function(generate_compiler_rt_tests test_objects test_suite testname arch) SUBDIR ${TEST_SUBDIR} OBJECTS ${${test_objects}} DEPS ${TEST_DEPS} - LINK_FLAGS ${TARGET_LINK_FLAGS} + LINK_FLAGS ${TEST_LINK_FLAGS} ) set("${test_objects}" "${${test_objects}}" PARENT_SCOPE) endfunction() -- cgit v1.2.1 From f1b1a7775f722048d4914c73d0a631890c9d5de3 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 16 Aug 2017 16:40:48 +0000 Subject: [scudo] Application & platform compatibility changes Summary: This patch changes a few (small) things around for compatibility purposes for the current Android & Fuchsia work: - `realloc`'ing some memory that was not allocated with `malloc`, `calloc` or `realloc`, while UB according to http://pubs.opengroup.org/onlinepubs/009695399/functions/realloc.html is more common that one would think. We now only check this if `DeallocationTypeMismatch` is set; change the "mismatch" error messages to be more homogeneous; - some sketchily written but widely used libraries expect a call to `realloc` to copy the usable size of the old chunk to the new one instead of the requested size. We have to begrundingly abide by this de-facto standard. This doesn't seem to impact security either way, unless someone comes up with something we didn't think about; - the CRC32 intrinsics for 64-bit take a 64-bit first argument. This is misleading as the upper 32 bits end up being ignored. This was also raising `-Wconversion` errors. Change things to take a `u32` as first argument. This also means we were (and are) only using 32 bits of the Cookie - not a big thing, but worth mentioning. - Includes-wise: prefer `stddef.h` to `cstddef`, move `scudo_flags.h` where it is actually needed. - Add tests for the memalign-realloc case, and the realloc-usable-size one. (Edited typos) Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36754 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311018 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 20 ++++---- lib/scudo/scudo_allocator.h | 2 - lib/scudo/scudo_new_delete.cpp | 2 +- test/scudo/mismatch.cpp | 23 +++++++--- test/scudo/options.cpp | 2 +- test/scudo/realloc.cpp | 102 +++++++++++++++++++++++++---------------- 6 files changed, 92 insertions(+), 59 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index e1758568b..4f87d3523 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -16,6 +16,7 @@ #include "scudo_allocator.h" #include "scudo_crc32.h" +#include "scudo_flags.h" #include "scudo_tls.h" #include "scudo_utils.h" @@ -35,7 +36,7 @@ static uptr Cookie; // at compilation or at runtime. static atomic_uint8_t HashAlgorithm = { CRC32Software }; -INLINE u32 computeCRC32(uptr Crc, uptr Value, uptr *Array, uptr ArraySize) { +INLINE u32 computeCRC32(u32 Crc, uptr Value, uptr *Array, uptr ArraySize) { // If the hardware CRC32 feature is defined here, it was enabled everywhere, // as opposed to only for scudo_crc32.cpp. This means that other hardware // specific instructions were likely emitted at other places, and as a @@ -87,7 +88,8 @@ struct ScudoChunk : UnpackedHeader { ZeroChecksumHeader.Checksum = 0; uptr HeaderHolder[sizeof(UnpackedHeader) / sizeof(uptr)]; memcpy(&HeaderHolder, &ZeroChecksumHeader, sizeof(HeaderHolder)); - u32 Crc = computeCRC32(Cookie, reinterpret_cast(this), HeaderHolder, + u32 Crc = computeCRC32(static_cast(Cookie), + reinterpret_cast(this), HeaderHolder, ARRAY_SIZE(HeaderHolder)); return static_cast(Crc); } @@ -514,8 +516,8 @@ struct ScudoAllocator { if (Header.AllocType != Type) { // With the exception of memalign'd Chunks, that can be still be free'd. if (Header.AllocType != FromMemalign || Type != FromMalloc) { - dieWithMessage("ERROR: allocation type mismatch on address %p\n", - UserPtr); + dieWithMessage("ERROR: allocation type mismatch when deallocating " + "address %p\n", UserPtr); } } } @@ -546,9 +548,11 @@ struct ScudoAllocator { dieWithMessage("ERROR: invalid chunk state when reallocating address " "%p\n", OldPtr); } - if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { - dieWithMessage("ERROR: invalid chunk type when reallocating address %p\n", - OldPtr); + if (DeallocationTypeMismatch) { + if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { + dieWithMessage("ERROR: allocation type mismatch when reallocating " + "address %p\n", OldPtr); + } } uptr UsableSize = Chunk->getUsableSize(&OldHeader); // The new size still fits in the current chunk, and the size difference @@ -567,7 +571,7 @@ struct ScudoAllocator { if (NewPtr) { uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes : UsableSize - OldHeader.SizeOrUnusedBytes; - memcpy(NewPtr, OldPtr, Min(NewSize, OldSize)); + memcpy(NewPtr, OldPtr, Min(NewSize, UsableSize)); quarantineOrDeallocateChunk(Chunk, &OldHeader, OldSize); } return NewPtr; diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 29d85995a..8ecc8cde3 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -14,8 +14,6 @@ #ifndef SCUDO_ALLOCATOR_H_ #define SCUDO_ALLOCATOR_H_ -#include "scudo_flags.h" - #include "sanitizer_common/sanitizer_allocator.h" #if !SANITIZER_LINUX diff --git a/lib/scudo/scudo_new_delete.cpp b/lib/scudo/scudo_new_delete.cpp index cdefb127b..c5a1abbed 100644 --- a/lib/scudo/scudo_new_delete.cpp +++ b/lib/scudo/scudo_new_delete.cpp @@ -15,7 +15,7 @@ #include "interception/interception.h" -#include +#include using namespace __scudo; diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index 15dce83ce..0e51da4a5 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -1,10 +1,12 @@ // RUN: %clang_scudo %s -o %t -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t newfree 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t newfree 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memalignrealloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memalignrealloc 2>&1 // Tests that type mismatches between allocation and deallocation functions are // caught when the related option is set. @@ -32,7 +34,14 @@ int main(int argc, char **argv) assert(p); delete p; } + if (!strcmp(argv[1], "memalignrealloc")) { + void *p = memalign(16, 16); + assert(p); + p = realloc(p, 32); + free(p); + } return 0; } -// CHECK: ERROR: allocation type mismatch on address +// CHECK-dealloc: ERROR: allocation type mismatch when deallocating address +// CHECK-realloc: ERROR: allocation type mismatch when reallocating address diff --git a/test/scudo/options.cpp b/test/scudo/options.cpp index f4afe7d79..bb0ed2963 100644 --- a/test/scudo/options.cpp +++ b/test/scudo/options.cpp @@ -22,4 +22,4 @@ int main(int argc, char **argv) return 0; } -// CHECK: ERROR: allocation type mismatch on address +// CHECK: ERROR: allocation type mismatch when deallocating address diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp index da377205f..01149670e 100644 --- a/test/scudo/realloc.cpp +++ b/test/scudo/realloc.cpp @@ -1,14 +1,13 @@ // RUN: %clang_scudo %s -lstdc++ -o %t -// RUN: %run %t pointers 2>&1 -// RUN: %run %t contents 2>&1 -// RUN: not %run %t memalign 2>&1 | FileCheck %s +// RUN: %run %t pointers 2>&1 +// RUN: %run %t contents 2>&1 +// RUN: %run %t usablesize 2>&1 // Tests that our reallocation function returns the same pointer when the // requested size can fit into the previously allocated chunk. Also tests that // a new chunk is returned if the size is greater, and that the contents of the -// chunk are left unchanged. -// As a final test, make sure that a chunk allocated by memalign cannot be -// reallocated. +// chunk are left unchanged. Finally, checks that realloc copies the usable +// size of the old chunk to the new one (as opposed to the requested size). #include #include @@ -24,42 +23,65 @@ int main(int argc, char **argv) assert(argc == 2); - for (size_t size : sizes) { - if (!strcmp(argv[1], "pointers")) { - old_p = p = realloc(nullptr, size); - assert(p); - size = malloc_usable_size(p); - // Our realloc implementation will return the same pointer if the size - // requested is lower than or equal to the usable size of the associated - // chunk. - p = realloc(p, size - 1); - assert(p == old_p); + if (!strcmp(argv[1], "usablesize")) { + // This tests a sketchy behavior inherited from poorly written libraries + // that have become somewhat standard. When realloc'ing a chunk, the + // copied contents should span the usable size of the chunk, not the + // requested size. + size_t size = 496, usable_size; + p = nullptr; + // Make sure we get a chunk with a usable size actually larger than size. + do { + if (p) free(p); + size += 16; + p = malloc(size); + usable_size = malloc_usable_size(p); + assert(usable_size >= size); + } while (usable_size == size); + for (int i = 0; i < usable_size; i++) + reinterpret_cast(p)[i] = 'A'; + old_p = p; + // Make sure we get a different chunk so that the data is actually copied. + do { + size *= 2; p = realloc(p, size); - assert(p == old_p); - // And a new one if the size is greater. - p = realloc(p, size + 1); - assert(p != old_p); - // A size of 0 will free the chunk and return nullptr. - p = realloc(p, 0); - assert(!p); - old_p = nullptr; - } - if (!strcmp(argv[1], "contents")) { - p = realloc(nullptr, size); assert(p); - for (int i = 0; i < size; i++) - reinterpret_cast(p)[i] = 'A'; - p = realloc(p, size + 1); - // The contents of the reallocated chunk must match the original one. - for (int i = 0; i < size; i++) - assert(reinterpret_cast(p)[i] == 'A'); - } - if (!strcmp(argv[1], "memalign")) { - // A chunk coming from memalign cannot be reallocated. - p = memalign(16, size); - assert(p); - p = realloc(p, size); - free(p); + } while (p == old_p); + // The contents of the new chunk must match the old one up to usable_size. + for (int i = 0; i < usable_size; i++) + assert(reinterpret_cast(p)[i] == 'A'); + free(p); + } else { + for (size_t size : sizes) { + if (!strcmp(argv[1], "pointers")) { + old_p = p = realloc(nullptr, size); + assert(p); + size = malloc_usable_size(p); + // Our realloc implementation will return the same pointer if the size + // requested is lower than or equal to the usable size of the associated + // chunk. + p = realloc(p, size - 1); + assert(p == old_p); + p = realloc(p, size); + assert(p == old_p); + // And a new one if the size is greater. + p = realloc(p, size + 1); + assert(p != old_p); + // A size of 0 will free the chunk and return nullptr. + p = realloc(p, 0); + assert(!p); + old_p = nullptr; + } + if (!strcmp(argv[1], "contents")) { + p = realloc(nullptr, size); + assert(p); + for (int i = 0; i < size; i++) + reinterpret_cast(p)[i] = 'A'; + p = realloc(p, size + 1); + // The contents of the reallocated chunk must match the original one. + for (int i = 0; i < size; i++) + assert(reinterpret_cast(p)[i] == 'A'); + } } } return 0; -- cgit v1.2.1 From 4a6d122a262547d4c6978bc6c87a9d417109fe61 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 16 Aug 2017 18:09:29 +0000 Subject: Add C++17 aligned new/delete interceptors to standalone lsan Summary: Based on r282019. Reviewers: kcc, jakubjelinek, alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36757 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311030 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_interceptors.cc | 49 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 168868b01..1aaaf1671 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -44,6 +44,7 @@ int pthread_setspecific(unsigned key, const void *v); namespace std { struct nothrow_t; + enum class align_val_t: size_t; } #if !SANITIZER_MAC @@ -203,13 +204,19 @@ INTERCEPTOR(int, mprobe, void *ptr) { #define OPERATOR_NEW_BODY(nothrow) \ ENSURE_LSAN_INITED; \ GET_STACK_TRACE_MALLOC; \ - void *res = Allocate(stack, size, 1, kAlwaysClearMemory);\ - if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + void *res = lsan_malloc(size, stack); \ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM(); \ + return res; +#define OPERATOR_NEW_BODY_ALIGN(nothrow) \ + ENSURE_LSAN_INITED; \ + GET_STACK_TRACE_MALLOC; \ + void *res = lsan_memalign((uptr)align, size, stack); \ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM(); \ return res; #define OPERATOR_DELETE_BODY \ ENSURE_LSAN_INITED; \ - Deallocate(ptr); + lsan_free(ptr); // On OS X it's not enough to just provide our own 'operator new' and // 'operator delete' implementations, because they're going to be in the runtime @@ -229,6 +236,18 @@ void *operator new(size_t size, std::nothrow_t const&) INTERCEPTOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } @@ -239,6 +258,30 @@ void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const &) { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT +{ OPERATOR_DELETE_BODY; } #else // SANITIZER_MAC -- cgit v1.2.1 From 229a2f64e23766755d32f1539f893d328a205edd Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 18 Aug 2017 05:24:32 +0000 Subject: [XRay][compiler-rt][NFC] Expand the PIC test case for XRay Summary: Here we add a build with -ffunction-sections -fdata-sections and -Wl,--gc-sections to ensure that we're still able to generate XRay traces. This is just adding a test, no functional changes. Differential Revision: https://reviews.llvm.org/D36863 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311145 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/pic_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/xray/TestCases/Linux/pic_test.cc b/test/xray/TestCases/Linux/pic_test.cc index 09c40b9e0..2999c6411 100644 --- a/test/xray/TestCases/Linux/pic_test.cc +++ b/test/xray/TestCases/Linux/pic_test.cc @@ -1,6 +1,7 @@ // Test to check if we handle pic code properly. -// RUN: %clangxx_xray -fxray-instrument -std=c++11 -fpic %s -o %t +// RUN: %clangxx_xray -fxray-instrument -std=c++11 -ffunction-sections \ +// RUN: -fdata-sections -fpic -fpie -Wl,--gc-sections %s -o %t // RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=pic-test-logging-" %run %t 2>&1 | FileCheck %s // After all that, clean up the output xray log. // -- cgit v1.2.1 From 98b5d659093f5626da815e58f2c8b501499e4983 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 18 Aug 2017 18:43:30 +0000 Subject: [SanitizerCoverage] Add stack depth tracing instrumentation. Summary: Augment SanitizerCoverage to insert maximum stack depth tracing for use by libFuzzer. The new instrumentation is enabled by the flag -fsanitize-coverage=stack-depth and is compatible with the existing trace-pc-guard coverage. The user must also declare the following global variable in their code: thread_local uintptr_t __sancov_lowest_stack https://bugs.llvm.org/show_bug.cgi?id=33857 Reviewers: vitalybuka, kcc Reviewed By: vitalybuka Subscribers: kubamracek, hiraditya, cfe-commits, llvm-commits Differential Revision: https://reviews.llvm.org/D36839 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311186 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/sanitizer_coverage_stack_depth.cc | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc new file mode 100644 index 000000000..90959ef5b --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_stack_depth.cc @@ -0,0 +1,32 @@ +// Tests -fsanitize-coverage=stack-depth +// +// XFAIL: tsan +// +// RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=stack-depth %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not Assertion{{.*}}failed +// RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=trace-pc-guard,stack-depth \ +// RUN: %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not Assertion{{.*}}failed + +#include +#include +#include + +thread_local uintptr_t __sancov_lowest_stack; +uintptr_t last_stack; + +void foo(int recurse) { + assert(__sancov_lowest_stack < last_stack); + last_stack = __sancov_lowest_stack; + if (recurse <= 0) return; + foo(recurse - 1); +} + +int main() { + last_stack = __sancov_lowest_stack; + foo(100); + printf("Success!\n"); + return 0; +} + +// CHECK: Success! -- cgit v1.2.1 From f66a808d62e199e81b05793186311ca542db5307 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Fri, 18 Aug 2017 19:22:39 +0000 Subject: [TSan] Update test values Summary: This test was broken by the tail duplication logic being changed in r311139, update the test values and add a note about how to properly run a benchmark to verify that the values are safe to update. Reviewers: vitalybuka Reviewed By: vitalybuka Subscribers: dvyukov, kubamracek Differential Revision: https://reviews.llvm.org/D36889 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311189 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/check_analyze.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh index 54dd1b023..9b5abc317 100755 --- a/lib/tsan/check_analyze.sh +++ b/lib/tsan/check_analyze.sh @@ -2,6 +2,14 @@ # # Script that checks that critical functions in TSan runtime have correct number # of push/pop/rsp instructions to verify that runtime is efficient enough. +# +# This test can fail when backend code generation changes the output for various +# tsan interceptors. When such a change happens, you can ensure that the +# performance has not regressed by running the following benchmarks before and +# after the breaking change to verify that the values in this file are safe to +# update: +# ./projects/compiler-rt/lib/tsan/tests/rtl/TsanRtlTest +# --gtest_also_run_disabled_tests --gtest_filter=DISABLED_BENCH.Mop* set -u @@ -35,7 +43,7 @@ done for f in read1 read2 read4 read8; do check $f rsp 1 check $f push 3 - check $f pop 3 + check $f pop 18 done for f in func_entry func_exit; do -- cgit v1.2.1 From 1f8b389efc80e8a38687d7fbad4eaf5730f401b4 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 20 Aug 2017 18:31:00 +0000 Subject: Remove "%T" from ASan Darwin tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311298 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Darwin/dyld_insert_libraries_reexec.cc | 16 +++++++--------- .../TestCases/Darwin/dyld_insert_libraries_remove.cc | 20 +++++++++----------- .../Darwin/unset-insert-libraries-on-exec.cc | 6 +++--- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc index 5c975b8da..d195258d7 100644 --- a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc @@ -3,30 +3,28 @@ // UNSUPPORTED: ios -// RUN: mkdir -p %T/dyld_insert_libraries_reexec -// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \ -// RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ -// RUN: | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ -// RUN: %T/dyld_insert_libraries_reexec/libclang_rt.asan_osx_dynamic.dylib -// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_reexec/a.out +// RUN: rm -rf %t && mkdir -p %t +// RUN: cp `%clang_asan -print-file-name=lib`/darwin/libclang_rt.asan_osx_dynamic.dylib \ +// RUN: %t/libclang_rt.asan_osx_dynamic.dylib +// RUN: %clangxx_asan %s -o %t/a.out // RUN: %env_asan_opts=verbosity=1 \ // RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib \ -// RUN: %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \ +// RUN: %run %t/a.out 2>&1 \ // RUN: | FileCheck %s // RUN: IS_OSX_10_11_OR_HIGHER=$([ `sw_vers -productVersion | cut -d'.' -f2` -lt 11 ]; echo $?) // On OS X 10.10 and lower, if the dylib is not DYLD-inserted, ASan will re-exec. // RUN: if [ $IS_OSX_10_11_OR_HIGHER == 0 ]; then \ -// RUN: %env_asan_opts=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \ +// RUN: %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-NOINSERT %s; \ // RUN: fi // On OS X 10.11 and higher, we don't need to DYLD-insert anymore, and the interceptors // still installed correctly. Let's just check that things work and we don't try to re-exec. // RUN: if [ $IS_OSX_10_11_OR_HIGHER == 1 ]; then \ -// RUN: %env_asan_opts=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \ +// RUN: %env_asan_opts=verbosity=1 %run %t/a.out 2>&1 \ // RUN: | FileCheck %s; \ // RUN: fi diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc index 69d849793..8a02105f6 100644 --- a/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc @@ -4,26 +4,24 @@ // UNSUPPORTED: ios -// RUN: mkdir -p %T/dyld_insert_libraries_remove -// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \ -// RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ -// RUN: | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ -// RUN: %T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib +// RUN: rm -rf %t && mkdir -p %t +// RUN: cp `%clang_asan -print-file-name=lib`/darwin/libclang_rt.asan_osx_dynamic.dylib \ +// RUN: %t/libclang_rt.asan_osx_dynamic.dylib -// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_remove/a.out +// RUN: %clangxx_asan %s -o %t/a.out // RUN: %clangxx -DSHARED_LIB %s \ -// RUN: -dynamiclib -o %T/dyld_insert_libraries_remove/dummy-so.dylib +// RUN: -dynamiclib -o %t/dummy-so.dylib -// RUN: ( cd %T/dyld_insert_libraries_remove && \ +// RUN: ( cd %t && \ // RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ // RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 -// RUN: ( cd %T/dyld_insert_libraries_remove && \ +// RUN: ( cd %t && \ // RUN: DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ // RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 -// RUN: ( cd %T/dyld_insert_libraries_remove && \ -// RUN: DYLD_INSERT_LIBRARIES=%T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: ( cd %t && \ +// RUN: DYLD_INSERT_LIBRARIES=%t/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ // RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 #if !defined(SHARED_LIB) diff --git a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc index 62cf853a5..966b46958 100644 --- a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc +++ b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc @@ -2,16 +2,16 @@ // executing other programs. // RUN: %clangxx_asan %s -o %t -// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env +// RUN: %clangxx %p/../Helpers/echo-env.cc -o %t-echo-env // RUN: %clangxx -DSHARED_LIB %s \ // RUN: -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib // Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before // execl(). -// RUN: %run %t %T/echo-env >/dev/null 2>&1 +// RUN: %run %t %t-echo-env >/dev/null 2>&1 // RUN: %env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \ -// RUN: %run %t %T/echo-env 2>&1 | FileCheck %s || exit 1 +// RUN: %run %t %t-echo-env 2>&1 | FileCheck %s || exit 1 #if !defined(SHARED_LIB) #include -- cgit v1.2.1 From bdf800ddb572949ce9cb5e27c89053a5b62b1083 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 21 Aug 2017 20:28:32 +0000 Subject: Fix multi-architecture build for lib/xray. Differential Revision: https://reviews.llvm.org/D36881 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311379 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index b140671c2..4ea03d37a 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -14,10 +14,10 @@ set(XRAY_UNITTEST_CFLAGS macro(add_xray_unittest testname) set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) - set(TEST_OBJECTS) # FIXME: Figure out how to run even just the unit tests on APPLE. if(UNIX AND NOT APPLE) foreach(arch ${XRAY_TEST_ARCH}) + set(TEST_OBJECTS) generate_compiler_rt_tests(TEST_OBJECTS XRayUnitTests "${testname}-${arch}" "${arch}" SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} -- cgit v1.2.1 From 916b56d6d731c57374e2635abaa39cdc3e8ff129 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 21 Aug 2017 21:19:13 +0000 Subject: [NFC CMake] Do not relink test targets every time in compiler-rt CMake's add_custom_target is considered to be *always* out of date. This patch changes it to a combination of add_custom_target and add_custom_command which actually tracks dependencies' timestamps. On my machine this reliably saves 6-7 seconds on each test group. This can be a large difference when debugging small tests. Differential Revision: https://reviews.llvm.org/D36912 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311384 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index aa6b4a30d..9220eab84 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -368,15 +368,18 @@ function(add_compiler_rt_test test_suite test_name arch) set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}") separate_arguments(TEST_LINK_FLAGS) endif() - add_custom_target(${test_name} - COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} - -o "${output_bin}" + + add_custom_command( + OUTPUT "${output_bin}" + COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} -o "${output_bin}" ${TEST_LINK_FLAGS} - DEPENDS ${TEST_DEPS}) - set_target_properties(${test_name} PROPERTIES FOLDER "Compiler-RT Tests") + DEPENDS ${TEST_DEPS} + ) + add_custom_target(T${test_name} DEPENDS "${output_bin}") + set_target_properties(T${test_name} PROPERTIES FOLDER "Compiler-RT Tests") # Make the test suite depend on the binary. - add_dependencies(${test_suite} ${test_name}) + add_dependencies(${test_suite} T${test_name}) endfunction() macro(add_compiler_rt_resource_file target_name file_name component) -- cgit v1.2.1 From bcdd70fe3bcf63a5e675d6070e9c86dd9becc9ff Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 21 Aug 2017 21:25:38 +0000 Subject: [sanitizer] Do not over-dup string flags Summary: String flags values appear to be duped twice. Once in `FlagParser::parse_flag` using the `LowLevelAllocator` via `ll_strndup`, once in `FlagHandler::Parse` using the `InternalAllocator` via `internal_strdup`. It looks like the second one is redundant, as the memory for the first one is never freed and not used for anything else. Assigning the value to the flag instead of duping it has a few advantages: - if it was the only use of the `InternalAllocator` (which is the case for Scudo), then the related code will not be compiled it, which saves us a whole instantiation of the CombinedAllocator worth of extra code; - in the event a string flag is parsed, the `InternalAllocator` would have created a whole SizeClassAllocator32 region for a single allocation, which is kind of wasteful. - also, the string is dup'ed twice for the whole lifetime of a process. I tested check-{sanitizer,asan,tsan,ubsan,scudo} successfully, so as far as I can tell this doesn't appear to have bad side effects. Reviewers: eugenis, alekseyshl Reviewed By: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D36970 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311386 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_flag_parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 4988fbb7a..f649f5bff 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -75,7 +75,7 @@ inline bool FlagHandler::Parse(const char *value) { template <> inline bool FlagHandler::Parse(const char *value) { - *t_ = internal_strdup(value); + *t_ = value; return true; } -- cgit v1.2.1 From 1a32c939c5eece22f3ca6cf70bd05a1527bc0970 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 21 Aug 2017 22:31:31 +0000 Subject: Fix ASan version list dependency in multi-arch builds. Fixes PR32390. Patch by Andrey Krayniak. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311394 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 355466f8c..c6005da6a 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -175,9 +175,9 @@ else() EXTRA asan.syms.extra) set(VERSION_SCRIPT_FLAG -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers) - set_source_files_properties( + set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc - PROPERTIES + APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers) else() set(VERSION_SCRIPT_FLAG) @@ -203,10 +203,11 @@ else() ARCHS ${arch} OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS} RTAsan_dynamic - # The only purpose of RTAsan_dynamic_version_script_dummy is to carry - # a dependency of the shared runtime on the version script. With CMake - # 3.1 or later it can be replaced with a straightforward + # The only purpose of RTAsan_dynamic_version_script_dummy is to + # carry a dependency of the shared runtime on the version script. + # Replacing it with a straightforward # add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list) + # generates an order-only dependency in ninja. RTAsan_dynamic_version_script_dummy RTUbsan_cxx ${ASAN_DYNAMIC_WEAK_INTERCEPTION} -- cgit v1.2.1 From 0c8339c8aab25f1156558e9e2082b4b124dc2327 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 21 Aug 2017 23:25:50 +0000 Subject: Move libFuzzer to compiler_rt. Resulting library binaries will be named libclang_rt.fuzzer*, and will be placed in Clang toolchain, allowing redistribution. Differential Revision: https://reviews.llvm.org/D36908 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311407 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 + cmake/Modules/AddCompilerRT.cmake | 7 +- cmake/base-config-ix.cmake | 13 + cmake/config-ix.cmake | 15 +- lib/CMakeLists.txt | 4 + lib/fuzzer/CMakeLists.txt | 63 ++ lib/fuzzer/FuzzerCorpus.h | 275 ++++++++ lib/fuzzer/FuzzerCrossOver.cpp | 52 ++ lib/fuzzer/FuzzerDefs.h | 128 ++++ lib/fuzzer/FuzzerDictionary.h | 127 ++++ lib/fuzzer/FuzzerDriver.cpp | 764 ++++++++++++++++++++++ lib/fuzzer/FuzzerExtFunctions.def | 46 ++ lib/fuzzer/FuzzerExtFunctions.h | 35 ++ lib/fuzzer/FuzzerExtFunctionsDlsym.cpp | 52 ++ lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp | 62 ++ lib/fuzzer/FuzzerExtFunctionsWeak.cpp | 54 ++ lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp | 56 ++ lib/fuzzer/FuzzerExtraCounters.cpp | 41 ++ lib/fuzzer/FuzzerFlags.def | 139 ++++ lib/fuzzer/FuzzerIO.cpp | 120 ++++ lib/fuzzer/FuzzerIO.h | 76 +++ lib/fuzzer/FuzzerIOPosix.cpp | 123 ++++ lib/fuzzer/FuzzerIOWindows.cpp | 323 ++++++++++ lib/fuzzer/FuzzerInterface.h | 67 ++ lib/fuzzer/FuzzerInternal.h | 150 +++++ lib/fuzzer/FuzzerLoop.cpp | 721 +++++++++++++++++++++ lib/fuzzer/FuzzerMain.cpp | 21 + lib/fuzzer/FuzzerMerge.cpp | 338 ++++++++++ lib/fuzzer/FuzzerMerge.h | 80 +++ lib/fuzzer/FuzzerMutate.cpp | 533 ++++++++++++++++ lib/fuzzer/FuzzerMutate.h | 150 +++++ lib/fuzzer/FuzzerOptions.h | 68 ++ lib/fuzzer/FuzzerRandom.h | 34 + lib/fuzzer/FuzzerSHA1.cpp | 222 +++++++ lib/fuzzer/FuzzerSHA1.h | 33 + lib/fuzzer/FuzzerShmem.h | 69 ++ lib/fuzzer/FuzzerShmemPosix.cpp | 103 +++ lib/fuzzer/FuzzerShmemWindows.cpp | 64 ++ lib/fuzzer/FuzzerTracePC.cpp | 566 +++++++++++++++++ lib/fuzzer/FuzzerTracePC.h | 253 ++++++++ lib/fuzzer/FuzzerUtil.cpp | 215 +++++++ lib/fuzzer/FuzzerUtil.h | 84 +++ lib/fuzzer/FuzzerUtilDarwin.cpp | 161 +++++ lib/fuzzer/FuzzerUtilLinux.cpp | 24 + lib/fuzzer/FuzzerUtilPosix.cpp | 144 +++++ lib/fuzzer/FuzzerUtilWindows.cpp | 193 ++++++ lib/fuzzer/FuzzerValueBitMap.h | 73 +++ lib/fuzzer/README.txt | 2 + lib/fuzzer/afl/afl_driver.cpp | 335 ++++++++++ lib/fuzzer/build.sh | 11 + lib/fuzzer/cxx.dict | 122 ++++ lib/fuzzer/standalone/StandaloneFuzzTargetMain.c | 41 ++ lib/fuzzer/tests/CMakeLists.txt | 46 ++ lib/fuzzer/tests/FuzzerUnittest.cpp | 768 +++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/fuzzer/AFLDriverTest.cpp | 28 + test/fuzzer/AbsNegAndConstant64Test.cpp | 24 + test/fuzzer/AbsNegAndConstantTest.cpp | 24 + test/fuzzer/AccumulateAllocationsTest.cpp | 17 + test/fuzzer/BadStrcmpTest.cpp | 19 + test/fuzzer/BogusInitializeTest.cpp | 15 + test/fuzzer/BufferOverflowOnInput.cpp | 24 + test/fuzzer/CMakeLists.txt | 40 ++ test/fuzzer/CallerCalleeTest.cpp | 59 ++ test/fuzzer/CleanseTest.cpp | 16 + test/fuzzer/CounterTest.cpp | 18 + test/fuzzer/CustomCrossOverAndMutateTest.cpp | 34 + test/fuzzer/CustomCrossOverTest.cpp | 64 ++ test/fuzzer/CustomMutatorTest.cpp | 39 ++ test/fuzzer/CxxStringEqTest.cpp | 25 + test/fuzzer/DSO1.cpp | 14 + test/fuzzer/DSO2.cpp | 14 + test/fuzzer/DSOTestExtra.cpp | 11 + test/fuzzer/DSOTestMain.cpp | 31 + test/fuzzer/DeepRecursionTest.cpp | 25 + test/fuzzer/DivTest.cpp | 20 + test/fuzzer/EmptyTest.cpp | 11 + test/fuzzer/EquivalenceATest.cpp | 17 + test/fuzzer/EquivalenceBTest.cpp | 27 + test/fuzzer/FlagsTest.cpp | 32 + test/fuzzer/FourIndependentBranchesTest.cpp | 22 + test/fuzzer/FullCoverageSetTest.cpp | 24 + test/fuzzer/InitializeTest.cpp | 28 + test/fuzzer/LargeTest.cpp | 37 ++ test/fuzzer/LeakTest.cpp | 17 + test/fuzzer/LeakTimeoutTest.cpp | 17 + test/fuzzer/LoadTest.cpp | 22 + test/fuzzer/Memcmp64BytesTest.cpp | 20 + test/fuzzer/MemcmpTest.cpp | 31 + test/fuzzer/NotinstrumentedTest.cpp | 11 + test/fuzzer/NthRunCrashTest.cpp | 19 + test/fuzzer/NullDerefOnEmptyTest.cpp | 19 + test/fuzzer/NullDerefTest.cpp | 26 + test/fuzzer/OneHugeAllocTest.cpp | 28 + test/fuzzer/OutOfMemorySingleLargeMallocTest.cpp | 27 + test/fuzzer/OutOfMemoryTest.cpp | 31 + test/fuzzer/OverwriteInputTest.cpp | 13 + test/fuzzer/RepeatedBytesTest.cpp | 31 + test/fuzzer/RepeatedMemcmp.cpp | 24 + test/fuzzer/ShrinkControlFlowSimpleTest.cpp | 19 + test/fuzzer/ShrinkControlFlowTest.cpp | 31 + test/fuzzer/ShrinkValueProfileTest.cpp | 22 + test/fuzzer/SignedIntOverflowTest.cpp | 28 + test/fuzzer/SimpleCmpTest.cpp | 47 ++ test/fuzzer/SimpleDictionaryTest.cpp | 30 + test/fuzzer/SimpleHashTest.cpp | 40 ++ test/fuzzer/SimpleTest.cpp | 28 + test/fuzzer/SimpleThreadedTest.cpp | 26 + test/fuzzer/SingleByteInputTest.cpp | 17 + test/fuzzer/SingleMemcmpTest.cpp | 17 + test/fuzzer/SingleStrcmpTest.cpp | 21 + test/fuzzer/SingleStrncmpTest.cpp | 18 + test/fuzzer/SpamyTest.cpp | 21 + test/fuzzer/StrcmpTest.cpp | 32 + test/fuzzer/StrncmpOOBTest.cpp | 21 + test/fuzzer/StrncmpTest.cpp | 28 + test/fuzzer/StrstrTest.cpp | 28 + test/fuzzer/SwapCmpTest.cpp | 35 ++ test/fuzzer/Switch2Test.cpp | 35 ++ test/fuzzer/SwitchTest.cpp | 58 ++ test/fuzzer/TableLookupTest.cpp | 44 ++ test/fuzzer/ThreadedLeakTest.cpp | 18 + test/fuzzer/ThreadedTest.cpp | 26 + test/fuzzer/TimeoutEmptyTest.cpp | 14 + test/fuzzer/TimeoutTest.cpp | 26 + test/fuzzer/TraceMallocTest.cpp | 27 + test/fuzzer/TwoDifferentBugsTest.cpp | 22 + test/fuzzer/afl-driver-extra-stats.test | 30 + test/fuzzer/afl-driver-stderr.test | 12 + test/fuzzer/afl-driver.test | 29 + test/fuzzer/bad-strcmp.test | 2 + test/fuzzer/caller-callee.test | 3 + test/fuzzer/cleanse.test | 4 + test/fuzzer/coverage.test | 21 + test/fuzzer/cxxstring.test | 6 + test/fuzzer/dict1.txt | 4 + test/fuzzer/disable-leaks.test | 5 + test/fuzzer/dump_coverage.test | 20 + test/fuzzer/equivalence-signals.test | 9 + test/fuzzer/equivalence.test | 9 + test/fuzzer/exit-report.test | 6 + test/fuzzer/exit_on_src_pos.test | 8 + test/fuzzer/extra-counters.test | 7 + test/fuzzer/fuzzer-customcrossover.test | 12 + test/fuzzer/fuzzer-customcrossoverandmutate.test | 2 + test/fuzzer/fuzzer-custommutator.test | 5 + test/fuzzer/fuzzer-dict.test | 8 + test/fuzzer/fuzzer-dirs.test | 21 + test/fuzzer/fuzzer-fdmask.test | 32 + test/fuzzer/fuzzer-finalstats.test | 12 + test/fuzzer/fuzzer-flags.test | 19 + test/fuzzer/fuzzer-leak.test | 37 ++ test/fuzzer/fuzzer-oom-with-profile.test | 7 + test/fuzzer/fuzzer-oom.test | 20 + test/fuzzer/fuzzer-printcovpcs.test | 9 + test/fuzzer/fuzzer-runs.test | 9 + test/fuzzer/fuzzer-seed.test | 4 + test/fuzzer/fuzzer-segv.test | 8 + test/fuzzer/fuzzer-singleinputs.test | 19 + test/fuzzer/fuzzer-threaded.test | 8 + test/fuzzer/fuzzer-timeout.test | 21 + test/fuzzer/fuzzer-ubsan.test | 5 + test/fuzzer/fuzzer.test | 70 +++ test/fuzzer/hi.txt | 1 + test/fuzzer/inline-8bit-counters.test | 5 + test/fuzzer/lit.cfg | 80 +++ test/fuzzer/lit.site.cfg.in | 17 + test/fuzzer/memcmp.test | 3 + test/fuzzer/memcmp64.test | 3 + test/fuzzer/merge-posix.test | 23 + test/fuzzer/merge-summary.test | 17 + test/fuzzer/merge.test | 55 ++ test/fuzzer/minimize_crash.test | 16 + test/fuzzer/minimize_two_crashes.test | 18 + test/fuzzer/overwrite-input.test | 3 + test/fuzzer/recommended-dictionary.test | 6 + test/fuzzer/reduce_inputs.test | 16 + test/fuzzer/repeated-bytes.test | 3 + test/fuzzer/shrink.test | 10 + test/fuzzer/simple-cmp.test | 3 + test/fuzzer/standalone.test | 8 + test/fuzzer/strcmp.test | 4 + test/fuzzer/strncmp.test | 4 + test/fuzzer/strstr.test | 4 + test/fuzzer/swap-cmp.test | 3 + test/fuzzer/trace-malloc-2.test | 10 + test/fuzzer/trace-malloc.test | 7 + test/fuzzer/trace-pc.test | 3 + test/fuzzer/ulimit.test | 3 + test/fuzzer/unit/lit.site.cfg.in | 9 + test/fuzzer/value-profile-cmp.test | 3 + test/fuzzer/value-profile-cmp2.test | 3 + test/fuzzer/value-profile-cmp3.test | 3 + test/fuzzer/value-profile-cmp4.test | 3 + test/fuzzer/value-profile-div.test | 4 + test/fuzzer/value-profile-load.test | 3 + test/fuzzer/value-profile-mem.test | 3 + test/fuzzer/value-profile-set.test | 4 + test/fuzzer/value-profile-strcmp.test | 3 + test/fuzzer/value-profile-strncmp.test | 3 + test/fuzzer/value-profile-switch.test | 5 + 201 files changed, 11012 insertions(+), 5 deletions(-) create mode 100644 lib/fuzzer/CMakeLists.txt create mode 100644 lib/fuzzer/FuzzerCorpus.h create mode 100644 lib/fuzzer/FuzzerCrossOver.cpp create mode 100644 lib/fuzzer/FuzzerDefs.h create mode 100644 lib/fuzzer/FuzzerDictionary.h create mode 100644 lib/fuzzer/FuzzerDriver.cpp create mode 100644 lib/fuzzer/FuzzerExtFunctions.def create mode 100644 lib/fuzzer/FuzzerExtFunctions.h create mode 100644 lib/fuzzer/FuzzerExtFunctionsDlsym.cpp create mode 100644 lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp create mode 100644 lib/fuzzer/FuzzerExtFunctionsWeak.cpp create mode 100644 lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp create mode 100644 lib/fuzzer/FuzzerExtraCounters.cpp create mode 100644 lib/fuzzer/FuzzerFlags.def create mode 100644 lib/fuzzer/FuzzerIO.cpp create mode 100644 lib/fuzzer/FuzzerIO.h create mode 100644 lib/fuzzer/FuzzerIOPosix.cpp create mode 100644 lib/fuzzer/FuzzerIOWindows.cpp create mode 100644 lib/fuzzer/FuzzerInterface.h create mode 100644 lib/fuzzer/FuzzerInternal.h create mode 100644 lib/fuzzer/FuzzerLoop.cpp create mode 100644 lib/fuzzer/FuzzerMain.cpp create mode 100644 lib/fuzzer/FuzzerMerge.cpp create mode 100644 lib/fuzzer/FuzzerMerge.h create mode 100644 lib/fuzzer/FuzzerMutate.cpp create mode 100644 lib/fuzzer/FuzzerMutate.h create mode 100644 lib/fuzzer/FuzzerOptions.h create mode 100644 lib/fuzzer/FuzzerRandom.h create mode 100644 lib/fuzzer/FuzzerSHA1.cpp create mode 100644 lib/fuzzer/FuzzerSHA1.h create mode 100644 lib/fuzzer/FuzzerShmem.h create mode 100644 lib/fuzzer/FuzzerShmemPosix.cpp create mode 100644 lib/fuzzer/FuzzerShmemWindows.cpp create mode 100644 lib/fuzzer/FuzzerTracePC.cpp create mode 100644 lib/fuzzer/FuzzerTracePC.h create mode 100644 lib/fuzzer/FuzzerUtil.cpp create mode 100644 lib/fuzzer/FuzzerUtil.h create mode 100644 lib/fuzzer/FuzzerUtilDarwin.cpp create mode 100644 lib/fuzzer/FuzzerUtilLinux.cpp create mode 100644 lib/fuzzer/FuzzerUtilPosix.cpp create mode 100644 lib/fuzzer/FuzzerUtilWindows.cpp create mode 100644 lib/fuzzer/FuzzerValueBitMap.h create mode 100644 lib/fuzzer/README.txt create mode 100644 lib/fuzzer/afl/afl_driver.cpp create mode 100755 lib/fuzzer/build.sh create mode 100644 lib/fuzzer/cxx.dict create mode 100644 lib/fuzzer/standalone/StandaloneFuzzTargetMain.c create mode 100644 lib/fuzzer/tests/CMakeLists.txt create mode 100644 lib/fuzzer/tests/FuzzerUnittest.cpp create mode 100644 test/fuzzer/AFLDriverTest.cpp create mode 100644 test/fuzzer/AbsNegAndConstant64Test.cpp create mode 100644 test/fuzzer/AbsNegAndConstantTest.cpp create mode 100644 test/fuzzer/AccumulateAllocationsTest.cpp create mode 100644 test/fuzzer/BadStrcmpTest.cpp create mode 100644 test/fuzzer/BogusInitializeTest.cpp create mode 100644 test/fuzzer/BufferOverflowOnInput.cpp create mode 100644 test/fuzzer/CMakeLists.txt create mode 100644 test/fuzzer/CallerCalleeTest.cpp create mode 100644 test/fuzzer/CleanseTest.cpp create mode 100644 test/fuzzer/CounterTest.cpp create mode 100644 test/fuzzer/CustomCrossOverAndMutateTest.cpp create mode 100644 test/fuzzer/CustomCrossOverTest.cpp create mode 100644 test/fuzzer/CustomMutatorTest.cpp create mode 100644 test/fuzzer/CxxStringEqTest.cpp create mode 100644 test/fuzzer/DSO1.cpp create mode 100644 test/fuzzer/DSO2.cpp create mode 100644 test/fuzzer/DSOTestExtra.cpp create mode 100644 test/fuzzer/DSOTestMain.cpp create mode 100644 test/fuzzer/DeepRecursionTest.cpp create mode 100644 test/fuzzer/DivTest.cpp create mode 100644 test/fuzzer/EmptyTest.cpp create mode 100644 test/fuzzer/EquivalenceATest.cpp create mode 100644 test/fuzzer/EquivalenceBTest.cpp create mode 100644 test/fuzzer/FlagsTest.cpp create mode 100644 test/fuzzer/FourIndependentBranchesTest.cpp create mode 100644 test/fuzzer/FullCoverageSetTest.cpp create mode 100644 test/fuzzer/InitializeTest.cpp create mode 100644 test/fuzzer/LargeTest.cpp create mode 100644 test/fuzzer/LeakTest.cpp create mode 100644 test/fuzzer/LeakTimeoutTest.cpp create mode 100644 test/fuzzer/LoadTest.cpp create mode 100644 test/fuzzer/Memcmp64BytesTest.cpp create mode 100644 test/fuzzer/MemcmpTest.cpp create mode 100644 test/fuzzer/NotinstrumentedTest.cpp create mode 100644 test/fuzzer/NthRunCrashTest.cpp create mode 100644 test/fuzzer/NullDerefOnEmptyTest.cpp create mode 100644 test/fuzzer/NullDerefTest.cpp create mode 100644 test/fuzzer/OneHugeAllocTest.cpp create mode 100644 test/fuzzer/OutOfMemorySingleLargeMallocTest.cpp create mode 100644 test/fuzzer/OutOfMemoryTest.cpp create mode 100644 test/fuzzer/OverwriteInputTest.cpp create mode 100644 test/fuzzer/RepeatedBytesTest.cpp create mode 100644 test/fuzzer/RepeatedMemcmp.cpp create mode 100644 test/fuzzer/ShrinkControlFlowSimpleTest.cpp create mode 100644 test/fuzzer/ShrinkControlFlowTest.cpp create mode 100644 test/fuzzer/ShrinkValueProfileTest.cpp create mode 100644 test/fuzzer/SignedIntOverflowTest.cpp create mode 100644 test/fuzzer/SimpleCmpTest.cpp create mode 100644 test/fuzzer/SimpleDictionaryTest.cpp create mode 100644 test/fuzzer/SimpleHashTest.cpp create mode 100644 test/fuzzer/SimpleTest.cpp create mode 100644 test/fuzzer/SimpleThreadedTest.cpp create mode 100644 test/fuzzer/SingleByteInputTest.cpp create mode 100644 test/fuzzer/SingleMemcmpTest.cpp create mode 100644 test/fuzzer/SingleStrcmpTest.cpp create mode 100644 test/fuzzer/SingleStrncmpTest.cpp create mode 100644 test/fuzzer/SpamyTest.cpp create mode 100644 test/fuzzer/StrcmpTest.cpp create mode 100644 test/fuzzer/StrncmpOOBTest.cpp create mode 100644 test/fuzzer/StrncmpTest.cpp create mode 100644 test/fuzzer/StrstrTest.cpp create mode 100644 test/fuzzer/SwapCmpTest.cpp create mode 100644 test/fuzzer/Switch2Test.cpp create mode 100644 test/fuzzer/SwitchTest.cpp create mode 100644 test/fuzzer/TableLookupTest.cpp create mode 100644 test/fuzzer/ThreadedLeakTest.cpp create mode 100644 test/fuzzer/ThreadedTest.cpp create mode 100644 test/fuzzer/TimeoutEmptyTest.cpp create mode 100644 test/fuzzer/TimeoutTest.cpp create mode 100644 test/fuzzer/TraceMallocTest.cpp create mode 100644 test/fuzzer/TwoDifferentBugsTest.cpp create mode 100644 test/fuzzer/afl-driver-extra-stats.test create mode 100644 test/fuzzer/afl-driver-stderr.test create mode 100644 test/fuzzer/afl-driver.test create mode 100644 test/fuzzer/bad-strcmp.test create mode 100644 test/fuzzer/caller-callee.test create mode 100644 test/fuzzer/cleanse.test create mode 100644 test/fuzzer/coverage.test create mode 100644 test/fuzzer/cxxstring.test create mode 100644 test/fuzzer/dict1.txt create mode 100644 test/fuzzer/disable-leaks.test create mode 100644 test/fuzzer/dump_coverage.test create mode 100644 test/fuzzer/equivalence-signals.test create mode 100644 test/fuzzer/equivalence.test create mode 100644 test/fuzzer/exit-report.test create mode 100644 test/fuzzer/exit_on_src_pos.test create mode 100644 test/fuzzer/extra-counters.test create mode 100644 test/fuzzer/fuzzer-customcrossover.test create mode 100644 test/fuzzer/fuzzer-customcrossoverandmutate.test create mode 100644 test/fuzzer/fuzzer-custommutator.test create mode 100644 test/fuzzer/fuzzer-dict.test create mode 100644 test/fuzzer/fuzzer-dirs.test create mode 100644 test/fuzzer/fuzzer-fdmask.test create mode 100644 test/fuzzer/fuzzer-finalstats.test create mode 100644 test/fuzzer/fuzzer-flags.test create mode 100644 test/fuzzer/fuzzer-leak.test create mode 100644 test/fuzzer/fuzzer-oom-with-profile.test create mode 100644 test/fuzzer/fuzzer-oom.test create mode 100644 test/fuzzer/fuzzer-printcovpcs.test create mode 100644 test/fuzzer/fuzzer-runs.test create mode 100644 test/fuzzer/fuzzer-seed.test create mode 100644 test/fuzzer/fuzzer-segv.test create mode 100644 test/fuzzer/fuzzer-singleinputs.test create mode 100644 test/fuzzer/fuzzer-threaded.test create mode 100644 test/fuzzer/fuzzer-timeout.test create mode 100644 test/fuzzer/fuzzer-ubsan.test create mode 100644 test/fuzzer/fuzzer.test create mode 100644 test/fuzzer/hi.txt create mode 100644 test/fuzzer/inline-8bit-counters.test create mode 100644 test/fuzzer/lit.cfg create mode 100644 test/fuzzer/lit.site.cfg.in create mode 100644 test/fuzzer/memcmp.test create mode 100644 test/fuzzer/memcmp64.test create mode 100644 test/fuzzer/merge-posix.test create mode 100644 test/fuzzer/merge-summary.test create mode 100644 test/fuzzer/merge.test create mode 100644 test/fuzzer/minimize_crash.test create mode 100644 test/fuzzer/minimize_two_crashes.test create mode 100644 test/fuzzer/overwrite-input.test create mode 100644 test/fuzzer/recommended-dictionary.test create mode 100644 test/fuzzer/reduce_inputs.test create mode 100644 test/fuzzer/repeated-bytes.test create mode 100644 test/fuzzer/shrink.test create mode 100644 test/fuzzer/simple-cmp.test create mode 100644 test/fuzzer/standalone.test create mode 100644 test/fuzzer/strcmp.test create mode 100644 test/fuzzer/strncmp.test create mode 100644 test/fuzzer/strstr.test create mode 100644 test/fuzzer/swap-cmp.test create mode 100644 test/fuzzer/trace-malloc-2.test create mode 100644 test/fuzzer/trace-malloc.test create mode 100644 test/fuzzer/trace-pc.test create mode 100644 test/fuzzer/ulimit.test create mode 100644 test/fuzzer/unit/lit.site.cfg.in create mode 100644 test/fuzzer/value-profile-cmp.test create mode 100644 test/fuzzer/value-profile-cmp2.test create mode 100644 test/fuzzer/value-profile-cmp3.test create mode 100644 test/fuzzer/value-profile-cmp4.test create mode 100644 test/fuzzer/value-profile-div.test create mode 100644 test/fuzzer/value-profile-load.test create mode 100644 test/fuzzer/value-profile-mem.test create mode 100644 test/fuzzer/value-profile-set.test create mode 100644 test/fuzzer/value-profile-strcmp.test create mode 100644 test/fuzzer/value-profile-strncmp.test create mode 100644 test/fuzzer/value-profile-switch.test diff --git a/CMakeLists.txt b/CMakeLists.txt index e3e5627e8..62118855b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,8 @@ option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON) mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS) option(COMPILER_RT_BUILD_XRAY "Build xray" ON) mark_as_advanced(COMPILER_RT_BUILD_XRAY) +option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON) +mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER) option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF) mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 9220eab84..966377cce 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -202,10 +202,10 @@ function(add_compiler_rt_runtime name type) set_target_properties(${libname} PROPERTIES OUTPUT_NAME ${output_name_${libname}}) set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime") + if(LIB_LINK_LIBS) + target_link_libraries(${libname} ${LIB_LINK_LIBS}) + endif() if(${type} STREQUAL "SHARED") - if(LIB_LINK_LIBS) - target_link_libraries(${libname} ${LIB_LINK_LIBS}) - endif() if(WIN32 AND NOT CYGWIN AND NOT MINGW) set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "") set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib") @@ -368,7 +368,6 @@ function(add_compiler_rt_test test_suite test_name arch) set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}") separate_arguments(TEST_LINK_FLAGS) endif() - add_custom_command( OUTPUT "${output_bin}" COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} -o "${output_bin}" diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index b38c6ca96..953d9e530 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -4,6 +4,8 @@ # runtime libraries. include(CheckIncludeFile) +include(CheckCXXSourceCompiles) + check_include_file(unwind.h HAVE_UNWIND_H) # Top level target used to build all compiler-rt libraries. @@ -86,6 +88,17 @@ if(APPLE) option(COMPILER_RT_ENABLE_IOS "Enable building for iOS" On) option(COMPILER_RT_ENABLE_WATCHOS "Enable building for watchOS - Experimental" Off) option(COMPILER_RT_ENABLE_TVOS "Enable building for tvOS - Experimental" Off) + + CHECK_CXX_SOURCE_COMPILES(" + static thread_local int blah; + int main() { + return 0; + } + " HAS_THREAD_LOCAL) + + if( NOT HAS_THREAD_LOCAL ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dthread_local=__thread") + endif() else() option(COMPILER_RT_DEFAULT_TARGET_ONLY "Build builtins only for the default target" Off) endif() diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 092d98dd1..d38e3f3b6 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -194,6 +194,7 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64}) +set(ALL_FUZZER_SUPPORTED_ARCH x86_64) if(APPLE) set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) @@ -413,7 +414,11 @@ if(APPLE) SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(XRAY_SUPPORTED_ARCH ALL_XRAY_SUPPORTED_ARCH - SANITIZER_COMMON_SUPPORTED_ARCH) + SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(FUZZER_SUPPORTED_ARCH + ALL_FUZZER_SUPPORTED_ARCH + ALL_SANITIZER_COMMON_SUPPORTED_ARCH) + else() # Architectures supported by compiler-rt libraries. filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH @@ -425,6 +430,7 @@ else() filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}) filter_available_targets(ASAN_SUPPORTED_ARCH ${ALL_ASAN_SUPPORTED_ARCH}) + filter_available_targets(FUZZER_SUPPORTED_ARCH ${ALL_FUZZER_SUPPORTED_ARCH}) filter_available_targets(DFSAN_SUPPORTED_ARCH ${ALL_DFSAN_SUPPORTED_ARCH}) filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH}) filter_available_targets(MSAN_SUPPORTED_ARCH ${ALL_MSAN_SUPPORTED_ARCH}) @@ -573,3 +579,10 @@ if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND else() set(COMPILER_RT_HAS_XRAY FALSE) endif() + +if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND + OS_NAME MATCHES "Darwin|Linux") + set(COMPILER_RT_HAS_FUZZER TRUE) +else() + set(COMPILER_RT_HAS_FUZZER FALSE) +endif() diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 90f72d02a..025320f47 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -46,3 +46,7 @@ endif() if(COMPILER_RT_BUILD_XRAY) compiler_rt_build_runtime(xray) endif() + +if(COMPILER_RT_BUILD_LIBFUZZER) + compiler_rt_build_runtime(fuzzer) +endif() diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt new file mode 100644 index 000000000..309a8b801 --- /dev/null +++ b/lib/fuzzer/CMakeLists.txt @@ -0,0 +1,63 @@ +set(LIBFUZZER_SOURCES + FuzzerCrossOver.cpp + FuzzerDriver.cpp + FuzzerExtFunctionsDlsym.cpp + FuzzerExtFunctionsDlsymWin.cpp + FuzzerExtFunctionsWeak.cpp + FuzzerExtraCounters.cpp + FuzzerIO.cpp + FuzzerIOPosix.cpp + FuzzerIOWindows.cpp + FuzzerLoop.cpp + FuzzerMerge.cpp + FuzzerMutate.cpp + FuzzerSHA1.cpp + FuzzerShmemPosix.cpp + FuzzerShmemWindows.cpp + FuzzerTracePC.cpp + FuzzerUtil.cpp + FuzzerUtilDarwin.cpp + FuzzerUtilLinux.cpp + FuzzerUtilPosix.cpp + FuzzerUtilWindows.cpp + ) + +if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage") + set(LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters) +endif() + +if(APPLE) + set(FUZZER_SUPPORTED_OS osx) +endif() + +add_compiler_rt_object_libraries(RTfuzzer + OS ${FUZZER_SUPPORTED_OS} + ARCHS ${FUZZER_SUPPORTED_ARCH} + SOURCES ${LIBFUZZER_SOURCES} + CFLAGS ${LIBFUZZER_CFLAGS}) + +add_compiler_rt_object_libraries(RTfuzzer_main + OS ${FUZZER_SUPPORTED_OS} + ARCHS ${FUZZER_SUPPORTED_ARCH} + SOURCES FuzzerMain.cpp + CFLAGS ${LIBFUZZER_CFLAGS}) + +add_compiler_rt_runtime(clang_rt.fuzzer + STATIC + OS ${FUZZER_SUPPORTED_OS} + ARCHS ${FUZZER_SUPPORTED_ARCH} + OBJECT_LIBS RTfuzzer RTfuzzer_main + CFLAGS ${LIBFUZZER_CFLAGS} + PARENT_TARGET fuzzer) + +add_compiler_rt_runtime(clang_rt.fuzzer_no_main + STATIC + OS ${FUZZER_SUPPORTED_OS} + ARCHS ${FUZZER_SUPPORTED_ARCH} + OBJECT_LIBS RTfuzzer + CFLAGS ${LIBFUZZER_CFLAGS} + PARENT_TARGET fuzzer) + +if(COMPILER_RT_INCLUDE_TESTS) + add_subdirectory(tests) +endif() diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h new file mode 100644 index 000000000..bae0aea78 --- /dev/null +++ b/lib/fuzzer/FuzzerCorpus.h @@ -0,0 +1,275 @@ +//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::InputCorpus +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_CORPUS +#define LLVM_FUZZER_CORPUS + +#include "FuzzerDefs.h" +#include "FuzzerIO.h" +#include "FuzzerRandom.h" +#include "FuzzerSHA1.h" +#include "FuzzerTracePC.h" +#include +#include +#include +#include + +namespace fuzzer { + +struct InputInfo { + Unit U; // The actual input data. + uint8_t Sha1[kSHA1NumBytes]; // Checksum. + // Number of features that this input has and no smaller input has. + size_t NumFeatures = 0; + size_t Tmp = 0; // Used by ValidateFeatureSet. + // Stats. + size_t NumExecutedMutations = 0; + size_t NumSuccessfullMutations = 0; + bool MayDeleteFile = false; + bool Reduced = false; + std::vector UniqFeatureSet; +}; + +class InputCorpus { + static const size_t kFeatureSetSize = 1 << 21; + public: + InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) { + memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); + memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); + } + ~InputCorpus() { + for (auto II : Inputs) + delete II; + } + size_t size() const { return Inputs.size(); } + size_t SizeInBytes() const { + size_t Res = 0; + for (auto II : Inputs) + Res += II->U.size(); + return Res; + } + size_t NumActiveUnits() const { + size_t Res = 0; + for (auto II : Inputs) + Res += !II->U.empty(); + return Res; + } + size_t MaxInputSize() const { + size_t Res = 0; + for (auto II : Inputs) + Res = std::max(Res, II->U.size()); + return Res; + } + bool empty() const { return Inputs.empty(); } + const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } + void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, + const std::vector &FeatureSet) { + assert(!U.empty()); + if (FeatureDebug) + Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); + Inputs.push_back(new InputInfo()); + InputInfo &II = *Inputs.back(); + II.U = U; + II.NumFeatures = NumFeatures; + II.MayDeleteFile = MayDeleteFile; + II.UniqFeatureSet = FeatureSet; + std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end()); + ComputeSHA1(U.data(), U.size(), II.Sha1); + Hashes.insert(Sha1ToString(II.Sha1)); + UpdateCorpusDistribution(); + PrintCorpus(); + // ValidateFeatureSet(); + } + + // Debug-only + void PrintUnit(const Unit &U) { + if (!FeatureDebug) return; + for (uint8_t C : U) { + if (C != 'F' && C != 'U' && C != 'Z') + C = '.'; + Printf("%c", C); + } + } + + // Debug-only + void PrintFeatureSet(const std::vector &FeatureSet) { + if (!FeatureDebug) return; + Printf("{"); + for (uint32_t Feature: FeatureSet) + Printf("%u,", Feature); + Printf("}"); + } + + // Debug-only + void PrintCorpus() { + if (!FeatureDebug) return; + Printf("======= CORPUS:\n"); + int i = 0; + for (auto II : Inputs) { + if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) { + Printf("[%2d] ", i); + Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size()); + PrintUnit(II->U); + Printf(" "); + PrintFeatureSet(II->UniqFeatureSet); + Printf("\n"); + } + i++; + } + } + + void Replace(InputInfo *II, const Unit &U) { + assert(II->U.size() > U.size()); + Hashes.erase(Sha1ToString(II->Sha1)); + DeleteFile(*II); + ComputeSHA1(U.data(), U.size(), II->Sha1); + Hashes.insert(Sha1ToString(II->Sha1)); + II->U = U; + II->Reduced = true; + } + + bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } + bool HasUnit(const std::string &H) { return Hashes.count(H); } + InputInfo &ChooseUnitToMutate(Random &Rand) { + InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)]; + assert(!II.U.empty()); + return II; + }; + + // Returns an index of random unit from the corpus to mutate. + // Hypothesis: units added to the corpus last are more likely to be + // interesting. This function gives more weight to the more recent units. + size_t ChooseUnitIdxToMutate(Random &Rand) { + size_t Idx = static_cast(CorpusDistribution(Rand)); + assert(Idx < Inputs.size()); + return Idx; + } + + void PrintStats() { + for (size_t i = 0; i < Inputs.size(); i++) { + const auto &II = *Inputs[i]; + Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i, + Sha1ToString(II.Sha1).c_str(), II.U.size(), + II.NumExecutedMutations, II.NumSuccessfullMutations); + } + } + + void PrintFeatureSet() { + for (size_t i = 0; i < kFeatureSetSize; i++) { + if(size_t Sz = GetFeature(i)) + Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz); + } + Printf("\n\t"); + for (size_t i = 0; i < Inputs.size(); i++) + if (size_t N = Inputs[i]->NumFeatures) + Printf(" %zd=>%zd ", i, N); + Printf("\n"); + } + + void DeleteFile(const InputInfo &II) { + if (!OutputCorpus.empty() && II.MayDeleteFile) + RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1))); + } + + void DeleteInput(size_t Idx) { + InputInfo &II = *Inputs[Idx]; + DeleteFile(II); + Unit().swap(II.U); + if (FeatureDebug) + Printf("EVICTED %zd\n", Idx); + } + + bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) { + assert(NewSize); + Idx = Idx % kFeatureSetSize; + uint32_t OldSize = GetFeature(Idx); + if (OldSize == 0 || (Shrink && OldSize > NewSize)) { + if (OldSize > 0) { + size_t OldIdx = SmallestElementPerFeature[Idx]; + InputInfo &II = *Inputs[OldIdx]; + assert(II.NumFeatures > 0); + II.NumFeatures--; + if (II.NumFeatures == 0) + DeleteInput(OldIdx); + } else { + NumAddedFeatures++; + } + NumUpdatedFeatures++; + if (FeatureDebug) + Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize); + SmallestElementPerFeature[Idx] = Inputs.size(); + InputSizesPerFeature[Idx] = NewSize; + return true; + } + return false; + } + + size_t NumFeatures() const { return NumAddedFeatures; } + size_t NumFeatureUpdates() const { return NumUpdatedFeatures; } + + void ResetFeatureSet() { + assert(Inputs.empty()); + memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); + memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); + } + +private: + + static const bool FeatureDebug = false; + + size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; } + + void ValidateFeatureSet() { + if (FeatureDebug) + PrintFeatureSet(); + for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) + if (GetFeature(Idx)) + Inputs[SmallestElementPerFeature[Idx]]->Tmp++; + for (auto II: Inputs) { + if (II->Tmp != II->NumFeatures) + Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures); + assert(II->Tmp == II->NumFeatures); + II->Tmp = 0; + } + } + + // Updates the probability distribution for the units in the corpus. + // Must be called whenever the corpus or unit weights are changed. + void UpdateCorpusDistribution() { + size_t N = Inputs.size(); + assert(N); + Intervals.resize(N + 1); + Weights.resize(N); + std::iota(Intervals.begin(), Intervals.end(), 0); + for (size_t i = 0; i < N; i++) + Weights[i] = Inputs[i]->NumFeatures * (i + 1); + CorpusDistribution = std::piecewise_constant_distribution( + Intervals.begin(), Intervals.end(), Weights.begin()); + } + std::piecewise_constant_distribution CorpusDistribution; + + std::vector Intervals; + std::vector Weights; + + std::unordered_set Hashes; + std::vector Inputs; + + size_t NumAddedFeatures = 0; + size_t NumUpdatedFeatures = 0; + uint32_t InputSizesPerFeature[kFeatureSetSize]; + uint32_t SmallestElementPerFeature[kFeatureSetSize]; + + std::string OutputCorpus; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_CORPUS diff --git a/lib/fuzzer/FuzzerCrossOver.cpp b/lib/fuzzer/FuzzerCrossOver.cpp new file mode 100644 index 000000000..8b0fd7d52 --- /dev/null +++ b/lib/fuzzer/FuzzerCrossOver.cpp @@ -0,0 +1,52 @@ +//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Cross over test inputs. +//===----------------------------------------------------------------------===// + +#include "FuzzerDefs.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" +#include + +namespace fuzzer { + +// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. +size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize) { + assert(Size1 || Size2); + MaxOutSize = Rand(MaxOutSize) + 1; + size_t OutPos = 0; + size_t Pos1 = 0; + size_t Pos2 = 0; + size_t *InPos = &Pos1; + size_t InSize = Size1; + const uint8_t *Data = Data1; + bool CurrentlyUsingFirstData = true; + while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) { + // Merge a part of Data into Out. + size_t OutSizeLeft = MaxOutSize - OutPos; + if (*InPos < InSize) { + size_t InSizeLeft = InSize - *InPos; + size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); + size_t ExtraSize = Rand(MaxExtraSize) + 1; + memcpy(Out + OutPos, Data + *InPos, ExtraSize); + OutPos += ExtraSize; + (*InPos) += ExtraSize; + } + // Use the other input data on the next iteration. + InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1; + InSize = CurrentlyUsingFirstData ? Size2 : Size1; + Data = CurrentlyUsingFirstData ? Data2 : Data1; + CurrentlyUsingFirstData = !CurrentlyUsingFirstData; + } + return OutPos; +} + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h new file mode 100644 index 000000000..27f571923 --- /dev/null +++ b/lib/fuzzer/FuzzerDefs.h @@ -0,0 +1,128 @@ +//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Basic definitions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_DEFS_H +#define LLVM_FUZZER_DEFS_H + +#include +#include +#include +#include +#include +#include + +// Platform detection. +#ifdef __linux__ +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_LINUX 1 +#define LIBFUZZER_WINDOWS 0 +#elif __APPLE__ +#define LIBFUZZER_APPLE 1 +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_WINDOWS 0 +#elif _WIN32 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_WINDOWS 1 +#else +#error "Support for your platform has not been implemented" +#endif + +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +#define LIBFUZZER_POSIX LIBFUZZER_APPLE || LIBFUZZER_LINUX + +#ifdef __x86_64 +# if __has_attribute(target) +# define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) +# else +# define ATTRIBUTE_TARGET_POPCNT +# endif +#else +# define ATTRIBUTE_TARGET_POPCNT +#endif + + +#ifdef __clang__ // avoid gcc warning. +# if __has_attribute(no_sanitize) +# define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory"))) +# else +# define ATTRIBUTE_NO_SANITIZE_MEMORY +# endif +# define ALWAYS_INLINE __attribute__((always_inline)) +#else +# define ATTRIBUTE_NO_SANITIZE_MEMORY +# define ALWAYS_INLINE +#endif // __clang__ + +#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) + +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS +# elif __has_feature(memory_sanitizer) +# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_MEMORY +# else +# define ATTRIBUTE_NO_SANITIZE_ALL +# endif +#else +# define ATTRIBUTE_NO_SANITIZE_ALL +#endif + +#if LIBFUZZER_WINDOWS +#define ATTRIBUTE_INTERFACE __declspec(dllexport) +#else +#define ATTRIBUTE_INTERFACE __attribute__((visibility("default"))) +#endif + +namespace fuzzer { + +template T Min(T a, T b) { return a < b ? a : b; } +template T Max(T a, T b) { return a > b ? a : b; } + +class Random; +class Dictionary; +class DictionaryEntry; +class MutationDispatcher; +struct FuzzingOptions; +class InputCorpus; +struct InputInfo; +struct ExternalFunctions; + +// Global interface to functions that may or may not be available. +extern ExternalFunctions *EF; + +typedef std::vector Unit; +typedef std::vector UnitVector; +typedef int (*UserCallback)(const uint8_t *Data, size_t Size); + +int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); + +struct ScopedDoingMyOwnMemOrStr { + ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr++; } + ~ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr--; } + static int DoingMyOwnMemOrStr; +}; + +inline uint8_t Bswap(uint8_t x) { return x; } +inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } +inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } +inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } + +uint8_t *ExtraCountersBegin(); +uint8_t *ExtraCountersEnd(); +void ClearExtraCounters(); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_DEFS_H diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h new file mode 100644 index 000000000..84cee87b8 --- /dev/null +++ b/lib/fuzzer/FuzzerDictionary.h @@ -0,0 +1,127 @@ +//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::Dictionary +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_DICTIONARY_H +#define LLVM_FUZZER_DICTIONARY_H + +#include "FuzzerDefs.h" +#include "FuzzerIO.h" +#include "FuzzerUtil.h" +#include +#include + +namespace fuzzer { +// A simple POD sized array of bytes. +template class FixedWord { +public: + static const size_t kMaxSize = kMaxSizeT; + FixedWord() {} + FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); } + + void Set(const uint8_t *B, uint8_t S) { + assert(S <= kMaxSize); + memcpy(Data, B, S); + Size = S; + } + + bool operator==(const FixedWord &w) const { + ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; + return Size == w.Size && 0 == memcmp(Data, w.Data, Size); + } + + bool operator<(const FixedWord &w) const { + ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; + if (Size != w.Size) + return Size < w.Size; + return memcmp(Data, w.Data, Size) < 0; + } + + static size_t GetMaxSize() { return kMaxSize; } + const uint8_t *data() const { return Data; } + uint8_t size() const { return Size; } + +private: + uint8_t Size = 0; + uint8_t Data[kMaxSize]; +}; + +typedef FixedWord<64> Word; + +class DictionaryEntry { + public: + DictionaryEntry() {} + DictionaryEntry(Word W) : W(W) {} + DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} + const Word &GetW() const { return W; } + + bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } + size_t GetPositionHint() const { + assert(HasPositionHint()); + return PositionHint; + } + void IncUseCount() { UseCount++; } + void IncSuccessCount() { SuccessCount++; } + size_t GetUseCount() const { return UseCount; } + size_t GetSuccessCount() const {return SuccessCount; } + + void Print(const char *PrintAfter = "\n") { + PrintASCII(W.data(), W.size()); + if (HasPositionHint()) + Printf("@%zd", GetPositionHint()); + Printf("%s", PrintAfter); + } + +private: + Word W; + size_t PositionHint = std::numeric_limits::max(); + size_t UseCount = 0; + size_t SuccessCount = 0; +}; + +class Dictionary { + public: + static const size_t kMaxDictSize = 1 << 14; + + bool ContainsWord(const Word &W) const { + return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { + return DE.GetW() == W; + }); + } + const DictionaryEntry *begin() const { return &DE[0]; } + const DictionaryEntry *end() const { return begin() + Size; } + DictionaryEntry & operator[] (size_t Idx) { + assert(Idx < Size); + return DE[Idx]; + } + void push_back(DictionaryEntry DE) { + if (Size < kMaxDictSize) + this->DE[Size++] = DE; + } + void clear() { Size = 0; } + bool empty() const { return Size == 0; } + size_t size() const { return Size; } + +private: + DictionaryEntry DE[kMaxDictSize]; + size_t Size = 0; +}; + +// Parses one dictionary entry. +// If successfull, write the enty to Unit and returns true, +// otherwise returns false. +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); +// Parses the dictionary file, fills Units, returns true iff all lines +// were parsed succesfully. +bool ParseDictionaryFile(const std::string &Text, std::vector *Units); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_DICTIONARY_H diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp new file mode 100644 index 000000000..17891d29c --- /dev/null +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -0,0 +1,764 @@ +//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// FuzzerDriver and flag parsing. +//===----------------------------------------------------------------------===// + +#include "FuzzerCorpus.h" +#include "FuzzerIO.h" +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" +#include "FuzzerShmem.h" +#include "FuzzerTracePC.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// This function should be present in the libFuzzer so that the client +// binary can test for its existence. +extern "C" __attribute__((used)) void __libfuzzer_is_present() {} + +namespace fuzzer { + +// Program arguments. +struct FlagDescription { + const char *Name; + const char *Description; + int Default; + int *IntFlag; + const char **StrFlag; + unsigned int *UIntFlag; +}; + +struct { +#define FUZZER_DEPRECATED_FLAG(Name) +#define FUZZER_FLAG_INT(Name, Default, Description) int Name; +#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; +#define FUZZER_FLAG_STRING(Name, Description) const char *Name; +#include "FuzzerFlags.def" +#undef FUZZER_DEPRECATED_FLAG +#undef FUZZER_FLAG_INT +#undef FUZZER_FLAG_UNSIGNED +#undef FUZZER_FLAG_STRING +} Flags; + +static const FlagDescription FlagDescriptions [] { +#define FUZZER_DEPRECATED_FLAG(Name) \ + {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, +#define FUZZER_FLAG_INT(Name, Default, Description) \ + {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, +#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ + {#Name, Description, static_cast(Default), \ + nullptr, nullptr, &Flags.Name}, +#define FUZZER_FLAG_STRING(Name, Description) \ + {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, +#include "FuzzerFlags.def" +#undef FUZZER_DEPRECATED_FLAG +#undef FUZZER_FLAG_INT +#undef FUZZER_FLAG_UNSIGNED +#undef FUZZER_FLAG_STRING +}; + +static const size_t kNumFlags = + sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); + +static std::vector *Inputs; +static std::string *ProgName; + +static void PrintHelp() { + Printf("Usage:\n"); + auto Prog = ProgName->c_str(); + Printf("\nTo run fuzzing pass 0 or more directories.\n"); + Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); + + Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); + Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); + + Printf("\nFlags: (strictly in form -flag=value)\n"); + size_t MaxFlagLen = 0; + for (size_t F = 0; F < kNumFlags; F++) + MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); + + for (size_t F = 0; F < kNumFlags; F++) { + const auto &D = FlagDescriptions[F]; + if (strstr(D.Description, "internal flag") == D.Description) continue; + Printf(" %s", D.Name); + for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) + Printf(" "); + Printf("\t"); + Printf("%d\t%s\n", D.Default, D.Description); + } + Printf("\nFlags starting with '--' will be ignored and " + "will be passed verbatim to subprocesses.\n"); +} + +static const char *FlagValue(const char *Param, const char *Name) { + size_t Len = strlen(Name); + if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && + Param[Len + 1] == '=') + return &Param[Len + 2]; + return nullptr; +} + +// Avoid calling stol as it triggers a bug in clang/glibc build. +static long MyStol(const char *Str) { + long Res = 0; + long Sign = 1; + if (*Str == '-') { + Str++; + Sign = -1; + } + for (size_t i = 0; Str[i]; i++) { + char Ch = Str[i]; + if (Ch < '0' || Ch > '9') + return Res; + Res = Res * 10 + (Ch - '0'); + } + return Res * Sign; +} + +static bool ParseOneFlag(const char *Param) { + if (Param[0] != '-') return false; + if (Param[1] == '-') { + static bool PrintedWarning = false; + if (!PrintedWarning) { + PrintedWarning = true; + Printf("INFO: libFuzzer ignores flags that start with '--'\n"); + } + for (size_t F = 0; F < kNumFlags; F++) + if (FlagValue(Param + 1, FlagDescriptions[F].Name)) + Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); + return true; + } + for (size_t F = 0; F < kNumFlags; F++) { + const char *Name = FlagDescriptions[F].Name; + const char *Str = FlagValue(Param, Name); + if (Str) { + if (FlagDescriptions[F].IntFlag) { + int Val = MyStol(Str); + *FlagDescriptions[F].IntFlag = Val; + if (Flags.verbosity >= 2) + Printf("Flag: %s %d\n", Name, Val); + return true; + } else if (FlagDescriptions[F].UIntFlag) { + unsigned int Val = std::stoul(Str); + *FlagDescriptions[F].UIntFlag = Val; + if (Flags.verbosity >= 2) + Printf("Flag: %s %u\n", Name, Val); + return true; + } else if (FlagDescriptions[F].StrFlag) { + *FlagDescriptions[F].StrFlag = Str; + if (Flags.verbosity >= 2) + Printf("Flag: %s %s\n", Name, Str); + return true; + } else { // Deprecated flag. + Printf("Flag: %s: deprecated, don't use\n", Name); + return true; + } + } + } + Printf("\n\nWARNING: unrecognized flag '%s'; " + "use -help=1 to list all flags\n\n", Param); + return true; +} + +// We don't use any library to minimize dependencies. +static void ParseFlags(const std::vector &Args) { + for (size_t F = 0; F < kNumFlags; F++) { + if (FlagDescriptions[F].IntFlag) + *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; + if (FlagDescriptions[F].UIntFlag) + *FlagDescriptions[F].UIntFlag = + static_cast(FlagDescriptions[F].Default); + if (FlagDescriptions[F].StrFlag) + *FlagDescriptions[F].StrFlag = nullptr; + } + Inputs = new std::vector; + for (size_t A = 1; A < Args.size(); A++) { + if (ParseOneFlag(Args[A].c_str())) { + if (Flags.ignore_remaining_args) + break; + continue; + } + Inputs->push_back(Args[A]); + } +} + +static std::mutex Mu; + +static void PulseThread() { + while (true) { + SleepSeconds(600); + std::lock_guard Lock(Mu); + Printf("pulse...\n"); + } +} + +static void WorkerThread(const std::string &Cmd, std::atomic *Counter, + unsigned NumJobs, std::atomic *HasErrors) { + while (true) { + unsigned C = (*Counter)++; + if (C >= NumJobs) break; + std::string Log = "fuzz-" + std::to_string(C) + ".log"; + std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; + if (Flags.verbosity) + Printf("%s", ToRun.c_str()); + int ExitCode = ExecuteCommand(ToRun); + if (ExitCode != 0) + *HasErrors = true; + std::lock_guard Lock(Mu); + Printf("================== Job %u exited with exit code %d ============\n", + C, ExitCode); + fuzzer::CopyFileToErr(Log); + } +} + +std::string CloneArgsWithoutX(const std::vector &Args, + const char *X1, const char *X2) { + std::string Cmd; + for (auto &S : Args) { + if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) + continue; + Cmd += S + " "; + } + return Cmd; +} + +static int RunInMultipleProcesses(const std::vector &Args, + unsigned NumWorkers, unsigned NumJobs) { + std::atomic Counter(0); + std::atomic HasErrors(false); + std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); + std::vector V; + std::thread Pulse(PulseThread); + Pulse.detach(); + for (unsigned i = 0; i < NumWorkers; i++) + V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); + for (auto &T : V) + T.join(); + return HasErrors ? 1 : 0; +} + +static void RssThread(Fuzzer *F, size_t RssLimitMb) { + while (true) { + SleepSeconds(1); + size_t Peak = GetPeakRSSMb(); + if (Peak > RssLimitMb) + F->RssLimitCallback(); + } +} + +static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { + if (!RssLimitMb) return; + std::thread T(RssThread, F, RssLimitMb); + T.detach(); +} + +int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { + Unit U = FileToVector(InputFilePath); + if (MaxLen && MaxLen < U.size()) + U.resize(MaxLen); + F->ExecuteCallback(U.data(), U.size()); + F->TryDetectingAMemoryLeak(U.data(), U.size(), true); + return 0; +} + +static bool AllInputsAreFiles() { + if (Inputs->empty()) return false; + for (auto &Path : *Inputs) + if (!IsFile(Path)) + return false; + return true; +} + +static std::string GetDedupTokenFromFile(const std::string &Path) { + auto S = FileToString(Path); + auto Beg = S.find("DEDUP_TOKEN:"); + if (Beg == std::string::npos) + return ""; + auto End = S.find('\n', Beg); + if (End == std::string::npos) + return ""; + return S.substr(Beg, End - Beg); +} + +int CleanseCrashInput(const std::vector &Args, + const FuzzingOptions &Options) { + if (Inputs->size() != 1 || !Flags.exact_artifact_path) { + Printf("ERROR: -cleanse_crash should be given one input file and" + " -exact_artifact_path\n"); + exit(1); + } + std::string InputFilePath = Inputs->at(0); + std::string OutputFilePath = Flags.exact_artifact_path; + std::string BaseCmd = + CloneArgsWithoutX(Args, "cleanse_crash", "cleanse_crash"); + + auto InputPos = BaseCmd.find(" " + InputFilePath + " "); + assert(InputPos != std::string::npos); + BaseCmd.erase(InputPos, InputFilePath.size() + 1); + + auto LogFilePath = DirPlusFile( + TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); + auto TmpFilePath = DirPlusFile( + TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro"); + auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; + + auto Cmd = BaseCmd + " " + TmpFilePath + LogFileRedirect; + + std::string CurrentFilePath = InputFilePath; + auto U = FileToVector(CurrentFilePath); + size_t Size = U.size(); + + const std::vector ReplacementBytes = {' ', 0xff}; + for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { + bool Changed = false; + for (size_t Idx = 0; Idx < Size; Idx++) { + Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts, + Idx, Size); + uint8_t OriginalByte = U[Idx]; + if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(), + ReplacementBytes.end(), + OriginalByte)) + continue; + for (auto NewByte : ReplacementBytes) { + U[Idx] = NewByte; + WriteToFile(U, TmpFilePath); + auto ExitCode = ExecuteCommand(Cmd); + RemoveFile(TmpFilePath); + if (!ExitCode) { + U[Idx] = OriginalByte; + } else { + Changed = true; + Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte); + WriteToFile(U, OutputFilePath); + break; + } + } + } + if (!Changed) break; + } + RemoveFile(LogFilePath); + return 0; +} + +int MinimizeCrashInput(const std::vector &Args, + const FuzzingOptions &Options) { + if (Inputs->size() != 1) { + Printf("ERROR: -minimize_crash should be given one input file\n"); + exit(1); + } + std::string InputFilePath = Inputs->at(0); + auto BaseCmd = SplitBefore( + "-ignore_remaining_args=1", + CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path")); + auto InputPos = BaseCmd.first.find(" " + InputFilePath + " "); + assert(InputPos != std::string::npos); + BaseCmd.first.erase(InputPos, InputFilePath.size() + 1); + if (Flags.runs <= 0 && Flags.max_total_time == 0) { + Printf("INFO: you need to specify -runs=N or " + "-max_total_time=N with -minimize_crash=1\n" + "INFO: defaulting to -max_total_time=600\n"); + BaseCmd.first += " -max_total_time=600"; + } + + auto LogFilePath = DirPlusFile( + TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); + auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; + + std::string CurrentFilePath = InputFilePath; + while (true) { + Unit U = FileToVector(CurrentFilePath); + Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", + CurrentFilePath.c_str(), U.size()); + + auto Cmd = BaseCmd.first + " " + CurrentFilePath + LogFileRedirect + " " + + BaseCmd.second; + + Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); + int ExitCode = ExecuteCommand(Cmd); + if (ExitCode == 0) { + Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); + exit(1); + } + Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " + "it further\n", + CurrentFilePath.c_str(), U.size()); + auto DedupToken1 = GetDedupTokenFromFile(LogFilePath); + if (!DedupToken1.empty()) + Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str()); + + std::string ArtifactPath = + Flags.exact_artifact_path + ? Flags.exact_artifact_path + : Options.ArtifactPrefix + "minimized-from-" + Hash(U); + Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" + + ArtifactPath; + Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); + ExitCode = ExecuteCommand(Cmd); + CopyFileToErr(LogFilePath); + if (ExitCode == 0) { + if (Flags.exact_artifact_path) { + CurrentFilePath = Flags.exact_artifact_path; + WriteToFile(U, CurrentFilePath); + } + Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", + CurrentFilePath.c_str(), U.size()); + break; + } + auto DedupToken2 = GetDedupTokenFromFile(LogFilePath); + if (!DedupToken2.empty()) + Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str()); + + if (DedupToken1 != DedupToken2) { + if (Flags.exact_artifact_path) { + CurrentFilePath = Flags.exact_artifact_path; + WriteToFile(U, CurrentFilePath); + } + Printf("CRASH_MIN: mismatch in dedup tokens" + " (looks like a different bug). Won't minimize further\n"); + break; + } + + CurrentFilePath = ArtifactPath; + Printf("*********************************\n"); + } + RemoveFile(LogFilePath); + return 0; +} + +int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { + assert(Inputs->size() == 1); + std::string InputFilePath = Inputs->at(0); + Unit U = FileToVector(InputFilePath); + Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); + if (U.size() < 2) { + Printf("INFO: The input is small enough, exiting\n"); + exit(0); + } + F->SetMaxInputLen(U.size()); + F->SetMaxMutationLen(U.size() - 1); + F->MinimizeCrashLoop(U); + Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); + exit(0); + return 0; +} + +int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, + UnitVector& Corpus) { + Printf("Started dictionary minimization (up to %d tests)\n", + Dict.size() * Corpus.size() * 2); + + // Scores and usage count for each dictionary unit. + std::vector Scores(Dict.size()); + std::vector Usages(Dict.size()); + + std::vector InitialFeatures; + std::vector ModifiedFeatures; + for (auto &C : Corpus) { + // Get coverage for the testcase without modifications. + F->ExecuteCallback(C.data(), C.size()); + InitialFeatures.clear(); + TPC.CollectFeatures([&](size_t Feature) -> bool { + InitialFeatures.push_back(Feature); + return true; + }); + + for (size_t i = 0; i < Dict.size(); ++i) { + auto Data = C; + auto StartPos = std::search(Data.begin(), Data.end(), + Dict[i].begin(), Dict[i].end()); + // Skip dictionary unit, if the testcase does not contain it. + if (StartPos == Data.end()) + continue; + + ++Usages[i]; + while (StartPos != Data.end()) { + // Replace all occurrences of dictionary unit in the testcase. + auto EndPos = StartPos + Dict[i].size(); + for (auto It = StartPos; It != EndPos; ++It) + *It ^= 0xFF; + + StartPos = std::search(EndPos, Data.end(), + Dict[i].begin(), Dict[i].end()); + } + + // Get coverage for testcase with masked occurrences of dictionary unit. + F->ExecuteCallback(Data.data(), Data.size()); + ModifiedFeatures.clear(); + TPC.CollectFeatures([&](size_t Feature) -> bool { + ModifiedFeatures.push_back(Feature); + return true; + }); + + if (InitialFeatures == ModifiedFeatures) + --Scores[i]; + else + Scores[i] += 2; + } + } + + Printf("###### Useless dictionary elements. ######\n"); + for (size_t i = 0; i < Dict.size(); ++i) { + // Dictionary units with positive score are treated as useful ones. + if (Scores[i] > 0) + continue; + + Printf("\""); + PrintASCII(Dict[i].data(), Dict[i].size(), "\""); + Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); + } + Printf("###### End of useless dictionary elements. ######\n"); + return 0; +} + +int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { + using namespace fuzzer; + assert(argc && argv && "Argument pointers cannot be nullptr"); + std::string Argv0((*argv)[0]); + EF = new ExternalFunctions(); + if (EF->LLVMFuzzerInitialize) + EF->LLVMFuzzerInitialize(argc, argv); + const std::vector Args(*argv, *argv + *argc); + assert(!Args.empty()); + ProgName = new std::string(Args[0]); + if (Argv0 != *ProgName) { + Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n"); + exit(1); + } + ParseFlags(Args); + if (Flags.help) { + PrintHelp(); + return 0; + } + + if (Flags.close_fd_mask & 2) + DupAndCloseStderr(); + if (Flags.close_fd_mask & 1) + CloseStdout(); + + if (Flags.jobs > 0 && Flags.workers == 0) { + Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); + if (Flags.workers > 1) + Printf("Running %u workers\n", Flags.workers); + } + + if (Flags.workers > 0 && Flags.jobs > 0) + return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); + + const size_t kMaxSaneLen = 1 << 20; + const size_t kMinDefaultLen = 4096; + FuzzingOptions Options; + Options.Verbosity = Flags.verbosity; + Options.MaxLen = Flags.max_len; + Options.ExperimentalLenControl = Flags.experimental_len_control; + Options.UnitTimeoutSec = Flags.timeout; + Options.ErrorExitCode = Flags.error_exitcode; + Options.TimeoutExitCode = Flags.timeout_exitcode; + Options.MaxTotalTimeSec = Flags.max_total_time; + Options.DoCrossOver = Flags.cross_over; + Options.MutateDepth = Flags.mutate_depth; + Options.UseCounters = Flags.use_counters; + Options.UseIndirCalls = Flags.use_indir_calls; + Options.UseMemmem = Flags.use_memmem; + Options.UseCmp = Flags.use_cmp; + Options.UseValueProfile = Flags.use_value_profile; + Options.Shrink = Flags.shrink; + Options.ReduceInputs = Flags.reduce_inputs; + Options.ShuffleAtStartUp = Flags.shuffle; + Options.PreferSmall = Flags.prefer_small; + Options.ReloadIntervalSec = Flags.reload; + Options.OnlyASCII = Flags.only_ascii; + Options.DetectLeaks = Flags.detect_leaks; + Options.TraceMalloc = Flags.trace_malloc; + Options.RssLimitMb = Flags.rss_limit_mb; + if (Flags.runs >= 0) + Options.MaxNumberOfRuns = Flags.runs; + if (!Inputs->empty() && !Flags.minimize_crash_internal_step) + Options.OutputCorpus = (*Inputs)[0]; + Options.ReportSlowUnits = Flags.report_slow_units; + if (Flags.artifact_prefix) + Options.ArtifactPrefix = Flags.artifact_prefix; + if (Flags.exact_artifact_path) + Options.ExactArtifactPath = Flags.exact_artifact_path; + std::vector Dictionary; + if (Flags.dict) + if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) + return 1; + if (Flags.verbosity > 0 && !Dictionary.empty()) + Printf("Dictionary: %zd entries\n", Dictionary.size()); + bool DoPlainRun = AllInputsAreFiles(); + Options.SaveArtifacts = + !DoPlainRun || Flags.minimize_crash_internal_step; + Options.PrintNewCovPcs = Flags.print_pcs; + Options.PrintFinalStats = Flags.print_final_stats; + Options.PrintCorpusStats = Flags.print_corpus_stats; + Options.PrintCoverage = Flags.print_coverage; + Options.DumpCoverage = Flags.dump_coverage; + if (Flags.exit_on_src_pos) + Options.ExitOnSrcPos = Flags.exit_on_src_pos; + if (Flags.exit_on_item) + Options.ExitOnItem = Flags.exit_on_item; + + unsigned Seed = Flags.seed; + // Initialize Seed. + if (Seed == 0) + Seed = + std::chrono::system_clock::now().time_since_epoch().count() + GetPid(); + if (Flags.verbosity) + Printf("INFO: Seed: %u\n", Seed); + + Random Rand(Seed); + auto *MD = new MutationDispatcher(Rand, Options); + auto *Corpus = new InputCorpus(Options.OutputCorpus); + auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); + + for (auto &U: Dictionary) + if (U.size() <= Word::GetMaxSize()) + MD->AddWordToManualDictionary(Word(U.data(), U.size())); + + StartRssThread(F, Flags.rss_limit_mb); + + Options.HandleAbrt = Flags.handle_abrt; + Options.HandleBus = Flags.handle_bus; + Options.HandleFpe = Flags.handle_fpe; + Options.HandleIll = Flags.handle_ill; + Options.HandleInt = Flags.handle_int; + Options.HandleSegv = Flags.handle_segv; + Options.HandleTerm = Flags.handle_term; + Options.HandleXfsz = Flags.handle_xfsz; + SetSignalHandler(Options); + + std::atexit(Fuzzer::StaticExitCallback); + + if (Flags.minimize_crash) + return MinimizeCrashInput(Args, Options); + + if (Flags.minimize_crash_internal_step) + return MinimizeCrashInputInternalStep(F, Corpus); + + if (Flags.cleanse_crash) + return CleanseCrashInput(Args, Options); + + if (auto Name = Flags.run_equivalence_server) { + SMR.Destroy(Name); + if (!SMR.Create(Name)) { + Printf("ERROR: can't create shared memory region\n"); + return 1; + } + Printf("INFO: EQUIVALENCE SERVER UP\n"); + while (true) { + SMR.WaitClient(); + size_t Size = SMR.ReadByteArraySize(); + SMR.WriteByteArray(nullptr, 0); + const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size); + F->ExecuteCallback(tmp.data(), tmp.size()); + SMR.PostServer(); + } + return 0; + } + + if (auto Name = Flags.use_equivalence_server) { + if (!SMR.Open(Name)) { + Printf("ERROR: can't open shared memory region\n"); + return 1; + } + Printf("INFO: EQUIVALENCE CLIENT UP\n"); + } + + if (DoPlainRun) { + Options.SaveArtifacts = false; + int Runs = std::max(1, Flags.runs); + Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), + Inputs->size(), Runs); + for (auto &Path : *Inputs) { + auto StartTime = system_clock::now(); + Printf("Running: %s\n", Path.c_str()); + for (int Iter = 0; Iter < Runs; Iter++) + RunOneTest(F, Path.c_str(), Options.MaxLen); + auto StopTime = system_clock::now(); + auto MS = duration_cast(StopTime - StartTime).count(); + Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); + } + Printf("***\n" + "*** NOTE: fuzzing was not performed, you have only\n" + "*** executed the target code on a fixed set of inputs.\n" + "***\n"); + F->PrintFinalStats(); + exit(0); + } + + if (Flags.merge) { + if (Options.MaxLen == 0) + F->SetMaxInputLen(kMaxSaneLen); + if (Flags.merge_control_file) + F->CrashResistantMergeInternalStep(Flags.merge_control_file); + else + F->CrashResistantMerge(Args, *Inputs, + Flags.load_coverage_summary, + Flags.save_coverage_summary); + exit(0); + } + + size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; + + UnitVector InitialCorpus; + for (auto &Inp : *Inputs) { + Printf("Loading corpus dir: %s\n", Inp.c_str()); + ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, + TemporaryMaxLen, /*ExitOnError=*/false); + } + + if (Flags.analyze_dict) { + if (Dictionary.empty() || Inputs->empty()) { + Printf("ERROR: can't analyze dict without dict and corpus provided\n"); + return 1; + } + if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { + Printf("Dictionary analysis failed\n"); + exit(1); + } + Printf("Dictionary analysis suceeded\n"); + exit(0); + } + + if (Options.MaxLen == 0) { + size_t MaxLen = 0; + for (auto &U : InitialCorpus) + MaxLen = std::max(U.size(), MaxLen); + F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); + } + + if (InitialCorpus.empty()) { + InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. + if (Options.Verbosity) + Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); + } + F->ShuffleAndMinimize(&InitialCorpus); + InitialCorpus.clear(); // Don't need this memory any more. + F->Loop(); + + if (Flags.verbosity) + Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), + F->secondsSinceProcessStartUp()); + F->PrintFinalStats(); + + exit(0); // Don't let F destroy itself. +} + +// Storage for global ExternalFunctions object. +ExternalFunctions *EF = nullptr; + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerExtFunctions.def b/lib/fuzzer/FuzzerExtFunctions.def new file mode 100644 index 000000000..3bc5302c3 --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctions.def @@ -0,0 +1,46 @@ +//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This defines the external function pointers that +// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The +// EXT_FUNC macro must be defined at the point of inclusion. The signature of +// the macro is: +// +// EXT_FUNC(, , , ) +//===----------------------------------------------------------------------===// + +// Optional user functions +EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); +EXT_FUNC(LLVMFuzzerCustomMutator, size_t, + (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed), + false); +EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, + (const uint8_t * Data1, size_t Size1, + const uint8_t * Data2, size_t Size2, + uint8_t * Out, size_t MaxOutSize, unsigned int Seed), + false); + +// Sanitizer functions +EXT_FUNC(__lsan_enable, void, (), false); +EXT_FUNC(__lsan_disable, void, (), false); +EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, + (void (*malloc_hook)(const volatile void *, size_t), + void (*free_hook)(const volatile void *)), + false); +EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false); +EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); +EXT_FUNC(__sanitizer_symbolize_pc, void, + (void *, const char *fmt, char *out_buf, size_t out_buf_size), false); +EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int, + (void *pc, char *module_path, + size_t module_path_len,void **pc_offset), false); +EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true); +EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); +EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t), + false); diff --git a/lib/fuzzer/FuzzerExtFunctions.h b/lib/fuzzer/FuzzerExtFunctions.h new file mode 100644 index 000000000..2672a3854 --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctions.h @@ -0,0 +1,35 @@ +//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Defines an interface to (possibly optional) functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H +#define LLVM_FUZZER_EXT_FUNCTIONS_H + +#include +#include + +namespace fuzzer { + +struct ExternalFunctions { + // Initialize function pointers. Functions that are not available will be set + // to nullptr. Do not call this constructor before ``main()`` has been + // entered. + ExternalFunctions(); + +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE(*NAME) FUNC_SIG = nullptr + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +}; +} // namespace fuzzer + +#endif diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp new file mode 100644 index 000000000..06bddd5de --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctionsDlsym.cpp @@ -0,0 +1,52 @@ +//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation for operating systems that support dlsym(). We only use it on +// Apple platforms for now. We don't use this approach on Linux because it +// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker. +// That is a complication we don't wish to expose to clients right now. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_APPLE + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include + +using namespace fuzzer; + +template +static T GetFnPtr(const char *FnName, bool WarnIfMissing) { + dlerror(); // Clear any previous errors. + void *Fn = dlsym(RTLD_DEFAULT, FnName); + if (Fn == nullptr) { + if (WarnIfMissing) { + const char *ErrorMsg = dlerror(); + Printf("WARNING: Failed to find function \"%s\".", FnName); + if (ErrorMsg) + Printf(" Reason %s.", ErrorMsg); + Printf("\n"); + } + } + return reinterpret_cast(Fn); +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr(#NAME, WARN) + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +} // namespace fuzzer + +#endif // LIBFUZZER_APPLE diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp new file mode 100644 index 000000000..321b3ec5d --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp @@ -0,0 +1,62 @@ +//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation using dynamic loading for Windows. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include "Windows.h" + +// This must be included after Windows.h. +#include "Psapi.h" + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { + HMODULE Modules[1024]; + DWORD BytesNeeded; + HANDLE CurrentProcess = GetCurrentProcess(); + + if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules), + &BytesNeeded)) { + Printf("EnumProcessModules failed (error: %d).\n", GetLastError()); + exit(1); + } + + if (sizeof(Modules) < BytesNeeded) { + Printf("Error: the array is not big enough to hold all loaded modules.\n"); + exit(1); + } + + for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++) + { + FARPROC Fn; +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + if (this->NAME == nullptr) { \ + Fn = GetProcAddress(Modules[i], #NAME); \ + if (Fn == nullptr) \ + Fn = GetProcAddress(Modules[i], #NAME "__dll"); \ + this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \ + } +#include "FuzzerExtFunctions.def" +#undef EXT_FUNC + } + +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + if (this->NAME == nullptr && WARN) \ + Printf("WARNING: Failed to find function \"%s\".\n", #NAME); +#include "FuzzerExtFunctions.def" +#undef EXT_FUNC +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp new file mode 100644 index 000000000..503f0395c --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp @@ -0,0 +1,54 @@ +//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation for Linux. This relies on the linker's support for weak +// symbols. We don't use this approach on Apple platforms because it requires +// clients of LibFuzzer to pass ``-U _`` to the linker to allow +// weak symbols to be undefined. That is a complication we don't want to expose +// to clients right now. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_LINUX + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" + +extern "C" { +// Declare these symbols as weak to allow them to be optionally defined. +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +using namespace fuzzer; + +static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) { + if (FnPtr == nullptr && WarnIfMissing) { + Printf("WARNING: Failed to find function \"%s\".\n", FnName); + } +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = ::NAME; \ + CheckFnPtr(reinterpret_cast(reinterpret_cast(::NAME)), \ + #NAME, WARN); + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +} // namespace fuzzer + +#endif // LIBFUZZER_LINUX diff --git a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp new file mode 100644 index 000000000..e10f7b4dc --- /dev/null +++ b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp @@ -0,0 +1,56 @@ +//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation using weak aliases. Works for Windows. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" + +using namespace fuzzer; + +extern "C" { +// Declare these symbols as weak to allow them to be optionally defined. +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + } \ + RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def"))); + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +template +static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) { + if (Fun == FunDef) { + if (WarnIfMissing) + Printf("WARNING: Failed to find function \"%s\".\n", FnName); + return nullptr; + } + return Fun; +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr(::NAME, ::NAME##Def, #NAME, WARN); + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerExtraCounters.cpp b/lib/fuzzer/FuzzerExtraCounters.cpp new file mode 100644 index 000000000..07dbe0fde --- /dev/null +++ b/lib/fuzzer/FuzzerExtraCounters.cpp @@ -0,0 +1,41 @@ +//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Extra coverage counters defined by user code. +//===----------------------------------------------------------------------===// + +#include "FuzzerDefs.h" + +#if LIBFUZZER_LINUX +__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters; +__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters; + +namespace fuzzer { +uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; } +uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; } +ATTRIBUTE_NO_SANITIZE_ALL +void ClearExtraCounters() { // hand-written memset, don't asan-ify. + uintptr_t *Beg = reinterpret_cast(ExtraCountersBegin()); + uintptr_t *End = reinterpret_cast(ExtraCountersEnd()); + for (; Beg < End; Beg++) { + *Beg = 0; + __asm__ __volatile__("" : : : "memory"); + } +} + +} // namespace fuzzer + +#else +// TODO: implement for other platforms. +namespace fuzzer { +uint8_t *ExtraCountersBegin() { return nullptr; } +uint8_t *ExtraCountersEnd() { return nullptr; } +void ClearExtraCounters() {} +} // namespace fuzzer + +#endif diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def new file mode 100644 index 000000000..2887fd24d --- /dev/null +++ b/lib/fuzzer/FuzzerFlags.def @@ -0,0 +1,139 @@ +//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the +// point of inclusion. We are not using any flag parsing library for better +// portability and independence. +//===----------------------------------------------------------------------===// +FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") +FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") +FUZZER_FLAG_INT(runs, -1, + "Number of individual test runs (-1 for infinite runs).") +FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " + "If 0, libFuzzer tries to guess a good value based on the corpus " + "and reports it. ") +FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag") +FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") +FUZZER_FLAG_INT(mutate_depth, 5, + "Apply this number of consecutive mutations to each input.") +FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") +FUZZER_FLAG_INT(prefer_small, 1, + "If 1, always prefer smaller inputs during the corpus shuffle.") +FUZZER_FLAG_INT( + timeout, 1200, + "Timeout in seconds (if positive). " + "If one unit runs more than this number of seconds the process will abort.") +FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug " + "this exit code will be used.") +FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout " + "this exit code will be used.") +FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " + "time in seconds to run the fuzzer.") +FUZZER_FLAG_INT(help, 0, "Print help.") +FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " + "merged into the 1-st corpus. Only interesting units will be taken. " + "This flag can be used to minimize a corpus.") +FUZZER_FLAG_STRING(merge_control_file, "internal flag") +FUZZER_FLAG_STRING(save_coverage_summary, "Experimental:" + " save coverage summary to a given file." + " Used with -merge=1") +FUZZER_FLAG_STRING(load_coverage_summary, "Experimental:" + " load coverage summary from a given file." + " Treat this coverage as belonging to the first corpus. " + " Used with -merge=1") +FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided" + " crash input. Use with -runs=N or -max_total_time=N to limit " + "the number attempts." + " Use with -exact_artifact_path to specify the output." + " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that" + " the minimized input triggers the same crash." + ) +FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided" + " crash input to make it contain fewer original bytes." + " Use with -exact_artifact_path to specify the output." + ) +FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag") +FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") +FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") +FUZZER_FLAG_INT(use_memmem, 1, + "Use hints from intercepting memmem, strstr, etc") +FUZZER_FLAG_INT(use_value_profile, 0, + "Experimental. Use value profile to guide fuzzing.") +FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations") +FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.") +FUZZER_FLAG_INT(reduce_inputs, 1, + "Try to reduce the size of inputs while preserving their full feature sets") +FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" + " this number of jobs in separate worker processes" + " with stdout/stderr redirected to fuzz-JOB.log.") +FUZZER_FLAG_UNSIGNED(workers, 0, + "Number of simultaneous worker processes to run the jobs." + " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") +FUZZER_FLAG_INT(reload, 1, + "Reload the main corpus every seconds to get new units" + " discovered by other processes. If 0, disabled") +FUZZER_FLAG_INT(report_slow_units, 10, + "Report slowest units if they run for more than this number of seconds.") +FUZZER_FLAG_INT(only_ascii, 0, + "If 1, generate only ASCII (isprint+isspace) inputs.") +FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") +FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " + "timeout, or slow inputs) as " + "$(artifact_prefix)file") +FUZZER_FLAG_STRING(exact_artifact_path, + "Write the single artifact on failure (crash, timeout) " + "as $(exact_artifact_path). This overrides -artifact_prefix " + "and will not use checksum in the file name. Do not " + "use the same path for several parallel processes.") +FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") +FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") +FUZZER_FLAG_INT(print_corpus_stats, 0, + "If 1, print statistics on corpus elements at exit.") +FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" + " at exit.") +FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a" + " .sancov file at exit.") +FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") +FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") +FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") +FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.") +FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") +FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") +FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") +FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.") +FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " + "if 2, close stderr; if 3, close both. " + "Be careful, this will also close e.g. asan's stderr/stdout.") +FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " + "try to detect memory leaks during fuzzing (i.e. not only at shut down).") +FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " + "If >= 2 will also print stack traces.") +FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" + "reaching this limit of RSS memory usage.") +FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates" + " from the given source location. Example: -exit_on_src_pos=foo.cc:123. " + "Used primarily for testing libFuzzer itself.") +FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" + " was added to the corpus. " + "Used primarily for testing libFuzzer itself.") +FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " + "after this one. Useful for fuzzers that need to do their own " + "argument parsing.") + +FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") +FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") +FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") + +FUZZER_DEPRECATED_FLAG(exit_on_first) +FUZZER_DEPRECATED_FLAG(save_minimized_corpus) +FUZZER_DEPRECATED_FLAG(sync_command) +FUZZER_DEPRECATED_FLAG(sync_timeout) +FUZZER_DEPRECATED_FLAG(test_single_input) +FUZZER_DEPRECATED_FLAG(drill) +FUZZER_DEPRECATED_FLAG(truncate_units) +FUZZER_DEPRECATED_FLAG(output_csv) diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp new file mode 100644 index 000000000..1a06d4420 --- /dev/null +++ b/lib/fuzzer/FuzzerIO.cpp @@ -0,0 +1,120 @@ +//===- FuzzerIO.cpp - IO utils. -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// IO functions. +//===----------------------------------------------------------------------===// + +#include "FuzzerIO.h" +#include "FuzzerDefs.h" +#include "FuzzerExtFunctions.h" +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +static FILE *OutputFile = stderr; + +long GetEpoch(const std::string &Path) { + struct stat St; + if (stat(Path.c_str(), &St)) + return 0; // Can't stat, be conservative. + return St.st_mtime; +} + +Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { + std::ifstream T(Path); + if (ExitOnError && !T) { + Printf("No such directory: %s; exiting\n", Path.c_str()); + exit(1); + } + + T.seekg(0, T.end); + auto EndPos = T.tellg(); + if (EndPos < 0) return {}; + size_t FileLen = EndPos; + if (MaxSize) + FileLen = std::min(FileLen, MaxSize); + + T.seekg(0, T.beg); + Unit Res(FileLen); + T.read(reinterpret_cast(Res.data()), FileLen); + return Res; +} + +std::string FileToString(const std::string &Path) { + std::ifstream T(Path); + return std::string((std::istreambuf_iterator(T)), + std::istreambuf_iterator()); +} + +void CopyFileToErr(const std::string &Path) { + Printf("%s", FileToString(Path).c_str()); +} + +void WriteToFile(const Unit &U, const std::string &Path) { + // Use raw C interface because this function may be called from a sig handler. + FILE *Out = fopen(Path.c_str(), "w"); + if (!Out) return; + fwrite(U.data(), sizeof(U[0]), U.size(), Out); + fclose(Out); +} + +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, + long *Epoch, size_t MaxSize, bool ExitOnError) { + long E = Epoch ? *Epoch : 0; + std::vector Files; + ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); + size_t NumLoaded = 0; + for (size_t i = 0; i < Files.size(); i++) { + auto &X = Files[i]; + if (Epoch && GetEpoch(X) < E) continue; + NumLoaded++; + if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) + Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); + auto S = FileToVector(X, MaxSize, ExitOnError); + if (!S.empty()) + V->push_back(S); + } +} + +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName) { + return DirPath + GetSeparator() + FileName; +} + +void DupAndCloseStderr() { + int OutputFd = DuplicateFile(2); + if (OutputFd > 0) { + FILE *NewOutputFile = OpenFile(OutputFd, "w"); + if (NewOutputFile) { + OutputFile = NewOutputFile; + if (EF->__sanitizer_set_report_fd) + EF->__sanitizer_set_report_fd( + reinterpret_cast(GetHandleFromFd(OutputFd))); + DiscardOutput(2); + } + } +} + +void CloseStdout() { + DiscardOutput(1); +} + +void Printf(const char *Fmt, ...) { + va_list ap; + va_start(ap, Fmt); + vfprintf(OutputFile, Fmt, ap); + va_end(ap); + fflush(OutputFile); +} + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h new file mode 100644 index 000000000..3b66a52d1 --- /dev/null +++ b/lib/fuzzer/FuzzerIO.h @@ -0,0 +1,76 @@ +//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// IO interface. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_IO_H +#define LLVM_FUZZER_IO_H + +#include "FuzzerDefs.h" + +namespace fuzzer { + +long GetEpoch(const std::string &Path); + +Unit FileToVector(const std::string &Path, size_t MaxSize = 0, + bool ExitOnError = true); + +std::string FileToString(const std::string &Path); + +void CopyFileToErr(const std::string &Path); + +void WriteToFile(const Unit &U, const std::string &Path); + +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, + long *Epoch, size_t MaxSize, bool ExitOnError); + +// Returns "Dir/FileName" or equivalent for the current OS. +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName); + +// Returns the name of the dir, similar to the 'dirname' utility. +std::string DirName(const std::string &FileName); + +// Returns path to a TmpDir. +std::string TmpDir(); + +bool IsInterestingCoverageFile(const std::string &FileName); + +void DupAndCloseStderr(); + +void CloseStdout(); + +void Printf(const char *Fmt, ...); + +// Print using raw syscalls, useful when printing at early init stages. +void RawPrint(const char *Str); + +// Platform specific functions: +bool IsFile(const std::string &Path); + +void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, + std::vector *V, bool TopDir); + +char GetSeparator(); + +FILE* OpenFile(int Fd, const char *Mode); + +int CloseFile(int Fd); + +int DuplicateFile(int Fd); + +void RemoveFile(const std::string &Path); + +void DiscardOutput(int Fd); + +intptr_t GetHandleFromFd(int fd); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_IO_H diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp new file mode 100644 index 000000000..c5ebdbac4 --- /dev/null +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -0,0 +1,123 @@ +//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// IO functions implementation using Posix API. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_POSIX + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +bool IsFile(const std::string &Path) { + struct stat St; + if (stat(Path.c_str(), &St)) + return false; + return S_ISREG(St.st_mode); +} + +void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, + std::vector *V, bool TopDir) { + auto E = GetEpoch(Dir); + if (Epoch) + if (E && *Epoch >= E) return; + + DIR *D = opendir(Dir.c_str()); + if (!D) { + Printf("No such directory: %s; exiting\n", Dir.c_str()); + exit(1); + } + while (auto E = readdir(D)) { + std::string Path = DirPlusFile(Dir, E->d_name); + if (E->d_type == DT_REG || E->d_type == DT_LNK) + V->push_back(Path); + else if (E->d_type == DT_DIR && *E->d_name != '.') + ListFilesInDirRecursive(Path, Epoch, V, false); + } + closedir(D); + if (Epoch && TopDir) + *Epoch = E; +} + +char GetSeparator() { + return '/'; +} + +FILE* OpenFile(int Fd, const char* Mode) { + return fdopen(Fd, Mode); +} + +int CloseFile(int fd) { + return close(fd); +} + +int DuplicateFile(int Fd) { + return dup(Fd); +} + +void RemoveFile(const std::string &Path) { + unlink(Path.c_str()); +} + +void DiscardOutput(int Fd) { + FILE* Temp = fopen("/dev/null", "w"); + if (!Temp) + return; + dup2(fileno(Temp), Fd); + fclose(Temp); +} + +intptr_t GetHandleFromFd(int fd) { + return static_cast(fd); +} + +std::string DirName(const std::string &FileName) { + char *Tmp = new char[FileName.size() + 1]; + memcpy(Tmp, FileName.c_str(), FileName.size() + 1); + std::string Res = dirname(Tmp); + delete [] Tmp; + return Res; +} + +std::string TmpDir() { + if (auto Env = getenv("TMPDIR")) + return Env; + return "/tmp"; +} + +bool IsInterestingCoverageFile(const std::string &FileName) { + if (FileName.find("compiler-rt/lib/") != std::string::npos) + return false; // sanitizer internal. + if (FileName.find("/usr/lib/") != std::string::npos) + return false; + if (FileName.find("/usr/include/") != std::string::npos) + return false; + if (FileName == "") + return false; + return true; +} + + +void RawPrint(const char *Str) { + write(2, Str, strlen(Str)); +} + +} // namespace fuzzer + +#endif // LIBFUZZER_POSIX diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp new file mode 100644 index 000000000..742520267 --- /dev/null +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -0,0 +1,323 @@ +//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// IO functions implementation for Windows. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS + +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +static bool IsFile(const std::string &Path, const DWORD &FileAttributes) { + + if (FileAttributes & FILE_ATTRIBUTE_NORMAL) + return true; + + if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return false; + + HANDLE FileHandle( + CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, 0)); + + if (FileHandle == INVALID_HANDLE_VALUE) { + Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(), + GetLastError()); + return false; + } + + DWORD FileType = GetFileType(FileHandle); + + if (FileType == FILE_TYPE_UNKNOWN) { + Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(), + GetLastError()); + CloseHandle(FileHandle); + return false; + } + + if (FileType != FILE_TYPE_DISK) { + CloseHandle(FileHandle); + return false; + } + + CloseHandle(FileHandle); + return true; +} + +bool IsFile(const std::string &Path) { + DWORD Att = GetFileAttributesA(Path.c_str()); + + if (Att == INVALID_FILE_ATTRIBUTES) { + Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n", + Path.c_str(), GetLastError()); + return false; + } + + return IsFile(Path, Att); +} + +void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, + std::vector *V, bool TopDir) { + auto E = GetEpoch(Dir); + if (Epoch) + if (E && *Epoch >= E) return; + + std::string Path(Dir); + assert(!Path.empty()); + if (Path.back() != '\\') + Path.push_back('\\'); + Path.push_back('*'); + + // Get the first directory entry. + WIN32_FIND_DATAA FindInfo; + HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo)); + if (FindHandle == INVALID_HANDLE_VALUE) + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return; + Printf("No such directory: %s; exiting\n", Dir.c_str()); + exit(1); + } + + do { + std::string FileName = DirPlusFile(Dir, FindInfo.cFileName); + + if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + size_t FilenameLen = strlen(FindInfo.cFileName); + if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') || + (FilenameLen == 2 && FindInfo.cFileName[0] == '.' && + FindInfo.cFileName[1] == '.')) + continue; + + ListFilesInDirRecursive(FileName, Epoch, V, false); + } + else if (IsFile(FileName, FindInfo.dwFileAttributes)) + V->push_back(FileName); + } while (FindNextFileA(FindHandle, &FindInfo)); + + DWORD LastError = GetLastError(); + if (LastError != ERROR_NO_MORE_FILES) + Printf("FindNextFileA failed (Error code: %lu).\n", LastError); + + FindClose(FindHandle); + + if (Epoch && TopDir) + *Epoch = E; +} + +char GetSeparator() { + return '\\'; +} + +FILE* OpenFile(int Fd, const char* Mode) { + return _fdopen(Fd, Mode); +} + +int CloseFile(int Fd) { + return _close(Fd); +} + +int DuplicateFile(int Fd) { + return _dup(Fd); +} + +void RemoveFile(const std::string &Path) { + _unlink(Path.c_str()); +} + +void DiscardOutput(int Fd) { + FILE* Temp = fopen("nul", "w"); + if (!Temp) + return; + _dup2(_fileno(Temp), Fd); + fclose(Temp); +} + +intptr_t GetHandleFromFd(int fd) { + return _get_osfhandle(fd); +} + +static bool IsSeparator(char C) { + return C == '\\' || C == '/'; +} + +// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:". +// Returns number of characters considered if successful. +static size_t ParseDrive(const std::string &FileName, const size_t Offset, + bool Relative = true) { + if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':') + return 0; + if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) { + if (!Relative) // Accept relative path? + return 0; + else + return 2; + } + return 3; +} + +// Parse a file name, like: SomeFile.txt +// Returns number of characters considered if successful. +static size_t ParseFileName(const std::string &FileName, const size_t Offset) { + size_t Pos = Offset; + const size_t End = FileName.size(); + for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos) + ; + return Pos - Offset; +} + +// Parse a directory ending in separator, like: `SomeDir\` +// Returns number of characters considered if successful. +static size_t ParseDir(const std::string &FileName, const size_t Offset) { + size_t Pos = Offset; + const size_t End = FileName.size(); + if (Pos >= End || IsSeparator(FileName[Pos])) + return 0; + for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos) + ; + if (Pos >= End) + return 0; + ++Pos; // Include separator. + return Pos - Offset; +} + +// Parse a servername and share, like: `SomeServer\SomeShare\` +// Returns number of characters considered if successful. +static size_t ParseServerAndShare(const std::string &FileName, + const size_t Offset) { + size_t Pos = Offset, Res; + if (!(Res = ParseDir(FileName, Pos))) + return 0; + Pos += Res; + if (!(Res = ParseDir(FileName, Pos))) + return 0; + Pos += Res; + return Pos - Offset; +} + +// Parse the given Ref string from the position Offset, to exactly match the given +// string Patt. +// Returns number of characters considered if successful. +static size_t ParseCustomString(const std::string &Ref, size_t Offset, + const char *Patt) { + size_t Len = strlen(Patt); + if (Offset + Len > Ref.size()) + return 0; + return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0; +} + +// Parse a location, like: +// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C: +// Returns number of characters considered if successful. +static size_t ParseLocation(const std::string &FileName) { + size_t Pos = 0, Res; + + if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) { + Pos += Res; + if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) { + Pos += Res; + if ((Res = ParseServerAndShare(FileName, Pos))) + return Pos + Res; + return 0; + } + if ((Res = ParseDrive(FileName, Pos, false))) + return Pos + Res; + return 0; + } + + if (Pos < FileName.size() && IsSeparator(FileName[Pos])) { + ++Pos; + if (Pos < FileName.size() && IsSeparator(FileName[Pos])) { + ++Pos; + if ((Res = ParseServerAndShare(FileName, Pos))) + return Pos + Res; + return 0; + } + return Pos; + } + + if ((Res = ParseDrive(FileName, Pos))) + return Pos + Res; + + return Pos; +} + +std::string DirName(const std::string &FileName) { + size_t LocationLen = ParseLocation(FileName); + size_t DirLen = 0, Res; + while ((Res = ParseDir(FileName, LocationLen + DirLen))) + DirLen += Res; + size_t FileLen = ParseFileName(FileName, LocationLen + DirLen); + + if (LocationLen + DirLen + FileLen != FileName.size()) { + Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str()); + exit(1); + } + + if (DirLen) { + --DirLen; // Remove trailing separator. + if (!FileLen) { // Path ended in separator. + assert(DirLen); + // Remove file name from Dir. + while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1])) + --DirLen; + if (DirLen) // Remove trailing separator. + --DirLen; + } + } + + if (!LocationLen) { // Relative path. + if (!DirLen) + return "."; + return std::string(".\\").append(FileName, 0, DirLen); + } + + return FileName.substr(0, LocationLen + DirLen); +} + +std::string TmpDir() { + std::string Tmp; + Tmp.resize(MAX_PATH + 1); + DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]); + if (Size == 0) { + Printf("Couldn't get Tmp path.\n"); + exit(1); + } + Tmp.resize(Size); + return Tmp; +} + +bool IsInterestingCoverageFile(const std::string &FileName) { + if (FileName.find("Program Files") != std::string::npos) + return false; + if (FileName.find("compiler-rt\\lib\\") != std::string::npos) + return false; // sanitizer internal. + if (FileName == "") + return false; + return true; +} + +void RawPrint(const char *Str) { + // Not tested, may or may not work. Fix if needed. + Printf("%s", Str); +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerInterface.h b/lib/fuzzer/FuzzerInterface.h new file mode 100644 index 000000000..c2c0a3984 --- /dev/null +++ b/lib/fuzzer/FuzzerInterface.h @@ -0,0 +1,67 @@ +//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Define the interface between libFuzzer and the library being tested. +//===----------------------------------------------------------------------===// + +// NOTE: the libFuzzer interface is thin and in the majority of cases +// you should not include this file into your target. In 95% of cases +// all you need is to define the following function in your file: +// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +// WARNING: keep the interface in C. + +#ifndef LLVM_FUZZER_INTERFACE_H +#define LLVM_FUZZER_INTERFACE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Mandatory user-provided target function. +// Executes the code under test with [Data, Data+Size) as the input. +// libFuzzer will invoke this function *many* times with different inputs. +// Must return 0. +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +// Optional user-provided initialization function. +// If provided, this function will be called by libFuzzer once at startup. +// It may read and modify argc/argv. +// Must return 0. +int LLVMFuzzerInitialize(int *argc, char ***argv); + +// Optional user-provided custom mutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +// Given the same Seed produces the same mutation. +size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, + unsigned int Seed); + +// Optional user-provided custom cross-over function. +// Combines pieces of Data1 & Data2 together into Out. +// Returns the new size, which is not greater than MaxOutSize. +// Should produce the same mutation given the same Seed. +size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed); + +// Experimental, may go away in future. +// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. +// Mutates raw data in [Data, Data+Size) inplace. +// Returns the new size, which is not greater than MaxSize. +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // LLVM_FUZZER_INTERFACE_H diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h new file mode 100644 index 000000000..1d68c0190 --- /dev/null +++ b/lib/fuzzer/FuzzerInternal.h @@ -0,0 +1,150 @@ +//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Define the main class fuzzer::Fuzzer and most functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_INTERNAL_H +#define LLVM_FUZZER_INTERNAL_H + +#include "FuzzerDefs.h" +#include "FuzzerExtFunctions.h" +#include "FuzzerInterface.h" +#include "FuzzerOptions.h" +#include "FuzzerSHA1.h" +#include "FuzzerValueBitMap.h" +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +using namespace std::chrono; + +class Fuzzer { +public: + + Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, + FuzzingOptions Options); + ~Fuzzer(); + void Loop(); + void MinimizeCrashLoop(const Unit &U); + void ShuffleAndMinimize(UnitVector *V); + void RereadOutputCorpus(size_t MaxSize); + + size_t secondsSinceProcessStartUp() { + return duration_cast(system_clock::now() - ProcessStartTime) + .count(); + } + + bool TimedOut() { + return Options.MaxTotalTimeSec > 0 && + secondsSinceProcessStartUp() > + static_cast(Options.MaxTotalTimeSec); + } + + size_t execPerSec() { + size_t Seconds = secondsSinceProcessStartUp(); + return Seconds ? TotalNumberOfRuns / Seconds : 0; + } + + size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; } + + static void StaticAlarmCallback(); + static void StaticCrashSignalCallback(); + static void StaticExitCallback(); + static void StaticInterruptCallback(); + static void StaticFileSizeExceedCallback(); + + void ExecuteCallback(const uint8_t *Data, size_t Size); + bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, + InputInfo *II = nullptr); + + // Merge Corpora[1:] into Corpora[0]. + void Merge(const std::vector &Corpora); + void CrashResistantMerge(const std::vector &Args, + const std::vector &Corpora, + const char *CoverageSummaryInputPathOrNull, + const char *CoverageSummaryOutputPathOrNull); + void CrashResistantMergeInternalStep(const std::string &ControlFilePath); + MutationDispatcher &GetMD() { return MD; } + void PrintFinalStats(); + void SetMaxInputLen(size_t MaxInputLen); + void SetMaxMutationLen(size_t MaxMutationLen); + void RssLimitCallback(); + + bool InFuzzingThread() const { return IsMyThread; } + size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; + void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, + bool DuringInitialCorpusExecution); + + void HandleMalloc(size_t Size); + void AnnounceOutput(const uint8_t *Data, size_t Size); + +private: + void AlarmCallback(); + void CrashCallback(); + void ExitCallback(); + void CrashOnOverwrittenData(); + void InterruptCallback(); + void MutateAndTestOne(); + void ReportNewCoverage(InputInfo *II, const Unit &U); + void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size); + void WriteToOutputCorpus(const Unit &U); + void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); + void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); + void PrintStatusForNewUnit(const Unit &U, const char *Text); + void ShuffleCorpus(UnitVector *V); + void CheckExitOnSrcPosOrItem(); + + static void StaticDeathCallback(); + void DumpCurrentUnit(const char *Prefix); + void DeathCallback(); + + void AllocateCurrentUnitData(); + uint8_t *CurrentUnitData = nullptr; + std::atomic CurrentUnitSize; + uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. + bool RunningCB = false; + + size_t TotalNumberOfRuns = 0; + size_t NumberOfNewUnitsAdded = 0; + + size_t LastCorpusUpdateRun = 0; + system_clock::time_point LastCorpusUpdateTime = system_clock::now(); + + + bool HasMoreMallocsThanFrees = false; + size_t NumberOfLeakDetectionAttempts = 0; + + UserCallback CB; + InputCorpus &Corpus; + MutationDispatcher &MD; + FuzzingOptions Options; + + system_clock::time_point ProcessStartTime = system_clock::now(); + system_clock::time_point UnitStartTime, UnitStopTime; + long TimeOfLongestUnitInSeconds = 0; + long EpochOfLastReadOfOutputCorpus = 0; + + size_t MaxInputLen = 0; + size_t MaxMutationLen = 0; + size_t TmpMaxMutationLen = 0; + + std::vector UniqFeatureSetTmp; + + // Need to know our own thread. + static thread_local bool IsMyThread; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_INTERNAL_H diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp new file mode 100644 index 000000000..2064783f3 --- /dev/null +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -0,0 +1,721 @@ +//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Fuzzer's main loop. +//===----------------------------------------------------------------------===// + +#include "FuzzerCorpus.h" +#include "FuzzerIO.h" +#include "FuzzerInternal.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" +#include "FuzzerShmem.h" +#include "FuzzerTracePC.h" +#include +#include +#include +#include + +#if defined(__has_include) +#if __has_include() +#include +#endif +#endif + +#define NO_SANITIZE_MEMORY +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#undef NO_SANITIZE_MEMORY +#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) +#endif +#endif + +namespace fuzzer { +static const size_t kMaxUnitSizeToPrint = 256; + +thread_local bool Fuzzer::IsMyThread; + +SharedMemoryRegion SMR; + +// Only one Fuzzer per process. +static Fuzzer *F; + +// Leak detection is expensive, so we first check if there were more mallocs +// than frees (using the sanitizer malloc hooks) and only then try to call lsan. +struct MallocFreeTracer { + void Start(int TraceLevel) { + this->TraceLevel = TraceLevel; + if (TraceLevel) + Printf("MallocFreeTracer: START\n"); + Mallocs = 0; + Frees = 0; + } + // Returns true if there were more mallocs than frees. + bool Stop() { + if (TraceLevel) + Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), + Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); + bool Result = Mallocs > Frees; + Mallocs = 0; + Frees = 0; + TraceLevel = 0; + return Result; + } + std::atomic Mallocs; + std::atomic Frees; + int TraceLevel = 0; +}; + +static MallocFreeTracer AllocTracer; + +ATTRIBUTE_NO_SANITIZE_MEMORY +void MallocHook(const volatile void *ptr, size_t size) { + size_t N = AllocTracer.Mallocs++; + F->HandleMalloc(size); + if (int TraceLevel = AllocTracer.TraceLevel) { + Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); + if (TraceLevel >= 2 && EF) + EF->__sanitizer_print_stack_trace(); + } +} + +ATTRIBUTE_NO_SANITIZE_MEMORY +void FreeHook(const volatile void *ptr) { + size_t N = AllocTracer.Frees++; + if (int TraceLevel = AllocTracer.TraceLevel) { + Printf("FREE[%zd] %p\n", N, ptr); + if (TraceLevel >= 2 && EF) + EF->__sanitizer_print_stack_trace(); + } +} + +// Crash on a single malloc that exceeds the rss limit. +void Fuzzer::HandleMalloc(size_t Size) { + if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb) + return; + Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), + Size); + Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); + DumpCurrentUnit("oom-"); + Printf("SUMMARY: libFuzzer: out-of-memory\n"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); // Stop right now. +} + +Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, + FuzzingOptions Options) + : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { + if (EF->__sanitizer_set_death_callback) + EF->__sanitizer_set_death_callback(StaticDeathCallback); + assert(!F); + F = this; + TPC.ResetMaps(); + IsMyThread = true; + if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) + EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); + TPC.SetUseCounters(Options.UseCounters); + TPC.SetUseValueProfile(Options.UseValueProfile); + + if (Options.Verbosity) + TPC.PrintModuleInfo(); + if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) + EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); + MaxInputLen = MaxMutationLen = Options.MaxLen; + TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); + AllocateCurrentUnitData(); + CurrentUnitSize = 0; + memset(BaseSha1, 0, sizeof(BaseSha1)); +} + +Fuzzer::~Fuzzer() { } + +void Fuzzer::AllocateCurrentUnitData() { + if (CurrentUnitData || MaxInputLen == 0) return; + CurrentUnitData = new uint8_t[MaxInputLen]; +} + +void Fuzzer::StaticDeathCallback() { + assert(F); + F->DeathCallback(); +} + +void Fuzzer::DumpCurrentUnit(const char *Prefix) { + if (!CurrentUnitData) return; // Happens when running individual inputs. + MD.PrintMutationSequence(); + Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); + size_t UnitSize = CurrentUnitSize; + if (UnitSize <= kMaxUnitSizeToPrint) { + PrintHexArray(CurrentUnitData, UnitSize, "\n"); + PrintASCII(CurrentUnitData, UnitSize, "\n"); + } + WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, + Prefix); +} + +NO_SANITIZE_MEMORY +void Fuzzer::DeathCallback() { + DumpCurrentUnit("crash-"); + PrintFinalStats(); +} + +void Fuzzer::StaticAlarmCallback() { + assert(F); + F->AlarmCallback(); +} + +void Fuzzer::StaticCrashSignalCallback() { + assert(F); + F->CrashCallback(); +} + +void Fuzzer::StaticExitCallback() { + assert(F); + F->ExitCallback(); +} + +void Fuzzer::StaticInterruptCallback() { + assert(F); + F->InterruptCallback(); +} + +void Fuzzer::StaticFileSizeExceedCallback() { + Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); + exit(1); +} + +void Fuzzer::CrashCallback() { + Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); + Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" + " Combine libFuzzer with AddressSanitizer or similar for better " + "crash reports.\n"); + Printf("SUMMARY: libFuzzer: deadly signal\n"); + DumpCurrentUnit("crash-"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); // Stop right now. +} + +void Fuzzer::ExitCallback() { + if (!RunningCB) + return; // This exit did not come from the user callback + Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); + Printf("SUMMARY: libFuzzer: fuzz target exited\n"); + DumpCurrentUnit("crash-"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); +} + + +void Fuzzer::InterruptCallback() { + Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); + PrintFinalStats(); + _Exit(0); // Stop right now, don't perform any at-exit actions. +} + +NO_SANITIZE_MEMORY +void Fuzzer::AlarmCallback() { + assert(Options.UnitTimeoutSec > 0); + // In Windows Alarm callback is executed by a different thread. +#if !LIBFUZZER_WINDOWS + if (!InFuzzingThread()) return; +#endif + if (!RunningCB) + return; // We have not started running units yet. + size_t Seconds = + duration_cast(system_clock::now() - UnitStartTime).count(); + if (Seconds == 0) + return; + if (Options.Verbosity >= 2) + Printf("AlarmCallback %zd\n", Seconds); + if (Seconds >= (size_t)Options.UnitTimeoutSec) { + Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); + Printf(" and the timeout value is %d (use -timeout=N to change)\n", + Options.UnitTimeoutSec); + DumpCurrentUnit("timeout-"); + Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), + Seconds); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); + Printf("SUMMARY: libFuzzer: timeout\n"); + PrintFinalStats(); + _Exit(Options.TimeoutExitCode); // Stop right now. + } +} + +void Fuzzer::RssLimitCallback() { + Printf( + "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", + GetPid(), GetPeakRSSMb(), Options.RssLimitMb); + Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); + if (EF->__sanitizer_print_memory_profile) + EF->__sanitizer_print_memory_profile(95, 8); + DumpCurrentUnit("oom-"); + Printf("SUMMARY: libFuzzer: out-of-memory\n"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); // Stop right now. +} + +void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { + size_t ExecPerSec = execPerSec(); + if (!Options.Verbosity) + return; + Printf("#%zd\t%s", TotalNumberOfRuns, Where); + if (size_t N = TPC.GetTotalPCCoverage()) + Printf(" cov: %zd", N); + if (size_t N = Corpus.NumFeatures()) + Printf( " ft: %zd", N); + if (!Corpus.empty()) { + Printf(" corp: %zd", Corpus.NumActiveUnits()); + if (size_t N = Corpus.SizeInBytes()) { + if (N < (1<<14)) + Printf("/%zdb", N); + else if (N < (1 << 24)) + Printf("/%zdKb", N >> 10); + else + Printf("/%zdMb", N >> 20); + } + } + if (Units) + Printf(" units: %zd", Units); + + Printf(" exec/s: %zd", ExecPerSec); + Printf(" rss: %zdMb", GetPeakRSSMb()); + Printf("%s", End); +} + +void Fuzzer::PrintFinalStats() { + if (Options.PrintCoverage) + TPC.PrintCoverage(); + if (Options.DumpCoverage) + TPC.DumpCoverage(); + if (Options.PrintCorpusStats) + Corpus.PrintStats(); + if (!Options.PrintFinalStats) return; + size_t ExecPerSec = execPerSec(); + Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); + Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); + Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); + Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); + Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); +} + +void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { + assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. + assert(MaxInputLen); + this->MaxInputLen = MaxInputLen; + this->MaxMutationLen = MaxInputLen; + AllocateCurrentUnitData(); + Printf("INFO: -max_len is not provided; " + "libFuzzer will not generate inputs larger than %zd bytes\n", + MaxInputLen); +} + +void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { + assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); + this->MaxMutationLen = MaxMutationLen; +} + +void Fuzzer::CheckExitOnSrcPosOrItem() { + if (!Options.ExitOnSrcPos.empty()) { + static auto *PCsSet = new std::set; + auto HandlePC = [&](uintptr_t PC) { + if (!PCsSet->insert(PC).second) return; + std::string Descr = DescribePC("%F %L", PC + 1); + if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { + Printf("INFO: found line matching '%s', exiting.\n", + Options.ExitOnSrcPos.c_str()); + _Exit(0); + } + }; + TPC.ForEachObservedPC(HandlePC); + } + if (!Options.ExitOnItem.empty()) { + if (Corpus.HasUnit(Options.ExitOnItem)) { + Printf("INFO: found item with checksum '%s', exiting.\n", + Options.ExitOnItem.c_str()); + _Exit(0); + } + } +} + +void Fuzzer::RereadOutputCorpus(size_t MaxSize) { + if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; + std::vector AdditionalCorpus; + ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, + &EpochOfLastReadOfOutputCorpus, MaxSize, + /*ExitOnError*/ false); + if (Options.Verbosity >= 2) + Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); + bool Reloaded = false; + for (auto &U : AdditionalCorpus) { + if (U.size() > MaxSize) + U.resize(MaxSize); + if (!Corpus.HasUnit(U)) { + if (RunOne(U.data(), U.size())) { + CheckExitOnSrcPosOrItem(); + Reloaded = true; + } + } + } + if (Reloaded) + PrintStats("RELOAD"); +} + +void Fuzzer::ShuffleCorpus(UnitVector *V) { + std::shuffle(V->begin(), V->end(), MD.GetRand()); + if (Options.PreferSmall) + std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) { + return A.size() < B.size(); + }); +} + +void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { + Printf("#0\tREAD units: %zd\n", InitialCorpus->size()); + if (Options.ShuffleAtStartUp) + ShuffleCorpus(InitialCorpus); + + // Test the callback with empty input and never try it again. + uint8_t dummy; + ExecuteCallback(&dummy, 0); + + for (const auto &U : *InitialCorpus) { + RunOne(U.data(), U.size()); + CheckExitOnSrcPosOrItem(); + TryDetectingAMemoryLeak(U.data(), U.size(), + /*DuringInitialCorpusExecution*/ true); + } + PrintStats("INITED"); + if (Corpus.empty()) { + Printf("ERROR: no interesting inputs were found. " + "Is the code instrumented for coverage? Exiting.\n"); + exit(1); + } +} + +void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { + auto TimeOfUnit = + duration_cast(UnitStopTime - UnitStartTime).count(); + if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && + secondsSinceProcessStartUp() >= 2) + PrintStats("pulse "); + if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && + TimeOfUnit >= Options.ReportSlowUnits) { + TimeOfLongestUnitInSeconds = TimeOfUnit; + Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); + WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); + } +} + +bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, + InputInfo *II) { + if (!Size) return false; + + ExecuteCallback(Data, Size); + + UniqFeatureSetTmp.clear(); + size_t FoundUniqFeaturesOfII = 0; + size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); + TPC.CollectFeatures([&](size_t Feature) { + if (Corpus.AddFeature(Feature, Size, Options.Shrink)) + UniqFeatureSetTmp.push_back(Feature); + if (Options.ReduceInputs && II) + if (std::binary_search(II->UniqFeatureSet.begin(), + II->UniqFeatureSet.end(), Feature)) + FoundUniqFeaturesOfII++; + }); + PrintPulseAndReportSlowInput(Data, Size); + size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; + if (NumNewFeatures) { + TPC.UpdateObservedPCs(); + Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, + UniqFeatureSetTmp); + return true; + } + if (II && FoundUniqFeaturesOfII && + FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && + II->U.size() > Size) { + Corpus.Replace(II, {Data, Data + Size}); + return true; + } + return false; +} + +size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { + assert(InFuzzingThread()); + *Data = CurrentUnitData; + return CurrentUnitSize; +} + +void Fuzzer::CrashOnOverwrittenData() { + Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", + GetPid()); + DumpCurrentUnit("crash-"); + Printf("SUMMARY: libFuzzer: out-of-memory\n"); + _Exit(Options.ErrorExitCode); // Stop right now. +} + +// Compare two arrays, but not all bytes if the arrays are large. +static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { + const size_t Limit = 64; + if (Size <= 64) + return !memcmp(A, B, Size); + // Compare first and last Limit/2 bytes. + return !memcmp(A, B, Limit / 2) && + !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); +} + +void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { + TPC.RecordInitialStack(); + TotalNumberOfRuns++; + assert(InFuzzingThread()); + if (SMR.IsClient()) + SMR.WriteByteArray(Data, Size); + // We copy the contents of Unit into a separate heap buffer + // so that we reliably find buffer overflows in it. + uint8_t *DataCopy = new uint8_t[Size]; + memcpy(DataCopy, Data, Size); + if (CurrentUnitData && CurrentUnitData != Data) + memcpy(CurrentUnitData, Data, Size); + CurrentUnitSize = Size; + AllocTracer.Start(Options.TraceMalloc); + UnitStartTime = system_clock::now(); + TPC.ResetMaps(); + RunningCB = true; + int Res = CB(DataCopy, Size); + RunningCB = false; + UnitStopTime = system_clock::now(); + (void)Res; + assert(Res == 0); + HasMoreMallocsThanFrees = AllocTracer.Stop(); + if (!LooseMemeq(DataCopy, Data, Size)) + CrashOnOverwrittenData(); + CurrentUnitSize = 0; + delete[] DataCopy; +} + +void Fuzzer::WriteToOutputCorpus(const Unit &U) { + if (Options.OnlyASCII) + assert(IsASCII(U)); + if (Options.OutputCorpus.empty()) + return; + std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); + WriteToFile(U, Path); + if (Options.Verbosity >= 2) + Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); +} + +void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { + if (!Options.SaveArtifacts) + return; + std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); + if (!Options.ExactArtifactPath.empty()) + Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. + WriteToFile(U, Path); + Printf("artifact_prefix='%s'; Test unit written to %s\n", + Options.ArtifactPrefix.c_str(), Path.c_str()); + if (U.size() <= kMaxUnitSizeToPrint) + Printf("Base64: %s\n", Base64(U).c_str()); +} + +void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { + if (!Options.PrintNEW) + return; + PrintStats(Text, ""); + if (Options.Verbosity) { + Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); + MD.PrintMutationSequence(); + Printf("\n"); + } +} + +void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { + II->NumSuccessfullMutations++; + MD.RecordSuccessfulMutationSequence(); + PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : + "NEW "); + WriteToOutputCorpus(U); + NumberOfNewUnitsAdded++; + CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. + LastCorpusUpdateRun = TotalNumberOfRuns; + LastCorpusUpdateTime = system_clock::now(); +} + +// Tries detecting a memory leak on the particular input that we have just +// executed before calling this function. +void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, + bool DuringInitialCorpusExecution) { + if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. + if (!Options.DetectLeaks) return; + if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || + !(EF->__lsan_do_recoverable_leak_check)) + return; // No lsan. + // Run the target once again, but with lsan disabled so that if there is + // a real leak we do not report it twice. + EF->__lsan_disable(); + ExecuteCallback(Data, Size); + EF->__lsan_enable(); + if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. + if (NumberOfLeakDetectionAttempts++ > 1000) { + Options.DetectLeaks = false; + Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" + " Most likely the target function accumulates allocated\n" + " memory in a global state w/o actually leaking it.\n" + " You may try running this binary with -trace_malloc=[12]" + " to get a trace of mallocs and frees.\n" + " If LeakSanitizer is enabled in this process it will still\n" + " run on the process shutdown.\n"); + return; + } + // Now perform the actual lsan pass. This is expensive and we must ensure + // we don't call it too often. + if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. + if (DuringInitialCorpusExecution) + Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); + Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); + CurrentUnitSize = Size; + DumpCurrentUnit("leak-"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. + } +} + +void Fuzzer::MutateAndTestOne() { + MD.StartMutationSequence(); + + auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); + const auto &U = II.U; + memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); + assert(CurrentUnitData); + size_t Size = U.size(); + assert(Size <= MaxInputLen && "Oversized Unit"); + memcpy(CurrentUnitData, U.data(), Size); + + assert(MaxMutationLen > 0); + + size_t CurrentMaxMutationLen = + Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); + assert(CurrentMaxMutationLen > 0); + + for (int i = 0; i < Options.MutateDepth; i++) { + if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) + break; + size_t NewSize = 0; + NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); + assert(NewSize > 0 && "Mutator returned empty unit"); + assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); + Size = NewSize; + II.NumExecutedMutations++; + if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) + ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); + + TryDetectingAMemoryLeak(CurrentUnitData, Size, + /*DuringInitialCorpusExecution*/ false); + } +} + +void Fuzzer::Loop() { + TPC.SetPrintNewPCs(Options.PrintNewCovPcs); + system_clock::time_point LastCorpusReload = system_clock::now(); + if (Options.DoCrossOver) + MD.SetCorpus(&Corpus); + while (true) { + auto Now = system_clock::now(); + if (duration_cast(Now - LastCorpusReload).count() >= + Options.ReloadIntervalSec) { + RereadOutputCorpus(MaxInputLen); + LastCorpusReload = system_clock::now(); + } + if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) + break; + if (TimedOut()) break; + + // Update TmpMaxMutationLen + if (Options.ExperimentalLenControl) { + if (TmpMaxMutationLen < MaxMutationLen && + (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && + duration_cast(Now - LastCorpusUpdateTime).count() >= 1)) { + LastCorpusUpdateRun = TotalNumberOfRuns; + LastCorpusUpdateTime = Now; + TmpMaxMutationLen = + Min(MaxMutationLen, + TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8)); + if (TmpMaxMutationLen <= MaxMutationLen) + Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns, + TmpMaxMutationLen); + } + } else { + TmpMaxMutationLen = MaxMutationLen; + } + + // Perform several mutations and runs. + MutateAndTestOne(); + } + + PrintStats("DONE ", "\n"); + MD.PrintRecommendedDictionary(); +} + +void Fuzzer::MinimizeCrashLoop(const Unit &U) { + if (U.size() <= 1) return; + while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { + MD.StartMutationSequence(); + memcpy(CurrentUnitData, U.data(), U.size()); + for (int i = 0; i < Options.MutateDepth; i++) { + size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); + assert(NewSize > 0 && NewSize <= MaxMutationLen); + ExecuteCallback(CurrentUnitData, NewSize); + PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); + TryDetectingAMemoryLeak(CurrentUnitData, NewSize, + /*DuringInitialCorpusExecution*/ false); + } + } +} + +void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { + if (SMR.IsServer()) { + SMR.WriteByteArray(Data, Size); + } else if (SMR.IsClient()) { + SMR.PostClient(); + SMR.WaitServer(); + size_t OtherSize = SMR.ReadByteArraySize(); + uint8_t *OtherData = SMR.GetByteArray(); + if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { + size_t i = 0; + for (i = 0; i < Min(Size, OtherSize); i++) + if (Data[i] != OtherData[i]) + break; + Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " + "offset %zd\n", GetPid(), Size, OtherSize, i); + DumpCurrentUnit("mismatch-"); + Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); + } + } +} + +} // namespace fuzzer + +extern "C" { + +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(fuzzer::F); + return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); +} + +// Experimental +void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { + assert(fuzzer::F); + fuzzer::F->AnnounceOutput(Data, Size); +} +} // extern "C" diff --git a/lib/fuzzer/FuzzerMain.cpp b/lib/fuzzer/FuzzerMain.cpp new file mode 100644 index 000000000..af8657200 --- /dev/null +++ b/lib/fuzzer/FuzzerMain.cpp @@ -0,0 +1,21 @@ +//===- FuzzerMain.cpp - main() function and flags -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// main() and flags. +//===----------------------------------------------------------------------===// + +#include "FuzzerDefs.h" + +extern "C" { +// This function should be defined by the user. +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +} // extern "C" + +int main(int argc, char **argv) { + return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); +} diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp new file mode 100644 index 000000000..616c0999a --- /dev/null +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -0,0 +1,338 @@ +//===- FuzzerMerge.cpp - merging corpora ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Merging corpora. +//===----------------------------------------------------------------------===// + +#include "FuzzerMerge.h" +#include "FuzzerIO.h" +#include "FuzzerInternal.h" +#include "FuzzerTracePC.h" +#include "FuzzerUtil.h" + +#include +#include +#include +#include + +namespace fuzzer { + +bool Merger::Parse(const std::string &Str, bool ParseCoverage) { + std::istringstream SS(Str); + return Parse(SS, ParseCoverage); +} + +void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) { + if (!Parse(IS, ParseCoverage)) { + Printf("MERGE: failed to parse the control file (unexpected error)\n"); + exit(1); + } +} + +// The control file example: +// +// 3 # The number of inputs +// 1 # The number of inputs in the first corpus, <= the previous number +// file0 +// file1 +// file2 # One file name per line. +// STARTED 0 123 # FileID, file size +// DONE 0 1 4 6 8 # FileID COV1 COV2 ... +// STARTED 1 456 # If DONE is missing, the input crashed while processing. +// STARTED 2 567 +// DONE 2 8 9 +bool Merger::Parse(std::istream &IS, bool ParseCoverage) { + LastFailure.clear(); + std::string Line; + + // Parse NumFiles. + if (!std::getline(IS, Line, '\n')) return false; + std::istringstream L1(Line); + size_t NumFiles = 0; + L1 >> NumFiles; + if (NumFiles == 0 || NumFiles > 10000000) return false; + + // Parse NumFilesInFirstCorpus. + if (!std::getline(IS, Line, '\n')) return false; + std::istringstream L2(Line); + NumFilesInFirstCorpus = NumFiles + 1; + L2 >> NumFilesInFirstCorpus; + if (NumFilesInFirstCorpus > NumFiles) return false; + + // Parse file names. + Files.resize(NumFiles); + for (size_t i = 0; i < NumFiles; i++) + if (!std::getline(IS, Files[i].Name, '\n')) + return false; + + // Parse STARTED and DONE lines. + size_t ExpectedStartMarker = 0; + const size_t kInvalidStartMarker = -1; + size_t LastSeenStartMarker = kInvalidStartMarker; + std::vector TmpFeatures; + while (std::getline(IS, Line, '\n')) { + std::istringstream ISS1(Line); + std::string Marker; + size_t N; + ISS1 >> Marker; + ISS1 >> N; + if (Marker == "STARTED") { + // STARTED FILE_ID FILE_SIZE + if (ExpectedStartMarker != N) + return false; + ISS1 >> Files[ExpectedStartMarker].Size; + LastSeenStartMarker = ExpectedStartMarker; + assert(ExpectedStartMarker < Files.size()); + ExpectedStartMarker++; + } else if (Marker == "DONE") { + // DONE FILE_ID COV1 COV2 COV3 ... + size_t CurrentFileIdx = N; + if (CurrentFileIdx != LastSeenStartMarker) + return false; + LastSeenStartMarker = kInvalidStartMarker; + if (ParseCoverage) { + TmpFeatures.clear(); // use a vector from outer scope to avoid resizes. + while (ISS1 >> std::hex >> N) + TmpFeatures.push_back(N); + std::sort(TmpFeatures.begin(), TmpFeatures.end()); + Files[CurrentFileIdx].Features = TmpFeatures; + } + } else { + return false; + } + } + if (LastSeenStartMarker != kInvalidStartMarker) + LastFailure = Files[LastSeenStartMarker].Name; + + FirstNotProcessedFile = ExpectedStartMarker; + return true; +} + +size_t Merger::ApproximateMemoryConsumption() const { + size_t Res = 0; + for (const auto &F: Files) + Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]); + return Res; +} + +// Decides which files need to be merged (add thost to NewFiles). +// Returns the number of new features added. +size_t Merger::Merge(const std::set &InitialFeatures, + std::vector *NewFiles) { + NewFiles->clear(); + assert(NumFilesInFirstCorpus <= Files.size()); + std::set AllFeatures(InitialFeatures); + + // What features are in the initial corpus? + for (size_t i = 0; i < NumFilesInFirstCorpus; i++) { + auto &Cur = Files[i].Features; + AllFeatures.insert(Cur.begin(), Cur.end()); + } + size_t InitialNumFeatures = AllFeatures.size(); + + // Remove all features that we already know from all other inputs. + for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { + auto &Cur = Files[i].Features; + std::vector Tmp; + std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), + AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); + Cur.swap(Tmp); + } + + // Sort. Give preference to + // * smaller files + // * files with more features. + std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(), + [&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool { + if (a.Size != b.Size) + return a.Size < b.Size; + return a.Features.size() > b.Features.size(); + }); + + // One greedy pass: add the file's features to AllFeatures. + // If new features were added, add this file to NewFiles. + for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { + auto &Cur = Files[i].Features; + // Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(), + // Files[i].Size, Cur.size()); + size_t OldSize = AllFeatures.size(); + AllFeatures.insert(Cur.begin(), Cur.end()); + if (AllFeatures.size() > OldSize) + NewFiles->push_back(Files[i].Name); + } + return AllFeatures.size() - InitialNumFeatures; +} + +void Merger::PrintSummary(std::ostream &OS) { + for (auto &File : Files) { + OS << std::hex; + OS << File.Name << " size: " << File.Size << " features: "; + for (auto Feature : File.Features) + OS << " " << Feature; + OS << "\n"; + } +} + +std::set Merger::AllFeatures() const { + std::set S; + for (auto &File : Files) + S.insert(File.Features.begin(), File.Features.end()); + return S; +} + +std::set Merger::ParseSummary(std::istream &IS) { + std::string Line, Tmp; + std::set Res; + while (std::getline(IS, Line, '\n')) { + size_t N; + std::istringstream ISS1(Line); + ISS1 >> Tmp; // Name + ISS1 >> Tmp; // size: + assert(Tmp == "size:" && "Corrupt summary file"); + ISS1 >> std::hex; + ISS1 >> N; // File Size + ISS1 >> Tmp; // features: + assert(Tmp == "features:" && "Corrupt summary file"); + while (ISS1 >> std::hex >> N) + Res.insert(N); + } + return Res; +} + +// Inner process. May crash if the target crashes. +void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { + Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str()); + Merger M; + std::ifstream IF(CFPath); + M.ParseOrExit(IF, false); + IF.close(); + if (!M.LastFailure.empty()) + Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n", + M.LastFailure.c_str()); + + Printf("MERGE-INNER: %zd total files;" + " %zd processed earlier; will process %zd files now\n", + M.Files.size(), M.FirstNotProcessedFile, + M.Files.size() - M.FirstNotProcessedFile); + + std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); + for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { + auto U = FileToVector(M.Files[i].Name); + if (U.size() > MaxInputLen) { + U.resize(MaxInputLen); + U.shrink_to_fit(); + } + std::ostringstream StartedLine; + // Write the pre-run marker. + OF << "STARTED " << std::dec << i << " " << U.size() << "\n"; + OF.flush(); // Flush is important since ExecuteCommand may crash. + // Run. + TPC.ResetMaps(); + ExecuteCallback(U.data(), U.size()); + // Collect coverage. + std::set Features; + TPC.CollectFeatures([&](size_t Feature) -> bool { + Features.insert(Feature); + return true; + }); + // Show stats. + if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1))) + PrintStats("pulse "); + // Write the post-run marker and the coverage. + OF << "DONE " << i; + for (size_t F : Features) + OF << " " << std::hex << F; + OF << "\n"; + } +} + +// Outer process. Does not call the target code and thus sohuld not fail. +void Fuzzer::CrashResistantMerge(const std::vector &Args, + const std::vector &Corpora, + const char *CoverageSummaryInputPathOrNull, + const char *CoverageSummaryOutputPathOrNull) { + if (Corpora.size() <= 1) { + Printf("Merge requires two or more corpus dirs\n"); + return; + } + std::vector AllFiles; + ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); + size_t NumFilesInFirstCorpus = AllFiles.size(); + for (size_t i = 1; i < Corpora.size(); i++) + ListFilesInDirRecursive(Corpora[i], nullptr, &AllFiles, /*TopDir*/true); + Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n", + AllFiles.size(), NumFilesInFirstCorpus); + auto CFPath = DirPlusFile(TmpDir(), + "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); + // Write the control file. + RemoveFile(CFPath); + std::ofstream ControlFile(CFPath); + ControlFile << AllFiles.size() << "\n"; + ControlFile << NumFilesInFirstCorpus << "\n"; + for (auto &Path: AllFiles) + ControlFile << Path << "\n"; + if (!ControlFile) { + Printf("MERGE-OUTER: failed to write to the control file: %s\n", + CFPath.c_str()); + exit(1); + } + ControlFile.close(); + + // Execute the inner process untill it passes. + // Every inner process should execute at least one input. + auto BaseCmd = SplitBefore("-ignore_remaining_args=1", + CloneArgsWithoutX(Args, "keep-all-flags")); + bool Success = false; + for (size_t i = 1; i <= AllFiles.size(); i++) { + Printf("MERGE-OUTER: attempt %zd\n", i); + auto ExitCode = ExecuteCommand(BaseCmd.first + " -merge_control_file=" + + CFPath + " " + BaseCmd.second); + if (!ExitCode) { + Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", i); + Success = true; + break; + } + } + if (!Success) { + Printf("MERGE-OUTER: zero succesfull attempts, exiting\n"); + exit(1); + } + // Read the control file and do the merge. + Merger M; + std::ifstream IF(CFPath); + IF.seekg(0, IF.end); + Printf("MERGE-OUTER: the control file has %zd bytes\n", (size_t)IF.tellg()); + IF.seekg(0, IF.beg); + M.ParseOrExit(IF, true); + IF.close(); + Printf("MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n", + M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb()); + if (CoverageSummaryOutputPathOrNull) { + Printf("MERGE-OUTER: writing coverage summary for %zd files to %s\n", + M.Files.size(), CoverageSummaryOutputPathOrNull); + std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); + M.PrintSummary(SummaryOut); + } + std::vector NewFiles; + std::set InitialFeatures; + if (CoverageSummaryInputPathOrNull) { + std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); + InitialFeatures = M.ParseSummary(SummaryIn); + Printf("MERGE-OUTER: coverage summary loaded from %s, %zd features found\n", + CoverageSummaryInputPathOrNull, InitialFeatures.size()); + } + size_t NumNewFeatures = M.Merge(InitialFeatures, &NewFiles); + Printf("MERGE-OUTER: %zd new files with %zd new features added\n", + NewFiles.size(), NumNewFeatures); + for (auto &F: NewFiles) + WriteToOutputCorpus(FileToVector(F)); + // We are done, delete the control file. + RemoveFile(CFPath); +} + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerMerge.h b/lib/fuzzer/FuzzerMerge.h new file mode 100644 index 000000000..dd4c37b6e --- /dev/null +++ b/lib/fuzzer/FuzzerMerge.h @@ -0,0 +1,80 @@ +//===- FuzzerMerge.h - merging corpa ----------------------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Merging Corpora. +// +// The task: +// Take the existing corpus (possibly empty) and merge new inputs into +// it so that only inputs with new coverage ('features') are added. +// The process should tolerate the crashes, OOMs, leaks, etc. +// +// Algorithm: +// The outter process collects the set of files and writes their names +// into a temporary "control" file, then repeatedly launches the inner +// process until all inputs are processed. +// The outer process does not actually execute the target code. +// +// The inner process reads the control file and sees a) list of all the inputs +// and b) the last processed input. Then it starts processing the inputs one +// by one. Before processing every input it writes one line to control file: +// STARTED INPUT_ID INPUT_SIZE +// After processing an input it write another line: +// DONE INPUT_ID Feature1 Feature2 Feature3 ... +// If a crash happens while processing an input the last line in the control +// file will be "STARTED INPUT_ID" and so the next process will know +// where to resume. +// +// Once all inputs are processed by the innner process(es) the outer process +// reads the control files and does the merge based entirely on the contents +// of control file. +// It uses a single pass greedy algorithm choosing first the smallest inputs +// within the same size the inputs that have more new features. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_MERGE_H +#define LLVM_FUZZER_MERGE_H + +#include "FuzzerDefs.h" + +#include +#include +#include +#include + +namespace fuzzer { + +struct MergeFileInfo { + std::string Name; + size_t Size = 0; + std::vector Features; +}; + +struct Merger { + std::vector Files; + size_t NumFilesInFirstCorpus = 0; + size_t FirstNotProcessedFile = 0; + std::string LastFailure; + + bool Parse(std::istream &IS, bool ParseCoverage); + bool Parse(const std::string &Str, bool ParseCoverage); + void ParseOrExit(std::istream &IS, bool ParseCoverage); + void PrintSummary(std::ostream &OS); + std::set ParseSummary(std::istream &IS); + size_t Merge(const std::set &InitialFeatures, + std::vector *NewFiles); + size_t Merge(std::vector *NewFiles) { + return Merge(std::set{}, NewFiles); + } + size_t ApproximateMemoryConsumption() const; + std::set AllFeatures() const; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_MERGE_H diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp new file mode 100644 index 000000000..5998ef9d3 --- /dev/null +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -0,0 +1,533 @@ +//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Mutate a test input. +//===----------------------------------------------------------------------===// + +#include "FuzzerMutate.h" +#include "FuzzerCorpus.h" +#include "FuzzerDefs.h" +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include "FuzzerOptions.h" + +namespace fuzzer { + +const size_t Dictionary::kMaxDictSize; + +static void PrintASCII(const Word &W, const char *PrintAfter) { + PrintASCII(W.data(), W.size(), PrintAfter); +} + +MutationDispatcher::MutationDispatcher(Random &Rand, + const FuzzingOptions &Options) + : Rand(Rand), Options(Options) { + DefaultMutators.insert( + DefaultMutators.begin(), + { + {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_InsertRepeatedBytes, + "InsertRepeatedBytes"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, + {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, + {&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "ManualDict"}, + {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, + "PersAutoDict"}, + }); + if(Options.UseCmp) + DefaultMutators.push_back( + {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); + + if (EF->LLVMFuzzerCustomMutator) + Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); + else + Mutators = DefaultMutators; + + if (EF->LLVMFuzzerCustomCrossOver) + Mutators.push_back( + {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); +} + +static char RandCh(Random &Rand) { + if (Rand.RandBool()) return Rand(256); + const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; + return Special[Rand(sizeof(Special) - 1)]; +} + +size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, + size_t MaxSize) { + return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); +} + +size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (!Corpus || Corpus->size() < 2 || Size == 0) + return 0; + size_t Idx = Rand(Corpus->size()); + const Unit &Other = (*Corpus)[Idx]; + if (Other.empty()) + return 0; + CustomCrossOverInPlaceHere.resize(MaxSize); + auto &U = CustomCrossOverInPlaceHere; + size_t NewSize = EF->LLVMFuzzerCustomCrossOver( + Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); + if (!NewSize) + return 0; + assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); + memcpy(Data, U.data(), NewSize); + return NewSize; +} + +size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize || Size == 0) return 0; + size_t ShuffleAmount = + Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. + size_t ShuffleStart = Rand(Size - ShuffleAmount); + assert(ShuffleStart + ShuffleAmount <= Size); + std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); + return Size; +} + +size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size <= 1) return 0; + size_t N = Rand(Size / 2) + 1; + assert(N < Size); + size_t Idx = Rand(Size - N + 1); + // Erase Data[Idx:Idx+N]. + memmove(Data + Idx, Data + Idx + N, Size - Idx - N); + // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); + return Size - N; +} + +size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size >= MaxSize) return 0; + size_t Idx = Rand(Size + 1); + // Insert new value at Data[Idx]. + memmove(Data + Idx + 1, Data + Idx, Size - Idx); + Data[Idx] = RandCh(Rand); + return Size + 1; +} + +size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, + size_t Size, + size_t MaxSize) { + const size_t kMinBytesToInsert = 3; + if (Size + kMinBytesToInsert >= MaxSize) return 0; + size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); + size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; + assert(Size + N <= MaxSize && N); + size_t Idx = Rand(Size + 1); + // Insert new values at Data[Idx]. + memmove(Data + Idx + N, Data + Idx, Size - Idx); + // Give preference to 0x00 and 0xff. + uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); + for (size_t i = 0; i < N; i++) + Data[Idx + i] = Byte; + return Size + N; +} + +size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize) return 0; + size_t Idx = Rand(Size); + Data[Idx] = RandCh(Rand); + return Size; +} + +size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize) return 0; + size_t Idx = Rand(Size); + Data[Idx] ^= 1 << Rand(8); + return Size; +} + +size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); +} + +size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, + size_t MaxSize, + DictionaryEntry &DE) { + const Word &W = DE.GetW(); + bool UsePositionHint = DE.HasPositionHint() && + DE.GetPositionHint() + W.size() < Size && + Rand.RandBool(); + if (Rand.RandBool()) { // Insert W. + if (Size + W.size() > MaxSize) return 0; + size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); + memmove(Data + Idx + W.size(), Data + Idx, Size - Idx); + memcpy(Data + Idx, W.data(), W.size()); + Size += W.size(); + } else { // Overwrite some bytes with W. + if (W.size() > Size) return 0; + size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); + memcpy(Data + Idx, W.data(), W.size()); + } + return Size; +} + +// Somewhere in the past we have observed a comparison instructions +// with arguments Arg1 Arg2. This function tries to guess a dictionary +// entry that will satisfy that comparison. +// It first tries to find one of the arguments (possibly swapped) in the +// input and if it succeeds it creates a DE with a position hint. +// Otherwise it creates a DE with one of the arguments w/o a position hint. +DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( + const void *Arg1, const void *Arg2, + const void *Arg1Mutation, const void *Arg2Mutation, + size_t ArgSize, const uint8_t *Data, + size_t Size) { + ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; + bool HandleFirst = Rand.RandBool(); + const void *ExistingBytes, *DesiredBytes; + Word W; + const uint8_t *End = Data + Size; + for (int Arg = 0; Arg < 2; Arg++) { + ExistingBytes = HandleFirst ? Arg1 : Arg2; + DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation; + HandleFirst = !HandleFirst; + W.Set(reinterpret_cast(DesiredBytes), ArgSize); + const size_t kMaxNumPositions = 8; + size_t Positions[kMaxNumPositions]; + size_t NumPositions = 0; + for (const uint8_t *Cur = Data; + Cur < End && NumPositions < kMaxNumPositions; Cur++) { + Cur = + (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize); + if (!Cur) break; + Positions[NumPositions++] = Cur - Data; + } + if (!NumPositions) continue; + return DictionaryEntry(W, Positions[Rand(NumPositions)]); + } + DictionaryEntry DE(W); + return DE; +} + + +template +DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( + T Arg1, T Arg2, const uint8_t *Data, size_t Size) { + if (Rand.RandBool()) Arg1 = Bswap(Arg1); + if (Rand.RandBool()) Arg2 = Bswap(Arg2); + T Arg1Mutation = Arg1 + Rand(-1, 1); + T Arg2Mutation = Arg2 + Rand(-1, 1); + return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation, + sizeof(Arg1), Data, Size); +} + +DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( + const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) { + return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(), + Arg2.data(), Arg1.size(), Data, Size); +} + +size_t MutationDispatcher::Mutate_AddWordFromTORC( + uint8_t *Data, size_t Size, size_t MaxSize) { + Word W; + DictionaryEntry DE; + switch (Rand(4)) { + case 0: { + auto X = TPC.TORC8.Get(Rand.Rand()); + DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); + } break; + case 1: { + auto X = TPC.TORC4.Get(Rand.Rand()); + if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) + DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size); + else + DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); + } break; + case 2: { + auto X = TPC.TORCW.Get(Rand.Rand()); + DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); + } break; + case 3: if (Options.UseMemmem) { + auto X = TPC.MMT.Get(Rand.Rand()); + DE = DictionaryEntry(X); + } break; + default: + assert(0); + } + if (!DE.GetW().size()) return 0; + Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); + if (!Size) return 0; + DictionaryEntry &DERef = + CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % + kCmpDictionaryEntriesDequeSize]; + DERef = DE; + CurrentDictionaryEntrySequence.push_back(&DERef); + return Size; +} + +size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( + uint8_t *Data, size_t Size, size_t MaxSize) { + return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); +} + +size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, + size_t Size, size_t MaxSize) { + if (Size > MaxSize) return 0; + if (D.empty()) return 0; + DictionaryEntry &DE = D[Rand(D.size())]; + Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); + if (!Size) return 0; + DE.IncUseCount(); + CurrentDictionaryEntrySequence.push_back(&DE); + return Size; +} + +// Overwrites part of To[0,ToSize) with a part of From[0,FromSize). +// Returns ToSize. +size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize, + uint8_t *To, size_t ToSize) { + // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize). + size_t ToBeg = Rand(ToSize); + size_t CopySize = Rand(ToSize - ToBeg) + 1; + assert(ToBeg + CopySize <= ToSize); + CopySize = std::min(CopySize, FromSize); + size_t FromBeg = Rand(FromSize - CopySize + 1); + assert(FromBeg + CopySize <= FromSize); + memmove(To + ToBeg, From + FromBeg, CopySize); + return ToSize; +} + +// Inserts part of From[0,ToSize) into To. +// Returns new size of To on success or 0 on failure. +size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize, + uint8_t *To, size_t ToSize, + size_t MaxToSize) { + if (ToSize >= MaxToSize) return 0; + size_t AvailableSpace = MaxToSize - ToSize; + size_t MaxCopySize = std::min(AvailableSpace, FromSize); + size_t CopySize = Rand(MaxCopySize) + 1; + size_t FromBeg = Rand(FromSize - CopySize + 1); + assert(FromBeg + CopySize <= FromSize); + size_t ToInsertPos = Rand(ToSize + 1); + assert(ToInsertPos + CopySize <= MaxToSize); + size_t TailSize = ToSize - ToInsertPos; + if (To == From) { + MutateInPlaceHere.resize(MaxToSize); + memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize); + memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); + memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize); + } else { + memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); + memmove(To + ToInsertPos, From + FromBeg, CopySize); + } + return ToSize + CopySize; +} + +size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize || Size == 0) return 0; + if (Rand.RandBool()) + return CopyPartOf(Data, Size, Data, Size); + else + return InsertPartOf(Data, Size, Data, Size, MaxSize); +} + +size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize) return 0; + size_t B = Rand(Size); + while (B < Size && !isdigit(Data[B])) B++; + if (B == Size) return 0; + size_t E = B; + while (E < Size && isdigit(Data[E])) E++; + assert(B < E); + // now we have digits in [B, E). + // strtol and friends don't accept non-zero-teminated data, parse it manually. + uint64_t Val = Data[B] - '0'; + for (size_t i = B + 1; i < E; i++) + Val = Val * 10 + Data[i] - '0'; + + // Mutate the integer value. + switch(Rand(5)) { + case 0: Val++; break; + case 1: Val--; break; + case 2: Val /= 2; break; + case 3: Val *= 2; break; + case 4: Val = Rand(Val * Val); break; + default: assert(0); + } + // Just replace the bytes with the new ones, don't bother moving bytes. + for (size_t i = B; i < E; i++) { + size_t Idx = E + B - i - 1; + assert(Idx >= B && Idx < E); + Data[Idx] = (Val % 10) + '0'; + Val /= 10; + } + return Size; +} + +template +size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { + if (Size < sizeof(T)) return 0; + size_t Off = Rand(Size - sizeof(T) + 1); + assert(Off + sizeof(T) <= Size); + T Val; + if (Off < 64 && !Rand(4)) { + Val = Size; + if (Rand.RandBool()) + Val = Bswap(Val); + } else { + memcpy(&Val, Data + Off, sizeof(Val)); + T Add = Rand(21); + Add -= 10; + if (Rand.RandBool()) + Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. + else + Val = Val + Add; // Add assuming current endiannes. + if (Add == 0 || Rand.RandBool()) // Maybe negate. + Val = -Val; + } + memcpy(Data + Off, &Val, sizeof(Val)); + return Size; +} + +size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, + size_t Size, + size_t MaxSize) { + if (Size > MaxSize) return 0; + switch (Rand(4)) { + case 3: return ChangeBinaryInteger(Data, Size, Rand); + case 2: return ChangeBinaryInteger(Data, Size, Rand); + case 1: return ChangeBinaryInteger(Data, Size, Rand); + case 0: return ChangeBinaryInteger(Data, Size, Rand); + default: assert(0); + } + return 0; +} + +size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size > MaxSize) return 0; + if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; + size_t Idx = Rand(Corpus->size()); + const Unit &O = (*Corpus)[Idx]; + if (O.empty()) return 0; + MutateInPlaceHere.resize(MaxSize); + auto &U = MutateInPlaceHere; + size_t NewSize = 0; + switch(Rand(3)) { + case 0: + NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size()); + break; + case 1: + NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize); + if (!NewSize) + NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); + break; + case 2: + NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); + break; + default: assert(0); + } + assert(NewSize > 0 && "CrossOver returned empty unit"); + assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); + memcpy(Data, U.data(), NewSize); + return NewSize; +} + +void MutationDispatcher::StartMutationSequence() { + CurrentMutatorSequence.clear(); + CurrentDictionaryEntrySequence.clear(); +} + +// Copy successful dictionary entries to PersistentAutoDictionary. +void MutationDispatcher::RecordSuccessfulMutationSequence() { + for (auto DE : CurrentDictionaryEntrySequence) { + // PersistentAutoDictionary.AddWithSuccessCountOne(DE); + DE->IncSuccessCount(); + assert(DE->GetW().size()); + // Linear search is fine here as this happens seldom. + if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) + PersistentAutoDictionary.push_back({DE->GetW(), 1}); + } +} + +void MutationDispatcher::PrintRecommendedDictionary() { + std::vector V; + for (auto &DE : PersistentAutoDictionary) + if (!ManualDictionary.ContainsWord(DE.GetW())) + V.push_back(DE); + if (V.empty()) return; + Printf("###### Recommended dictionary. ######\n"); + for (auto &DE: V) { + assert(DE.GetW().size()); + Printf("\""); + PrintASCII(DE.GetW(), "\""); + Printf(" # Uses: %zd\n", DE.GetUseCount()); + } + Printf("###### End of recommended dictionary. ######\n"); +} + +void MutationDispatcher::PrintMutationSequence() { + Printf("MS: %zd ", CurrentMutatorSequence.size()); + for (auto M : CurrentMutatorSequence) + Printf("%s-", M.Name); + if (!CurrentDictionaryEntrySequence.empty()) { + Printf(" DE: "); + for (auto DE : CurrentDictionaryEntrySequence) { + Printf("\""); + PrintASCII(DE->GetW(), "\"-"); + } + } +} + +size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, Mutators); +} + +size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, + size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, DefaultMutators); +} + +// Mutates Data in place, returns new size. +size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, + size_t MaxSize, + const std::vector &Mutators) { + assert(MaxSize > 0); + // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), + // in which case they will return 0. + // Try several times before returning un-mutated data. + for (int Iter = 0; Iter < 100; Iter++) { + auto M = Mutators[Rand(Mutators.size())]; + size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); + if (NewSize && NewSize <= MaxSize) { + if (Options.OnlyASCII) + ToASCII(Data, NewSize); + CurrentMutatorSequence.push_back(M); + return NewSize; + } + } + *Data = ' '; + return 1; // Fallback, should not happen frequently. +} + +void MutationDispatcher::AddWordToManualDictionary(const Word &W) { + ManualDictionary.push_back( + {W, std::numeric_limits::max()}); +} + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h new file mode 100644 index 000000000..84b04c0db --- /dev/null +++ b/lib/fuzzer/FuzzerMutate.h @@ -0,0 +1,150 @@ +//===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::MutationDispatcher +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_MUTATE_H +#define LLVM_FUZZER_MUTATE_H + +#include "FuzzerDefs.h" +#include "FuzzerDictionary.h" +#include "FuzzerOptions.h" +#include "FuzzerRandom.h" + +namespace fuzzer { + +class MutationDispatcher { +public: + MutationDispatcher(Random &Rand, const FuzzingOptions &Options); + ~MutationDispatcher() {} + /// Indicate that we are about to start a new sequence of mutations. + void StartMutationSequence(); + /// Print the current sequence of mutations. + void PrintMutationSequence(); + /// Indicate that the current sequence of mutations was successfull. + void RecordSuccessfulMutationSequence(); + /// Mutates data by invoking user-provided mutator. + size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by invoking user-provided crossover. + size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by shuffling bytes. + size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by erasing bytes. + size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting a byte. + size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting several repeated bytes. + size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one byte. + size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one bit. + size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by copying/inserting a part of data into a different place. + size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Mutates data by adding a word from the manual dictionary. + size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Mutates data by adding a word from the TORC. + size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Mutates data by adding a word from the persistent automatic dictionary. + size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Tries to find an ASCII integer in Data, changes it to another ASCII int. + size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); + /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways. + size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize); + + /// CrossOver Data with some other element of the corpus. + size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Applies one of the configured mutations. + /// Returns the new size of data which could be up to MaxSize. + size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + /// Applies one of the default mutations. Provided as a service + /// to mutation authors. + size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Creates a cross-over of two pieces of Data, returns its size. + size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, + size_t Size2, uint8_t *Out, size_t MaxOutSize); + + void AddWordToManualDictionary(const Word &W); + + void PrintRecommendedDictionary(); + + void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; } + + Random &GetRand() { return Rand; } + +private: + + struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; + }; + + size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, + size_t MaxSize); + size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, + const std::vector &Mutators); + + size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, + size_t ToSize, size_t MaxToSize); + size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, + size_t ToSize); + size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize, + DictionaryEntry &DE); + + template + DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2, + const uint8_t *Data, size_t Size); + DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2, + const uint8_t *Data, size_t Size); + DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2, + const void *Arg1Mutation, + const void *Arg2Mutation, + size_t ArgSize, + const uint8_t *Data, size_t Size); + + Random &Rand; + const FuzzingOptions Options; + + // Dictionary provided by the user via -dict=DICT_FILE. + Dictionary ManualDictionary; + // Temporary dictionary modified by the fuzzer itself, + // recreated periodically. + Dictionary TempAutoDictionary; + // Persistent dictionary modified by the fuzzer, consists of + // entries that led to successfull discoveries in the past mutations. + Dictionary PersistentAutoDictionary; + + std::vector CurrentMutatorSequence; + std::vector CurrentDictionaryEntrySequence; + + static const size_t kCmpDictionaryEntriesDequeSize = 16; + DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; + size_t CmpDictionaryEntriesDequeIdx = 0; + + const InputCorpus *Corpus = nullptr; + std::vector MutateInPlaceHere; + // CustomCrossOver needs its own buffer as a custom implementation may call + // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. + std::vector CustomCrossOverInPlaceHere; + + std::vector Mutators; + std::vector DefaultMutators; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_MUTATE_H diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h new file mode 100644 index 000000000..9500235e2 --- /dev/null +++ b/lib/fuzzer/FuzzerOptions.h @@ -0,0 +1,68 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::FuzzingOptions +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_OPTIONS_H +#define LLVM_FUZZER_OPTIONS_H + +#include "FuzzerDefs.h" + +namespace fuzzer { + +struct FuzzingOptions { + int Verbosity = 1; + size_t MaxLen = 0; + bool ExperimentalLenControl = false; + int UnitTimeoutSec = 300; + int TimeoutExitCode = 77; + int ErrorExitCode = 77; + int MaxTotalTimeSec = 0; + int RssLimitMb = 0; + bool DoCrossOver = true; + int MutateDepth = 5; + bool UseCounters = false; + bool UseIndirCalls = true; + bool UseMemmem = true; + bool UseCmp = false; + bool UseValueProfile = false; + bool Shrink = false; + bool ReduceInputs = false; + int ReloadIntervalSec = 1; + bool ShuffleAtStartUp = true; + bool PreferSmall = true; + size_t MaxNumberOfRuns = -1L; + int ReportSlowUnits = 10; + bool OnlyASCII = false; + std::string OutputCorpus; + std::string ArtifactPrefix = "./"; + std::string ExactArtifactPath; + std::string ExitOnSrcPos; + std::string ExitOnItem; + bool SaveArtifacts = true; + bool PrintNEW = true; // Print a status line when new units are found; + bool PrintNewCovPcs = false; + bool PrintFinalStats = false; + bool PrintCorpusStats = false; + bool PrintCoverage = false; + bool DumpCoverage = false; + bool DetectLeaks = true; + int TraceMalloc = 0; + bool HandleAbrt = false; + bool HandleBus = false; + bool HandleFpe = false; + bool HandleIll = false; + bool HandleInt = false; + bool HandleSegv = false; + bool HandleTerm = false; + bool HandleXfsz = false; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_OPTIONS_H diff --git a/lib/fuzzer/FuzzerRandom.h b/lib/fuzzer/FuzzerRandom.h new file mode 100644 index 000000000..8a1aa3ef5 --- /dev/null +++ b/lib/fuzzer/FuzzerRandom.h @@ -0,0 +1,34 @@ +//===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::Random +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_RANDOM_H +#define LLVM_FUZZER_RANDOM_H + +#include + +namespace fuzzer { +class Random : public std::mt19937 { + public: + Random(unsigned int seed) : std::mt19937(seed) {} + result_type operator()() { return this->std::mt19937::operator()(); } + size_t Rand() { return this->operator()(); } + size_t RandBool() { return Rand() % 2; } + size_t operator()(size_t n) { return n ? Rand() % n : 0; } + intptr_t operator()(intptr_t From, intptr_t To) { + assert(From < To); + intptr_t RangeSize = To - From + 1; + return operator()(RangeSize) + From; + } +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_RANDOM_H diff --git a/lib/fuzzer/FuzzerSHA1.cpp b/lib/fuzzer/FuzzerSHA1.cpp new file mode 100644 index 000000000..d2f8e811b --- /dev/null +++ b/lib/fuzzer/FuzzerSHA1.cpp @@ -0,0 +1,222 @@ +//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This code is taken from public domain +// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) +// and modified by adding anonymous namespace, adding an interface +// function fuzzer::ComputeSHA1() and removing unnecessary code. +// +// lib/Fuzzer can not use SHA1 implementation from openssl because +// openssl may not be available and because we may be fuzzing openssl itself. +// For the same reason we do not want to depend on SHA1 from LLVM tree. +//===----------------------------------------------------------------------===// + +#include "FuzzerSHA1.h" +#include "FuzzerDefs.h" + +/* This code is public-domain - it is based on libcrypt + * placed in the public domain by Wei Dai and other contributors. + */ + +#include +#include +#include +#include + +namespace { // Added for LibFuzzer + +#ifdef __BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +#elif defined __LITTLE_ENDIAN__ +/* override */ +#elif defined __BYTE_ORDER +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#else // ! defined __LITTLE_ENDIAN__ +# include // machine/endian.h +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#endif + + +/* header */ + +#define HASH_LENGTH 20 +#define BLOCK_LENGTH 64 + +typedef struct sha1nfo { + uint32_t buffer[BLOCK_LENGTH/4]; + uint32_t state[HASH_LENGTH/4]; + uint32_t byteCount; + uint8_t bufferOffset; + uint8_t keyBuffer[BLOCK_LENGTH]; + uint8_t innerHash[HASH_LENGTH]; +} sha1nfo; + +/* public API - prototypes - TODO: doxygen*/ + +/** + */ +void sha1_init(sha1nfo *s); +/** + */ +void sha1_writebyte(sha1nfo *s, uint8_t data); +/** + */ +void sha1_write(sha1nfo *s, const char *data, size_t len); +/** + */ +uint8_t* sha1_result(sha1nfo *s); + + +/* code */ +#define SHA1_K0 0x5a827999 +#define SHA1_K20 0x6ed9eba1 +#define SHA1_K40 0x8f1bbcdc +#define SHA1_K60 0xca62c1d6 + +void sha1_init(sha1nfo *s) { + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->byteCount = 0; + s->bufferOffset = 0; +} + +uint32_t sha1_rol32(uint32_t number, uint8_t bits) { + return ((number << bits) | (number >> (32-bits))); +} + +void sha1_hashBlock(sha1nfo *s) { + uint8_t i; + uint32_t a,b,c,d,e,t; + + a=s->state[0]; + b=s->state[1]; + c=s->state[2]; + d=s->state[3]; + e=s->state[4]; + for (i=0; i<80; i++) { + if (i>=16) { + t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; + s->buffer[i&15] = sha1_rol32(t,1); + } + if (i<20) { + t = (d ^ (b & (c ^ d))) + SHA1_K0; + } else if (i<40) { + t = (b ^ c ^ d) + SHA1_K20; + } else if (i<60) { + t = ((b & c) | (d & (b | c))) + SHA1_K40; + } else { + t = (b ^ c ^ d) + SHA1_K60; + } + t+=sha1_rol32(a,5) + e + s->buffer[i&15]; + e=d; + d=c; + c=sha1_rol32(b,30); + b=a; + a=t; + } + s->state[0] += a; + s->state[1] += b; + s->state[2] += c; + s->state[3] += d; + s->state[4] += e; +} + +void sha1_addUncounted(sha1nfo *s, uint8_t data) { + uint8_t * const b = (uint8_t*) s->buffer; +#ifdef SHA_BIG_ENDIAN + b[s->bufferOffset] = data; +#else + b[s->bufferOffset ^ 3] = data; +#endif + s->bufferOffset++; + if (s->bufferOffset == BLOCK_LENGTH) { + sha1_hashBlock(s); + s->bufferOffset = 0; + } +} + +void sha1_writebyte(sha1nfo *s, uint8_t data) { + ++s->byteCount; + sha1_addUncounted(s, data); +} + +void sha1_write(sha1nfo *s, const char *data, size_t len) { + for (;len--;) sha1_writebyte(s, (uint8_t) *data++); +} + +void sha1_pad(sha1nfo *s) { + // Implement SHA-1 padding (fips180-2 §5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + sha1_addUncounted(s, 0x80); + while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); + + // Append length in the last 8 bytes + sha1_addUncounted(s, 0); // We're only using 32 bit lengths + sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths + sha1_addUncounted(s, 0); // So zero pad the top bits + sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 + sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as + sha1_addUncounted(s, s->byteCount >> 13); // byte. + sha1_addUncounted(s, s->byteCount >> 5); + sha1_addUncounted(s, s->byteCount << 3); +} + +uint8_t* sha1_result(sha1nfo *s) { + // Pad to complete the last block + sha1_pad(s); + +#ifndef SHA_BIG_ENDIAN + // Swap byte order back + int i; + for (i=0; i<5; i++) { + s->state[i]= + (((s->state[i])<<24)& 0xff000000) + | (((s->state[i])<<8) & 0x00ff0000) + | (((s->state[i])>>8) & 0x0000ff00) + | (((s->state[i])>>24)& 0x000000ff); + } +#endif + + // Return pointer to hash (20 characters) + return (uint8_t*) s->state; +} + +} // namespace; Added for LibFuzzer + +namespace fuzzer { + +// The rest is added for LibFuzzer +void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { + sha1nfo s; + sha1_init(&s); + sha1_write(&s, (const char*)Data, Len); + memcpy(Out, sha1_result(&s), HASH_LENGTH); +} + +std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) { + std::stringstream SS; + for (int i = 0; i < kSHA1NumBytes; i++) + SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i]; + return SS.str(); +} + +std::string Hash(const Unit &U) { + uint8_t Hash[kSHA1NumBytes]; + ComputeSHA1(U.data(), U.size(), Hash); + return Sha1ToString(Hash); +} + +} diff --git a/lib/fuzzer/FuzzerSHA1.h b/lib/fuzzer/FuzzerSHA1.h new file mode 100644 index 000000000..3b5e6e807 --- /dev/null +++ b/lib/fuzzer/FuzzerSHA1.h @@ -0,0 +1,33 @@ +//===- FuzzerSHA1.h - Internal header for the SHA1 utils --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// SHA1 utils. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_SHA1_H +#define LLVM_FUZZER_SHA1_H + +#include "FuzzerDefs.h" +#include +#include + +namespace fuzzer { + +// Private copy of SHA1 implementation. +static const int kSHA1NumBytes = 20; + +// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. +void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); + +std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]); + +std::string Hash(const Unit &U); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_SHA1_H diff --git a/lib/fuzzer/FuzzerShmem.h b/lib/fuzzer/FuzzerShmem.h new file mode 100644 index 000000000..53568e0ac --- /dev/null +++ b/lib/fuzzer/FuzzerShmem.h @@ -0,0 +1,69 @@ +//===- FuzzerShmem.h - shared memory interface ------------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// SharedMemoryRegion +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_SHMEM_H +#define LLVM_FUZZER_SHMEM_H + +#include +#include +#include + +#include "FuzzerDefs.h" + +namespace fuzzer { + +class SharedMemoryRegion { + public: + bool Create(const char *Name); + bool Open(const char *Name); + bool Destroy(const char *Name); + uint8_t *GetData() { return Data; } + void PostServer() {Post(0);} + void WaitServer() {Wait(0);} + void PostClient() {Post(1);} + void WaitClient() {Wait(1);} + + size_t WriteByteArray(const uint8_t *Bytes, size_t N) { + assert(N <= kShmemSize - sizeof(N)); + memcpy(GetData(), &N, sizeof(N)); + memcpy(GetData() + sizeof(N), Bytes, N); + assert(N == ReadByteArraySize()); + return N; + } + size_t ReadByteArraySize() { + size_t Res; + memcpy(&Res, GetData(), sizeof(Res)); + return Res; + } + uint8_t *GetByteArray() { return GetData() + sizeof(size_t); } + + bool IsServer() const { return Data && IAmServer; } + bool IsClient() const { return Data && !IAmServer; } + +private: + + static const size_t kShmemSize = 1 << 22; + bool IAmServer; + std::string Path(const char *Name); + std::string SemName(const char *Name, int Idx); + void Post(int Idx); + void Wait(int Idx); + + bool Map(int fd); + uint8_t *Data = nullptr; + void *Semaphore[2]; +}; + +extern SharedMemoryRegion SMR; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_SHMEM_H diff --git a/lib/fuzzer/FuzzerShmemPosix.cpp b/lib/fuzzer/FuzzerShmemPosix.cpp new file mode 100644 index 000000000..50cdcfb50 --- /dev/null +++ b/lib/fuzzer/FuzzerShmemPosix.cpp @@ -0,0 +1,103 @@ +//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// SharedMemoryRegion +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_POSIX + +#include "FuzzerIO.h" +#include "FuzzerShmem.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +std::string SharedMemoryRegion::Path(const char *Name) { + return DirPlusFile(TmpDir(), Name); +} + +std::string SharedMemoryRegion::SemName(const char *Name, int Idx) { + std::string Res(Name); + return Res + (char)('0' + Idx); +} + +bool SharedMemoryRegion::Map(int fd) { + Data = + (uint8_t *)mmap(0, kShmemSize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); + if (Data == (uint8_t*)-1) + return false; + return true; +} + +bool SharedMemoryRegion::Create(const char *Name) { + int fd = open(Path(Name).c_str(), O_CREAT | O_RDWR, 0777); + if (fd < 0) return false; + if (ftruncate(fd, kShmemSize) < 0) return false; + if (!Map(fd)) + return false; + for (int i = 0; i < 2; i++) { + sem_unlink(SemName(Name, i).c_str()); + Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0); + if (Semaphore[i] == (void *)-1) + return false; + } + IAmServer = true; + return true; +} + +bool SharedMemoryRegion::Open(const char *Name) { + int fd = open(Path(Name).c_str(), O_RDWR); + if (fd < 0) return false; + struct stat stat_res; + if (0 != fstat(fd, &stat_res)) + return false; + assert(stat_res.st_size == kShmemSize); + if (!Map(fd)) + return false; + for (int i = 0; i < 2; i++) { + Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0); + if (Semaphore[i] == (void *)-1) + return false; + } + IAmServer = false; + return true; +} + +bool SharedMemoryRegion::Destroy(const char *Name) { + return 0 == unlink(Path(Name).c_str()); +} + +void SharedMemoryRegion::Post(int Idx) { + assert(Idx == 0 || Idx == 1); + sem_post((sem_t*)Semaphore[Idx]); +} + +void SharedMemoryRegion::Wait(int Idx) { + assert(Idx == 0 || Idx == 1); + for (int i = 0; i < 10 && sem_wait((sem_t*)Semaphore[Idx]); i++) { + // sem_wait may fail if interrupted by a signal. + sleep(i); + if (i) + Printf("%s: sem_wait[%d] failed %s\n", i < 9 ? "WARNING" : "ERROR", i, + strerror(errno)); + if (i == 9) abort(); + } +} + +} // namespace fuzzer + +#endif // LIBFUZZER_POSIX diff --git a/lib/fuzzer/FuzzerShmemWindows.cpp b/lib/fuzzer/FuzzerShmemWindows.cpp new file mode 100644 index 000000000..d330ebf4f --- /dev/null +++ b/lib/fuzzer/FuzzerShmemWindows.cpp @@ -0,0 +1,64 @@ +//===- FuzzerShmemWindows.cpp - Posix shared memory -------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// SharedMemoryRegion +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS + +#include "FuzzerIO.h" +#include "FuzzerShmem.h" + +#include +#include +#include +#include + +namespace fuzzer { + +std::string SharedMemoryRegion::Path(const char *Name) { + return DirPlusFile(TmpDir(), Name); +} + +std::string SharedMemoryRegion::SemName(const char *Name, int Idx) { + std::string Res(Name); + return Res + (char)('0' + Idx); +} + +bool SharedMemoryRegion::Map(int fd) { + assert(0 && "UNIMPLEMENTED"); + return false; +} + +bool SharedMemoryRegion::Create(const char *Name) { + assert(0 && "UNIMPLEMENTED"); + return false; +} + +bool SharedMemoryRegion::Open(const char *Name) { + assert(0 && "UNIMPLEMENTED"); + return false; +} + +bool SharedMemoryRegion::Destroy(const char *Name) { + assert(0 && "UNIMPLEMENTED"); + return false; +} + +void SharedMemoryRegion::Post(int Idx) { + assert(0 && "UNIMPLEMENTED"); +} + +void SharedMemoryRegion::Wait(int Idx) { + Semaphore[1] = nullptr; + assert(0 && "UNIMPLEMENTED"); +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp new file mode 100644 index 000000000..d038374dc --- /dev/null +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -0,0 +1,566 @@ +//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Trace PCs. +// This module implements __sanitizer_cov_trace_pc_guard[_init], +// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation. +// +//===----------------------------------------------------------------------===// + +#include "FuzzerTracePC.h" +#include "FuzzerCorpus.h" +#include "FuzzerDefs.h" +#include "FuzzerDictionary.h" +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include "FuzzerUtil.h" +#include "FuzzerValueBitMap.h" +#include + +// The coverage counters and PCs. +// These are declared as global variables named "__sancov_*" to simplify +// experiments with inlined instrumentation. +alignas(64) ATTRIBUTE_INTERFACE +uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs]; + +ATTRIBUTE_INTERFACE +uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; + +namespace fuzzer { + +TracePC TPC; + +int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr; + +uint8_t *TracePC::Counters() const { + return __sancov_trace_pc_guard_8bit_counters; +} + +uintptr_t *TracePC::PCs() const { + return __sancov_trace_pc_pcs; +} + +size_t TracePC::GetTotalPCCoverage() { + if (ObservedPCs.size()) + return ObservedPCs.size(); + size_t Res = 0; + for (size_t i = 1, N = GetNumPCs(); i < N; i++) + if (PCs()[i]) + Res++; + return Res; +} + + +void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { + if (Start == Stop) return; + if (NumModulesWithInline8bitCounters && + ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return; + assert(NumModulesWithInline8bitCounters < + sizeof(ModuleCounters) / sizeof(ModuleCounters[0])); + ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop}; + NumInline8bitCounters += Stop - Start; +} + +void TracePC::HandlePCsInit(const uint8_t *Start, const uint8_t *Stop) { + const uintptr_t *B = reinterpret_cast(Start); + const uintptr_t *E = reinterpret_cast(Stop); + if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return; + assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0])); + ModulePCTable[NumPCTables++] = {B, E}; + NumPCsInPCTables += E - B; +} + +void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { + if (Start == Stop || *Start) return; + assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); + for (uint32_t *P = Start; P < Stop; P++) { + NumGuards++; + if (NumGuards == kNumPCs) { + RawPrint( + "WARNING: The binary has too many instrumented PCs.\n" + " You may want to reduce the size of the binary\n" + " for more efficient fuzzing and precise coverage data\n"); + } + *P = NumGuards % kNumPCs; + } + Modules[NumModules].Start = Start; + Modules[NumModules].Stop = Stop; + NumModules++; +} + +void TracePC::PrintModuleInfo() { + if (NumGuards) { + Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards); + for (size_t i = 0; i < NumModules; i++) + Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start, + Modules[i].Start, Modules[i].Stop); + Printf("\n"); + } + if (NumModulesWithInline8bitCounters) { + Printf("INFO: Loaded %zd modules (%zd inline 8-bit counters): ", + NumModulesWithInline8bitCounters, NumInline8bitCounters); + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) + Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start, + ModuleCounters[i].Start, ModuleCounters[i].Stop); + Printf("\n"); + } + if (NumPCTables) { + Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables, + NumPCsInPCTables); + for (size_t i = 0; i < NumPCTables; i++) { + Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start, + ModulePCTable[i].Start, ModulePCTable[i].Stop); + } + Printf("\n"); + + if ((NumGuards && NumGuards != NumPCsInPCTables) || + (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) { + Printf("ERROR: The size of coverage PC tables does not match the" + " number of instrumented PCs. This might be a bug in the compiler," + " please contact the libFuzzer developers.\n"); + _Exit(1); + } + } +} + +ATTRIBUTE_NO_SANITIZE_ALL +void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { + const uintptr_t kBits = 12; + const uintptr_t kMask = (1 << kBits) - 1; + uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits); + ValueProfileMap.AddValueModPrime(Idx); +} + +void TracePC::UpdateObservedPCs() { + if (NumPCsInPCTables) { + auto Observe = [&](uintptr_t PC) { + bool Inserted = ObservedPCs.insert(PC).second; + if (Inserted && DoPrintNewPCs) + PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); + }; + + if (NumInline8bitCounters == NumPCsInPCTables) { + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + uint8_t *Beg = ModuleCounters[i].Start; + size_t Size = ModuleCounters[i].Stop - Beg; + assert(Size == + (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); + for (size_t j = 0; j < Size; j++) + if (Beg[j]) + Observe(ModulePCTable[i].Start[j]); + } + } else if (NumGuards == NumPCsInPCTables) { + size_t GuardIdx = 1; + for (size_t i = 0; i < NumModules; i++) { + uint32_t *Beg = Modules[i].Start; + size_t Size = Modules[i].Stop - Beg; + assert(Size == + (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); + for (size_t j = 0; j < Size; j++, GuardIdx++) + if (Counters()[GuardIdx]) + Observe(ModulePCTable[i].Start[j]); + } + } + } +} + +inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { + // TODO: this implementation is x86 only. + // see sanitizer_common GetPreviousInstructionPc for full implementation. + return PC - 1; +} + +inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) { + // TODO: this implementation is x86 only. + // see sanitizer_common GetPreviousInstructionPc for full implementation. + return PC + 1; +} + +static std::string GetModuleName(uintptr_t PC) { + char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++? + void *OffsetRaw = nullptr; + if (!EF->__sanitizer_get_module_and_offset_for_pc( + reinterpret_cast(PC), ModulePathRaw, + sizeof(ModulePathRaw), &OffsetRaw)) + return ""; + return ModulePathRaw; +} + +void TracePC::PrintCoverage() { + if (!EF->__sanitizer_symbolize_pc || + !EF->__sanitizer_get_module_and_offset_for_pc) { + Printf("INFO: __sanitizer_symbolize_pc or " + "__sanitizer_get_module_and_offset_for_pc is not available," + " not printing coverage\n"); + return; + } + Printf("COVERAGE:\n"); + std::string LastFunctionName = ""; + std::string LastFileStr = ""; + std::set UncoveredLines; + std::set CoveredLines; + + auto FunctionEndCallback = [&](const std::string &CurrentFunc, + const std::string &CurrentFile) { + if (LastFunctionName != CurrentFunc) { + if (CoveredLines.empty() && !UncoveredLines.empty()) { + Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str()); + } else { + for (auto Line : UncoveredLines) { + if (!CoveredLines.count(Line)) + Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(), + LastFileStr.c_str(), Line); + } + } + + UncoveredLines.clear(); + CoveredLines.clear(); + LastFunctionName = CurrentFunc; + LastFileStr = CurrentFile; + } + }; + + for (size_t i = 0; i < NumPCTables; i++) { + auto &M = ModulePCTable[i]; + assert(M.Start < M.Stop); + auto ModuleName = GetModuleName(*M.Start); + for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) { + auto PC = *Ptr; + auto VisualizePC = GetNextInstructionPc(PC); + bool IsObserved = ObservedPCs.count(PC); + std::string FileStr = DescribePC("%s", VisualizePC); + if (!IsInterestingCoverageFile(FileStr)) continue; + std::string FunctionStr = DescribePC("%F", VisualizePC); + FunctionEndCallback(FunctionStr, FileStr); + std::string LineStr = DescribePC("%l", VisualizePC); + size_t Line = std::stoul(LineStr); + if (IsObserved && CoveredLines.insert(Line).second) + Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), + Line); + else + UncoveredLines.insert(Line); + } + } + FunctionEndCallback("", ""); +} + +void TracePC::DumpCoverage() { + if (EF->__sanitizer_dump_coverage) { + std::vector PCsCopy(GetNumPCs()); + for (size_t i = 0; i < GetNumPCs(); i++) + PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; + EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); + } +} + +// Value profile. +// We keep track of various values that affect control flow. +// These values are inserted into a bit-set-based hash map. +// Every new bit in the map is treated as a new coverage. +// +// For memcmp/strcmp/etc the interesting value is the length of the common +// prefix of the parameters. +// For cmp instructions the interesting value is a XOR of the parameters. +// The interesting value is mixed up with the PC and is then added to the map. + +ATTRIBUTE_NO_SANITIZE_ALL +void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, + size_t n, bool StopAtZero) { + if (!n) return; + size_t Len = std::min(n, Word::GetMaxSize()); + const uint8_t *A1 = reinterpret_cast(s1); + const uint8_t *A2 = reinterpret_cast(s2); + uint8_t B1[Word::kMaxSize]; + uint8_t B2[Word::kMaxSize]; + // Copy the data into locals in this non-msan-instrumented function + // to avoid msan complaining further. + size_t Hash = 0; // Compute some simple hash of both strings. + for (size_t i = 0; i < Len; i++) { + B1[i] = A1[i]; + B2[i] = A2[i]; + size_t T = B1[i]; + Hash ^= (T << 8) | B2[i]; + } + size_t I = 0; + for (; I < Len; I++) + if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0)) + break; + size_t PC = reinterpret_cast(caller_pc); + size_t Idx = (PC & 4095) | (I << 12); + ValueProfileMap.AddValue(Idx); + TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len)); +} + +template +ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE +ATTRIBUTE_NO_SANITIZE_ALL +void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { + uint64_t ArgXor = Arg1 ^ Arg2; + uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65] + uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance; + if (sizeof(T) == 4) + TORC4.Insert(ArgXor, Arg1, Arg2); + else if (sizeof(T) == 8) + TORC8.Insert(ArgXor, Arg1, Arg2); + ValueProfileMap.AddValue(Idx); +} + +static size_t InternalStrnlen(const char *S, size_t MaxLen) { + size_t Len = 0; + for (; Len < MaxLen && S[Len]; Len++) {} + return Len; +} + +// Finds min of (strlen(S1), strlen(S2)). +// Needed bacause one of these strings may actually be non-zero terminated. +static size_t InternalStrnlen2(const char *S1, const char *S2) { + size_t Len = 0; + for (; S1[Len] && S2[Len]; Len++) {} + return Len; +} + +void TracePC::ClearInlineCounters() { + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + uint8_t *Beg = ModuleCounters[i].Start; + size_t Size = ModuleCounters[i].Stop - Beg; + memset(Beg, 0, Size); + } +} + +} // namespace fuzzer + +extern "C" { +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uint32_t Idx = *Guard; + __sancov_trace_pc_pcs[Idx] = PC; + __sancov_trace_pc_guard_8bit_counters[Idx]++; + // Uncomment the following line to get stack-depth profiling. + // fuzzer::TPC.RecordCurrentStack(); +} + +// Best-effort support for -fsanitize-coverage=trace-pc, which is available +// in both Clang and GCC. +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +void __sanitizer_cov_trace_pc() { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1); + __sancov_trace_pc_pcs[Idx] = PC; + __sancov_trace_pc_guard_8bit_counters[Idx]++; +} + +ATTRIBUTE_INTERFACE +void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { + fuzzer::TPC.HandleInit(Start, Stop); +} + +ATTRIBUTE_INTERFACE +void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { + fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop); +} + +ATTRIBUTE_INTERFACE +void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, const uint8_t *pcs_end) { + fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCallerCallee(PC, Callee); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic +// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however, +// should be changed later to make full use of instrumentation. +void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { + uint64_t N = Cases[0]; + uint64_t ValSizeInBits = Cases[1]; + uint64_t *Vals = Cases + 2; + // Skip the most common and the most boring case. + if (Vals[N - 1] < 256 && Val < 256) + return; + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + size_t i; + uint64_t Token = 0; + for (i = 0; i < N; i++) { + Token = Val ^ Vals[i]; + if (Val < Vals[i]) + break; + } + + if (ValSizeInBits == 16) + fuzzer::TPC.HandleCmp(PC + i, static_cast(Token), (uint16_t)(0)); + else if (ValSizeInBits == 32) + fuzzer::TPC.HandleCmp(PC + i, static_cast(Token), (uint32_t)(0)); + else + fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0)); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_div4(uint32_t Val) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_div8(uint64_t Val) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); +} + +ATTRIBUTE_INTERFACE +ATTRIBUTE_NO_SANITIZE_ALL +ATTRIBUTE_TARGET_POPCNT +void __sanitizer_cov_trace_gep(uintptr_t Idx) { + uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, + const void *s2, size_t n, int result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (result == 0) return; // No reason to mutate. + if (n <= 1) return; // Not interesting. + fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, + const char *s2, size_t n, int result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (result == 0) return; // No reason to mutate. + size_t Len1 = fuzzer::InternalStrnlen(s1, n); + size_t Len2 = fuzzer::InternalStrnlen(s2, n); + n = std::min(n, Len1); + n = std::min(n, Len2); + if (n <= 1) return; // Not interesting. + fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, + const char *s2, int result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + if (result == 0) return; // No reason to mutate. + size_t N = fuzzer::InternalStrnlen2(s1, s2); + if (N <= 1) return; // Not interesting. + fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, + const char *s2, int result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, + const char *s2, char *result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + fuzzer::TPC.MMT.Add(reinterpret_cast(s2), strlen(s2)); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, + const char *s2, char *result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + fuzzer::TPC.MMT.Add(reinterpret_cast(s2), strlen(s2)); +} + +ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY +void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, + const void *s2, size_t len2, void *result) { + if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; + fuzzer::TPC.MMT.Add(reinterpret_cast(s2), len2); +} +} // extern "C" diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h new file mode 100644 index 000000000..ea6794c75 --- /dev/null +++ b/lib/fuzzer/FuzzerTracePC.h @@ -0,0 +1,253 @@ +//===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::TracePC +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_TRACE_PC +#define LLVM_FUZZER_TRACE_PC + +#include "FuzzerDefs.h" +#include "FuzzerDictionary.h" +#include "FuzzerValueBitMap.h" + +#include + +namespace fuzzer { + +// TableOfRecentCompares (TORC) remembers the most recently performed +// comparisons of type T. +// We record the arguments of CMP instructions in this table unconditionally +// because it seems cheaper this way than to compute some expensive +// conditions inside __sanitizer_cov_trace_cmp*. +// After the unit has been executed we may decide to use the contents of +// this table to populate a Dictionary. +template +struct TableOfRecentCompares { + static const size_t kSize = kSizeT; + struct Pair { + T A, B; + }; + ATTRIBUTE_NO_SANITIZE_ALL + void Insert(size_t Idx, const T &Arg1, const T &Arg2) { + Idx = Idx % kSize; + Table[Idx].A = Arg1; + Table[Idx].B = Arg2; + } + + Pair Get(size_t I) { return Table[I % kSize]; } + + Pair Table[kSize]; +}; + +template +struct MemMemTable { + static const size_t kSize = kSizeT; + Word MemMemWords[kSize]; + Word EmptyWord; + + void Add(const uint8_t *Data, size_t Size) { + if (Size <= 2) return; + Size = std::min(Size, Word::GetMaxSize()); + size_t Idx = SimpleFastHash(Data, Size) % kSize; + MemMemWords[Idx].Set(Data, Size); + } + const Word &Get(size_t Idx) { + for (size_t i = 0; i < kSize; i++) { + const Word &W = MemMemWords[(Idx + i) % kSize]; + if (W.size()) return W; + } + EmptyWord.Set(nullptr, 0); + return EmptyWord; + } +}; + +class TracePC { + public: + static const size_t kNumPCs = 1 << 21; + // How many bits of PC are used from __sanitizer_cov_trace_pc. + static const size_t kTracePcBits = 18; + + void HandleInit(uint32_t *Start, uint32_t *Stop); + void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); + void HandlePCsInit(const uint8_t *Start, const uint8_t *Stop); + void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); + template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); + size_t GetTotalPCCoverage(); + void SetUseCounters(bool UC) { UseCounters = UC; } + void SetUseValueProfile(bool VP) { UseValueProfile = VP; } + void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } + void UpdateObservedPCs(); + template void CollectFeatures(Callback CB) const; + + void ResetMaps() { + ValueProfileMap.Reset(); + if (NumModules) + memset(Counters(), 0, GetNumPCs()); + ClearExtraCounters(); + ClearInlineCounters(); + } + + void ClearInlineCounters(); + + void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize); + void PrintFeatureSet(); + + void PrintModuleInfo(); + + void PrintCoverage(); + void DumpCoverage(); + + void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, + size_t n, bool StopAtZero); + + TableOfRecentCompares TORC4; + TableOfRecentCompares TORC8; + TableOfRecentCompares TORCW; + MemMemTable<1024> MMT; + + size_t GetNumPCs() const { + return NumGuards == 0 ? (1 << kTracePcBits) : Min(kNumPCs, NumGuards + 1); + } + uintptr_t GetPC(size_t Idx) { + assert(Idx < GetNumPCs()); + return PCs()[Idx]; + } + + void RecordCurrentStack() { + uintptr_t Stack = GetCurrentStack(); + if (Stack < LowestStack) + LowestStack = Stack; + } + void RecordInitialStack() { + InitialStack = GetCurrentStack(); + LowestStack = InitialStack; + } + uintptr_t GetCurrentStack() const { + return reinterpret_cast(__builtin_frame_address(0)); + } + uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; } + + template + void ForEachObservedPC(CallBack CB) { + for (auto PC : ObservedPCs) + CB(PC); + } + +private: + bool UseCounters = false; + bool UseValueProfile = false; + bool DoPrintNewPCs = false; + + struct Module { + uint32_t *Start, *Stop; + }; + + Module Modules[4096]; + size_t NumModules; // linker-initialized. + size_t NumGuards; // linker-initialized. + + struct { uint8_t *Start, *Stop; } ModuleCounters[4096]; + size_t NumModulesWithInline8bitCounters; // linker-initialized. + size_t NumInline8bitCounters; + + struct { const uintptr_t *Start, *Stop; } ModulePCTable[4096]; + size_t NumPCTables; + size_t NumPCsInPCTables; + + uint8_t *Counters() const; + uintptr_t *PCs() const; + + std::set ObservedPCs; + + ValueBitMap ValueProfileMap; + uintptr_t InitialStack, LowestStack; // Assume stack grows down. +}; + +template +// void Callback(size_t FirstFeature, size_t Idx, uint8_t Value); +ATTRIBUTE_NO_SANITIZE_ALL +void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End, + size_t FirstFeature, Callback Handle8bitCounter) { + typedef uintptr_t LargeType; + const size_t Step = sizeof(LargeType) / sizeof(uint8_t); + const size_t StepMask = Step - 1; + auto P = Begin; + // Iterate by 1 byte until either the alignment boundary or the end. + for (; reinterpret_cast(P) & StepMask && P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature, P - Begin, V); + + // Iterate by Step bytes at a time. + for (; P < End; P += Step) + if (LargeType Bundle = *reinterpret_cast(P)) + for (size_t I = 0; I < Step; I++, Bundle >>= 8) + if (uint8_t V = Bundle & 0xff) + Handle8bitCounter(FirstFeature, P - Begin + I, V); + + // Iterate by 1 byte until the end. + for (; P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature, P - Begin, V); +} + +template // bool Callback(size_t Feature) +ATTRIBUTE_NO_SANITIZE_ADDRESS +__attribute__((noinline)) +void TracePC::CollectFeatures(Callback HandleFeature) const { + uint8_t *Counters = this->Counters(); + size_t N = GetNumPCs(); + auto Handle8bitCounter = [&](size_t FirstFeature, + size_t Idx, uint8_t Counter) { + assert(Counter); + unsigned Bit = 0; + /**/ if (Counter >= 128) Bit = 7; + else if (Counter >= 32) Bit = 6; + else if (Counter >= 16) Bit = 5; + else if (Counter >= 8) Bit = 4; + else if (Counter >= 4) Bit = 3; + else if (Counter >= 3) Bit = 2; + else if (Counter >= 2) Bit = 1; + HandleFeature(FirstFeature + Idx * 8 + Bit); + }; + + size_t FirstFeature = 0; + + if (!NumInline8bitCounters) { + ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter); + FirstFeature += N * 8; + } + + if (NumInline8bitCounters) { + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + ForEachNonZeroByte(ModuleCounters[i].Start, ModuleCounters[i].Stop, + FirstFeature, Handle8bitCounter); + FirstFeature += 8 * (ModuleCounters[i].Stop - ModuleCounters[i].Start); + } + } + + ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature, + Handle8bitCounter); + FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8; + + if (UseValueProfile) { + ValueProfileMap.ForEach([&](size_t Idx) { + HandleFeature(FirstFeature + Idx); + }); + FirstFeature += ValueProfileMap.SizeInBits(); + } + + if (auto MaxStackOffset = GetMaxStackOffset()) + HandleFeature(FirstFeature + MaxStackOffset); +} + +extern TracePC TPC; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_TRACE_PC diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp new file mode 100644 index 000000000..f5a777374 --- /dev/null +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -0,0 +1,215 @@ +//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils. +//===----------------------------------------------------------------------===// + +#include "FuzzerUtil.h" +#include "FuzzerIO.h" +#include "FuzzerInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +void PrintHexArray(const uint8_t *Data, size_t Size, + const char *PrintAfter) { + for (size_t i = 0; i < Size; i++) + Printf("0x%x,", (unsigned)Data[i]); + Printf("%s", PrintAfter); +} + +void Print(const Unit &v, const char *PrintAfter) { + PrintHexArray(v.data(), v.size(), PrintAfter); +} + +void PrintASCIIByte(uint8_t Byte) { + if (Byte == '\\') + Printf("\\\\"); + else if (Byte == '"') + Printf("\\\""); + else if (Byte >= 32 && Byte < 127) + Printf("%c", Byte); + else + Printf("\\x%02x", Byte); +} + +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { + for (size_t i = 0; i < Size; i++) + PrintASCIIByte(Data[i]); + Printf("%s", PrintAfter); +} + +void PrintASCII(const Unit &U, const char *PrintAfter) { + PrintASCII(U.data(), U.size(), PrintAfter); +} + +bool ToASCII(uint8_t *Data, size_t Size) { + bool Changed = false; + for (size_t i = 0; i < Size; i++) { + uint8_t &X = Data[i]; + auto NewX = X; + NewX &= 127; + if (!isspace(NewX) && !isprint(NewX)) + NewX = ' '; + Changed |= NewX != X; + X = NewX; + } + return Changed; +} + +bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } + +bool IsASCII(const uint8_t *Data, size_t Size) { + for (size_t i = 0; i < Size; i++) + if (!(isprint(Data[i]) || isspace(Data[i]))) return false; + return true; +} + +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { + U->clear(); + if (Str.empty()) return false; + size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. + // Skip spaces from both sides. + while (L < R && isspace(Str[L])) L++; + while (R > L && isspace(Str[R])) R--; + if (R - L < 2) return false; + // Check the closing " + if (Str[R] != '"') return false; + R--; + // Find the opening " + while (L < R && Str[L] != '"') L++; + if (L >= R) return false; + assert(Str[L] == '\"'); + L++; + assert(L <= R); + for (size_t Pos = L; Pos <= R; Pos++) { + uint8_t V = (uint8_t)Str[Pos]; + if (!isprint(V) && !isspace(V)) return false; + if (V =='\\') { + // Handle '\\' + if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { + U->push_back(Str[Pos + 1]); + Pos++; + continue; + } + // Handle '\xAB' + if (Pos + 3 <= R && Str[Pos + 1] == 'x' + && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { + char Hex[] = "0xAA"; + Hex[2] = Str[Pos + 2]; + Hex[3] = Str[Pos + 3]; + U->push_back(strtol(Hex, nullptr, 16)); + Pos += 3; + continue; + } + return false; // Invalid escape. + } else { + // Any other character. + U->push_back(V); + } + } + return true; +} + +bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { + if (Text.empty()) { + Printf("ParseDictionaryFile: file does not exist or is empty\n"); + return false; + } + std::istringstream ISS(Text); + Units->clear(); + Unit U; + int LineNo = 0; + std::string S; + while (std::getline(ISS, S, '\n')) { + LineNo++; + size_t Pos = 0; + while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces. + if (Pos == S.size()) continue; // Empty line. + if (S[Pos] == '#') continue; // Comment line. + if (ParseOneDictionaryEntry(S, &U)) { + Units->push_back(U); + } else { + Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo, + S.c_str()); + return false; + } + } + return true; +} + +std::string Base64(const Unit &U) { + static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + std::string Res; + size_t i; + for (i = 0; i + 2 < U.size(); i += 3) { + uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2]; + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += Table[(x >> 6) & 63]; + Res += Table[x & 63]; + } + if (i + 1 == U.size()) { + uint32_t x = (U[i] << 16); + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += "=="; + } else if (i + 2 == U.size()) { + uint32_t x = (U[i] << 16) + (U[i + 1] << 8); + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += Table[(x >> 6) & 63]; + Res += "="; + } + return Res; +} + +std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { + if (!EF->__sanitizer_symbolize_pc) return ""; + char PcDescr[1024]; + EF->__sanitizer_symbolize_pc(reinterpret_cast(PC), + SymbolizedFMT, PcDescr, sizeof(PcDescr)); + PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. + return PcDescr; +} + +void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { + if (EF->__sanitizer_symbolize_pc) + Printf("%s", DescribePC(SymbolizedFMT, PC).c_str()); + else + Printf(FallbackFMT, PC); +} + +unsigned NumberOfCpuCores() { + unsigned N = std::thread::hardware_concurrency(); + if (!N) { + Printf("WARNING: std::thread::hardware_concurrency not well defined for " + "your platform. Assuming CPU count of 1.\n"); + N = 1; + } + return N; +} + +size_t SimpleFastHash(const uint8_t *Data, size_t Size) { + size_t Res = 0; + for (size_t i = 0; i < Size; i++) + Res = Res * 11 + Data[i]; + return Res; +} + +} // namespace fuzzer diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h new file mode 100644 index 000000000..9c90040b0 --- /dev/null +++ b/lib/fuzzer/FuzzerUtil.h @@ -0,0 +1,84 @@ +//===- FuzzerUtil.h - Internal header for the Fuzzer Utils ------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Util functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_UTIL_H +#define LLVM_FUZZER_UTIL_H + +#include "FuzzerDefs.h" + +namespace fuzzer { + +void PrintHexArray(const Unit &U, const char *PrintAfter = ""); + +void PrintHexArray(const uint8_t *Data, size_t Size, + const char *PrintAfter = ""); + +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); + +void PrintASCII(const Unit &U, const char *PrintAfter = ""); + +// Changes U to contain only ASCII (isprint+isspace) characters. +// Returns true iff U has been changed. +bool ToASCII(uint8_t *Data, size_t Size); + +bool IsASCII(const Unit &U); + +bool IsASCII(const uint8_t *Data, size_t Size); + +std::string Base64(const Unit &U); + +void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); + +std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC); + +unsigned NumberOfCpuCores(); + +// Platform specific functions. +void SetSignalHandler(const FuzzingOptions& Options); + +void SleepSeconds(int Seconds); + +unsigned long GetPid(); + +size_t GetPeakRSSMb(); + +int ExecuteCommand(const std::string &Command); + +FILE *OpenProcessPipe(const char *Command, const char *Mode); + +const void *SearchMemory(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); + +std::string CloneArgsWithoutX(const std::vector &Args, + const char *X1, const char *X2); + +inline std::string CloneArgsWithoutX(const std::vector &Args, + const char *X) { + return CloneArgsWithoutX(Args, X, X); +} + +inline std::pair SplitBefore(std::string X, + std::string S) { + auto Pos = S.find(X); + if (Pos == std::string::npos) + return std::make_pair(S, ""); + return std::make_pair(S.substr(0, Pos), S.substr(Pos)); +} + +std::string DisassembleCmd(const std::string &FileName); + +std::string SearchRegexCmd(const std::string &Regex); + +size_t SimpleFastHash(const uint8_t *Data, size_t Size); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_UTIL_H diff --git a/lib/fuzzer/FuzzerUtilDarwin.cpp b/lib/fuzzer/FuzzerUtilDarwin.cpp new file mode 100644 index 000000000..2df4872a9 --- /dev/null +++ b/lib/fuzzer/FuzzerUtilDarwin.cpp @@ -0,0 +1,161 @@ +//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils for Darwin. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_APPLE + +#include "FuzzerIO.h" +#include +#include +#include +#include +#include +#include + +// There is no header for this on macOS so declare here +extern "C" char **environ; + +namespace fuzzer { + +static std::mutex SignalMutex; +// Global variables used to keep track of how signal handling should be +// restored. They should **not** be accessed without holding `SignalMutex`. +static int ActiveThreadCount = 0; +static struct sigaction OldSigIntAction; +static struct sigaction OldSigQuitAction; +static sigset_t OldBlockedSignalsSet; + +// This is a reimplementation of Libc's `system()`. On Darwin the Libc +// implementation contains a mutex which prevents it from being used +// concurrently. This implementation **can** be used concurrently. It sets the +// signal handlers when the first thread enters and restores them when the last +// thread finishes execution of the function and ensures this is not racey by +// using a mutex. +int ExecuteCommand(const std::string &Command) { + posix_spawnattr_t SpawnAttributes; + if (posix_spawnattr_init(&SpawnAttributes)) + return -1; + // Block and ignore signals of the current process when the first thread + // enters. + { + std::lock_guard Lock(SignalMutex); + if (ActiveThreadCount == 0) { + static struct sigaction IgnoreSignalAction; + sigset_t BlockedSignalsSet; + memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction)); + IgnoreSignalAction.sa_handler = SIG_IGN; + + if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) { + Printf("Failed to ignore SIGINT\n"); + (void)posix_spawnattr_destroy(&SpawnAttributes); + return -1; + } + if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) { + Printf("Failed to ignore SIGQUIT\n"); + // Try our best to restore the signal handlers. + (void)sigaction(SIGINT, &OldSigIntAction, NULL); + (void)posix_spawnattr_destroy(&SpawnAttributes); + return -1; + } + + (void)sigemptyset(&BlockedSignalsSet); + (void)sigaddset(&BlockedSignalsSet, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) == + -1) { + Printf("Failed to block SIGCHLD\n"); + // Try our best to restore the signal handlers. + (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL); + (void)sigaction(SIGINT, &OldSigIntAction, NULL); + (void)posix_spawnattr_destroy(&SpawnAttributes); + return -1; + } + } + ++ActiveThreadCount; + } + + // NOTE: Do not introduce any new `return` statements past this + // point. It is important that `ActiveThreadCount` always be decremented + // when leaving this function. + + // Make sure the child process uses the default handlers for the + // following signals rather than inheriting what the parent has. + sigset_t DefaultSigSet; + (void)sigemptyset(&DefaultSigSet); + (void)sigaddset(&DefaultSigSet, SIGQUIT); + (void)sigaddset(&DefaultSigSet, SIGINT); + (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet); + // Make sure the child process doesn't block SIGCHLD + (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet); + short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; + (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags); + + pid_t Pid; + char **Environ = environ; // Read from global + const char *CommandCStr = Command.c_str(); + char *const Argv[] = { + strdup("sh"), + strdup("-c"), + strdup(CommandCStr), + NULL + }; + int ErrorCode = 0, ProcessStatus = 0; + // FIXME: We probably shouldn't hardcode the shell path. + ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes, + Argv, Environ); + (void)posix_spawnattr_destroy(&SpawnAttributes); + if (!ErrorCode) { + pid_t SavedPid = Pid; + do { + // Repeat until call completes uninterrupted. + Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0); + } while (Pid == -1 && errno == EINTR); + if (Pid == -1) { + // Fail for some other reason. + ProcessStatus = -1; + } + } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) { + // Fork failure. + ProcessStatus = -1; + } else { + // Shell execution failure. + ProcessStatus = W_EXITCODE(127, 0); + } + for (unsigned i = 0, n = sizeof(Argv) / sizeof(Argv[0]); i < n; ++i) + free(Argv[i]); + + // Restore the signal handlers of the current process when the last thread + // using this function finishes. + { + std::lock_guard Lock(SignalMutex); + --ActiveThreadCount; + if (ActiveThreadCount == 0) { + bool FailedRestore = false; + if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) { + Printf("Failed to restore SIGINT handling\n"); + FailedRestore = true; + } + if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) { + Printf("Failed to restore SIGQUIT handling\n"); + FailedRestore = true; + } + if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) { + Printf("Failed to unblock SIGCHLD\n"); + FailedRestore = true; + } + if (FailedRestore) + ProcessStatus = -1; + } + } + return ProcessStatus; +} + +} // namespace fuzzer + +#endif // LIBFUZZER_APPLE diff --git a/lib/fuzzer/FuzzerUtilLinux.cpp b/lib/fuzzer/FuzzerUtilLinux.cpp new file mode 100644 index 000000000..dfe7e6f4e --- /dev/null +++ b/lib/fuzzer/FuzzerUtilLinux.cpp @@ -0,0 +1,24 @@ +//===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils for Linux. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_LINUX + +#include + +namespace fuzzer { + +int ExecuteCommand(const std::string &Command) { + return system(Command.c_str()); +} + +} // namespace fuzzer + +#endif // LIBFUZZER_LINUX diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp new file mode 100644 index 000000000..bc85264ac --- /dev/null +++ b/lib/fuzzer/FuzzerUtilPosix.cpp @@ -0,0 +1,144 @@ +//===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils implementation using Posix API. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_POSIX +#include "FuzzerIO.h" +#include "FuzzerInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +static void AlarmHandler(int, siginfo_t *, void *) { + Fuzzer::StaticAlarmCallback(); +} + +static void CrashHandler(int, siginfo_t *, void *) { + Fuzzer::StaticCrashSignalCallback(); +} + +static void InterruptHandler(int, siginfo_t *, void *) { + Fuzzer::StaticInterruptCallback(); +} + +static void FileSizeExceedHandler(int, siginfo_t *, void *) { + Fuzzer::StaticFileSizeExceedCallback(); +} + +static void SetSigaction(int signum, + void (*callback)(int, siginfo_t *, void *)) { + struct sigaction sigact = {}; + if (sigaction(signum, nullptr, &sigact)) { + Printf("libFuzzer: sigaction failed with %d\n", errno); + exit(1); + } + 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; + } + + sigact = {}; + sigact.sa_sigaction = callback; + if (sigaction(signum, &sigact, 0)) { + Printf("libFuzzer: sigaction failed with %d\n", errno); + exit(1); + } +} + +void SetTimer(int Seconds) { + struct itimerval T { + {Seconds, 0}, { Seconds, 0 } + }; + if (setitimer(ITIMER_REAL, &T, nullptr)) { + Printf("libFuzzer: setitimer failed with %d\n", errno); + exit(1); + } + SetSigaction(SIGALRM, AlarmHandler); +} + +void SetSignalHandler(const FuzzingOptions& Options) { + if (Options.UnitTimeoutSec > 0) + SetTimer(Options.UnitTimeoutSec / 2 + 1); + if (Options.HandleInt) + SetSigaction(SIGINT, InterruptHandler); + if (Options.HandleTerm) + SetSigaction(SIGTERM, InterruptHandler); + if (Options.HandleSegv) + SetSigaction(SIGSEGV, CrashHandler); + if (Options.HandleBus) + SetSigaction(SIGBUS, CrashHandler); + if (Options.HandleAbrt) + SetSigaction(SIGABRT, CrashHandler); + if (Options.HandleIll) + SetSigaction(SIGILL, CrashHandler); + if (Options.HandleFpe) + SetSigaction(SIGFPE, CrashHandler); + if (Options.HandleXfsz) + SetSigaction(SIGXFSZ, FileSizeExceedHandler); +} + +void SleepSeconds(int Seconds) { + sleep(Seconds); // Use C API to avoid coverage from instrumented libc++. +} + +unsigned long GetPid() { return (unsigned long)getpid(); } + +size_t GetPeakRSSMb() { + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage)) + return 0; + if (LIBFUZZER_LINUX) { + // ru_maxrss is in KiB + return usage.ru_maxrss >> 10; + } else if (LIBFUZZER_APPLE) { + // ru_maxrss is in bytes + return usage.ru_maxrss >> 20; + } + assert(0 && "GetPeakRSSMb() is not implemented for your platform"); + return 0; +} + +FILE *OpenProcessPipe(const char *Command, const char *Mode) { + return popen(Command, Mode); +} + +const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, + size_t PattLen) { + return memmem(Data, DataLen, Patt, PattLen); +} + +std::string DisassembleCmd(const std::string &FileName) { + return "objdump -d " + FileName; +} + +std::string SearchRegexCmd(const std::string &Regex) { + return "grep '" + Regex + "'"; +} + +} // namespace fuzzer + +#endif // LIBFUZZER_POSIX diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp new file mode 100644 index 000000000..25ac976fc --- /dev/null +++ b/lib/fuzzer/FuzzerUtilWindows.cpp @@ -0,0 +1,193 @@ +//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils implementation for Windows. +//===----------------------------------------------------------------------===// +#include "FuzzerDefs.h" +#if LIBFUZZER_WINDOWS +#include "FuzzerIO.h" +#include "FuzzerInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This must be included after windows.h. +#include + +namespace fuzzer { + +static const FuzzingOptions* HandlerOpt = nullptr; + +static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_STACK_OVERFLOW: + if (HandlerOpt->HandleSegv) + Fuzzer::StaticCrashSignalCallback(); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_IN_PAGE_ERROR: + if (HandlerOpt->HandleBus) + Fuzzer::StaticCrashSignalCallback(); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + if (HandlerOpt->HandleIll) + Fuzzer::StaticCrashSignalCallback(); + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + if (HandlerOpt->HandleFpe) + Fuzzer::StaticCrashSignalCallback(); + break; + // TODO: handle (Options.HandleXfsz) + } + return EXCEPTION_CONTINUE_SEARCH; +} + +BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { + switch (dwCtrlType) { + case CTRL_C_EVENT: + if (HandlerOpt->HandleInt) + Fuzzer::StaticInterruptCallback(); + return TRUE; + case CTRL_BREAK_EVENT: + if (HandlerOpt->HandleTerm) + Fuzzer::StaticInterruptCallback(); + return TRUE; + } + return FALSE; +} + +void CALLBACK AlarmHandler(PVOID, BOOLEAN) { + Fuzzer::StaticAlarmCallback(); +} + +class TimerQ { + HANDLE TimerQueue; + public: + TimerQ() : TimerQueue(NULL) {}; + ~TimerQ() { + if (TimerQueue) + DeleteTimerQueueEx(TimerQueue, NULL); + }; + void SetTimer(int Seconds) { + if (!TimerQueue) { + TimerQueue = CreateTimerQueue(); + if (!TimerQueue) { + Printf("libFuzzer: CreateTimerQueue failed.\n"); + exit(1); + } + } + HANDLE Timer; + if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, + Seconds*1000, Seconds*1000, 0)) { + Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); + exit(1); + } + }; +}; + +static TimerQ Timer; + +static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } + +void SetSignalHandler(const FuzzingOptions& Options) { + HandlerOpt = &Options; + + if (Options.UnitTimeoutSec > 0) + Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); + + if (Options.HandleInt || Options.HandleTerm) + if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { + DWORD LastError = GetLastError(); + Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", + LastError); + exit(1); + } + + if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || + Options.HandleFpe) + SetUnhandledExceptionFilter(ExceptionHandler); + + if (Options.HandleAbrt) + if (SIG_ERR == signal(SIGABRT, CrashHandler)) { + Printf("libFuzzer: signal failed with %d\n", errno); + exit(1); + } +} + +void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } + +unsigned long GetPid() { return GetCurrentProcessId(); } + +size_t GetPeakRSSMb() { + PROCESS_MEMORY_COUNTERS info; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) + return 0; + return info.PeakWorkingSetSize >> 20; +} + +FILE *OpenProcessPipe(const char *Command, const char *Mode) { + return _popen(Command, Mode); +} + +int ExecuteCommand(const std::string &Command) { + return system(Command.c_str()); +} + +const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, + size_t PattLen) { + // TODO: make this implementation more efficient. + const char *Cdata = (const char *)Data; + const char *Cpatt = (const char *)Patt; + + if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) + return NULL; + + if (PattLen == 1) + return memchr(Data, *Cpatt, DataLen); + + const char *End = Cdata + DataLen - PattLen + 1; + + for (const char *It = Cdata; It < End; ++It) + if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) + return It; + + return NULL; +} + +std::string DisassembleCmd(const std::string &FileName) { + if (ExecuteCommand("dumpbin /summary > nul") == 0) + return "dumpbin /disasm " + FileName; + Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); + exit(1); +} + +std::string SearchRegexCmd(const std::string &Regex) { + return "findstr /r \"" + Regex + "\""; +} + +} // namespace fuzzer + +#endif // LIBFUZZER_WINDOWS diff --git a/lib/fuzzer/FuzzerValueBitMap.h b/lib/fuzzer/FuzzerValueBitMap.h new file mode 100644 index 000000000..13d7cbd95 --- /dev/null +++ b/lib/fuzzer/FuzzerValueBitMap.h @@ -0,0 +1,73 @@ +//===- FuzzerValueBitMap.h - INTERNAL - Bit map -----------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// ValueBitMap. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_VALUE_BIT_MAP_H +#define LLVM_FUZZER_VALUE_BIT_MAP_H + +#include "FuzzerDefs.h" + +namespace fuzzer { + +// A bit map containing kMapSizeInWords bits. +struct ValueBitMap { + static const size_t kMapSizeInBits = 1 << 16; + static const size_t kMapPrimeMod = 65371; // Largest Prime < kMapSizeInBits; + static const size_t kBitsInWord = (sizeof(uintptr_t) * 8); + static const size_t kMapSizeInWords = kMapSizeInBits / kBitsInWord; + public: + + // Clears all bits. + void Reset() { memset(Map, 0, sizeof(Map)); } + + // Computes a hash function of Value and sets the corresponding bit. + // Returns true if the bit was changed from 0 to 1. + ATTRIBUTE_NO_SANITIZE_ALL + inline bool AddValue(uintptr_t Value) { + uintptr_t Idx = Value % kMapSizeInBits; + uintptr_t WordIdx = Idx / kBitsInWord; + uintptr_t BitIdx = Idx % kBitsInWord; + uintptr_t Old = Map[WordIdx]; + uintptr_t New = Old | (1UL << BitIdx); + Map[WordIdx] = New; + return New != Old; + } + + ATTRIBUTE_NO_SANITIZE_ALL + inline bool AddValueModPrime(uintptr_t Value) { + return AddValue(Value % kMapPrimeMod); + } + + inline bool Get(uintptr_t Idx) { + assert(Idx < kMapSizeInBits); + uintptr_t WordIdx = Idx / kBitsInWord; + uintptr_t BitIdx = Idx % kBitsInWord; + return Map[WordIdx] & (1UL << BitIdx); + } + + size_t SizeInBits() const { return kMapSizeInBits; } + + template + ATTRIBUTE_NO_SANITIZE_ALL + void ForEach(Callback CB) const { + for (size_t i = 0; i < kMapSizeInWords; i++) + if (uintptr_t M = Map[i]) + for (size_t j = 0; j < sizeof(M) * 8; j++) + if (M & ((uintptr_t)1 << j)) + CB(i * sizeof(M) * 8 + j); + } + + private: + uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_VALUE_BIT_MAP_H diff --git a/lib/fuzzer/README.txt b/lib/fuzzer/README.txt new file mode 100644 index 000000000..79f49b550 --- /dev/null +++ b/lib/fuzzer/README.txt @@ -0,0 +1,2 @@ +Move to http://llvm.org/docs/LibFuzzer.html + diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp new file mode 100644 index 000000000..15bceb896 --- /dev/null +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -0,0 +1,335 @@ +//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===// + +/* This file allows to fuzz libFuzzer-style target functions + (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. + +Usage: +################################################################################ +cat << EOF > test_fuzzer.cc +#include +#include +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size > 0 && data[0] == 'H') + if (size > 1 && data[1] == 'I') + if (size > 2 && data[2] == '!') + __builtin_trap(); + return 0; +} +EOF +# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. +clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c +# Build afl-llvm-rt.o.c from the AFL distribution. +clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c +# Build this file, link it with afl-llvm-rt.o.o and the target code. +clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o +# Run AFL: +rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; +$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out +################################################################################ +Environment Variables: +There are a few environment variables that can be set to use features that +afl-fuzz doesn't have. + +AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file +specified. If the file does not exist, it is created. This is useful for getting +stack traces (when using ASAN for example) or original error messages on hard to +reproduce bugs. + +AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra +statistics to the file specified. Currently these are peak_rss_mb +(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If +the file does not exist it is created. If the file does exist then +afl_driver assumes it was restarted by afl-fuzz and will try to read old +statistics from the file. If that fails then the process will quit. + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Platform detection. Copied from FuzzerInternal.h +#ifdef __linux__ +#define LIBFUZZER_LINUX 1 +#define LIBFUZZER_APPLE 0 +#elif __APPLE__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 1 +#else +#error "Support for your platform has not been implemented" +#endif + +// Used to avoid repeating error checking boilerplate. If cond is false, a +// fatal error has occured in the program. In this event print error_message +// to stderr and abort(). Otherwise do nothing. Note that setting +// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended +// to the file as well, if the error occurs after the duplication is performed. +#define CHECK_ERROR(cond, error_message) \ + if (!(cond)) { \ + fprintf(stderr, (error_message)); \ + abort(); \ + } + +// libFuzzer interface is thin, so we don't include any libFuzzer headers. +extern "C" { +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); +} + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +extern "C" int __afl_persistent_loop(unsigned int); +static volatile char suppress_warning2 = AFL_PERSISTENT[0]; + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +extern "C" void __afl_manual_init(); +static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; + +// Input buffer. +static const size_t kMaxAflInputSize = 1 << 20; +static uint8_t AflInputBuf[kMaxAflInputSize]; + +// Variables we need for writing to the extra stats file. +static FILE *extra_stats_file = NULL; +static uint32_t previous_peak_rss = 0; +static time_t slowest_unit_time_secs = 0; +static const int kNumExtraStats = 2; +static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n" + "slowest_unit_time_sec : %u\n"; + +// Copied from FuzzerUtil.cpp. +size_t GetPeakRSSMb() { + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage)) + return 0; + if (LIBFUZZER_LINUX) { + // ru_maxrss is in KiB + return usage.ru_maxrss >> 10; + } else if (LIBFUZZER_APPLE) { + // ru_maxrss is in bytes + return usage.ru_maxrss >> 20; + } + assert(0 && "GetPeakRSSMb() is not implemented for your platform"); + return 0; +} + +// Based on SetSigaction in FuzzerUtil.cpp +static void SetSigaction(int signum, + void (*callback)(int, siginfo_t *, void *)) { + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = callback; + if (sigaction(signum, &sigact, 0)) { + fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno); + exit(1); + } +} + +// Write extra stats to the file specified by the user. If none is specified +// this function will never be called. +static void write_extra_stats() { + uint32_t peak_rss = GetPeakRSSMb(); + + if (peak_rss < previous_peak_rss) + peak_rss = previous_peak_rss; + + int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString, + peak_rss, slowest_unit_time_secs); + + CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file"); + + CHECK_ERROR(fclose(extra_stats_file) == 0, + "Failed to close extra_stats_file"); +} + +// Call write_extra_stats before we exit. +static void crash_handler(int, siginfo_t *, void *) { + // Make sure we don't try calling write_extra_stats again if we crashed while + // trying to call it. + static bool first_crash = true; + CHECK_ERROR(first_crash, + "Crashed in crash signal handler. This is a bug in the fuzzer."); + + first_crash = false; + write_extra_stats(); +} + +// If the user has specified an extra_stats_file through the environment +// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up +// to write stats to it on exit. If no file is specified, do nothing. Otherwise +// install signal and exit handlers to write to the file when the process exits. +// Then if the file doesn't exist create it and set extra stats to 0. But if it +// does exist then read the initial values of the extra stats from the file +// and check that the file is writable. +static void maybe_initialize_extra_stats() { + // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do. + char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME"); + if (!extra_stats_filename) + return; + + // Open the file and find the previous peak_rss_mb value. + // This is necessary because the fuzzing process is restarted after N + // iterations are completed. So we may need to get this value from a previous + // process to be accurate. + extra_stats_file = fopen(extra_stats_filename, "r"); + + // If extra_stats_file already exists: read old stats from it. + if (extra_stats_file) { + int matches = fscanf(extra_stats_file, kExtraStatsFormatString, + &previous_peak_rss, &slowest_unit_time_secs); + + // Make sure we have read a real extra stats file and that we have used it + // to set slowest_unit_time_secs and previous_peak_rss. + CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt"); + + CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file"); + + // Now open the file for writing. + extra_stats_file = fopen(extra_stats_filename, "w"); + CHECK_ERROR(extra_stats_file, + "Failed to open extra stats file for writing"); + } else { + // Looks like this is the first time in a fuzzing job this is being called. + extra_stats_file = fopen(extra_stats_filename, "w+"); + CHECK_ERROR(extra_stats_file, "failed to create extra stats file"); + } + + // Make sure that crash_handler gets called on any kind of fatal error. + int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT, + SIGTERM}; + + const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]); + + for (size_t idx = 0; idx < num_signals; idx++) + SetSigaction(crash_signals[idx], crash_handler); + + // Make sure it gets called on other kinds of exits. + atexit(write_extra_stats); +} + +// If the user asks us to duplicate stderr, then do it. +static void maybe_duplicate_stderr() { + char* stderr_duplicate_filename = + getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + + if (!stderr_duplicate_filename) + return; + + FILE* stderr_duplicate_stream = + freopen(stderr_duplicate_filename, "a+", stderr); + + if (!stderr_duplicate_stream) { + fprintf( + stderr, + "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + abort(); + } +} + +// Define LLVMFuzzerMutate to avoid link failures for targets that use it +// with libFuzzer's LLVMFuzzerCustomMutator. +extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); + return 0; +} + +// Execute any files provided as parameters. +int ExecuteFilesOnyByOne(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + std::ifstream in(argv[i]); + in.seekg(0, in.end); + size_t length = in.tellg(); + in.seekg (0, in.beg); + std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl; + // Allocate exactly length bytes so that we reliably catch buffer overflows. + std::vector bytes(length); + in.read(bytes.data(), bytes.size()); + assert(in); + LLVMFuzzerTestOneInput(reinterpret_cast(bytes.data()), + bytes.size()); + std::cout << "Execution successfull" << std::endl; + } + return 0; +} + +int main(int argc, char **argv) { + fprintf(stderr, + "======================= INFO =========================\n" + "This binary is built for AFL-fuzz.\n" + "To run the target function on individual input(s) execute this:\n" + " %s < INPUT_FILE\n" + "or\n" + " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" + "To fuzz with afl-fuzz execute this:\n" + " afl-fuzz [afl-flags] %s [-N]\n" + "afl-fuzz will run N iterations before " + "re-spawning the process (default: 1000)\n" + "======================================================\n", + argv[0], argv[0], argv[0]); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + // Do any other expensive one-time initialization here. + + maybe_duplicate_stderr(); + maybe_initialize_extra_stats(); + + __afl_manual_init(); + + int N = 1000; + if (argc == 2 && argv[1][0] == '-') + N = atoi(argv[1] + 1); + else if(argc == 2 && (N = atoi(argv[1])) > 0) + fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n", + argv[0], N); + else if (argc > 1) + return ExecuteFilesOnyByOne(argc, argv); + + assert(N > 0); + time_t unit_time_secs; + int num_runs = 0; + while (__afl_persistent_loop(N)) { + ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); + if (n_read > 0) { + // Copy AflInputBuf into a separate buffer to let asan find buffer + // overflows. Don't use unique_ptr/etc to avoid extra dependencies. + uint8_t *copy = new uint8_t[n_read]; + memcpy(copy, AflInputBuf, n_read); + + struct timeval unit_start_time; + CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0, + "Calling gettimeofday failed"); + + num_runs++; + LLVMFuzzerTestOneInput(copy, n_read); + + struct timeval unit_stop_time; + CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0, + "Calling gettimeofday failed"); + + // Update slowest_unit_time_secs if we see a new max. + unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec; + if (slowest_unit_time_secs < unit_time_secs) + slowest_unit_time_secs = unit_time_secs; + + delete[] copy; + } + } + fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); +} diff --git a/lib/fuzzer/build.sh b/lib/fuzzer/build.sh new file mode 100755 index 000000000..4556af5da --- /dev/null +++ b/lib/fuzzer/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +LIBFUZZER_SRC_DIR=$(dirname $0) +CXX="${CXX:-clang}" +for f in $LIBFUZZER_SRC_DIR/*.cpp; do + $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c & +done +wait +rm -f libFuzzer.a +ar ru libFuzzer.a Fuzzer*.o +rm -f Fuzzer*.o + diff --git a/lib/fuzzer/cxx.dict b/lib/fuzzer/cxx.dict new file mode 100644 index 000000000..41350f475 --- /dev/null +++ b/lib/fuzzer/cxx.dict @@ -0,0 +1,122 @@ +"++" +"--" +"<<" +">>" +"+=" +"-=" +"*=" +"/=" +">>=" +"<<=" +"&=" +"|=" +"^=" +"%=" +"!=" +"&&" +"||" +"==" +">=" +"<=" +"->" +"alignas" +"alignof" +"and" +"and_eq" +"asm" +"auto" +"bitand" +"bitor" +"bool" +"break" +"case" +"catch" +"char" +"char16_t" +"char32_t" +"class" +"compl" +"concept" +"const" +"constexpr" +"const_cast" +"continue" +"decltype" +"default" +"delete" +"do" +"double" +"dynamic_cast" +"else" +"enum" +"explicit" +"export" +"extern" +"false" +"float" +"for" +"friend" +"goto" +"if" +"inline" +"int" +"long" +"mutable" +"namespace" +"new" +"noexcept" +"not" +"not_eq" +"nullptr" +"operator" +"or" +"or_eq" +"private" +"protected" +"public" +"register" +"reinterpret_cast" +"requires" +"return" +"short" +"signed" +"sizeof" +"static" +"static_assert" +"static_cast" +"struct" +"switch" +"template" +"this" +"thread_local" +"throw" +"true" +"try" +"typedef" +"typeid" +"typename" +"union" +"unsigned" +"using" +"virtual" +"void" +"volatile" +"wchar_t" +"while" +"xor" +"xor_eq" +"if" +"elif" +"else" +"endif" +"defined" +"ifdef" +"ifndef" +"define" +"undef" +"include" +"line" +"error" +"pragma" +"override" +"final" diff --git a/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c b/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c new file mode 100644 index 000000000..0d76ea49e --- /dev/null +++ b/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c @@ -0,0 +1,41 @@ +/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This main() function can be linked to a fuzz target (i.e. a library +// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) +// instead of libFuzzer. This main() function will not perform any fuzzing +// but will simply feed all input files one by one to the fuzz target. +// +// Use this file to provide reproducers for bugs when linking against libFuzzer +// or other fuzzing engine is undesirable. +//===----------------------------------------------------------------------===*/ +#include +#include +#include + +extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); +int main(int argc, char **argv) { + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + for (int i = 1; i < argc; i++) { + fprintf(stderr, "Running: %s\n", argv[i]); + FILE *f = fopen(argv[i], "r"); + assert(f); + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + fseek(f, 0, SEEK_SET); + unsigned char *buf = (unsigned char*)malloc(len); + size_t n_read = fread(buf, 1, len, f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); + } +} diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt new file mode 100644 index 000000000..dac877359 --- /dev/null +++ b/lib/fuzzer/tests/CMakeLists.txt @@ -0,0 +1,46 @@ +set(LIBFUZZER_UNITTEST_CFLAGS + ${COMPILER_RT_UNITTEST_CFLAGS} + ${COMPILER_RT_GTEST_CFLAGS} + -I${COMPILER_RT_SOURCE_DIR}/lib/fuzzer + -fno-rtti + -Werror + -O2) + +add_custom_target(FuzzerUnitTests) +set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT Tests") + +set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS}) +list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++) + +if(APPLE) + list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++) +else() + list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread) +endif() + +foreach(arch ${FUZZER_SUPPORTED_ARCH}) + set(LIBFUZZER_TEST_RUNTIME RTFuzzerTest.${arch}) + if(APPLE) + set(LIBFUZZER_TEST_RUNTIME_OBJECTS + $) + else() + set(LIBFUZZER_TEST_RUNTIME_OBJECTS + $) + endif() + add_library(${LIBFUZZER_TEST_RUNTIME} STATIC + ${LIBFUZZER_TEST_RUNTIME_OBJECTS}) + set_target_properties(${LIBFUZZER_TEST_RUNTIME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + FOLDER "Compiler-RT Runtime tests") + + set(FuzzerTestObjects) + generate_compiler_rt_tests(FuzzerTestObjects + FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch} + SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE} + RUNTIME ${LIBFUZZER_TEST_RUNTIME} + DEPS gtest + CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} + LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS}) + set_target_properties(FuzzerUnitTests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +endforeach() diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp new file mode 100644 index 000000000..858e61d75 --- /dev/null +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -0,0 +1,768 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Avoid ODR violations (LibFuzzer is built without ASan and this test is built +// with ASan) involving C++ standard library types when using libcxx. +#define _LIBCPP_HAS_NO_ASAN + +// Do not attempt to use LLVM ostream from gtest. +#define GTEST_NO_LLVM_RAW_OSTREAM 1 + +#include "FuzzerCorpus.h" +#include "FuzzerDictionary.h" +#include "FuzzerInternal.h" +#include "FuzzerMerge.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" +#include "FuzzerTracePC.h" +#include "gtest/gtest.h" +#include +#include +#include + +using namespace fuzzer; + +// For now, have LLVMFuzzerTestOneInput just to make it link. +// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + abort(); +} + +TEST(Fuzzer, CrossOver) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + Unit A({0, 1, 2}), B({5, 6, 7}); + Unit C; + Unit Expected[] = { + { 0 }, + { 0, 1 }, + { 0, 5 }, + { 0, 1, 2 }, + { 0, 1, 5 }, + { 0, 5, 1 }, + { 0, 5, 6 }, + { 0, 1, 2, 5 }, + { 0, 1, 5, 2 }, + { 0, 1, 5, 6 }, + { 0, 5, 1, 2 }, + { 0, 5, 1, 6 }, + { 0, 5, 6, 1 }, + { 0, 5, 6, 7 }, + { 0, 1, 2, 5, 6 }, + { 0, 1, 5, 2, 6 }, + { 0, 1, 5, 6, 2 }, + { 0, 1, 5, 6, 7 }, + { 0, 5, 1, 2, 6 }, + { 0, 5, 1, 6, 2 }, + { 0, 5, 1, 6, 7 }, + { 0, 5, 6, 1, 2 }, + { 0, 5, 6, 1, 7 }, + { 0, 5, 6, 7, 1 }, + { 0, 1, 2, 5, 6, 7 }, + { 0, 1, 5, 2, 6, 7 }, + { 0, 1, 5, 6, 2, 7 }, + { 0, 1, 5, 6, 7, 2 }, + { 0, 5, 1, 2, 6, 7 }, + { 0, 5, 1, 6, 2, 7 }, + { 0, 5, 1, 6, 7, 2 }, + { 0, 5, 6, 1, 2, 7 }, + { 0, 5, 6, 1, 7, 2 }, + { 0, 5, 6, 7, 1, 2 } + }; + for (size_t Len = 1; Len < 8; Len++) { + std::set FoundUnits, ExpectedUnitsWitThisLength; + for (int Iter = 0; Iter < 3000; Iter++) { + C.resize(Len); + size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(), + C.data(), C.size()); + C.resize(NewSize); + FoundUnits.insert(C); + } + for (const Unit &U : Expected) + if (U.size() <= Len) + ExpectedUnitsWitThisLength.insert(U); + EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits); + } +} + +TEST(Fuzzer, Hash) { + uint8_t A[] = {'a', 'b', 'c'}; + fuzzer::Unit U(A, A + sizeof(A)); + EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U)); + U.push_back('d'); + EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U)); +} + +typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, + size_t MaxSize); + +void TestEraseBytes(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77}; + uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77}; + uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77}; + uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + + uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; + uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77}; + + uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44}; + uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77}; + + + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T)); + if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4; + if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5; + if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6; + if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7; + + if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8; + if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9; + if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10; + + if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11; + if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12; + if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13; + } + EXPECT_EQ(FoundMask, (1 << 14) - 1); +} + +TEST(FuzzerMutate, EraseBytes1) { + TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200); +} +TEST(FuzzerMutate, EraseBytes2) { + TestEraseBytes(&MutationDispatcher::Mutate, 2000); +} + +void TestInsertByte(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66}; + uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66}; + uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66}; + uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + size_t NewSize = (MD.*M)(T, 7, 8); + if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, InsertByte1) { + TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15); +} +TEST(FuzzerMutate, InsertByte2) { + TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); +} + +void TestInsertRepeatedBytes(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'}; + uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33}; + uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33}; + uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33}; + uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33}; + + uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'}; + uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33}; + uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33}; + uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33}; + uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33}; + + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33}; + size_t NewSize = (MD.*M)(T, 4, 8); + if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4; + + if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; + if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8; + if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9; + + } + EXPECT_EQ(FoundMask, (1 << 10) - 1); +} + +TEST(FuzzerMutate, InsertRepeatedBytes1) { + TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000); +} +TEST(FuzzerMutate, InsertRepeatedBytes2) { + TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000); +} + +void TestChangeByte(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77}; + uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77}; + uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77}; + uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 8, 9); + if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, ChangeByte1) { + TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15); +} +TEST(FuzzerMutate, ChangeByte2) { + TestChangeByte(&MutationDispatcher::Mutate, 1 << 17); +} + +void TestChangeBit(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77}; + uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77}; + uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77}; + uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 8, 9); + if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, ChangeBit1) { + TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16); +} +TEST(FuzzerMutate, ChangeBit2) { + TestChangeBit(&MutationDispatcher::Mutate, 1 << 18); +} + +void TestShuffleBytes(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66}; + uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66}; + uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66}; + uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33}; + uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + size_t NewSize = (MD.*M)(T, 7, 7); + if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; + } + EXPECT_EQ(FoundMask, 31); +} + +TEST(FuzzerMutate, ShuffleBytes1) { + TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16); +} +TEST(FuzzerMutate, ShuffleBytes2) { + TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20); +} + +void TestCopyPart(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11}; + uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66}; + uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66}; + uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66}; + + for (int i = 0; i < NumIter; i++) { + uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + size_t NewSize = (MD.*M)(T, 7, 7); + if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; + } + + uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22}; + uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44}; + uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44}; + uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44}; + uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44}; + + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 5, 8); + if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8; + if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9; + } + + EXPECT_EQ(FoundMask, 1023); +} + +TEST(FuzzerMutate, CopyPart1) { + TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10); +} +TEST(FuzzerMutate, CopyPart2) { + TestCopyPart(&MutationDispatcher::Mutate, 1 << 13); +} + +void TestAddWordFromDictionary(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; + uint8_t Word2[3] = {0xFF, 0xEE, 0xEF}; + MD.AddWordToManualDictionary(Word(Word1, sizeof(Word1))); + MD.AddWordToManualDictionary(Word(Word2, sizeof(Word2))); + int FoundMask = 0; + uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD}; + uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22}; + uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22}; + uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22}; + uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF}; + uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22}; + uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22}; + uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[7] = {0x00, 0x11, 0x22}; + size_t NewSize = (MD.*M)(T, 3, 7); + if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4; + if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5; + if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6; + if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, AddWordFromDictionary1) { + TestAddWordFromDictionary( + &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15); +} + +TEST(FuzzerMutate, AddWordFromDictionary2) { + TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15); +} + +void TestChangeASCIIInteger(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + + uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'}; + uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'}; + uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'}; + uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'}; + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'}; + size_t NewSize = (MD.*M)(T, 8, 8); + /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + else if (NewSize == 8) FoundMask |= 1 << 4; + } + EXPECT_EQ(FoundMask, 31); +} + +TEST(FuzzerMutate, ChangeASCIIInteger1) { + TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger, + 1 << 15); +} + +TEST(FuzzerMutate, ChangeASCIIInteger2) { + TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15); +} + +void TestChangeBinaryInteger(Mutator M, int NumIter) { + std::unique_ptr t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + + uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79}; + uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77}; + uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88}; + uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size + uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size) + + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 8, 8); + /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; + else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, ChangeBinaryInteger1) { + TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger, + 1 << 12); +} + +TEST(FuzzerMutate, ChangeBinaryInteger2) { + TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15); +} + + +TEST(FuzzerDictionary, ParseOneDictionaryEntry) { + Unit U; + EXPECT_FALSE(ParseOneDictionaryEntry("", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry("\t ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" zz\" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \"zz ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \"\" ", &U)); + EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U)); + EXPECT_EQ(U, Unit({'a'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U)); + EXPECT_EQ(U, Unit({'a', 'b', 'c'})); + EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U)); + EXPECT_EQ(U, Unit({'a', 'b', 'c'})); + EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U)); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U)); + EXPECT_EQ(U, Unit({'\\'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U)); + EXPECT_EQ(U, Unit({0xAB})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U)); + EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U)); + EXPECT_EQ(U, Unit({'#'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U)); + EXPECT_EQ(U, Unit({'"'})); +} + +TEST(FuzzerDictionary, ParseDictionaryFile) { + std::vector Units; + EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); + EXPECT_FALSE(ParseDictionaryFile("", &Units)); + EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); + EXPECT_EQ(Units, std::vector({Unit({'a', 'a'})})); + EXPECT_TRUE( + ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); + EXPECT_EQ(Units, + std::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); +} + +TEST(FuzzerUtil, Base64) { + EXPECT_EQ("", Base64({})); + EXPECT_EQ("YQ==", Base64({'a'})); + EXPECT_EQ("eA==", Base64({'x'})); + EXPECT_EQ("YWI=", Base64({'a', 'b'})); + EXPECT_EQ("eHk=", Base64({'x', 'y'})); + EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'})); + EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'})); + EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'})); + EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'})); + EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'})); +} + +TEST(Corpus, Distribution) { + Random Rand(0); + std::unique_ptr C(new InputCorpus("")); + size_t N = 10; + size_t TriesPerUnit = 1<<16; + for (size_t i = 0; i < N; i++) + C->AddToCorpus(Unit{ static_cast(i) }, 1, false, {}); + + std::vector Hist(N); + for (size_t i = 0; i < N * TriesPerUnit; i++) { + Hist[C->ChooseUnitIdxToMutate(Rand)]++; + } + for (size_t i = 0; i < N; i++) { + // A weak sanity check that every unit gets invoked. + EXPECT_GT(Hist[i], TriesPerUnit / N / 3); + } +} + +TEST(Merge, Bad) { + const char *kInvalidInputs[] = { + "", + "x", + "3\nx", + "2\n3", + "2\n2", + "2\n2\nA\n", + "2\n2\nA\nB\nC\n", + "0\n0\n", + "1\n1\nA\nDONE 0", + "1\n1\nA\nSTARTED 1", + }; + Merger M; + for (auto S : kInvalidInputs) { + // fprintf(stderr, "TESTING:\n%s\n", S); + EXPECT_FALSE(M.Parse(S, false)); + } +} + +void EQ(const std::vector &A, const std::vector &B) { + EXPECT_EQ(A, B); +} + +void EQ(const std::vector &A, const std::vector &B) { + std::set a(A.begin(), A.end()); + std::set b(B.begin(), B.end()); + EXPECT_EQ(a, b); +} + +static void Merge(const std::string &Input, + const std::vector Result, + size_t NumNewFeatures) { + Merger M; + std::vector NewFiles; + EXPECT_TRUE(M.Parse(Input, true)); + std::stringstream SS; + M.PrintSummary(SS); + EXPECT_EQ(NumNewFeatures, M.Merge(&NewFiles)); + EXPECT_EQ(M.AllFeatures(), M.ParseSummary(SS)); + EQ(NewFiles, Result); +} + +TEST(Merge, Good) { + Merger M; + + EXPECT_TRUE(M.Parse("1\n0\nAA\n", false)); + EXPECT_EQ(M.Files.size(), 1U); + EXPECT_EQ(M.NumFilesInFirstCorpus, 0U); + EXPECT_EQ(M.Files[0].Name, "AA"); + EXPECT_TRUE(M.LastFailure.empty()); + EXPECT_EQ(M.FirstNotProcessedFile, 0U); + + EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false)); + EXPECT_EQ(M.Files.size(), 2U); + EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); + EXPECT_EQ(M.Files[0].Name, "AA"); + EXPECT_EQ(M.Files[1].Name, "BB"); + EXPECT_EQ(M.LastFailure, "AA"); + EXPECT_EQ(M.FirstNotProcessedFile, 1U); + + EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n" + "STARTED 0 1000\n" + "DONE 0 1 2 3\n" + "STARTED 1 1001\n" + "DONE 1 4 5 6 \n" + "STARTED 2 1002\n" + "", true)); + EXPECT_EQ(M.Files.size(), 3U); + EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); + EXPECT_EQ(M.Files[0].Name, "AA"); + EXPECT_EQ(M.Files[0].Size, 1000U); + EXPECT_EQ(M.Files[1].Name, "BB"); + EXPECT_EQ(M.Files[1].Size, 1001U); + EXPECT_EQ(M.Files[2].Name, "C"); + EXPECT_EQ(M.Files[2].Size, 1002U); + EXPECT_EQ(M.LastFailure, "C"); + EXPECT_EQ(M.FirstNotProcessedFile, 3U); + EQ(M.Files[0].Features, {1, 2, 3}); + EQ(M.Files[1].Features, {4, 5, 6}); + + + std::vector NewFiles; + + EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" + "STARTED 0 1000\nDONE 0 1 2 3\n" + "STARTED 1 1001\nDONE 1 4 5 6 \n" + "STARTED 2 1002\nDONE 2 6 1 3 \n" + "", true)); + EXPECT_EQ(M.Files.size(), 3U); + EXPECT_EQ(M.NumFilesInFirstCorpus, 2U); + EXPECT_TRUE(M.LastFailure.empty()); + EXPECT_EQ(M.FirstNotProcessedFile, 3U); + EQ(M.Files[0].Features, {1, 2, 3}); + EQ(M.Files[1].Features, {4, 5, 6}); + EQ(M.Files[2].Features, {1, 3, 6}); + EXPECT_EQ(0U, M.Merge(&NewFiles)); + EQ(NewFiles, {}); + + EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n" + "STARTED 0 1000\nDONE 0 1 2 3\n" + "STARTED 1 1001\nDONE 1 4 5 6 \n" + "STARTED 2 1002\nDONE 2 6 1 3\n" + "", true)); + EQ(M.Files[0].Features, {1, 2, 3}); + EQ(M.Files[1].Features, {4, 5, 6}); + EQ(M.Files[2].Features, {1, 3, 6}); + EXPECT_EQ(3U, M.Merge(&NewFiles)); + EQ(NewFiles, {"B"}); + + // Same as the above, but with InitialFeatures. + EXPECT_TRUE(M.Parse("2\n0\nB\nC\n" + "STARTED 0 1001\nDONE 0 4 5 6 \n" + "STARTED 1 1002\nDONE 1 6 1 3\n" + "", true)); + EQ(M.Files[0].Features, {4, 5, 6}); + EQ(M.Files[1].Features, {1, 3, 6}); + EXPECT_EQ(3U, M.Merge({1, 2, 3}, &NewFiles)); + EQ(NewFiles, {"B"}); +} + +TEST(Merge, Merge) { + + Merge("3\n1\nA\nB\nC\n" + "STARTED 0 1000\nDONE 0 1 2 3\n" + "STARTED 1 1001\nDONE 1 4 5 6 \n" + "STARTED 2 1002\nDONE 2 6 1 3 \n", + {"B"}, 3); + + Merge("3\n0\nA\nB\nC\n" + "STARTED 0 2000\nDONE 0 1 2 3\n" + "STARTED 1 1001\nDONE 1 4 5 6 \n" + "STARTED 2 1002\nDONE 2 6 1 3 \n", + {"A", "B", "C"}, 6); + + Merge("4\n0\nA\nB\nC\nD\n" + "STARTED 0 2000\nDONE 0 1 2 3\n" + "STARTED 1 1101\nDONE 1 4 5 6 \n" + "STARTED 2 1102\nDONE 2 6 1 3 100 \n" + "STARTED 3 1000\nDONE 3 1 \n", + {"A", "B", "C", "D"}, 7); + + Merge("4\n1\nA\nB\nC\nD\n" + "STARTED 0 2000\nDONE 0 4 5 6 7 8\n" + "STARTED 1 1100\nDONE 1 1 2 3 \n" + "STARTED 2 1100\nDONE 2 2 3 \n" + "STARTED 3 1000\nDONE 3 1 \n", + {"B", "D"}, 3); +} + +TEST(Fuzzer, ForEachNonZeroByte) { + const size_t N = 64; + alignas(64) uint8_t Ar[N + 8] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8, + 9, 9, 9, 9, 9, 9, 9, 9, + }; + typedef std::vector > Vec; + Vec Res, Expected; + auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) { + Res.push_back({FirstFeature + Idx, V}); + }; + ForEachNonZeroByte(Ar, Ar + N, 100, CB); + Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}, {163, 8}}; + EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}, {163, 8}}; + EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}}; + EXPECT_EQ(Res, Expected); +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9b4759dfb..ade658a2c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,6 +58,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) # CFI tests require diagnostic mode, which is implemented in UBSan. compiler_rt_test_runtime(ubsan cfi) compiler_rt_test_runtime(sanitizer_common) + compiler_rt_test_runtime(fuzzer) foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) # cfi testing is gated on ubsan diff --git a/test/fuzzer/AFLDriverTest.cpp b/test/fuzzer/AFLDriverTest.cpp new file mode 100644 index 000000000..b949adc7d --- /dev/null +++ b/test/fuzzer/AFLDriverTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Contains dummy functions used to avoid dependency on AFL. +#include +#include +#include + +extern "C" void __afl_manual_init() {} + +extern "C" int __afl_persistent_loop(unsigned int N) { + static int Count = N; + fprintf(stderr, "__afl_persistent_loop calle, Count = %d\n", Count); + if (Count--) return 1; + return 0; +} + +// This declaration exists to prevent the Darwin linker +// from complaining about this being a missing weak symbol. +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + fprintf(stderr, "LLVMFuzzerInitialize called\n"); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + fprintf(stderr, "LLVMFuzzerTestOneInput called; Size = %zd\n", Size); + return 0; +} diff --git a/test/fuzzer/AbsNegAndConstant64Test.cpp b/test/fuzzer/AbsNegAndConstant64Test.cpp new file mode 100644 index 000000000..abeb784e9 --- /dev/null +++ b/test/fuzzer/AbsNegAndConstant64Test.cpp @@ -0,0 +1,24 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// abs(x) < 0 and y == Const puzzle, 64-bit variant. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 16) return 0; + int64_t x; + uint64_t y; + memcpy(&x, Data, sizeof(x)); + memcpy(&y, Data + sizeof(x), sizeof(y)); + if (llabs(x) < 0 && y == 0xbaddcafedeadbeefULL) { + printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y); + fflush(stdout); + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/AbsNegAndConstantTest.cpp b/test/fuzzer/AbsNegAndConstantTest.cpp new file mode 100644 index 000000000..049db0a60 --- /dev/null +++ b/test/fuzzer/AbsNegAndConstantTest.cpp @@ -0,0 +1,24 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// abs(x) < 0 and y == Const puzzle. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 8) return 0; + int x; + unsigned y; + memcpy(&x, Data, sizeof(x)); + memcpy(&y, Data + sizeof(x), sizeof(y)); + if (abs(x) < 0 && y == 0xbaddcafe) { + printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y); + fflush(stdout); + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/AccumulateAllocationsTest.cpp b/test/fuzzer/AccumulateAllocationsTest.cpp new file mode 100644 index 000000000..e9acd7ccb --- /dev/null +++ b/test/fuzzer/AccumulateAllocationsTest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test with a more mallocs than frees, but no leak. +#include +#include + +const int kAllocatedPointersSize = 10000; +int NumAllocatedPointers = 0; +int *AllocatedPointers[kAllocatedPointersSize]; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (NumAllocatedPointers < kAllocatedPointersSize) + AllocatedPointers[NumAllocatedPointers++] = new int; + return 0; +} + diff --git a/test/fuzzer/BadStrcmpTest.cpp b/test/fuzzer/BadStrcmpTest.cpp new file mode 100644 index 000000000..ba2b068f7 --- /dev/null +++ b/test/fuzzer/BadStrcmpTest.cpp @@ -0,0 +1,19 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that we don't creash in case of bad strcmp params. +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size != 10) return 0; + // Data is not zero-terminated, so this call is bad. + // Still, there are cases when such calles appear, see e.g. + // https://bugs.llvm.org/show_bug.cgi?id=32357 + Sink = strcmp(reinterpret_cast(Data), "123456789"); + return 0; +} + diff --git a/test/fuzzer/BogusInitializeTest.cpp b/test/fuzzer/BogusInitializeTest.cpp new file mode 100644 index 000000000..c7e81a547 --- /dev/null +++ b/test/fuzzer/BogusInitializeTest.cpp @@ -0,0 +1,15 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Make sure LLVMFuzzerInitialize does not change argv[0]. +#include +#include + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + ***argv = 'X'; + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return 0; +} diff --git a/test/fuzzer/BufferOverflowOnInput.cpp b/test/fuzzer/BufferOverflowOnInput.cpp new file mode 100644 index 000000000..159da92d4 --- /dev/null +++ b/test/fuzzer/BufferOverflowOnInput.cpp @@ -0,0 +1,24 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include +#include +#include + +static volatile bool SeedLargeBuffer; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + if (Size >= 4) + SeedLargeBuffer = true; + if (Size == 3 && SeedLargeBuffer && Data[3]) { + std::cout << "Woops, reading Data[3] w/o crashing\n" << std::flush; + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/CMakeLists.txt b/test/fuzzer/CMakeLists.txt new file mode 100644 index 000000000..339978a82 --- /dev/null +++ b/test/fuzzer/CMakeLists.txt @@ -0,0 +1,40 @@ +set(LIBFUZZER_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if (NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND LIBFUZZER_TEST_DEPS fuzzer asan) +endif() + +if(COMPILER_RT_INCLUDE_TESTS) + list(APPEND LIBFUZZER_TEST_DEPS FuzzerUnitTests) +endif() + +set(LIBFUZZER_TESTSUITES) + + +if(COMPILER_RT_INCLUDE_TESTS) + # libFuzzer unit tests. + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg) + list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit) +endif() + +foreach(arch ${FUZZER_SUPPORTED_ARCH}) + set(LIBFUZZER_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER}) + get_test_cc_for_arch(${arch} LIBFUZZER_TEST_COMPILER LIBFUZZER_TEST_FLAGS) + + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + + # LIT-based libFuzzer tests. + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg + ) + list(APPEND LIBFUZZER_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) + +endforeach() + +add_lit_testsuite(check-fuzzer "Running Fuzzer tests" + ${LIBFUZZER_TESTSUITES} + DEPENDS ${LIBFUZZER_TEST_DEPS}) +set_target_properties(check-fuzzer PROPERTIES FOLDER "Compiler-RT Tests") diff --git a/test/fuzzer/CallerCalleeTest.cpp b/test/fuzzer/CallerCalleeTest.cpp new file mode 100644 index 000000000..ed9f37cc1 --- /dev/null +++ b/test/fuzzer/CallerCalleeTest.cpp @@ -0,0 +1,59 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. +// Try to find the target using the indirect caller-callee pairs. +#include +#include +#include +#include +#include + +typedef void (*F)(); +static F t[256]; + +void f34() { + std::cerr << "BINGO\n"; + exit(1); +} +void f23() { t[(unsigned)'d'] = f34;} +void f12() { t[(unsigned)'c'] = f23;} +void f01() { t[(unsigned)'b'] = f12;} +void f00() {} + +static F t0[256] = { + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 4) return 0; + // Spoof the counters. + for (int i = 0; i < 200; i++) { + f23(); + f12(); + f01(); + } + memcpy(t, t0, sizeof(t)); + t[(unsigned)'a'] = f01; + t[Data[0]](); + t[Data[1]](); + t[Data[2]](); + t[Data[3]](); + return 0; +} + diff --git a/test/fuzzer/CleanseTest.cpp b/test/fuzzer/CleanseTest.cpp new file mode 100644 index 000000000..ee1845701 --- /dev/null +++ b/test/fuzzer/CleanseTest.cpp @@ -0,0 +1,16 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test the the fuzzer is able to 'cleanse' the reproducer +// by replacing all irrelevant bytes with garbage. +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size >= 20 && Data[1] == '1' && Data[5] == '5' && Data[10] == 'A' && + Data[19] == 'Z') + abort(); + return 0; +} + diff --git a/test/fuzzer/CounterTest.cpp b/test/fuzzer/CounterTest.cpp new file mode 100644 index 000000000..4917934c6 --- /dev/null +++ b/test/fuzzer/CounterTest.cpp @@ -0,0 +1,18 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test for a fuzzer: must find the case where a particular basic block is +// executed many times. +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int Num = 0; + for (size_t i = 0; i < Size; i++) + if (Data[i] == 'A' + i) + Num++; + if (Num >= 4) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} diff --git a/test/fuzzer/CustomCrossOverAndMutateTest.cpp b/test/fuzzer/CustomCrossOverAndMutateTest.cpp new file mode 100644 index 000000000..74fc93953 --- /dev/null +++ b/test/fuzzer/CustomCrossOverAndMutateTest.cpp @@ -0,0 +1,34 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that libFuzzer does not crash when LLVMFuzzerMutate called from +// LLVMFuzzerCustomCrossOver. +#include +#include +#include +#include +#include +#include +#include + +#include "FuzzerInterface.h" + +static volatile int sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + std::string Str(reinterpret_cast(Data), Size); + if (Size && Data[0] == '0') + sink++; + return 0; +} + +extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed) { + std::vector Buffer(MaxOutSize * 10); + LLVMFuzzerMutate(Buffer.data(), Buffer.size(), Buffer.size()); + size_t Size = std::min(Size1, MaxOutSize); + memcpy(Out, Data1, Size); + return Size; +} diff --git a/test/fuzzer/CustomCrossOverTest.cpp b/test/fuzzer/CustomCrossOverTest.cpp new file mode 100644 index 000000000..58059c9c1 --- /dev/null +++ b/test/fuzzer/CustomCrossOverTest.cpp @@ -0,0 +1,64 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a cutom mutator. +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FuzzerInterface.h" + +static const char *Separator = "-_^_-"; +static const char *Target = "012-_^_-abc"; + +static volatile int sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + std::string Str(reinterpret_cast(Data), Size); + + // Ensure that two different elements exist in the corpus. + if (Size && Data[0] == '0') sink++; + if (Size && Data[0] == 'a') sink--; + + if (Str.find(Target) != std::string::npos) { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + exit(1); + } + return 0; +} + +extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed) { + static bool Printed; + static size_t SeparatorLen = strlen(Separator); + + if (!Printed) { + std::cerr << "In LLVMFuzzerCustomCrossover\n"; + Printed = true; + } + + std::mt19937 R(Seed); + + size_t Offset1 = 0; + size_t Len1 = R() % (Size1 - Offset1); + size_t Offset2 = 0; + size_t Len2 = R() % (Size2 - Offset2); + size_t Size = Len1 + Len2 + SeparatorLen; + + if (Size > MaxOutSize) + return 0; + + memcpy(Out, Data1 + Offset1, Len1); + memcpy(Out + Len1, Separator, SeparatorLen); + memcpy(Out + Len1 + SeparatorLen, Data2 + Offset2, Len2); + + return Len1 + Len2 + SeparatorLen; +} diff --git a/test/fuzzer/CustomMutatorTest.cpp b/test/fuzzer/CustomMutatorTest.cpp new file mode 100644 index 000000000..b2adb9408 --- /dev/null +++ b/test/fuzzer/CustomMutatorTest.cpp @@ -0,0 +1,39 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a cutom mutator. +#include +#include +#include +#include +#include +#include + +#include "FuzzerInterface.h" + +static volatile int Sink; + +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] == '!') { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + exit(1); + } + } + } + return 0; +} + +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, + size_t MaxSize, unsigned int Seed) { + static bool Printed; + if (!Printed) { + std::cerr << "In LLVMFuzzerCustomMutator\n"; + Printed = true; + } + return LLVMFuzzerMutate(Data, Size, MaxSize); +} diff --git a/test/fuzzer/CxxStringEqTest.cpp b/test/fuzzer/CxxStringEqTest.cpp new file mode 100644 index 000000000..924851c5a --- /dev/null +++ b/test/fuzzer/CxxStringEqTest.cpp @@ -0,0 +1,25 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. Must find a specific string +// used in std::string operator ==. +#include +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + std::string Str((const char*)Data, Size); + bool Eq = Str == "FooBar"; + Sink = Str == "123456"; // Try to confuse the fuzzer + if (Eq) { + std::cout << "BINGO; Found the target, exiting\n"; + std::cout.flush(); + abort(); + } + return 0; +} + diff --git a/test/fuzzer/DSO1.cpp b/test/fuzzer/DSO1.cpp new file mode 100644 index 000000000..72a5ec4a0 --- /dev/null +++ b/test/fuzzer/DSO1.cpp @@ -0,0 +1,14 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. +#ifdef _WIN32 +__declspec( dllexport ) +#endif +int DSO1(int a) { + if (a < 123456) + return 0; + return 1; +} + +void Uncovered1() { } diff --git a/test/fuzzer/DSO2.cpp b/test/fuzzer/DSO2.cpp new file mode 100644 index 000000000..2967055dc --- /dev/null +++ b/test/fuzzer/DSO2.cpp @@ -0,0 +1,14 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. +#ifdef _WIN32 +__declspec( dllexport ) +#endif +int DSO2(int a) { + if (a < 3598235) + return 0; + return 1; +} + +void Uncovered2() {} diff --git a/test/fuzzer/DSOTestExtra.cpp b/test/fuzzer/DSOTestExtra.cpp new file mode 100644 index 000000000..a2274d070 --- /dev/null +++ b/test/fuzzer/DSOTestExtra.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +int DSOTestExtra(int a) { + if (a < 452345) + return 0; + return 1; +} + diff --git a/test/fuzzer/DSOTestMain.cpp b/test/fuzzer/DSOTestMain.cpp new file mode 100644 index 000000000..e0c857d4f --- /dev/null +++ b/test/fuzzer/DSOTestMain.cpp @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +#include +#include +#include +#include +extern int DSO1(int a); +extern int DSO2(int a); +extern int DSOTestExtra(int a); + +static volatile int *nil = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int x, y, z; + if (Size < sizeof(int) * 3) { + x = y = z = 0; + } else { + memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); + memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); + memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); + } + int sum = DSO1(x) + DSO2(y) + (z ? DSOTestExtra(z) : 0); + if (sum == 3) { + fprintf(stderr, "BINGO %d %d %d\n", x, y, z); + *nil = 0; + } + return 0; +} diff --git a/test/fuzzer/DeepRecursionTest.cpp b/test/fuzzer/DeepRecursionTest.cpp new file mode 100644 index 000000000..bf4621d04 --- /dev/null +++ b/test/fuzzer/DeepRecursionTest.cpp @@ -0,0 +1,25 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the deep recursion. +// To generate a crashy input: +// for((i=0;i<110;i++)); do echo -n ABCDEFGHIJ >> INPUT; done +#include +#include +#include + +static volatile int Sink; + +void Recursive(const uint8_t *Data, size_t Size, int Depth) { + if (Depth > 1000) abort(); + if (!Size) return; + if (*Data == ('A' + Depth % 10)) + Recursive(Data + 1, Size - 1, Depth + 1); + Sink++; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + Recursive(Data, Size, 0); + return 0; +} + diff --git a/test/fuzzer/DivTest.cpp b/test/fuzzer/DivTest.cpp new file mode 100644 index 000000000..bce13feb7 --- /dev/null +++ b/test/fuzzer/DivTest.cpp @@ -0,0 +1,20 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer: find the interesting argument for div. +#include +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 4) return 0; + int a; + memcpy(&a, Data, 4); + Sink = 12345678 / (987654 - a); + return 0; +} + diff --git a/test/fuzzer/EmptyTest.cpp b/test/fuzzer/EmptyTest.cpp new file mode 100644 index 000000000..5e843308f --- /dev/null +++ b/test/fuzzer/EmptyTest.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// A fuzzer with empty target function. + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return 0; +} diff --git a/test/fuzzer/EquivalenceATest.cpp b/test/fuzzer/EquivalenceATest.cpp new file mode 100644 index 000000000..7d1ebb0f6 --- /dev/null +++ b/test/fuzzer/EquivalenceATest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +#include +#include +#include + +// Test for libFuzzer's "equivalence" fuzzing, part A. +extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // fprintf(stderr, "A %zd\n", Size); + uint8_t Result[50]; + if (Size > 50) Size = 50; + for (size_t i = 0; i < Size; i++) + Result[Size - i - 1] = Data[i]; + LLVMFuzzerAnnounceOutput(Result, Size); + return 0; +} diff --git a/test/fuzzer/EquivalenceBTest.cpp b/test/fuzzer/EquivalenceBTest.cpp new file mode 100644 index 000000000..b1de208b5 --- /dev/null +++ b/test/fuzzer/EquivalenceBTest.cpp @@ -0,0 +1,27 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +#include +#include +#include + +// Test for libFuzzer's "equivalence" fuzzing, part B. +extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // fprintf(stderr, "B %zd\n", Size); + uint8_t Result[50]; + if (Size > 50) Size = 50; + for (size_t i = 0; i < Size; i++) + Result[Size - i - 1] = Data[i]; + + // Be a bit different from EquivalenceATest + if (Size > 10 && Data[5] == 'B' && Data[6] == 'C' && Data[7] == 'D') { + static int c; + if (!c) + fprintf(stderr, "ZZZZZZZ\n"); + c = 1; + Result[2]++; + } + + LLVMFuzzerAnnounceOutput(Result, Size); + return 0; +} diff --git a/test/fuzzer/FlagsTest.cpp b/test/fuzzer/FlagsTest.cpp new file mode 100644 index 000000000..ac64b9d48 --- /dev/null +++ b/test/fuzzer/FlagsTest.cpp @@ -0,0 +1,32 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Parse some flags +#include +#include + +static std::vector Flags; + +extern "C" int LLVMFuzzerInitialize(int *Argc, char ***Argv) { + // Parse --flags and anything after -ignore_remaining_args=1 is passed. + int I = 1; + while (I < *Argc) { + std::string S((*Argv)[I++]); + if (S == "-ignore_remaining_args=1") + break; + if (S.substr(0, 2) == "--") + Flags.push_back(S); + } + while (I < *Argc) + Flags.push_back(std::string((*Argv)[I++])); + + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + fprintf(stderr, "BINGO "); + for (auto Flag : Flags) + fprintf(stderr, "%s ", Flag.c_str()); + fprintf(stderr, "\n"); + exit(0); +} diff --git a/test/fuzzer/FourIndependentBranchesTest.cpp b/test/fuzzer/FourIndependentBranchesTest.cpp new file mode 100644 index 000000000..bbf5ea235 --- /dev/null +++ b/test/fuzzer/FourIndependentBranchesTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "FUZZ". +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int bits = 0; + if (Size > 0 && Data[0] == 'F') bits |= 1; + if (Size > 1 && Data[1] == 'U') bits |= 2; + if (Size > 2 && Data[2] == 'Z') bits |= 4; + if (Size > 3 && Data[3] == 'Z') bits |= 8; + if (bits == 15) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/FullCoverageSetTest.cpp b/test/fuzzer/FullCoverageSetTest.cpp new file mode 100644 index 000000000..6d7e48fe5 --- /dev/null +++ b/test/fuzzer/FullCoverageSetTest.cpp @@ -0,0 +1,24 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "FUZZER". +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int bits = 0; + if (Size > 0 && Data[0] == 'F') bits |= 1; + if (Size > 1 && Data[1] == 'U') bits |= 2; + if (Size > 2 && Data[2] == 'Z') bits |= 4; + if (Size > 3 && Data[3] == 'Z') bits |= 8; + if (Size > 4 && Data[4] == 'E') bits |= 16; + if (Size > 5 && Data[5] == 'R') bits |= 32; + if (bits == 63) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/InitializeTest.cpp b/test/fuzzer/InitializeTest.cpp new file mode 100644 index 000000000..d640a8d10 --- /dev/null +++ b/test/fuzzer/InitializeTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Make sure LLVMFuzzerInitialize is called. +#include +#include +#include +#include +#include +#include + +static char *argv0; + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + assert(*argc > 0); + argv0 = **argv; + fprintf(stderr, "LLVMFuzzerInitialize: %s\n", argv0); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == strlen(argv0) && + !memmem(Data, Size, argv0, Size)) { + fprintf(stderr, "BINGO %s\n", argv0); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/LargeTest.cpp b/test/fuzzer/LargeTest.cpp new file mode 100644 index 000000000..83ed61971 --- /dev/null +++ b/test/fuzzer/LargeTest.cpp @@ -0,0 +1,37 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// A fuzz target with lots of edges. +#include +#include + +static inline void break_optimization(const void *arg) { + __asm__ __volatile__("" : : "r" (arg) : "memory"); +} + +#define A \ + do { \ + i++; \ + c++; \ + if (Data[(i + __LINE__) % Size] == (c % 256)) \ + break_optimization(Data); \ + else \ + break_optimization(0); \ + } while (0) + +// for (int i = 0, n = Data[(__LINE__ - 1) % Size] % 16; i < n; i++) + +#define B do{A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; }while(0) +#define C do{B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; }while(0) +#define D do{C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; }while(0) +#define E do{D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; }while(0) + +volatile int sink; +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (!Size) return 0; + int c = 0; + int i = 0; + D; + return 0; +} + diff --git a/test/fuzzer/LeakTest.cpp b/test/fuzzer/LeakTest.cpp new file mode 100644 index 000000000..ea89e3901 --- /dev/null +++ b/test/fuzzer/LeakTest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test with a leak. +#include +#include + +static volatile void *Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && *Data == 'H') { + Sink = new int; + Sink = nullptr; + } + return 0; +} + diff --git a/test/fuzzer/LeakTimeoutTest.cpp b/test/fuzzer/LeakTimeoutTest.cpp new file mode 100644 index 000000000..92526194a --- /dev/null +++ b/test/fuzzer/LeakTimeoutTest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test with a leak. +#include +#include + +static volatile int *Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (!Size) return 0; + Sink = new int; + Sink = new int; + while (Sink) *Sink = 0; // Infinite loop. + return 0; +} + diff --git a/test/fuzzer/LoadTest.cpp b/test/fuzzer/LoadTest.cpp new file mode 100644 index 000000000..67a28c7cb --- /dev/null +++ b/test/fuzzer/LoadTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer: find interesting value of array index. +#include +#include +#include +#include +#include + +static volatile int Sink; +const int kArraySize = 1234567; +int array[kArraySize]; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 8) return 0; + uint64_t a = 0; + memcpy(&a, Data, 8); + Sink = array[a % (kArraySize + 1)]; + return 0; +} + diff --git a/test/fuzzer/Memcmp64BytesTest.cpp b/test/fuzzer/Memcmp64BytesTest.cpp new file mode 100644 index 000000000..5b6cb7071 --- /dev/null +++ b/test/fuzzer/Memcmp64BytesTest.cpp @@ -0,0 +1,20 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const char kString64Bytes[] = + "123456789 123456789 123456789 123456789 123456789 123456789 1234"; + assert(sizeof(kString64Bytes) == 65); + if (Size >= 64 && memcmp(Data, kString64Bytes, 64) == 0) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/MemcmpTest.cpp b/test/fuzzer/MemcmpTest.cpp new file mode 100644 index 000000000..8dbb7d84f --- /dev/null +++ b/test/fuzzer/MemcmpTest.cpp @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // TODO: check other sizes. + if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) { + if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) { + if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) { + if (Size >= 17 && memcmp(Data + 14, "KLM", 3) == 0) { + if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){ + fprintf(stderr, "BINGO %zd\n", Size); + for (size_t i = 0; i < Size; i++) { + uint8_t C = Data[i]; + if (C >= 32 && C < 127) + fprintf(stderr, "%c", C); + } + fprintf(stderr, "\n"); + exit(1); + } + } + } + } + } + return 0; +} diff --git a/test/fuzzer/NotinstrumentedTest.cpp b/test/fuzzer/NotinstrumentedTest.cpp new file mode 100644 index 000000000..91418990b --- /dev/null +++ b/test/fuzzer/NotinstrumentedTest.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// This test should not be instrumented. +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return 0; +} + diff --git a/test/fuzzer/NthRunCrashTest.cpp b/test/fuzzer/NthRunCrashTest.cpp new file mode 100644 index 000000000..26cdc8f17 --- /dev/null +++ b/test/fuzzer/NthRunCrashTest.cpp @@ -0,0 +1,19 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Crash on the N-th execution. +#include +#include +#include +#include + +static int Counter; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Counter++ == 1000) { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/NullDerefOnEmptyTest.cpp b/test/fuzzer/NullDerefOnEmptyTest.cpp new file mode 100644 index 000000000..459db51f8 --- /dev/null +++ b/test/fuzzer/NullDerefOnEmptyTest.cpp @@ -0,0 +1,19 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the empty string. +#include +#include +#include +#include + +static volatile int *Null = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) { + std::cout << "Found the target, dereferencing NULL\n"; + *Null = 1; + } + return 0; +} + diff --git a/test/fuzzer/NullDerefTest.cpp b/test/fuzzer/NullDerefTest.cpp new file mode 100644 index 000000000..1b44b682a --- /dev/null +++ b/test/fuzzer/NullDerefTest.cpp @@ -0,0 +1,26 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include + +static volatile int Sink; +static volatile int *Null = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + std::cout << "Found the target, dereferencing NULL\n"; + *Null = 1; + } + } + } + return 0; +} + diff --git a/test/fuzzer/OneHugeAllocTest.cpp b/test/fuzzer/OneHugeAllocTest.cpp new file mode 100644 index 000000000..32a557871 --- /dev/null +++ b/test/fuzzer/OneHugeAllocTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Tests OOM handling when there is a single large allocation. +#include +#include +#include +#include +#include +#include + +static volatile char *SinkPtr; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + if (Size > 1 && Data[1] == 'i') { + if (Size > 2 && Data[2] == '!') { + size_t kSize = (size_t)1 << 31; + char *p = new char[kSize]; + memset(p, 0, kSize); + SinkPtr = p; + delete [] p; + } + } + } + return 0; +} + diff --git a/test/fuzzer/OutOfMemorySingleLargeMallocTest.cpp b/test/fuzzer/OutOfMemorySingleLargeMallocTest.cpp new file mode 100644 index 000000000..a07795a08 --- /dev/null +++ b/test/fuzzer/OutOfMemorySingleLargeMallocTest.cpp @@ -0,0 +1,27 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Tests OOM handling. +#include +#include +#include +#include +#include +#include + +static volatile char *SinkPtr; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + if (Size > 1 && Data[1] == 'i') { + if (Size > 2 && Data[2] == '!') { + size_t kSize = 0x20000000U; + char *p = new char[kSize]; + SinkPtr = p; + delete [] p; + } + } + } + return 0; +} + diff --git a/test/fuzzer/OutOfMemoryTest.cpp b/test/fuzzer/OutOfMemoryTest.cpp new file mode 100644 index 000000000..5e59bde09 --- /dev/null +++ b/test/fuzzer/OutOfMemoryTest.cpp @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Tests OOM handling. +#include +#include +#include +#include +#include +#include +#include + +static volatile char *SinkPtr; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + if (Size > 1 && Data[1] == 'i') { + if (Size > 2 && Data[2] == '!') { + while (true) { + size_t kSize = 1 << 28; + char *p = new char[kSize]; + memset(p, 0, kSize); + SinkPtr = p; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + } + return 0; +} + diff --git a/test/fuzzer/OverwriteInputTest.cpp b/test/fuzzer/OverwriteInputTest.cpp new file mode 100644 index 000000000..e68868234 --- /dev/null +++ b/test/fuzzer/OverwriteInputTest.cpp @@ -0,0 +1,13 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. Make sure we abort if Data is overwritten. +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size) + *const_cast(Data) = 1; + return 0; +} + diff --git a/test/fuzzer/RepeatedBytesTest.cpp b/test/fuzzer/RepeatedBytesTest.cpp new file mode 100644 index 000000000..31868cf8c --- /dev/null +++ b/test/fuzzer/RepeatedBytesTest.cpp @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find repeated bytes. +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + // Looking for AAAAAAAAAAAAAAAAAAAAAA or some such. + size_t CurA = 0, MaxA = 0; + for (size_t i = 0; i < Size; i++) { + // Make sure there are no conditionals in the loop so that + // coverage can't help the fuzzer. + int EQ = Data[i] == 'A'; + CurA = EQ * (CurA + 1); + int GT = CurA > MaxA; + MaxA = GT * CurA + (!GT) * MaxA; + } + if (MaxA >= 20) { + std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n" + << std::flush; + exit(0); + } + return 0; +} + diff --git a/test/fuzzer/RepeatedMemcmp.cpp b/test/fuzzer/RepeatedMemcmp.cpp new file mode 100644 index 000000000..18369deac --- /dev/null +++ b/test/fuzzer/RepeatedMemcmp.cpp @@ -0,0 +1,24 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int Matches1 = 0; + for (size_t i = 0; i + 2 < Size; i += 3) + if (!memcmp(Data + i, "foo", 3)) + Matches1++; + int Matches2 = 0; + for (size_t i = 0; i + 2 < Size; i += 3) + if (!memcmp(Data + i, "bar", 3)) + Matches2++; + + if (Matches1 > 10 && Matches2 > 10) { + fprintf(stderr, "BINGO!\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/ShrinkControlFlowSimpleTest.cpp b/test/fuzzer/ShrinkControlFlowSimpleTest.cpp new file mode 100644 index 000000000..0afd26df2 --- /dev/null +++ b/test/fuzzer/ShrinkControlFlowSimpleTest.cpp @@ -0,0 +1,19 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). +#include +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 2) return 0; + if (Data[0] == 'F' && Data[Size / 2] == 'U' && Data[Size - 1] == 'Z') + Sink++; + return 0; +} + diff --git a/test/fuzzer/ShrinkControlFlowTest.cpp b/test/fuzzer/ShrinkControlFlowTest.cpp new file mode 100644 index 000000000..1957c1f90 --- /dev/null +++ b/test/fuzzer/ShrinkControlFlowTest.cpp @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). +#include +#include +#include +#include +#include + +static volatile int Sink; + +void Foo() { + Sink++; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int8_t Ids[256]; + memset(Ids, -1, sizeof(Ids)); + for (size_t i = 0; i < Size; i++) + if (Ids[Data[i]] == -1) + Ids[Data[i]] = i; + int F = Ids[(unsigned char)'F']; + int U = Ids[(unsigned char)'U']; + int Z = Ids[(unsigned char)'Z']; + if (F >= 0 && U > F && Z > U) { + Foo(); + } + return 0; +} + diff --git a/test/fuzzer/ShrinkValueProfileTest.cpp b/test/fuzzer/ShrinkValueProfileTest.cpp new file mode 100644 index 000000000..86e4e3cb0 --- /dev/null +++ b/test/fuzzer/ShrinkValueProfileTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). +#include +#include +#include +#include +#include + +static volatile uint32_t Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < sizeof(uint32_t)) return 0; + uint32_t X, Y; + size_t Offset = Size < 8 ? 0 : Size / 2; + memcpy(&X, Data + Offset, sizeof(uint32_t)); + memcpy(&Y, "FUZZ", sizeof(uint32_t)); + Sink = X == Y; + return 0; +} + diff --git a/test/fuzzer/SignedIntOverflowTest.cpp b/test/fuzzer/SignedIntOverflowTest.cpp new file mode 100644 index 000000000..d80060207 --- /dev/null +++ b/test/fuzzer/SignedIntOverflowTest.cpp @@ -0,0 +1,28 @@ +// 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 int Large = INT_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++; // int overflow. + } + } + } + return 0; +} + diff --git a/test/fuzzer/SimpleCmpTest.cpp b/test/fuzzer/SimpleCmpTest.cpp new file mode 100644 index 000000000..8acad4ac7 --- /dev/null +++ b/test/fuzzer/SimpleCmpTest.cpp @@ -0,0 +1,47 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find several narrow ranges. +#include +#include +#include +#include + +extern int AllLines[]; + +bool PrintOnce(int Line) { + if (!AllLines[Line]) + fprintf(stderr, "Seen line %d\n", Line); + AllLines[Line] = 1; + return true; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size != 22) return 0; + uint64_t x = 0; + int64_t y = 0; + int32_t z = 0; + uint16_t a = 0; + memcpy(&x, Data, 8); // 8 + memcpy(&y, Data + 8, 8); // 16 + memcpy(&z, Data + 16, sizeof(z)); // 20 + memcpy(&a, Data + 20, sizeof(a)); // 22 + const bool k32bit = sizeof(void*) == 4; + + if ((k32bit || x > 1234567890) && PrintOnce(__LINE__) && + (k32bit || x < 1234567895) && PrintOnce(__LINE__) && + a == 0x4242 && PrintOnce(__LINE__) && + (k32bit || y >= 987654321) && PrintOnce(__LINE__) && + (k32bit || y <= 987654325) && PrintOnce(__LINE__) && + z < -10000 && PrintOnce(__LINE__) && + z >= -10005 && PrintOnce(__LINE__) && + z != -10003 && PrintOnce(__LINE__) && + true) { + fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n", + Size, x, y, z, a); + exit(1); + } + return 0; +} + +int AllLines[__LINE__ + 1]; // Must be the last line. diff --git a/test/fuzzer/SimpleDictionaryTest.cpp b/test/fuzzer/SimpleDictionaryTest.cpp new file mode 100644 index 000000000..ffa2e4137 --- /dev/null +++ b/test/fuzzer/SimpleDictionaryTest.cpp @@ -0,0 +1,30 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. +// The fuzzer must find a string based on dictionary words: +// "Elvis" +// "Presley" +#include +#include +#include +#include +#include +#include + +static volatile int Zero = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const char *Expected = "ElvisPresley"; + if (Size < strlen(Expected)) return 0; + size_t Match = 0; + for (size_t i = 0; Expected[i]; i++) + if (Expected[i] + Zero == Data[i]) + Match++; + if (Match == strlen(Expected)) { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/SimpleHashTest.cpp b/test/fuzzer/SimpleHashTest.cpp new file mode 100644 index 000000000..99e96cb25 --- /dev/null +++ b/test/fuzzer/SimpleHashTest.cpp @@ -0,0 +1,40 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// This test computes a checksum of the data (all but the last 4 bytes), +// and then compares the last 4 bytes with the computed value. +// A fuzzer with cmp traces is expected to defeat this check. +#include +#include +#include +#include + +// A modified jenkins_one_at_a_time_hash initialized by non-zero, +// so that simple_hash(0) != 0. See also +// https://en.wikipedia.org/wiki/Jenkins_hash_function +static uint32_t simple_hash(const uint8_t *Data, size_t Size) { + uint32_t Hash = 0x12039854; + for (uint32_t i = 0; i < Size; i++) { + Hash += Data[i]; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + Hash += (Hash << 3); + Hash ^= (Hash >> 11); + Hash += (Hash << 15); + return Hash; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 14) + return 0; + + uint32_t Hash = simple_hash(&Data[0], Size - 4); + uint32_t Want = reinterpret_cast(&Data[Size - 4])[0]; + if (Hash != Want) + return 0; + fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash, + (unsigned int)Want); + exit(1); + return 0; +} diff --git a/test/fuzzer/SimpleTest.cpp b/test/fuzzer/SimpleTest.cpp new file mode 100644 index 000000000..3882a842b --- /dev/null +++ b/test/fuzzer/SimpleTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include +#include +#include + +static volatile int Sink; + +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] == '!') { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + exit(0); + } + } + } + return 0; +} + diff --git a/test/fuzzer/SimpleThreadedTest.cpp b/test/fuzzer/SimpleThreadedTest.cpp new file mode 100644 index 000000000..deeae756a --- /dev/null +++ b/test/fuzzer/SimpleThreadedTest.cpp @@ -0,0 +1,26 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Threaded test for a fuzzer. The fuzzer should find "H" +#include +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + auto C = [&] { + if (Size >= 2 && Data[0] == 'H') { + std::cout << "BINGO; Found the target, exiting\n" << std::flush; + abort(); + } + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} + diff --git a/test/fuzzer/SingleByteInputTest.cpp b/test/fuzzer/SingleByteInputTest.cpp new file mode 100644 index 000000000..72b58ba91 --- /dev/null +++ b/test/fuzzer/SingleByteInputTest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer, need just one byte to crash. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[Size/2] == 42) { + fprintf(stderr, "BINGO\n"); + abort(); + } + return 0; +} + diff --git a/test/fuzzer/SingleMemcmpTest.cpp b/test/fuzzer/SingleMemcmpTest.cpp new file mode 100644 index 000000000..19781ba4c --- /dev/null +++ b/test/fuzzer/SingleMemcmpTest.cpp @@ -0,0 +1,17 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const char *S = (const char*)Data; + if (Size >= 6 && !memcmp(S, "qwerty", 6)) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/SingleStrcmpTest.cpp b/test/fuzzer/SingleStrcmpTest.cpp new file mode 100644 index 000000000..149073444 --- /dev/null +++ b/test/fuzzer/SingleStrcmpTest.cpp @@ -0,0 +1,21 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size >= 7) { + char Copy[7]; + memcpy(Copy, Data, 6); + Copy[6] = 0; + if (!strcmp(Copy, "qwerty")) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + } + return 0; +} diff --git a/test/fuzzer/SingleStrncmpTest.cpp b/test/fuzzer/SingleStrncmpTest.cpp new file mode 100644 index 000000000..47298763f --- /dev/null +++ b/test/fuzzer/SingleStrncmpTest.cpp @@ -0,0 +1,18 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const char *S = (const char*)Data; + volatile auto Strncmp = &(strncmp); // Make sure strncmp is not inlined. + if (Size >= 6 && !Strncmp(S, "qwerty", 6)) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/SpamyTest.cpp b/test/fuzzer/SpamyTest.cpp new file mode 100644 index 000000000..721134e18 --- /dev/null +++ b/test/fuzzer/SpamyTest.cpp @@ -0,0 +1,21 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// The test spams to stderr and stdout. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + printf("PRINTF_STDOUT\n"); + fflush(stdout); + fprintf(stderr, "PRINTF_STDERR\n"); + std::cout << "STREAM_COUT\n"; + std::cout.flush(); + std::cerr << "STREAM_CERR\n"; + return 0; +} + diff --git a/test/fuzzer/StrcmpTest.cpp b/test/fuzzer/StrcmpTest.cpp new file mode 100644 index 000000000..81f041d91 --- /dev/null +++ b/test/fuzzer/StrcmpTest.cpp @@ -0,0 +1,32 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Break through a series of strcmp. +#include +#include +#include +#include +#include + +bool Eq(const uint8_t *Data, size_t Size, const char *Str) { + char Buff[1024]; + size_t Len = strlen(Str); + if (Size < Len) return false; + if (Len >= sizeof(Buff)) return false; + memcpy(Buff, (const char*)Data, Len); + Buff[Len] = 0; + int res = strcmp(Buff, Str); + return res == 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Eq(Data, Size, "ABC") && + Size >= 3 && Eq(Data + 3, Size - 3, "QWER") && + Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") && + Size >= 14 && Data[13] == 42 + ) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/StrncmpOOBTest.cpp b/test/fuzzer/StrncmpOOBTest.cpp new file mode 100644 index 000000000..4ed71d9d0 --- /dev/null +++ b/test/fuzzer/StrncmpOOBTest.cpp @@ -0,0 +1,21 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test that libFuzzer itself does not read out of bounds. +#include +#include +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 5) return 0; + const char *Ch = reinterpret_cast(Data); + if (Ch[Size - 3] == 'a') + Sink = strncmp(Ch + Size - 3, "abcdefg", 6); + return 0; +} + diff --git a/test/fuzzer/StrncmpTest.cpp b/test/fuzzer/StrncmpTest.cpp new file mode 100644 index 000000000..a40e05690 --- /dev/null +++ b/test/fuzzer/StrncmpTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include +#include +#include +#include + +static volatile int sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // TODO: check other sizes. + const char *S = (const char*)Data; + if (Size >= 8 && strncmp(S, "123", 8)) + sink = 1; + if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { + if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { + if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { + if (Size >= 17 && strncmp(S + 14, "KLM", 3) == 0) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + } + } + } + return 0; +} diff --git a/test/fuzzer/StrstrTest.cpp b/test/fuzzer/StrstrTest.cpp new file mode 100644 index 000000000..a3ea4e03b --- /dev/null +++ b/test/fuzzer/StrstrTest.cpp @@ -0,0 +1,28 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Test strstr and strcasestr hooks. +#include +#include +#include +#include +#include + +// Windows does not have strcasestr and memmem, so we are not testing them. +#ifdef _WIN32 +#define strcasestr strstr +#define memmem(a, b, c, d) true +#endif + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 4) return 0; + std::string s(reinterpret_cast(Data), Size); + if (strstr(s.c_str(), "FUZZ") && + strcasestr(s.c_str(), "aBcD") && + memmem(s.data(), s.size(), "kuku", 4) + ) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/test/fuzzer/SwapCmpTest.cpp b/test/fuzzer/SwapCmpTest.cpp new file mode 100644 index 000000000..bbfbefe6a --- /dev/null +++ b/test/fuzzer/SwapCmpTest.cpp @@ -0,0 +1,35 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// The fuzzer must find several constants with swapped bytes. +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 14) return 0; + uint64_t x = 0; + uint32_t y = 0; + uint16_t z = 0; + memcpy(&x, Data, sizeof(x)); + memcpy(&y, Data + Size / 2, sizeof(y)); + memcpy(&z, Data + Size - sizeof(z), sizeof(z)); + + x = __builtin_bswap64(x); + y = __builtin_bswap32(y); + z = __builtin_bswap16(z); + const bool k32bit = sizeof(void*) == 4; + + if ((k32bit || x == 0x46555A5A5A5A5546ULL) && + z == 0x4F4B && + y == 0x66757A7A && + true + ) { + if (Data[Size - 3] == 'z') { + fprintf(stderr, "BINGO; Found the target\n"); + exit(1); + } + } + return 0; +} diff --git a/test/fuzzer/Switch2Test.cpp b/test/fuzzer/Switch2Test.cpp new file mode 100644 index 000000000..5f66ac8b4 --- /dev/null +++ b/test/fuzzer/Switch2Test.cpp @@ -0,0 +1,35 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the interesting switch value. +#include +#include +#include +#include +#include + +int Switch(int a) { + switch(a) { + case 100001: return 1; + case 100002: return 2; + case 100003: return 4; + } + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const int N = 3; + if (Size < N * sizeof(int)) return 0; + int Res = 0; + for (int i = 0; i < N; i++) { + int X; + memcpy(&X, Data + i * sizeof(int), sizeof(int)); + Res += Switch(X); + } + if (Res == 5 || Res == 3 || Res == 6 || Res == 7) { + fprintf(stderr, "BINGO; Found the target, exiting; Res=%d\n", Res); + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/SwitchTest.cpp b/test/fuzzer/SwitchTest.cpp new file mode 100644 index 000000000..86944cad2 --- /dev/null +++ b/test/fuzzer/SwitchTest.cpp @@ -0,0 +1,58 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the interesting switch value. +#include +#include +#include +#include +#include + +static volatile int Sink; + +template +bool Switch(const uint8_t *Data, size_t Size) { + T X; + if (Size < sizeof(X)) return false; + memcpy(&X, Data, sizeof(X)); + switch (X) { + case 1: Sink = __LINE__; break; + case 101: Sink = __LINE__; break; + case 1001: Sink = __LINE__; break; + case 10001: Sink = __LINE__; break; + case 100001: Sink = __LINE__; break; + case 1000001: Sink = __LINE__; break; + case 10000001: Sink = __LINE__; break; + case 100000001: return true; + } + return false; +} + +bool ShortSwitch(const uint8_t *Data, size_t Size) { + short X; + if (Size < sizeof(short)) return false; + memcpy(&X, Data, sizeof(short)); + switch(X) { + case 42: Sink = __LINE__; break; + case 402: Sink = __LINE__; break; + case 4002: Sink = __LINE__; break; + case 5002: Sink = __LINE__; break; + case 7002: Sink = __LINE__; break; + case 9002: Sink = __LINE__; break; + case 14002: Sink = __LINE__; break; + case 21402: return true; + } + return false; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size >= 4 && Switch(Data, Size) && + Size >= 12 && Switch(Data + 4, Size - 4) && + Size >= 14 && ShortSwitch(Data + 12, 2) + ) { + fprintf(stderr, "BINGO; Found the target, exiting\n"); + exit(1); + } + return 0; +} + diff --git a/test/fuzzer/TableLookupTest.cpp b/test/fuzzer/TableLookupTest.cpp new file mode 100644 index 000000000..4d8ab0611 --- /dev/null +++ b/test/fuzzer/TableLookupTest.cpp @@ -0,0 +1,44 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Make sure the fuzzer eventually finds all possible values of a variable +// within a range. +#include +#include +#include +#include +#include +#include + +const size_t N = 1 << 12; + +// Define an array of counters that will be understood by libFuzzer +// as extra coverage signal. The array must be: +// * uint8_t +// * in the section named __libfuzzer_extra_counters. +// The target code may declare more than one such array. +// +// Use either `Counters[Idx] = 1` or `Counters[Idx]++;` +// depending on whether multiple occurrences of the event 'Idx' +// is important to distinguish from one occurrence. +#ifdef __linux__ +__attribute__((section("__libfuzzer_extra_counters"))) +#endif +static uint8_t Counters[N]; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static std::set SeenIdx; + if (Size != 4) return 0; + uint32_t Idx; + memcpy(&Idx, Data, 4); + Idx %= N; + assert(Counters[Idx] == 0); // libFuzzer should reset these between the runs. + // Or Counters[Idx]=1 if we don't care how many times this happened. + Counters[Idx]++; + SeenIdx.insert(Idx); + if (SeenIdx.size() == N) { + fprintf(stderr, "BINGO: found all values\n"); + abort(); + } + return 0; +} diff --git a/test/fuzzer/ThreadedLeakTest.cpp b/test/fuzzer/ThreadedLeakTest.cpp new file mode 100644 index 000000000..538d3b434 --- /dev/null +++ b/test/fuzzer/ThreadedLeakTest.cpp @@ -0,0 +1,18 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// The fuzzer should find a leak in a non-main thread. +#include +#include +#include + +static volatile int *Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) return 0; + if (Data[0] != 'F') return 0; + std::thread T([&] { Sink = new int; }); + T.join(); + return 0; +} + diff --git a/test/fuzzer/ThreadedTest.cpp b/test/fuzzer/ThreadedTest.cpp new file mode 100644 index 000000000..bb51ba764 --- /dev/null +++ b/test/fuzzer/ThreadedTest.cpp @@ -0,0 +1,26 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Threaded test for a fuzzer. The fuzzer should not crash. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 8) return 0; + assert(Data); + auto C = [&] { + size_t Res = 0; + for (size_t i = 0; i < Size / 2; i++) + Res += memcmp(Data, Data + Size / 2, 4); + return Res; + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} + diff --git a/test/fuzzer/TimeoutEmptyTest.cpp b/test/fuzzer/TimeoutEmptyTest.cpp new file mode 100644 index 000000000..1ddf1fa34 --- /dev/null +++ b/test/fuzzer/TimeoutEmptyTest.cpp @@ -0,0 +1,14 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the empty string. +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static volatile int Zero = 0; + if (!Size) + while(!Zero) + ; + return 0; +} diff --git a/test/fuzzer/TimeoutTest.cpp b/test/fuzzer/TimeoutTest.cpp new file mode 100644 index 000000000..e3cdba3ee --- /dev/null +++ b/test/fuzzer/TimeoutTest.cpp @@ -0,0 +1,26 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + Sink = 2; + while (Sink) + ; + } + } + } + return 0; +} + diff --git a/test/fuzzer/TraceMallocTest.cpp b/test/fuzzer/TraceMallocTest.cpp new file mode 100644 index 000000000..af9975603 --- /dev/null +++ b/test/fuzzer/TraceMallocTest.cpp @@ -0,0 +1,27 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Tests -trace_malloc +#include +#include +#include +#include +#include + +int *Ptr; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (!Size) return 0; + if (*Data == 1) { + delete Ptr; + Ptr = nullptr; + } else if (*Data == 2) { + delete Ptr; + Ptr = new int; + } else if (*Data == 3) { + if (!Ptr) + Ptr = new int; + } + return 0; +} + diff --git a/test/fuzzer/TwoDifferentBugsTest.cpp b/test/fuzzer/TwoDifferentBugsTest.cpp new file mode 100644 index 000000000..77d2cb1a2 --- /dev/null +++ b/test/fuzzer/TwoDifferentBugsTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. This test may trigger two different bugs. +#include +#include +#include +#include + +static volatile int *Null = 0; + +void Foo() { Null[1] = 0; } +void Bar() { Null[2] = 0; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 10 && Data[0] == 'H') + Foo(); + if (Size >= 10 && Data[0] == 'H') + Bar(); + return 0; +} + diff --git a/test/fuzzer/afl-driver-extra-stats.test b/test/fuzzer/afl-driver-extra-stats.test new file mode 100644 index 000000000..a6de53302 --- /dev/null +++ b/test/fuzzer/afl-driver-extra-stats.test @@ -0,0 +1,30 @@ +RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest + +; Test that not specifying an extra stats file isn't broken. +RUN: unset AFL_DRIVER_EXTRA_STATS_FILENAME +RUN: %t-AFLDriverTest + +; Test that specifying an invalid extra stats file causes a crash. +RUN: ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%T not --crash %t-AFLDriverTest + +; Test that specifying a corrupted stats file causes a crash. +echo "peak_rss_mb :0" > %t +ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%t not --crash %t-AFLDriverTest + +; Test that specifying a valid nonexistent stats file works. +RUN: rm -f %t +RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest +RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] + +; Test that specifying a valid preexisting stats file works. +RUN: printf "peak_rss_mb : 0\nslowest_unit_time_sec: 0\n" > %t +RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest +; Check that both lines were printed. +RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] + +; Test that peak_rss_mb and slowest_unit_time_in_secs are only updated when necessary. +; Check that both lines have 9999 since there's no way we have exceeded that +; amount of time or virtual memory. +RUN: printf "peak_rss_mb : 9999\nslowest_unit_time_sec: 9999\n" > %t +RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest +RUN: [[ $(grep "9999" %t | wc -l) -eq 2 ]] diff --git a/test/fuzzer/afl-driver-stderr.test b/test/fuzzer/afl-driver-stderr.test new file mode 100644 index 000000000..be0efaa8f --- /dev/null +++ b/test/fuzzer/afl-driver-stderr.test @@ -0,0 +1,12 @@ +RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest + +; Test that not specifying a stderr file isn't broken. +RUN: unset AFL_DRIVER_STDERR_DUPLICATE_FILENAME +RUN: %t-AFLDriverTest + +; Test that specifying an invalid file causes a crash. +RUN: ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash %t-AFLDriverTest + +; Test that a file is created when specified as the duplicate stderr. +RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t %t-AFLDriverTest +RUN: stat %t diff --git a/test/fuzzer/afl-driver.test b/test/fuzzer/afl-driver.test new file mode 100644 index 000000000..32e7d03b4 --- /dev/null +++ b/test/fuzzer/afl-driver.test @@ -0,0 +1,29 @@ +REQUIRES: linux + +RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest + +RUN: echo -n "abc" > %t.file3 +RUN: echo -n "abcd" > %t.file4 + +RUN: %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: __afl_persistent_loop calle, Count = 1000 +CHECK1: LLVMFuzzerTestOneInput called; Size = 3 + + +RUN: %t-AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: __afl_persistent_loop calle, Count = 42 +CHECK2: LLVMFuzzerTestOneInput called; Size = 3 + + +RUN: %t-AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: WARNING: using the deprecated call style +CHECK3: __afl_persistent_loop calle, Count = 666 +CHECK3: LLVMFuzzerTestOneInput called; Size = 3 + + +RUN: %t-AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4 +CHECK4: LLVMFuzzerTestOneInput called; Size = 3 + +RUN: %t-AFLDriverTest %t.file3 %t.file4 2>&1 | FileCheck %s --check-prefix=CHECK5 +CHECK5: LLVMFuzzerTestOneInput called; Size = 3 +CHECK5: LLVMFuzzerTestOneInput called; Size = 4 diff --git a/test/fuzzer/bad-strcmp.test b/test/fuzzer/bad-strcmp.test new file mode 100644 index 000000000..fd1621a4e --- /dev/null +++ b/test/fuzzer/bad-strcmp.test @@ -0,0 +1,2 @@ +RUN: %cpp_compiler %S/BadStrcmpTest.cpp -o %t-BadStrcmpTest +RUN: %t-BadStrcmpTest -runs=100000 diff --git a/test/fuzzer/caller-callee.test b/test/fuzzer/caller-callee.test new file mode 100644 index 000000000..e4eccdc30 --- /dev/null +++ b/test/fuzzer/caller-callee.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/CallerCalleeTest.cpp -o %t-CallerCalleeTest +CHECK: BINGO +RUN: not %t-CallerCalleeTest -use_value_profile=1 -cross_over=0 -seed=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/cleanse.test b/test/fuzzer/cleanse.test new file mode 100644 index 000000000..8e45dc77d --- /dev/null +++ b/test/fuzzer/cleanse.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/CleanseTest.cpp -o %t-CleanseTest +RUN: echo -n 0123456789ABCDEFGHIZ > %t-in +RUN: %t-CleanseTest -cleanse_crash=1 %t-in -exact_artifact_path=%t-out +RUN: echo -n ' 1 5 A Z' | diff - %t-out diff --git a/test/fuzzer/coverage.test b/test/fuzzer/coverage.test new file mode 100644 index 000000000..9a2179d91 --- /dev/null +++ b/test/fuzzer/coverage.test @@ -0,0 +1,21 @@ +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so +RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest + +CHECK: COVERAGE: +CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 +CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14 +CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16 +RUN: not %t-NullDerefTest -print_coverage=1 2>&1 | FileCheck %s + +RUN: %t-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO +DSO: COVERAGE: +DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp +DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp +DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain +DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp +DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp +DSO-DAG: UNCOVERED_FUNC: in Uncovered1 +DSO-DAG: UNCOVERED_FUNC: in Uncovered2 +DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput diff --git a/test/fuzzer/cxxstring.test b/test/fuzzer/cxxstring.test new file mode 100644 index 000000000..7bb341ba2 --- /dev/null +++ b/test/fuzzer/cxxstring.test @@ -0,0 +1,6 @@ +UNSUPPORTED: windows + +RUN: %cpp_compiler %S/CxxStringEqTest.cpp -o %t-CxxStringEqTest + +RUN: not %t-CxxStringEqTest -seed=1 -runs=1000000 2>&1 | FileCheck %s +CHECK: BINGO diff --git a/test/fuzzer/dict1.txt b/test/fuzzer/dict1.txt new file mode 100644 index 000000000..520d0cc7b --- /dev/null +++ b/test/fuzzer/dict1.txt @@ -0,0 +1,4 @@ +# Dictionary for SimpleDictionaryTest + +a="Elvis" +b="Presley" diff --git a/test/fuzzer/disable-leaks.test b/test/fuzzer/disable-leaks.test new file mode 100644 index 000000000..bc120d98b --- /dev/null +++ b/test/fuzzer/disable-leaks.test @@ -0,0 +1,5 @@ +REQUIRES: lsan +RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest +RUN: %t-AccumulateAllocationsTest -detect_leaks=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=ACCUMULATE_ALLOCS +ACCUMULATE_ALLOCS: INFO: libFuzzer disabled leak detection after every mutation + diff --git a/test/fuzzer/dump_coverage.test b/test/fuzzer/dump_coverage.test new file mode 100644 index 000000000..a733355ee --- /dev/null +++ b/test/fuzzer/dump_coverage.test @@ -0,0 +1,20 @@ +RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so +RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so +RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest + +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest + +RUN: rm -rf %t_workdir && mkdir -p %t_workdir +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s +RUN: sancov -covered-functions %t-NullDerefTest* %t_workdir/*.sancov | FileCheck %s --check-prefix=SANCOV +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' %t-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO +RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV + +CHECK: SanitizerCoverage: {{.*}}NullDerefTest.{{.*}}.sancov: {{.*}} PCs written +SANCOV: LLVMFuzzerTestOneInput + +DSO: SanitizerCoverage: {{.*}}DSOTest.{{.*}}.sancov: {{.*}} PCs written +DSO-DAG: SanitizerCoverage: {{.*}}DSO1.{{.*}}.sancov: {{.*}} PCs written +DSO-DAG: SanitizerCoverage: {{.*}}DSO2.{{.*}}.sancov: {{.*}} PCs written + +NOCOV-NOT: SanitizerCoverage: {{.*}} PCs written diff --git a/test/fuzzer/equivalence-signals.test b/test/fuzzer/equivalence-signals.test new file mode 100644 index 000000000..7951636e8 --- /dev/null +++ b/test/fuzzer/equivalence-signals.test @@ -0,0 +1,9 @@ +# Run EquivalenceATest against itself with a small timeout +# to stress the signal handling and ensure that shmem doesn't mind +# the signals. + +RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest +RUN: %t-EquivalenceATest -timeout=1 -run_equivalence_server=EQUIV_SIG_TEST & export APID=$! +RUN: sleep 3 +RUN: %t-EquivalenceATest -timeout=1 -use_equivalence_server=EQUIV_SIG_TEST -runs=500000 2>&1 +RUN: kill -9 $APID diff --git a/test/fuzzer/equivalence.test b/test/fuzzer/equivalence.test new file mode 100644 index 000000000..12964f478 --- /dev/null +++ b/test/fuzzer/equivalence.test @@ -0,0 +1,9 @@ +RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest +RUN: %cpp_compiler %S/EquivalenceBTest.cpp -o %t-EquivalenceBTest + +RUN: %t-EquivalenceATest -run_equivalence_server=EQUIV_TEST & export APID=$! +RUN: sleep 3 +RUN: not %t-EquivalenceBTest -use_equivalence_server=EQUIV_TEST -max_len=4096 2>&1 | FileCheck %s +CHECK: ERROR: libFuzzer: equivalence-mismatch. Sizes: {{.*}}; offset 2 +CHECK: SUMMARY: libFuzzer: equivalence-mismatch +RUN: kill -9 $APID diff --git a/test/fuzzer/exit-report.test b/test/fuzzer/exit-report.test new file mode 100644 index 000000000..f754c1376 --- /dev/null +++ b/test/fuzzer/exit-report.test @@ -0,0 +1,6 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest +RUN: not %t-SimpleTest 2>&1 | FileCheck %s + +CHECK: ERROR: libFuzzer: fuzz target exited +CHECK: SUMMARY: libFuzzer: fuzz target exited +CHECK: Test unit written to diff --git a/test/fuzzer/exit_on_src_pos.test b/test/fuzzer/exit_on_src_pos.test new file mode 100644 index 000000000..6a42c7ae9 --- /dev/null +++ b/test/fuzzer/exit_on_src_pos.test @@ -0,0 +1,8 @@ +# Temporary use -mllvm -use-unknown-locations=Disable so that +# all instructions have debug info (file line numbers) attached. +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -mllvm -use-unknown-locations=Disable +RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest + +RUN: %t-SimpleTest -exit_on_src_pos=SimpleTest.cpp:18 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS +RUN: %t-ShrinkControlFlowTest -exit_on_src_pos=Foo 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS +EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting. diff --git a/test/fuzzer/extra-counters.test b/test/fuzzer/extra-counters.test new file mode 100644 index 000000000..230f74a1b --- /dev/null +++ b/test/fuzzer/extra-counters.test @@ -0,0 +1,7 @@ +REQUIRES: linux + +RUN: %cpp_compiler %S/TableLookupTest.cpp -o %t-TableLookupTest +RUN: not %t-TableLookupTest -print_final_stats=1 2>&1 | FileCheck %s +CHECK: BINGO +// Expecting >= 4096 new_units_added +CHECK: stat::new_units_added:{{.*[4][0-9][0-9][0-9]}} diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test new file mode 100644 index 000000000..8f74cd98f --- /dev/null +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -0,0 +1,12 @@ +RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest + +RUN: rm -rf %t/CustomCrossover +RUN: mkdir -p %t/CustomCrossover +RUN: echo "0123456789" > %t/CustomCrossover/digits +RUN: echo "abcdefghij" > %t/CustomCrossover/chars +RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover +RUN: rm -rf %t/CustomCrossover + +LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover +LLVMFuzzerCustomCrossover: BINGO + diff --git a/test/fuzzer/fuzzer-customcrossoverandmutate.test b/test/fuzzer/fuzzer-customcrossoverandmutate.test new file mode 100644 index 000000000..4a7dfba2a --- /dev/null +++ b/test/fuzzer/fuzzer-customcrossoverandmutate.test @@ -0,0 +1,2 @@ +RUN: %cpp_compiler %S/CustomCrossOverAndMutateTest.cpp -o %t-CustomCrossOverAndMutateTest +RUN: %t-CustomCrossOverAndMutateTest -seed=1 -runs=100000 diff --git a/test/fuzzer/fuzzer-custommutator.test b/test/fuzzer/fuzzer-custommutator.test new file mode 100644 index 000000000..7a693cd47 --- /dev/null +++ b/test/fuzzer/fuzzer-custommutator.test @@ -0,0 +1,5 @@ +RUN: %cpp_compiler %S/CustomMutatorTest.cpp -o %t-CustomMutatorTest +RUN: not %t-CustomMutatorTest 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomMutator +LLVMFuzzerCustomMutator: In LLVMFuzzerCustomMutator +LLVMFuzzerCustomMutator: BINGO + diff --git a/test/fuzzer/fuzzer-dict.test b/test/fuzzer/fuzzer-dict.test new file mode 100644 index 000000000..48c91dc1d --- /dev/null +++ b/test/fuzzer/fuzzer-dict.test @@ -0,0 +1,8 @@ +RUN: %cpp_compiler %S/SimpleDictionaryTest.cpp -o %t-SimpleDictionaryTest + +CHECK: BINGO +Done1000000: Done 1000000 runs in + +RUN: not %t-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s +RUN: %t-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + diff --git a/test/fuzzer/fuzzer-dirs.test b/test/fuzzer/fuzzer-dirs.test new file mode 100644 index 000000000..ef0888f3b --- /dev/null +++ b/test/fuzzer/fuzzer-dirs.test @@ -0,0 +1,21 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest + +RUN: rm -rf %t/SUB1 +RUN: mkdir -p %t/SUB1/SUB2/SUB3 +RUN: echo a > %t/SUB1/a +RUN: echo b > %t/SUB1/SUB2/b +RUN: echo c > %t/SUB1/SUB2/SUB3/c +RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS +SUBDIRS: READ units: 3 +RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/f64 +RUN: cat %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 > %t/SUB1/f256 +RUN: cat %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 > %t/SUB1/f1024 +RUN: cat %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 > %t/SUB1/f4096 +RUN: cat %t/SUB1/f4096 %t/SUB1/f4096 > %t/SUB1/f8192 +RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG +LONG: INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 8192 bytes +RUN: rm -rf %t/SUB1 + +RUN: not %t-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR +NONEXISTENT_DIR: No such directory: NONEXISTENT_DIR; exiting + diff --git a/test/fuzzer/fuzzer-fdmask.test b/test/fuzzer/fuzzer-fdmask.test new file mode 100644 index 000000000..3f04993b5 --- /dev/null +++ b/test/fuzzer/fuzzer-fdmask.test @@ -0,0 +1,32 @@ +RUN: %cpp_compiler %S/SpamyTest.cpp -o %t-SpamyTest + +RUN: %t-SpamyTest -runs=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 +RUN: %t-SpamyTest -runs=1 -close_fd_mask=0 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 +RUN: %t-SpamyTest -runs=1 -close_fd_mask=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_1 +RUN: %t-SpamyTest -runs=1 -close_fd_mask=2 2>&1 | FileCheck %s --check-prefix=FD_MASK_2 +RUN: %t-SpamyTest -runs=1 -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=FD_MASK_3 + +FD_MASK_0: PRINTF_STDOUT +FD_MASK_0: PRINTF_STDERR +FD_MASK_0: STREAM_COUT +FD_MASK_0: STREAM_CERR +FD_MASK_0: INITED + +FD_MASK_1-NOT: PRINTF_STDOUT +FD_MASK_1: PRINTF_STDERR +FD_MASK_1-NOT: STREAM_COUT +FD_MASK_1: STREAM_CERR +FD_MASK_1: INITED + +FD_MASK_2: PRINTF_STDOUT +FD_MASK_2-NOT: PRINTF_STDERR +FD_MASK_2: STREAM_COUT +FD_MASK_2-NOTE: STREAM_CERR +FD_MASK_2: INITED + +FD_MASK_3-NOT: PRINTF_STDOUT +FD_MASK_3-NOT: PRINTF_STDERR +FD_MASK_3-NOT: STREAM_COUT +FD_MASK_3-NOT: STREAM_CERR +FD_MASK_3: INITED + diff --git a/test/fuzzer/fuzzer-finalstats.test b/test/fuzzer/fuzzer-finalstats.test new file mode 100644 index 000000000..4f983bea8 --- /dev/null +++ b/test/fuzzer/fuzzer-finalstats.test @@ -0,0 +1,12 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest +RUN: %t-SimpleTest -seed=1 -runs=77 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS +FINAL_STATS: stat::number_of_executed_units: 77 +FINAL_STATS: stat::average_exec_per_sec: 0 +FINAL_STATS: stat::new_units_added: +FINAL_STATS: stat::slowest_unit_time_sec: 0 +FINAL_STATS: stat::peak_rss_mb: + +RUN: %t-SimpleTest %S/dict1.txt -runs=33 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS1 +FINAL_STATS1: stat::number_of_executed_units: 33 +FINAL_STATS1: stat::peak_rss_mb: + diff --git a/test/fuzzer/fuzzer-flags.test b/test/fuzzer/fuzzer-flags.test new file mode 100644 index 000000000..2f9a31063 --- /dev/null +++ b/test/fuzzer/fuzzer-flags.test @@ -0,0 +1,19 @@ +RUN: %cpp_compiler %S/FlagsTest.cpp -o %t-FlagsTest +RUN: not %t-FlagsTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR +FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags +FOO_BAR: BINGO + +RUN: not %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH +DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)? +DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus + +RUN: %t-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL +NO_INTERNAL-NOT: internal flag + +RUN: not %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU +PASSTHRU: BINGO --foo-bar --baz -help=1 test + +RUN: mkdir -p %t/T0 %t/T1 +RUN: touch %t/T1/empty +RUN: not %t-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE +PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test diff --git a/test/fuzzer/fuzzer-leak.test b/test/fuzzer/fuzzer-leak.test new file mode 100644 index 000000000..f8e99ce3f --- /dev/null +++ b/test/fuzzer/fuzzer-leak.test @@ -0,0 +1,37 @@ +REQUIRES: lsan +RUN: %cpp_compiler %S/LeakTest.cpp -o %t-LeakTest +RUN: %cpp_compiler %S/ThreadedLeakTest.cpp -o %t-ThreadedLeakTest +RUN: %cpp_compiler %S/LeakTimeoutTest.cpp -o %t-LeakTimeoutTest + +RUN: not %t-LeakTest -runs=100000 -detect_leaks=1 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +LEAK_DURING: ERROR: LeakSanitizer: detected memory leaks +LEAK_DURING: Direct leak of 4 byte(s) in 1 object(s) allocated from: +LEAK_DURING: INFO: to ignore leaks on libFuzzer side use -detect_leaks=0 +LEAK_DURING: Test unit written to ./leak- +LEAK_DURING-NOT: DONE +LEAK_DURING-NOT: Done + +RUN: not %t-LeakTest -runs=0 -detect_leaks=1 %S 2>&1 | FileCheck %s --check-prefix=LEAK_IN_CORPUS +LEAK_IN_CORPUS: ERROR: LeakSanitizer: detected memory leaks +LEAK_IN_CORPUS: INFO: a leak has been found in the initial corpus. + +RUN: not %t-LeakTest -runs=100000000 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=MULTI_RUN_LEAK +MULTI_RUN_LEAK-NOT: pulse +MULTI_RUN_LEAK: LeakSanitizer: detected memory leaks + +RUN: not %t-LeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER +RUN: not %t-LeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +RUN: not %t-ThreadedLeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER +RUN: not %t-ThreadedLeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING +LEAK_AFTER: Done 100000 runs in +LEAK_AFTER: ERROR: LeakSanitizer: detected memory leaks + +RUN: not %t-LeakTest -runs=100000 -max_len=1 2>&1 | FileCheck %s --check-prefix=MAX_LEN_1 +MAX_LEN_1: Test unit written to ./leak-7cf184f4c67ad58283ecb19349720b0cae756829 + +RUN: not %t-LeakTimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=LEAK_TIMEOUT +LEAK_TIMEOUT: ERROR: libFuzzer: timeout after +LEAK_TIMEOUT-NOT: LeakSanitizer + + +RUN: %t-LeakTest -error_exitcode=0 diff --git a/test/fuzzer/fuzzer-oom-with-profile.test b/test/fuzzer/fuzzer-oom-with-profile.test new file mode 100644 index 000000000..75cf48430 --- /dev/null +++ b/test/fuzzer/fuzzer-oom-with-profile.test @@ -0,0 +1,7 @@ +REQUIRES: linux +RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest +RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s +CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb) +CHECK: Live Heap Allocations +CHECK: Test unit written to ./oom- +SUMMARY: libFuzzer: out-of-memory diff --git a/test/fuzzer/fuzzer-oom.test b/test/fuzzer/fuzzer-oom.test new file mode 100644 index 000000000..9ef7c485d --- /dev/null +++ b/test/fuzzer/fuzzer-oom.test @@ -0,0 +1,20 @@ +RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest +RUN: %cpp_compiler %S/OutOfMemorySingleLargeMallocTest.cpp -o %t-OutOfMemorySingleLargeMallocTest +RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest + +RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s + +CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb) +CHECK: Test unit written to ./oom- +SUMMARY: libFuzzer: out-of-memory + +RUN: not %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC + +We used to check for "out-of-memory (malloc(53{{.*}}))", but that would fail +sometimes, so now we accept any OOM message. + +SINGLE_LARGE_MALLOC: libFuzzer: out-of-memory +SINGLE_LARGE_MALLOC: in LLVMFuzzerTestOneInput + +# Check that -rss_limit_mb=0 means no limit. +RUN: %t-AccumulateAllocationsTest -runs=1000 -rss_limit_mb=0 diff --git a/test/fuzzer/fuzzer-printcovpcs.test b/test/fuzzer/fuzzer-printcovpcs.test new file mode 100644 index 000000000..e55ce14aa --- /dev/null +++ b/test/fuzzer/fuzzer-printcovpcs.test @@ -0,0 +1,9 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest +RUN: not %t-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS +PCS-NOT: NEW_PC +PCS:INITED +PCS:NEW_PC: {{0x[a-f0-9]+}} +PCS:NEW_PC: {{0x[a-f0-9]+}} +PCS:NEW +PCS:BINGO + diff --git a/test/fuzzer/fuzzer-runs.test b/test/fuzzer/fuzzer-runs.test new file mode 100644 index 000000000..04987eee5 --- /dev/null +++ b/test/fuzzer/fuzzer-runs.test @@ -0,0 +1,9 @@ +RUN: mkdir -p %t +RUN: %cpp_compiler %S/NthRunCrashTest.cpp -o %t-NthRunCrashTest +RUN: echo abcd > %t/NthRunCrashTest.in +RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in +RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10 +RUN: not %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10000 2>&1 | FileCheck %s +RUN: rm %t/NthRunCrashTest.in +CHECK: BINGO + diff --git a/test/fuzzer/fuzzer-seed.test b/test/fuzzer/fuzzer-seed.test new file mode 100644 index 000000000..a69ea5432 --- /dev/null +++ b/test/fuzzer/fuzzer-seed.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-SimpleCmpTest +RUN: %t-SimpleCmpTest -seed=-1 -runs=0 2>&1 | FileCheck %s --check-prefix=CHECK_SEED_MINUS_ONE +CHECK_SEED_MINUS_ONE: Seed: 4294967295 + diff --git a/test/fuzzer/fuzzer-segv.test b/test/fuzzer/fuzzer-segv.test new file mode 100644 index 000000000..4d3c7575f --- /dev/null +++ b/test/fuzzer/fuzzer-segv.test @@ -0,0 +1,8 @@ +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: env ASAN_OPTIONS=handle_segv=0 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER +LIBFUZZER_OWN_SEGV_HANDLER: == ERROR: libFuzzer: deadly signal +LIBFUZZER_OWN_SEGV_HANDLER: SUMMARY: libFuzzer: deadly signal +LIBFUZZER_OWN_SEGV_HANDLER: Test unit written to ./crash- + +RUN: env ASAN_OPTIONS=handle_segv=1 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_ASAN_SEGV_HANDLER +LIBFUZZER_ASAN_SEGV_HANDLER: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address diff --git a/test/fuzzer/fuzzer-singleinputs.test b/test/fuzzer/fuzzer-singleinputs.test new file mode 100644 index 000000000..468da5622 --- /dev/null +++ b/test/fuzzer/fuzzer-singleinputs.test @@ -0,0 +1,19 @@ +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest + +RUN: not %t-NullDerefTest %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput +SingleInput-NOT: Test unit written to ./crash- + +RUN: rm -rf %tmp/SINGLE_INPUTS +RUN: mkdir -p %tmp/SINGLE_INPUTS +RUN: echo aaa > %tmp/SINGLE_INPUTS/aaa +RUN: echo bbb > %tmp/SINGLE_INPUTS/bbb +RUN: %t-SimpleTest %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS +RUN: %t-SimpleTest -max_len=2 %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS +RUN: rm -rf %tmp/SINGLE_INPUTS +SINGLE_INPUTS: SimpleTest{{.*}}: Running 2 inputs 1 time(s) each. +SINGLE_INPUTS: aaa in +SINGLE_INPUTS: bbb in +SINGLE_INPUTS: NOTE: fuzzing was not performed, you have only +SINGLE_INPUTS: executed the target code on a fixed set of inputs. + diff --git a/test/fuzzer/fuzzer-threaded.test b/test/fuzzer/fuzzer-threaded.test new file mode 100644 index 000000000..572ed5a35 --- /dev/null +++ b/test/fuzzer/fuzzer-threaded.test @@ -0,0 +1,8 @@ +CHECK: Done 1000 runs in +RUN: %cpp_compiler %S/ThreadedTest.cpp -o %t-ThreadedTest + +RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s + diff --git a/test/fuzzer/fuzzer-timeout.test b/test/fuzzer/fuzzer-timeout.test new file mode 100644 index 000000000..41f4ba364 --- /dev/null +++ b/test/fuzzer/fuzzer-timeout.test @@ -0,0 +1,21 @@ +RUN: %cpp_compiler %S/TimeoutTest.cpp -o %t-TimeoutTest +RUN: %cpp_compiler %S/TimeoutEmptyTest.cpp -o %t-TimeoutEmptyTest +RUN: not %t-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest +TimeoutTest: ALARM: working on the last Unit for +TimeoutTest: Test unit written to ./timeout- +TimeoutTest: == ERROR: libFuzzer: timeout after +TimeoutTest: #0 +TimeoutTest: #1 +TimeoutTest: #2 +TimeoutTest: SUMMARY: libFuzzer: timeout + +RUN: not %t-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest +SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds +SingleInputTimeoutTest-NOT: Test unit written to ./timeout- + +RUN: %t-TimeoutTest -timeout=1 -timeout_exitcode=0 + +RUN: not %t-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest +TimeoutEmptyTest: ALARM: working on the last Unit for +TimeoutEmptyTest: == ERROR: libFuzzer: timeout after +TimeoutEmptyTest: SUMMARY: libFuzzer: timeout diff --git a/test/fuzzer/fuzzer-ubsan.test b/test/fuzzer/fuzzer-ubsan.test new file mode 100644 index 000000000..49c190cd0 --- /dev/null +++ b/test/fuzzer/fuzzer-ubsan.test @@ -0,0 +1,5 @@ +RUN: %cpp_compiler -fsanitize=undefined -fno-sanitize-recover=all %S/SignedIntOverflowTest.cpp -o %t-SignedIntOverflowTest-Ubsan +RUN: not %t-SignedIntOverflowTest-Ubsan 2>&1 | FileCheck %s +CHECK: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' +CHECK: Test unit written to ./crash- + diff --git a/test/fuzzer/fuzzer.test b/test/fuzzer/fuzzer.test new file mode 100644 index 000000000..e506fcbee --- /dev/null +++ b/test/fuzzer/fuzzer.test @@ -0,0 +1,70 @@ +CHECK: BINGO +Done1000000: Done 1000000 runs in +RUN: %cpp_compiler %S/BogusInitializeTest.cpp -o %t-BogusInitializeTest +RUN: %cpp_compiler %S/BufferOverflowOnInput.cpp -o %t-BufferOverflowOnInput +RUN: %cpp_compiler %S/CounterTest.cpp -o %t-CounterTest +RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so +RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so +RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest +RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest +RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest +RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -o %t-NotinstrumentedTest-NoCoverage +RUN: %cpp_compiler %S/NullDerefOnEmptyTest.cpp -o %t-NullDerefOnEmptyTest +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest +RUN: %cpp_compiler %S/StrncmpOOBTest.cpp -o %t-StrncmpOOBTest + +RUN: not %t-SimpleTest 2>&1 | FileCheck %s + +# only_ascii mode. Will perform some minimal self-validation. +RUN: not %t-SimpleTest -only_ascii=1 2>&1 + +RUN: %t-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime +MaxTotalTime: Done {{.*}} runs in {{.}} second(s) + +RUN: not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest +RUN: not %t-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest +NullDerefTest: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address +NullDerefTest: Test unit written to ./crash- +RUN: not %t-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix +NullDerefTestPrefix: Test unit written to ZZZcrash- +RUN: not %t-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath +NullDerefTestExactPath: Test unit written to FOOBAR + +RUN: not %t-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY +NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: + +#not %t-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s + +RUN: not %t-CounterTest -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS + +COUNTERS: INITED {{.*}} {{bits:|ft:}} +COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} +COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} +COUNTERS: BINGO + +# Don't run UninstrumentedTest for now since we build libFuzzer itself with asan. +DISABLED: not %t-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED +UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. + +RUN: not %t-NotinstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE +NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting + +RUN: not %t-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB +OOB: AddressSanitizer: heap-buffer-overflow +OOB: is located 0 bytes to the right of 3-byte region + +RUN: not %t-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s + +RUN: not %t-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO +DSO: INFO: Loaded 3 modules +DSO: BINGO + +RUN: env ASAN_OPTIONS=strict_string_checks=1 not %t-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP +STRNCMP: AddressSanitizer: heap-buffer-overflow +STRNCMP-NOT: __sanitizer_weak_hook_strncmp +STRNCMP: in LLVMFuzzerTestOneInput + +RUN: not %t-BogusInitializeTest 2>&1 | FileCheck %s --check-prefix=BOGUS_INITIALIZE +BOGUS_INITIALIZE: argv[0] has been modified in LLVMFuzzerInitialize diff --git a/test/fuzzer/hi.txt b/test/fuzzer/hi.txt new file mode 100644 index 000000000..2f9031f0e --- /dev/null +++ b/test/fuzzer/hi.txt @@ -0,0 +1 @@ +Hi! \ No newline at end of file diff --git a/test/fuzzer/inline-8bit-counters.test b/test/fuzzer/inline-8bit-counters.test new file mode 100644 index 000000000..5723c70b1 --- /dev/null +++ b/test/fuzzer/inline-8bit-counters.test @@ -0,0 +1,5 @@ +REQUIRES: linux +RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters -o %t-SimpleTest-Inline8bitCounters +CHECK: INFO: Loaded 1 modules ({{.*}} inline 8-bit counters) +CHECK: BINGO +RUN: not %t-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/lit.cfg b/test/fuzzer/lit.cfg new file mode 100644 index 000000000..a82ca23b9 --- /dev/null +++ b/test/fuzzer/lit.cfg @@ -0,0 +1,80 @@ +import lit.formats +import sys +import os + +config.name = "LLVMFuzzer" +config.test_format = lit.formats.ShTest(True) +config.suffixes = ['.test'] +config.test_source_root = os.path.dirname(__file__) + +# Choose between lit's internal shell pipeline runner and a real shell. If +# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. +use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") +if use_lit_shell: + # 0 is external, "" is default, and everything else is internal. + execute_external = (use_lit_shell == "0") +else: + # Otherwise we default to internal on Windows and external elsewhere, as + # bash on Windows is usually very slow. + execute_external = (not sys.platform in ['win32']) + +# testFormat: The test format to use to interpret tests. +# +# For now we require '&&' between commands, until they get globally killed and +# the test runner updated. +config.test_format = lit.formats.ShTest(execute_external) + +# LeakSanitizer is not supported on OSX right now. +if sys.platform.startswith('darwin'): + lit_config.note('lsan feature unavailable') +else: + lit_config.note('lsan feature available') + config.available_features.add('lsan') + +if sys.platform.startswith('win') or sys.platform.startswith('cygwin'): + config.available_features.add('windows') + +if sys.platform.startswith('darwin'): + config.available_features.add('darwin') + +if sys.platform.startswith('linux'): + # Note the value of ``sys.platform`` is not consistent + # between python 2 and 3, hence the use of ``.startswith()``. + lit_config.note('linux feature available') + config.available_features.add('linux') +else: + lit_config.note('linux feature unavailable') + +config.substitutions.append(('%build_dir', config.cmake_binary_dir)) +libfuzzer_src_root = os.path.join(config.compiler_rt_src_root, "lib", "fuzzer") +config.substitutions.append(('%libfuzzer_src', libfuzzer_src_root)) + +def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True): + compiler_cmd = config.c_compiler + link_cmd = '-lc++' if 'darwin' in config.target_triple else '-lstdc++' + std_cmd = '-std=c++11' if is_cpp else '' + sanitizers = ['address'] + if fuzzer_enabled: + sanitizers.append('fuzzer') + sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers)) + isysroot_cmd = ('-isysroot %s' % config.osx_sysroot + ) if 'darwin' in config.target_triple else '' + include_cmd = '-I%s' % libfuzzer_src_root + return '%s %s %s -gline-tables-only %s %s %s' % ( + compiler_cmd, std_cmd, link_cmd, isysroot_cmd, sanitizers_cmd, include_cmd) + +config.substitutions.append(('%cpp_compiler', + generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True) + )) + +config.substitutions.append(('%c_compiler', + generate_compiler_cmd(is_cpp=False, fuzzer_enabled=True) + )) + +config.substitutions.append(('%no_fuzzer_cpp_compiler', + generate_compiler_cmd(is_cpp=True, fuzzer_enabled=False) + )) + +config.substitutions.append(('%no_fuzzer_c_compiler', + generate_compiler_cmd(is_cpp=False, fuzzer_enabled=False) + )) diff --git a/test/fuzzer/lit.site.cfg.in b/test/fuzzer/lit.site.cfg.in new file mode 100644 index 000000000..3f1957511 --- /dev/null +++ b/test/fuzzer/lit.site.cfg.in @@ -0,0 +1,17 @@ +@LIT_SITE_CFG_IN_HEADER@ + +config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" + +config.cpp_compiler = "@LIBFUZZER_TEST_COMPILER@" +config.target_flags = "@LIBFUZZER_TEST_FLAGS@" +config.c_compiler = "@LIBFUZZER_TEST_COMPILER@" + +config.osx_sysroot = "@CMAKE_OSX_SYSROOT@" +config.cmake_binary_dir = "@CMAKE_BINARY_DIR@" +config.target_triple = "@TARGET_TRIPLE@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, + "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/test/fuzzer/memcmp.test b/test/fuzzer/memcmp.test new file mode 100644 index 000000000..3431a524c --- /dev/null +++ b/test/fuzzer/memcmp.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/MemcmpTest.cpp -o %t-MemcmpTest +RUN: not %t-MemcmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s +CHECK: BINGO diff --git a/test/fuzzer/memcmp64.test b/test/fuzzer/memcmp64.test new file mode 100644 index 000000000..223c3bd42 --- /dev/null +++ b/test/fuzzer/memcmp64.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/Memcmp64BytesTest.cpp -o %t-Memcmp64BytesTest +RUN: not %t-Memcmp64BytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s +CHECK: BINGO diff --git a/test/fuzzer/merge-posix.test b/test/fuzzer/merge-posix.test new file mode 100644 index 000000000..e34e3a325 --- /dev/null +++ b/test/fuzzer/merge-posix.test @@ -0,0 +1,23 @@ +RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest + +RUN: rm -rf %tmp/T1 %tmp/T2 +RUN: mkdir -p %tmp/T1 %tmp/T2 + +RUN: echo F..... > %tmp/T1/1 +RUN: echo .U.... > %tmp/T1/2 +RUN: echo ..Z... > %tmp/T1/3 + +RUN: echo .....F > %tmp/T2/1 +RUN: echo ....U. > %tmp/T2/2 +RUN: echo ...Z.. > %tmp/T2/3 +RUN: echo ...Z.. > %tmp/T2/4 +RUN: echo ....E. > %tmp/T2/5 +RUN: echo .....R > %tmp/T2/6 + +# Check that we can report an error if file size exceeded +RUN: (ulimit -f 1; not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ) +SIGXFSZ: ERROR: libFuzzer: file size exceeded + +# Check that we honor TMPDIR +RUN: TMPDIR=DIR_DOES_NOT_EXIST not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=TMPDIR +TMPDIR: MERGE-OUTER: failed to write to the control file: DIR_DOES_NOT_EXIST/libFuzzerTemp diff --git a/test/fuzzer/merge-summary.test b/test/fuzzer/merge-summary.test new file mode 100644 index 000000000..3e21c23ef --- /dev/null +++ b/test/fuzzer/merge-summary.test @@ -0,0 +1,17 @@ +RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest + +RUN: rm -rf %t/T1 %t/T2 +RUN: mkdir -p %t/T0 %t/T1 %t/T2 +RUN: echo ...Z.. > %t/T2/1 +RUN: echo ....E. > %t/T2/2 +RUN: echo .....R > %t/T2/3 +RUN: echo F..... > %t/T2/a +RUN: echo .U.... > %t/T2/b +RUN: echo ..Z... > %t/T2/c + +RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY +SAVE_SUMMARY: MERGE-OUTER: writing coverage summary for 6 files to {{.*}}SUMMARY +RUN: rm %t/T1/* +RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY +LOAD_SUMMARY: MERGE-OUTER: coverage summary loaded from {{.*}}SUMMAR +LOAD_SUMMARY: MERGE-OUTER: 0 new files with 0 new features added diff --git a/test/fuzzer/merge.test b/test/fuzzer/merge.test new file mode 100644 index 000000000..30e27b8d2 --- /dev/null +++ b/test/fuzzer/merge.test @@ -0,0 +1,55 @@ +CHECK: BINGO + +RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest + +RUN: rm -rf %tmp/T0 %tmp/T1 %tmp/T2 +RUN: mkdir -p %tmp/T0 %tmp/T1 %tmp/T2 +RUN: echo F..... > %tmp/T0/1 +RUN: echo .U.... > %tmp/T0/2 +RUN: echo ..Z... > %tmp/T0/3 + +# T1 has 3 elements, T2 is empty. +RUN: cp %tmp/T0/* %tmp/T1/ +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: MERGE-OUTER: 3 files, 3 in the initial corpus +CHECK1: MERGE-OUTER: 0 new files with 0 new features added + +RUN: echo ...Z.. > %tmp/T2/1 +RUN: echo ....E. > %tmp/T2/2 +RUN: echo .....R > %tmp/T2/3 +RUN: echo F..... > %tmp/T2/a +RUN: echo .U.... > %tmp/T2/b +RUN: echo ..Z... > %tmp/T2/c + +# T1 has 3 elements, T2 has 6 elements, only 3 are new. +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: MERGE-OUTER: 9 files, 3 in the initial corpus +CHECK2: MERGE-OUTER: 3 new files with 3 new features added + +# Now, T1 has 6 units and T2 has no new interesting units. +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: MERGE-OUTER: 12 files, 6 in the initial corpus +CHECK3: MERGE-OUTER: 0 new files with 0 new features added + +# Check that we respect max_len during the merge and don't crash. +RUN: rm %tmp/T1/* +RUN: cp %tmp/T0/* %tmp/T1/ +RUN: echo looooooooong > %tmp/T2/looooooooong +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=6 2>&1 | FileCheck %s --check-prefix=MAX_LEN +MAX_LEN: MERGE-OUTER: 3 new files + +# Check that merge tolerates failures. +RUN: rm %tmp/T1/* +RUN: cp %tmp/T0/* %tmp/T1/ +RUN: echo 'FUZZER' > %tmp/T2/FUZZER +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=MERGE_WITH_CRASH +MERGE_WITH_CRASH: MERGE-OUTER: succesfull in 2 attempt(s) +MERGE_WITH_CRASH: MERGE-OUTER: 3 new files + +# Check that we actually limit the size with max_len +RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=5 2>&1 | FileCheck %s --check-prefix=MERGE_LEN5 +MERGE_LEN5: MERGE-OUTER: succesfull in 1 attempt(s) + +RUN: rm -rf %tmp/T1/* %tmp/T2/* +RUN: not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=EMPTY +EMPTY: MERGE-OUTER: zero succesfull attempts, exiting diff --git a/test/fuzzer/minimize_crash.test b/test/fuzzer/minimize_crash.test new file mode 100644 index 000000000..77ab370fa --- /dev/null +++ b/test/fuzzer/minimize_crash.test @@ -0,0 +1,16 @@ +RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: %cpp_compiler %S/SingleByteInputTest.cpp -o %t-SingleByteInputTest + +RUN: echo 'Hi!rv349f34t3gg' > not_minimal_crash +RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s +CHECK: CRASH_MIN: failed to minimize beyond ./minimized-from-{{.*}} (3 bytes), exiting +RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=CHECK_EXACT +CHECK_EXACT: CRASH_MIN: failed to minimize beyond exact_minimized_path (3 bytes), exiting +RUN: rm not_minimal_crash minimized-from-* exact_minimized_path + +RUN: echo -n 'abcd*xyz' > not_minimal_crash +RUN: %t-SingleByteInputTest -minimize_crash=1 not_minimal_crash -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=MIN1 +MIN1: Test unit written to exact_minimized_path +MIN1: Test unit written to exact_minimized_path +MIN1: INFO: The input is small enough, exiting +MIN1: CRASH_MIN: failed to minimize beyond exact_minimized_path (1 bytes), exiting diff --git a/test/fuzzer/minimize_two_crashes.test b/test/fuzzer/minimize_two_crashes.test new file mode 100644 index 000000000..e6ff9990f --- /dev/null +++ b/test/fuzzer/minimize_two_crashes.test @@ -0,0 +1,18 @@ +# Test that the minimizer stops when it sees a differe bug. + +RUN: %cpp_compiler %S/TwoDifferentBugsTest.cpp -o %t-TwoDifferentBugsTest + +RUN: rm -rf %t && mkdir %t +RUN: echo H12345678901234667888090 > %t/long_crash +RUN: env ASAN_OPTIONS=dedup_token_length=3 %t-TwoDifferentBugsTest -seed=1 -minimize_crash=1 %t/long_crash -exact_artifact_path=%t/result 2>&1 | FileCheck %s + +CHECK: DedupToken1: DEDUP_TOKEN: Bar +CHECK: DedupToken2: DEDUP_TOKEN: Bar +CHECK: DedupToken1: DEDUP_TOKEN: Bar +CHECK: DedupToken2: DEDUP_TOKEN: Foo +CHECK: CRASH_MIN: mismatch in dedup tokens + +RUN: not %t-TwoDifferentBugsTest %t/result 2>&1 | FileCheck %s --check-prefix=VERIFY + +VERIFY: ERROR: AddressSanitizer: +VERIFY: in Bar diff --git a/test/fuzzer/overwrite-input.test b/test/fuzzer/overwrite-input.test new file mode 100644 index 000000000..3695622d0 --- /dev/null +++ b/test/fuzzer/overwrite-input.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/OverwriteInputTest.cpp -o %t-OverwriteInputTest +RUN: not %t-OverwriteInputTest 2>&1 | FileCheck %s +CHECK: ERROR: libFuzzer: fuzz target overwrites it's const input diff --git a/test/fuzzer/recommended-dictionary.test b/test/fuzzer/recommended-dictionary.test new file mode 100644 index 000000000..41b62c924 --- /dev/null +++ b/test/fuzzer/recommended-dictionary.test @@ -0,0 +1,6 @@ +RUN: %cpp_compiler %S/RepeatedMemcmp.cpp -o %t-RepeatedMemcmp +RUN: %t-RepeatedMemcmp -seed=11 -runs=100000 -max_len=20 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT +RECOMMENDED_DICT:###### Recommended dictionary. ###### +RECOMMENDED_DICT-DAG: "foo" +RECOMMENDED_DICT-DAG: "bar" +RECOMMENDED_DICT:###### End of recommended dictionary. ###### diff --git a/test/fuzzer/reduce_inputs.test b/test/fuzzer/reduce_inputs.test new file mode 100644 index 000000000..02e090ebd --- /dev/null +++ b/test/fuzzer/reduce_inputs.test @@ -0,0 +1,16 @@ +# Test -reduce_inputs=1 + +RUN: rm -rf %t/C +RUN: mkdir -p %t/C +RUN: %cpp_compiler %S/ShrinkControlFlowSimpleTest.cpp -o %t-ShrinkControlFlowSimpleTest +RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest +RUN: %t-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 %t/C 2>&1 | FileCheck %s +CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60' + +# Test that reduce_inputs deletes redundant files in the corpus. +RUN: %t-ShrinkControlFlowSimpleTest -runs=0 %t/C 2>&1 | FileCheck %s --check-prefix=COUNT +COUNT: READ units: 4 + +# a bit longer test +RUN: %t-ShrinkControlFlowTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -seed=1 -runs=1000000 2>&1 | FileCheck %s + diff --git a/test/fuzzer/repeated-bytes.test b/test/fuzzer/repeated-bytes.test new file mode 100644 index 000000000..0bba2a916 --- /dev/null +++ b/test/fuzzer/repeated-bytes.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/RepeatedBytesTest.cpp -o %t-RepeatedBytesTest +CHECK: BINGO +RUN: not %t-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/shrink.test b/test/fuzzer/shrink.test new file mode 100644 index 000000000..2988d4bbb --- /dev/null +++ b/test/fuzzer/shrink.test @@ -0,0 +1,10 @@ +RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest +RUN: %cpp_compiler %S/ShrinkValueProfileTest.cpp -o %t-ShrinkValueProfileTest +RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=1 -reduce_inputs=0 2>&1 | FileCheck %s --check-prefix=SHRINK1 +# Limit max_len to run this negative test faster. +RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=0 -reduce_inputs=0 -max_len=64 2>&1 | FileCheck %s --check-prefix=SHRINK0 +RUN: %t-ShrinkValueProfileTest -seed=1 -exit_on_item=aea2e3923af219a8956f626558ef32f30a914ebc -runs=100000 -shrink=1 -reduce_inputs=0 -use_value_profile=1 2>&1 | FileCheck %s --check-prefix=SHRINK1_VP + +SHRINK0: Done 1000000 runs in +SHRINK1: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60', exiting. +SHRINK1_VP: INFO: found item with checksum 'aea2e3923af219a8956f626558ef32f30a914ebc', exiting diff --git a/test/fuzzer/simple-cmp.test b/test/fuzzer/simple-cmp.test new file mode 100644 index 000000000..08123ed3a --- /dev/null +++ b/test/fuzzer/simple-cmp.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest +CHECK: BINGO +RUN: not %t-SimpleCmpTest -seed=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/standalone.test b/test/fuzzer/standalone.test new file mode 100644 index 000000000..e6483703f --- /dev/null +++ b/test/fuzzer/standalone.test @@ -0,0 +1,8 @@ +RUN: %no_fuzzer_c_compiler %libfuzzer_src/standalone/StandaloneFuzzTargetMain.c -c -o %t_1.o +RUN: %no_fuzzer_cpp_compiler %S/InitializeTest.cpp -c -o %t_2.o + +RUN: %no_fuzzer_cpp_compiler %t_1.o %t_2.o -o %t-StandaloneInitializeTest +RUN: %t-StandaloneInitializeTest %S/hi.txt %S/dict1.txt 2>&1 | FileCheck %s +CHECK: StandaloneFuzzTargetMain: running 2 inputs +CHECK: Done: {{.*}}hi.txt: (3 bytes) +CHECK: Done: {{.*}}dict1.txt: (61 bytes) diff --git a/test/fuzzer/strcmp.test b/test/fuzzer/strcmp.test new file mode 100644 index 000000000..47ad8f9ba --- /dev/null +++ b/test/fuzzer/strcmp.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/StrcmpTest.cpp -o %t-StrcmpTest +RUN: not %t-StrcmpTest -seed=1 -runs=2000000 2>&1 | FileCheck %s +CHECK: BINGO + diff --git a/test/fuzzer/strncmp.test b/test/fuzzer/strncmp.test new file mode 100644 index 000000000..49693c8de --- /dev/null +++ b/test/fuzzer/strncmp.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/StrncmpTest.cpp -o %t-StrncmpTest +RUN: not %t-StrncmpTest -seed=2 -runs=10000000 2>&1 | FileCheck %s +CHECK: BINGO + diff --git a/test/fuzzer/strstr.test b/test/fuzzer/strstr.test new file mode 100644 index 000000000..c39d5801a --- /dev/null +++ b/test/fuzzer/strstr.test @@ -0,0 +1,4 @@ +RUN: %cpp_compiler %S/StrstrTest.cpp -o %t-StrstrTest +RUN: not %t-StrstrTest -seed=1 -runs=2000000 2>&1 | FileCheck %s +CHECK: BINGO + diff --git a/test/fuzzer/swap-cmp.test b/test/fuzzer/swap-cmp.test new file mode 100644 index 000000000..5c2379cde --- /dev/null +++ b/test/fuzzer/swap-cmp.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/SwapCmpTest.cpp -o %t-SwapCmpTest +CHECK: BINGO +RUN: not %t-SwapCmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/trace-malloc-2.test b/test/fuzzer/trace-malloc-2.test new file mode 100644 index 000000000..56f16d786 --- /dev/null +++ b/test/fuzzer/trace-malloc-2.test @@ -0,0 +1,10 @@ +// FIXME: This test infinite loops on darwin because it crashes +// printing a stack trace repeatedly +UNSUPPORTED: darwin + +RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=1000 2>&1 | FileCheck %s --check-prefix=TRACE2 +TRACE2-DAG: FREE[0] +TRACE2-DAG: MALLOC[0] +TRACE2-DAG: in LLVMFuzzerTestOneInput diff --git a/test/fuzzer/trace-malloc.test b/test/fuzzer/trace-malloc.test new file mode 100644 index 000000000..979be99b7 --- /dev/null +++ b/test/fuzzer/trace-malloc.test @@ -0,0 +1,7 @@ +RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s +CHECK-DAG: MallocFreeTracer: STOP 0 0 (same) +CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT) +CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT) +CHECK-DAG: MallocFreeTracer: STOP 1 1 (same) diff --git a/test/fuzzer/trace-pc.test b/test/fuzzer/trace-pc.test new file mode 100644 index 000000000..eaa0cb08a --- /dev/null +++ b/test/fuzzer/trace-pc.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -fsanitize-coverage=trace-pc -o %t-SimpleTest-TracePC +CHECK: BINGO +RUN: not %t-SimpleTest-TracePC -runs=1000000 -seed=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/ulimit.test b/test/fuzzer/ulimit.test new file mode 100644 index 000000000..8772caa2d --- /dev/null +++ b/test/fuzzer/ulimit.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest +RUN: ulimit -s 1000 +RUN: not %t-SimpleTest diff --git a/test/fuzzer/unit/lit.site.cfg.in b/test/fuzzer/unit/lit.site.cfg.in new file mode 100644 index 000000000..bab2824e4 --- /dev/null +++ b/test/fuzzer/unit/lit.site.cfg.in @@ -0,0 +1,9 @@ +@LIT_SITE_CFG_IN_HEADER@ + +config.name = "LLVMFuzzer-Unittest" +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured") + +config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", + "lib", "fuzzer", "tests") +config.test_source_root = config.test_exec_root diff --git a/test/fuzzer/value-profile-cmp.test b/test/fuzzer/value-profile-cmp.test new file mode 100644 index 000000000..64244297c --- /dev/null +++ b/test/fuzzer/value-profile-cmp.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest +RUN: not %t-SimpleCmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp2.test b/test/fuzzer/value-profile-cmp2.test new file mode 100644 index 000000000..43dd8f9dd --- /dev/null +++ b/test/fuzzer/value-profile-cmp2.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SimpleHashTest.cpp -o %t-SimpleHashTest +RUN: not %t-SimpleHashTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 -max_len=64 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp3.test b/test/fuzzer/value-profile-cmp3.test new file mode 100644 index 000000000..d2284750b --- /dev/null +++ b/test/fuzzer/value-profile-cmp3.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/AbsNegAndConstantTest.cpp -o %t-AbsNegAndConstantTest +RUN: not %t-AbsNegAndConstantTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-cmp4.test b/test/fuzzer/value-profile-cmp4.test new file mode 100644 index 000000000..bcbc67b18 --- /dev/null +++ b/test/fuzzer/value-profile-cmp4.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/AbsNegAndConstant64Test.cpp -o %t-AbsNegAndConstant64Test +RUN: not %t-AbsNegAndConstant64Test -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-div.test b/test/fuzzer/value-profile-div.test new file mode 100644 index 000000000..8711a2546 --- /dev/null +++ b/test/fuzzer/value-profile-div.test @@ -0,0 +1,4 @@ +CHECK: AddressSanitizer: {{FPE|int-divide-by-zero}} +RUN: %cpp_compiler %S/DivTest.cpp -fsanitize-coverage=trace-div -o %t-DivTest +RUN: not %t-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s + diff --git a/test/fuzzer/value-profile-load.test b/test/fuzzer/value-profile-load.test new file mode 100644 index 000000000..3bf2a658a --- /dev/null +++ b/test/fuzzer/value-profile-load.test @@ -0,0 +1,3 @@ +CHECK: AddressSanitizer: global-buffer-overflow +RUN: %cpp_compiler %S/LoadTest.cpp -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-gep,trace-div,trace-cmp -o %t-LoadTest +RUN: not %t-LoadTest -seed=2 -use_cmp=0 -use_value_profile=1 -runs=20000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-mem.test b/test/fuzzer/value-profile-mem.test new file mode 100644 index 000000000..0b0c21d68 --- /dev/null +++ b/test/fuzzer/value-profile-mem.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SingleMemcmpTest.cpp -o %t-SingleMemcmpTest +RUN: not %t-SingleMemcmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-set.test b/test/fuzzer/value-profile-set.test new file mode 100644 index 000000000..e2e3fb47f --- /dev/null +++ b/test/fuzzer/value-profile-set.test @@ -0,0 +1,4 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/FourIndependentBranchesTest.cpp -o %t-FourIndependentBranchesTest +RUN: not %t-FourIndependentBranchesTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s + diff --git a/test/fuzzer/value-profile-strcmp.test b/test/fuzzer/value-profile-strcmp.test new file mode 100644 index 000000000..f5c766a65 --- /dev/null +++ b/test/fuzzer/value-profile-strcmp.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SingleStrcmpTest.cpp -o %t-SingleStrcmpTest +RUN: not %t-SingleStrcmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-strncmp.test b/test/fuzzer/value-profile-strncmp.test new file mode 100644 index 000000000..2dfe43c4a --- /dev/null +++ b/test/fuzzer/value-profile-strncmp.test @@ -0,0 +1,3 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SingleStrncmpTest.cpp -o %t-SingleStrncmpTest +RUN: not %t-SingleStrncmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s diff --git a/test/fuzzer/value-profile-switch.test b/test/fuzzer/value-profile-switch.test new file mode 100644 index 000000000..7edb312a0 --- /dev/null +++ b/test/fuzzer/value-profile-switch.test @@ -0,0 +1,5 @@ +CHECK: BINGO +RUN: %cpp_compiler %S/SwitchTest.cpp -o %t-SwitchTest +RUN: %cpp_compiler %S/Switch2Test.cpp -o %t-Switch2Test +RUN: not %t-SwitchTest -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s +RUN: not %t-Switch2Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s -- cgit v1.2.1 From 63c10e62482994a0cf57989dab859e5e3d0ca960 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 22 Aug 2017 00:54:57 +0000 Subject: Remove check-fuzzer from check-all, as tests don't pass on some bots. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311415 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/fuzzer/CMakeLists.txt b/test/fuzzer/CMakeLists.txt index 339978a82..f997556be 100644 --- a/test/fuzzer/CMakeLists.txt +++ b/test/fuzzer/CMakeLists.txt @@ -34,6 +34,8 @@ foreach(arch ${FUZZER_SUPPORTED_ARCH}) endforeach() +set(EXCLUDE_FROM_ALL ON) + add_lit_testsuite(check-fuzzer "Running Fuzzer tests" ${LIBFUZZER_TESTSUITES} DEPENDS ${LIBFUZZER_TEST_DEPS}) -- cgit v1.2.1 From 893db08e148cce7fedbea310c86cbeb3159e9925 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 22 Aug 2017 01:14:53 +0000 Subject: [libFuzzer] remove stale file git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311417 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/cxx.dict | 122 ---------------------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 lib/fuzzer/cxx.dict diff --git a/lib/fuzzer/cxx.dict b/lib/fuzzer/cxx.dict deleted file mode 100644 index 41350f475..000000000 --- a/lib/fuzzer/cxx.dict +++ /dev/null @@ -1,122 +0,0 @@ -"++" -"--" -"<<" -">>" -"+=" -"-=" -"*=" -"/=" -">>=" -"<<=" -"&=" -"|=" -"^=" -"%=" -"!=" -"&&" -"||" -"==" -">=" -"<=" -"->" -"alignas" -"alignof" -"and" -"and_eq" -"asm" -"auto" -"bitand" -"bitor" -"bool" -"break" -"case" -"catch" -"char" -"char16_t" -"char32_t" -"class" -"compl" -"concept" -"const" -"constexpr" -"const_cast" -"continue" -"decltype" -"default" -"delete" -"do" -"double" -"dynamic_cast" -"else" -"enum" -"explicit" -"export" -"extern" -"false" -"float" -"for" -"friend" -"goto" -"if" -"inline" -"int" -"long" -"mutable" -"namespace" -"new" -"noexcept" -"not" -"not_eq" -"nullptr" -"operator" -"or" -"or_eq" -"private" -"protected" -"public" -"register" -"reinterpret_cast" -"requires" -"return" -"short" -"signed" -"sizeof" -"static" -"static_assert" -"static_cast" -"struct" -"switch" -"template" -"this" -"thread_local" -"throw" -"true" -"try" -"typedef" -"typeid" -"typename" -"union" -"unsigned" -"using" -"virtual" -"void" -"volatile" -"wchar_t" -"while" -"xor" -"xor_eq" -"if" -"elif" -"else" -"endif" -"defined" -"ifdef" -"ifndef" -"define" -"undef" -"include" -"line" -"error" -"pragma" -"override" -"final" -- cgit v1.2.1 From 5ffcba415d94a51dfeb07d7fe67645619008789d Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 22 Aug 2017 01:15:40 +0000 Subject: [libFuzzer] better README.txt git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311418 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/README.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/fuzzer/README.txt b/lib/fuzzer/README.txt index 79f49b550..3eee01c77 100644 --- a/lib/fuzzer/README.txt +++ b/lib/fuzzer/README.txt @@ -1,2 +1 @@ -Move to http://llvm.org/docs/LibFuzzer.html - +See http://llvm.org/docs/LibFuzzer.html -- cgit v1.2.1 From 8713a9766f1d0a033de92dc57b8df67ae53ff425 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 22 Aug 2017 01:19:17 +0000 Subject: [NFC] do not run linter on libFuzzer's tests. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311419 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fuzzer/CMakeLists.txt b/test/fuzzer/CMakeLists.txt index f997556be..cf83c00b6 100644 --- a/test/fuzzer/CMakeLists.txt +++ b/test/fuzzer/CMakeLists.txt @@ -1,4 +1,5 @@ set(LIBFUZZER_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +list(REMOVE_ITEM LIBFUZZER_TEST_DEPS SanitizerLintCheck) if (NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND LIBFUZZER_TEST_DEPS fuzzer asan) endif() -- cgit v1.2.1 From 190938f453f63c379a3c07c0140a69d87ff812a8 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 22 Aug 2017 01:28:32 +0000 Subject: [libFuzzer] apply changes lost during the migration to compiler-rt git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311420 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/CMakeLists.txt | 1 + lib/fuzzer/FuzzerClangCounters.cpp | 49 +++++++++++++++++++++++++++++++++++++ lib/fuzzer/FuzzerDefs.h | 4 +++ lib/fuzzer/FuzzerLoop.cpp | 3 ++- lib/fuzzer/FuzzerTracePC.cpp | 33 +++++++++++++++++++------ lib/fuzzer/FuzzerTracePC.h | 50 ++++++++++++++++++++------------------ 6 files changed, 108 insertions(+), 32 deletions(-) create mode 100644 lib/fuzzer/FuzzerClangCounters.cpp diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index 309a8b801..03cb7fb0a 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -1,4 +1,5 @@ set(LIBFUZZER_SOURCES + FuzzerClangCounters.cpp FuzzerCrossOver.cpp FuzzerDriver.cpp FuzzerExtFunctionsDlsym.cpp diff --git a/lib/fuzzer/FuzzerClangCounters.cpp b/lib/fuzzer/FuzzerClangCounters.cpp new file mode 100644 index 000000000..f69e922cf --- /dev/null +++ b/lib/fuzzer/FuzzerClangCounters.cpp @@ -0,0 +1,49 @@ +//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Coverage counters from Clang's SourceBasedCodeCoverage. +//===----------------------------------------------------------------------===// + +// Support for SourceBasedCodeCoverage is experimental: +// * Works only for the main binary, not DSOs yet. +// * Works only on Linux. +// * Does not implement print_pcs/print_coverage yet. +// * Is not fully evaluated for performance and sensitivity. +// We expect large performance drop due to 64-bit counters, +// and *maybe* better sensitivity due to more fine-grained counters. +// Preliminary comparison on a single benchmark (RE2) shows +// a bit worse sensitivity though. + +#include "FuzzerDefs.h" + +#if LIBFUZZER_LINUX +__attribute__((weak)) extern uint64_t __start___llvm_prf_cnts; +__attribute__((weak)) extern uint64_t __stop___llvm_prf_cnts; +namespace fuzzer { +uint64_t *ClangCountersBegin() { return &__start___llvm_prf_cnts; } +uint64_t *ClangCountersEnd() { return &__stop___llvm_prf_cnts; } +} // namespace fuzzer +#else +// TODO: Implement on Mac (if the data shows it's worth it). +//__attribute__((visibility("hidden"))) +//extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts"); +//__attribute__((visibility("hidden"))) +//extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts"); +namespace fuzzer { +uint64_t *ClangCountersBegin() { return nullptr; } +uint64_t *ClangCountersEnd() { return nullptr; } +} // namespace fuzzer +#endif + +namespace fuzzer { +ATTRIBUTE_NO_SANITIZE_ALL +void ClearClangCounters() { // hand-written memset, don't asan-ify. + for (auto P = ClangCountersBegin(); P < ClangCountersEnd(); P++) + *P = 0; +} +} diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index 27f571923..bbb44514a 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -123,6 +123,10 @@ uint8_t *ExtraCountersBegin(); uint8_t *ExtraCountersEnd(); void ClearExtraCounters(); +uint64_t *ClangCountersBegin(); +uint64_t *ClangCountersEnd(); +void ClearClangCounters(); + } // namespace fuzzer #endif // LLVM_FUZZER_DEFS_H diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 2064783f3..234945932 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -388,11 +388,12 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { uint8_t dummy; ExecuteCallback(&dummy, 0); - for (const auto &U : *InitialCorpus) { + for (auto &U : *InitialCorpus) { RunOne(U.data(), U.size()); CheckExitOnSrcPosOrItem(); TryDetectingAMemoryLeak(U.data(), U.size(), /*DuringInitialCorpusExecution*/ true); + U.clear(); } PrintStats("INITED"); if (Corpus.empty()) { diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index d038374dc..ebd33d3ec 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -31,6 +31,9 @@ uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs]; ATTRIBUTE_INTERFACE uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; +// Used by -fsanitize-coverage=stack-depth to track stack depth +ATTRIBUTE_INTERFACE thread_local uintptr_t __sancov_lowest_stack; + namespace fuzzer { TracePC TPC; @@ -126,6 +129,8 @@ void TracePC::PrintModuleInfo() { _Exit(1); } } + if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) + Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters); } ATTRIBUTE_NO_SANITIZE_ALL @@ -137,13 +142,12 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { } void TracePC::UpdateObservedPCs() { + auto Observe = [&](uintptr_t PC) { + bool Inserted = ObservedPCs.insert(PC).second; + if (Inserted && DoPrintNewPCs) + PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); + }; if (NumPCsInPCTables) { - auto Observe = [&](uintptr_t PC) { - bool Inserted = ObservedPCs.insert(PC).second; - if (Inserted && DoPrintNewPCs) - PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); - }; - if (NumInline8bitCounters == NumPCsInPCTables) { for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { uint8_t *Beg = ModuleCounters[i].Start; @@ -167,6 +171,13 @@ void TracePC::UpdateObservedPCs() { } } } + if (size_t NumClangCounters = + ClangCountersEnd() - ClangCountersBegin()) { + auto P = ClangCountersBegin(); + for (size_t Idx = 0; Idx < NumClangCounters; Idx++) + if (P[Idx]) + Observe((uintptr_t)Idx); + } } inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { @@ -332,6 +343,14 @@ void TracePC::ClearInlineCounters() { } } +void TracePC::RecordInitialStack() { + InitialStack = __sancov_lowest_stack; +} + +uintptr_t TracePC::GetMaxStackOffset() const { + return InitialStack - __sancov_lowest_stack; // Stack grows down +} + } // namespace fuzzer extern "C" { @@ -342,8 +361,6 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { uint32_t Idx = *Guard; __sancov_trace_pc_pcs[Idx] = PC; __sancov_trace_pc_guard_8bit_counters[Idx]++; - // Uncomment the following line to get stack-depth profiling. - // fuzzer::TPC.RecordCurrentStack(); } // Best-effort support for -fsanitize-coverage=trace-pc, which is available diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index ea6794c75..56f1820f7 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -91,6 +91,7 @@ class TracePC { memset(Counters(), 0, GetNumPCs()); ClearExtraCounters(); ClearInlineCounters(); + ClearClangCounters(); } void ClearInlineCounters(); @@ -119,19 +120,8 @@ class TracePC { return PCs()[Idx]; } - void RecordCurrentStack() { - uintptr_t Stack = GetCurrentStack(); - if (Stack < LowestStack) - LowestStack = Stack; - } - void RecordInitialStack() { - InitialStack = GetCurrentStack(); - LowestStack = InitialStack; - } - uintptr_t GetCurrentStack() const { - return reinterpret_cast(__builtin_frame_address(0)); - } - uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; } + void RecordInitialStack(); + uintptr_t GetMaxStackOffset() const; template void ForEachObservedPC(CallBack CB) { @@ -166,7 +156,7 @@ private: std::set ObservedPCs; ValueBitMap ValueProfileMap; - uintptr_t InitialStack, LowestStack; // Assume stack grows down. + uintptr_t InitialStack; }; template @@ -196,14 +186,9 @@ void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End, Handle8bitCounter(FirstFeature, P - Begin, V); } -template // bool Callback(size_t Feature) -ATTRIBUTE_NO_SANITIZE_ADDRESS -__attribute__((noinline)) -void TracePC::CollectFeatures(Callback HandleFeature) const { - uint8_t *Counters = this->Counters(); - size_t N = GetNumPCs(); - auto Handle8bitCounter = [&](size_t FirstFeature, - size_t Idx, uint8_t Counter) { +// Given a non-zero Counters returns a number in [0,7]. +template +unsigned CounterToFeature(T Counter) { assert(Counter); unsigned Bit = 0; /**/ if (Counter >= 128) Bit = 7; @@ -213,7 +198,18 @@ void TracePC::CollectFeatures(Callback HandleFeature) const { else if (Counter >= 4) Bit = 3; else if (Counter >= 3) Bit = 2; else if (Counter >= 2) Bit = 1; - HandleFeature(FirstFeature + Idx * 8 + Bit); + return Bit; +} + +template // bool Callback(size_t Feature) +ATTRIBUTE_NO_SANITIZE_ADDRESS +__attribute__((noinline)) +void TracePC::CollectFeatures(Callback HandleFeature) const { + uint8_t *Counters = this->Counters(); + size_t N = GetNumPCs(); + auto Handle8bitCounter = [&](size_t FirstFeature, + size_t Idx, uint8_t Counter) { + HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Counter)); }; size_t FirstFeature = 0; @@ -231,6 +227,14 @@ void TracePC::CollectFeatures(Callback HandleFeature) const { } } + if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) { + auto P = ClangCountersBegin(); + for (size_t Idx = 0; Idx < NumClangCounters; Idx++) + if (auto Cnt = P[Idx]) + HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Cnt)); + FirstFeature += NumClangCounters; + } + ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature, Handle8bitCounter); FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8; -- cgit v1.2.1 From 63b65394978b2a5e37988e275e07127cc558c11b Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 22 Aug 2017 01:50:00 +0000 Subject: [libFuzzer] fix the stack-depth initialization, add a lit test for DeepRecursionTest.cpp git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311421 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerTracePC.cpp | 4 +++- test/fuzzer/deep-recursion.test | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/fuzzer/deep-recursion.test diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index ebd33d3ec..985649a80 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -343,8 +343,10 @@ void TracePC::ClearInlineCounters() { } } +ATTRIBUTE_NO_SANITIZE_ALL void TracePC::RecordInitialStack() { - InitialStack = __sancov_lowest_stack; + int stack; + __sancov_lowest_stack = InitialStack = reinterpret_cast(&stack); } uintptr_t TracePC::GetMaxStackOffset() const { diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test new file mode 100644 index 000000000..23b7af1df --- /dev/null +++ b/test/fuzzer/deep-recursion.test @@ -0,0 +1,4 @@ +# Test that we can find a stack overflow +RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s +CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 672167943f148689557e70a137e8f8f19ffdd412 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 22 Aug 2017 04:05:50 +0000 Subject: builtins: erase `struct` modifier for EH personality On ARM, the `_Unwind_Exception` is an alias for `struct _Unwind_Control_Block`. The extra `struct` modifier causes a warning due to the locally scoped type. Special case this to avoid the warning. NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311425 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/gcc_personality_v0.c | 42 +++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c index 0bc765624..4e27ac0a9 100644 --- a/lib/builtins/gcc_personality_v0.c +++ b/lib/builtins/gcc_personality_v0.c @@ -145,23 +145,29 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) #define USING_ARM_EHABI 1 -_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *, +_Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *, struct _Unwind_Context *); #endif +#if USING_ARM_EHABI +static inline _Unwind_Reason_Code +continueUnwind(_Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) { + /* + * On ARM EHABI the personality routine is responsible for actually + * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + */ + if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) + return _URC_FAILURE; + return _URC_CONTINUE_UNWIND; +} +#else static inline _Unwind_Reason_Code continueUnwind(struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) { -#if USING_ARM_EHABI - /* - * On ARM EHABI the personality routine is responsible for actually - * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). - */ - if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) - return _URC_FAILURE; -#endif - return _URC_CONTINUE_UNWIND; + return _URC_CONTINUE_UNWIND; } +#endif /* * The C compiler makes references to __gcc_personality_v0 in @@ -176,18 +182,20 @@ continueUnwind(struct _Unwind_Exception *exceptionObject, * different name */ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, - uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, - struct _Unwind_Context *context) + uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) #elif USING_ARM_EHABI /* The ARM EHABI personality routine has a different signature. */ -COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( - _Unwind_State state, struct _Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) +COMPILER_RT_ABI _Unwind_Reason_Code +__gcc_personality_v0(_Unwind_State state, _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) #else COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, - uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, - struct _Unwind_Context *context) + uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) #endif { /* Since C does not have catch clauses, there is nothing to do during */ -- cgit v1.2.1 From 13fb8966806c7ff29bea6eb47647689f7c0b1115 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 22 Aug 2017 04:19:51 +0000 Subject: Revert "builtins: erase `struct` modifier for EH personality" This reverts SVN r311425 which broke one of the buildbots. It is unclear what header is being used there. Revert it until that can be handled properly. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311426 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/gcc_personality_v0.c | 42 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c index 4e27ac0a9..0bc765624 100644 --- a/lib/builtins/gcc_personality_v0.c +++ b/lib/builtins/gcc_personality_v0.c @@ -145,29 +145,23 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) #define USING_ARM_EHABI 1 -_Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *, +_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *, struct _Unwind_Context *); #endif -#if USING_ARM_EHABI -static inline _Unwind_Reason_Code -continueUnwind(_Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) { - /* - * On ARM EHABI the personality routine is responsible for actually - * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). - */ - if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) - return _URC_FAILURE; - return _URC_CONTINUE_UNWIND; -} -#else static inline _Unwind_Reason_Code continueUnwind(struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) { - return _URC_CONTINUE_UNWIND; -} +#if USING_ARM_EHABI + /* + * On ARM EHABI the personality routine is responsible for actually + * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + */ + if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) + return _URC_FAILURE; #endif + return _URC_CONTINUE_UNWIND; +} /* * The C compiler makes references to __gcc_personality_v0 in @@ -182,20 +176,18 @@ continueUnwind(struct _Unwind_Exception *exceptionObject, * different name */ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, - uint64_t exceptionClass, - struct _Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + struct _Unwind_Context *context) #elif USING_ARM_EHABI /* The ARM EHABI personality routine has a different signature. */ -COMPILER_RT_ABI _Unwind_Reason_Code -__gcc_personality_v0(_Unwind_State state, _Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) +COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( + _Unwind_State state, struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) #else COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, - uint64_t exceptionClass, - struct _Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + struct _Unwind_Context *context) #endif { /* Since C does not have catch clauses, there is nothing to do during */ -- cgit v1.2.1 From 6c60ed285ac8446f30cef11a983e1cc398a6bac4 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 22 Aug 2017 05:15:57 +0000 Subject: [libFuzzer] disable a test failing on the bot git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311427 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/deep-recursion.test | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 23b7af1df..06e612c28 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,4 +1,5 @@ # Test that we can find a stack overflow -RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t -RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s -CHECK: ERROR: libFuzzer: deadly signal +RUN: echo DISABLED +DISABLED: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +DISABLED: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s +DISABLED: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From e8a32dc127ff883b7ba27fe912570d5357d6763b Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 22 Aug 2017 18:34:28 +0000 Subject: [libFuzzer] Move check for thread_local back into libFuzzer's CMake, as it breaks builtin standalone build on some bots. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311482 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/base-config-ix.cmake | 10 ---------- lib/fuzzer/CMakeLists.txt | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 953d9e530..f9904fbd1 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -89,16 +89,6 @@ if(APPLE) option(COMPILER_RT_ENABLE_WATCHOS "Enable building for watchOS - Experimental" Off) option(COMPILER_RT_ENABLE_TVOS "Enable building for tvOS - Experimental" Off) - CHECK_CXX_SOURCE_COMPILES(" - static thread_local int blah; - int main() { - return 0; - } - " HAS_THREAD_LOCAL) - - if( NOT HAS_THREAD_LOCAL ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dthread_local=__thread") - endif() else() option(COMPILER_RT_DEFAULT_TARGET_ONLY "Build builtins only for the default target" Off) endif() diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index 03cb7fb0a..f06f93881 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -23,9 +23,19 @@ set(LIBFUZZER_SOURCES FuzzerUtilWindows.cpp ) +CHECK_CXX_SOURCE_COMPILES(" + static thread_local int blah; + int main() { + return 0; + } + " HAS_THREAD_LOCAL) + if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage") set(LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters) endif() +if(NOT HAS_THREAD_LOCAL) + set(LIBFUZZER_CFLAGS "${LIBFUZZER_CFLAGS} -Dthread_local=__thread") +endif() if(APPLE) set(FUZZER_SUPPORTED_OS osx) -- cgit v1.2.1 From 9cc823951b57e684a0a7f6ff9328b5698b1cf228 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 22 Aug 2017 21:28:29 +0000 Subject: [SanitizerCoverage] Optimize stack-depth instrumentation. Summary: Use the initialexec TLS type and eliminate calls to the TLS wrapper. Fixes the sanitizer-x86_64-linux-fuzzer bot failure. Reviewers: vitalybuka, kcc Reviewed By: kcc Subscribers: hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D37026 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311490 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerTracePC.cpp | 3 ++- test/fuzzer/deep-recursion.test | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 985649a80..6513b4f64 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -32,7 +32,8 @@ ATTRIBUTE_INTERFACE uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; // Used by -fsanitize-coverage=stack-depth to track stack depth -ATTRIBUTE_INTERFACE thread_local uintptr_t __sancov_lowest_stack; +ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) +thread_local uintptr_t __sancov_lowest_stack; namespace fuzzer { diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 06e612c28..23b7af1df 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,5 +1,4 @@ # Test that we can find a stack overflow -RUN: echo DISABLED -DISABLED: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t -DISABLED: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s -DISABLED: ERROR: libFuzzer: deadly signal +RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s +CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 0d45586b90cb9895cb9effab1aebd76110716e2c Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 22 Aug 2017 21:54:37 +0000 Subject: [esan] Use stack_t instead of struct sigaltstack (PR34011) The struct tag is going away in soon-to-be-released glibc 2.26 and the stack_t typedef seems to have been there forever. Patch by Bernhard Rosenkraenzer! git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311495 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/esan/esan_sideline_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/esan/esan_sideline_linux.cpp b/lib/esan/esan_sideline_linux.cpp index d04f5909d..bc272dfe4 100644 --- a/lib/esan/esan_sideline_linux.cpp +++ b/lib/esan/esan_sideline_linux.cpp @@ -70,7 +70,7 @@ int SidelineThread::runSideline(void *Arg) { // Set up a signal handler on an alternate stack for safety. InternalScopedBuffer StackMap(SigAltStackSize); - struct sigaltstack SigAltStack; + stack_t SigAltStack; SigAltStack.ss_sp = StackMap.data(); SigAltStack.ss_size = SigAltStackSize; SigAltStack.ss_flags = 0; -- cgit v1.2.1 From 24e609bda53ee838eb1f2f6eef82fc04deb7db13 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 22 Aug 2017 21:54:37 +0000 Subject: [profile] Fix warning about C++ style comment in C file git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311496 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingNameVar.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/profile/InstrProfilingNameVar.c b/lib/profile/InstrProfilingNameVar.c index a0c448c67..264568fbc 100644 --- a/lib/profile/InstrProfilingNameVar.c +++ b/lib/profile/InstrProfilingNameVar.c @@ -1,11 +1,11 @@ -//===- InstrProfilingNameVar.c - profile name variable setup --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// +/*===- InstrProfilingNameVar.c - profile name variable setup -------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +\*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" -- cgit v1.2.1 From 94fc5971be53f669387763bf9599d23da08b30be Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 23 Aug 2017 04:42:37 +0000 Subject: [XRay][compiler-rt] Support sled versioning for custom event sleds Summary: This change introduces versions to the instrumentation map entries we emit for XRay instrumentaiton points. The status quo for the version is currently set to 0 (as emitted by the LLVM back-end), and versions will count up to 255 (unsigned char). This change is in preparation for supporting the newer version of the custom event sleds that will be emitted by the LLVM compiler. While we're here, we take the opportunity to stash more registers and align the stack properly in the __xray_CustomEvent trampoline. Reviewers: kpw, pcc, dblaikie Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D36816 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311524 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_interface_internal.h | 6 ++-- lib/xray/xray_trampoline_x86_64.S | 21 ++++++----- lib/xray/xray_x86_64.cc | 36 +++++++++++++------ .../Linux/custom-event-handler-alignment.cc | 42 ++++++++++++++++++++++ test/xray/TestCases/Linux/custom-event-logging.cc | 2 ++ 5 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 test/xray/TestCases/Linux/custom-event-handler-alignment.cc diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index 4a2784612..5811e2b73 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -28,13 +28,15 @@ struct XRaySledEntry { uint64_t Function; unsigned char Kind; unsigned char AlwaysInstrument; - unsigned char Padding[14]; // Need 32 bytes + unsigned char Version; + unsigned char Padding[13]; // Need 32 bytes #elif SANITIZER_WORDSIZE == 32 uint32_t Address; uint32_t Function; unsigned char Kind; unsigned char AlwaysInstrument; - unsigned char Padding[6]; // Need 16 bytes + unsigned char Version; + unsigned char Padding[5]; // Need 16 bytes #else #error "Unsupported word size." #endif diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index b59eedc4b..5c38c40e2 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -202,10 +202,7 @@ __xray_ArgLoggerEntry: .type __xray_CustomEvent,@function __xray_CustomEvent: .cfi_startproc - subq $16, %rsp - .cfi_def_cfa_offset 24 - movq %rbp, 8(%rsp) - movq %rax, 0(%rsp) + SAVE_REGISTERS // We take two arguments to this trampoline, which should be in rdi and rsi // already. We also make sure that we stash %rax because we use that register @@ -215,14 +212,20 @@ __xray_CustomEvent: je .LcustomEventCleanup // At this point we know that rcx and rdx already has the data, so we just - // call the logging handler. + // call the logging handler, after aligning the stack to a 16-byte boundary. + // The approach we're taking here uses additional stack space to stash the + // stack pointer twice before aligning the pointer to 16-bytes. If the stack + // was 8-byte aligned, it will become 16-byte aligned -- when restoring the + // pointer, we can always look -8 bytes from the current position to get + // either of the values we've stashed in the first place. + pushq %rsp + pushq (%rsp) + andq $-0x10, %rsp callq *%rax + movq 8(%rsp), %rsp .LcustomEventCleanup: - movq 0(%rsp), %rax - movq 8(%rsp), %rbp - addq $16, %rsp - .cfi_def_cfa_offset 8 + RESTORE_REGISTERS retq .Ltmp8: diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index e34806fa1..3c12682cc 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -76,6 +76,7 @@ static constexpr uint8_t CallOpCode = 0xe8; static constexpr uint16_t MovR10Seq = 0xba41; static constexpr uint16_t Jmp9Seq = 0x09eb; static constexpr uint16_t Jmp20Seq = 0x14eb; +static constexpr uint16_t Jmp15Seq = 0x0feb; static constexpr uint8_t JmpOpCode = 0xe9; static constexpr uint8_t RetOpCode = 0xc3; static constexpr uint16_t NopwSeq = 0x9066; @@ -207,8 +208,10 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the following sled: // + // In Version 0: + // // xray_sled_n: - // jmp +19 // 2 bytes + // jmp +20 // 2 bytes // ... // // With the following: @@ -216,24 +219,35 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId, // nopw // 2 bytes* // ... // - // We need to do this in the following order: // - // 1. Overwrite the 5-byte nop with the call (relative), where (relative) is - // the relative offset to the __xray_CustomEvent trampoline. - // 2. Do a two-byte atomic write over the 'jmp +24' to turn it into a 'nopw'. - // This allows us to "enable" this code once the changes have committed. + // The "unpatch" should just turn the 'nopw' back to a 'jmp +20'. + // + // --- // - // The "unpatch" should just turn the 'nopw' back to a 'jmp +24'. + // In Version 1: + // + // The jump offset is now 15 bytes (0x0f), so when restoring the nopw back + // to a jmp, use 15 bytes instead. // if (Enable) { std::atomic_store_explicit( reinterpret_cast *>(Sled.Address), NopwSeq, std::memory_order_release); } else { - std::atomic_store_explicit( - reinterpret_cast *>(Sled.Address), Jmp20Seq, - std::memory_order_release); - } + switch (Sled.Version) { + case 1: + std::atomic_store_explicit( + reinterpret_cast *>(Sled.Address), Jmp15Seq, + std::memory_order_release); + break; + case 0: + default: + std::atomic_store_explicit( + reinterpret_cast *>(Sled.Address), Jmp20Seq, + std::memory_order_release); + break; + } + } return false; } diff --git a/test/xray/TestCases/Linux/custom-event-handler-alignment.cc b/test/xray/TestCases/Linux/custom-event-handler-alignment.cc new file mode 100644 index 000000000..447f6e4f2 --- /dev/null +++ b/test/xray/TestCases/Linux/custom-event-handler-alignment.cc @@ -0,0 +1,42 @@ +// Make sure we're aligning the stack properly when lowering the custom event +// calls. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false" \ +// RUN: %run %t 2>&1 +// REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree +#include +#include +#include "xray/xray_interface.h" + +[[clang::xray_never_instrument]] __attribute__((weak)) __m128 f(__m128 *i) { + return *i; +} + +[[clang::xray_always_instrument]] void foo() { + __xray_customevent(0, 0); + __m128 v = {}; + f(&v); +} + +[[clang::xray_always_instrument]] void bar() { + __xray_customevent(0, 0); +} + +void printer(void* ptr, size_t size) { + printf("handler called\n"); + __m128 v = {}; + f(&v); +} + +int main(int argc, char* argv[]) { + __xray_set_customevent_handler(printer); + __xray_patch(); + foo(); // CHECK: handler called + bar(); // CHECK: handler called + __xray_unpatch(); + __xray_remove_customevent_handler(); + foo(); + bar(); +} diff --git a/test/xray/TestCases/Linux/custom-event-logging.cc b/test/xray/TestCases/Linux/custom-event-logging.cc index 9bb5d44e1..48fd62034 100644 --- a/test/xray/TestCases/Linux/custom-event-logging.cc +++ b/test/xray/TestCases/Linux/custom-event-logging.cc @@ -2,6 +2,8 @@ // // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_xray -std=c++11 -fpic -fpie %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s // FIXME: Support this in non-x86_64 as well // REQUIRES: x86_64-linux // REQUIRES: built-in-llvm-tree -- cgit v1.2.1 From 4854a215fc3c0b10ab57b4b9b5e4cbeb5bf0624a Mon Sep 17 00:00:00 2001 From: Oleg Ranevskyy Date: Wed, 23 Aug 2017 14:26:31 +0000 Subject: [ARM][Compiler-rt] Fix AEABI builtins to correctly pass arguments to non-AEABI functions on HF targets Summary: This is a patch for PR34167. On HF targets functions like `__{eq,lt,le,ge,gt}df2` and `__{eq,lt,le,ge,gt}sf2` expect their arguments to be passed in d/s registers, while some of the AEABI builtins pass them in r registers. Reviewers: compnerd, peter.smith, asl Reviewed By: peter.smith, asl Subscribers: peter.smith, aemerson, dberris, javed.absar, llvm-commits, asl, kristof.beyls Differential Revision: https://reviews.llvm.org/D36675 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311555 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_dcmp.S | 9 +++++++++ lib/builtins/arm/aeabi_fcmp.S | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/builtins/arm/aeabi_dcmp.S b/lib/builtins/arm/aeabi_dcmp.S index 51539c0ac..9fa78b461 100644 --- a/lib/builtins/arm/aeabi_dcmp.S +++ b/lib/builtins/arm/aeabi_dcmp.S @@ -18,11 +18,20 @@ // } // } +#if defined(COMPILER_RT_ARMHF_TARGET) +# define CONVERT_DCMP_ARGS_TO_DF2_ARGS \ + vmov d0, r0, r1 SEPARATOR \ + vmov d1, r2, r3 +#else +# define CONVERT_DCMP_ARGS_TO_DF2_ARGS +#endif + #define DEFINE_AEABI_DCMP(cond) \ .syntax unified SEPARATOR \ .p2align 2 SEPARATOR \ DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \ push { r4, lr } SEPARATOR \ + CONVERT_DCMP_ARGS_TO_DF2_ARGS SEPARATOR \ bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \ cmp r0, #0 SEPARATOR \ b ## cond 1f SEPARATOR \ diff --git a/lib/builtins/arm/aeabi_fcmp.S b/lib/builtins/arm/aeabi_fcmp.S index 8e7774b58..ea5b96c21 100644 --- a/lib/builtins/arm/aeabi_fcmp.S +++ b/lib/builtins/arm/aeabi_fcmp.S @@ -18,11 +18,20 @@ // } // } +#if defined(COMPILER_RT_ARMHF_TARGET) +# define CONVERT_FCMP_ARGS_TO_SF2_ARGS \ + vmov s0, r0 SEPARATOR \ + vmov s1, r1 +#else +# define CONVERT_FCMP_ARGS_TO_SF2_ARGS +#endif + #define DEFINE_AEABI_FCMP(cond) \ .syntax unified SEPARATOR \ .p2align 2 SEPARATOR \ DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \ push { r4, lr } SEPARATOR \ + CONVERT_FCMP_ARGS_TO_SF2_ARGS SEPARATOR \ bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \ cmp r0, #0 SEPARATOR \ b ## cond 1f SEPARATOR \ -- cgit v1.2.1 From 6c8e0272792ff33e494ab3ea0e3c264e1d2abadf Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Wed, 23 Aug 2017 21:39:33 +0000 Subject: [Profile] create a copy of profile file name from environment Original patch by Max Moroz. Differential Revsion: http://reviews.llvm.org/D36903 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311607 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfilingFile.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index d038bb9cb..8ae2b7d98 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -519,8 +519,10 @@ void __llvm_profile_initialize_file(void) { EnvFilenamePat = getFilenamePatFromEnv(); if (EnvFilenamePat) { - SelectedPat = EnvFilenamePat; - PNS = PNS_environment; + /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid + at the moment when __llvm_profile_write_file() gets executed. */ + parseAndSetFilename(EnvFilenamePat, PNS_environment, 1); + return; } else if (hasCommandLineOverrider) { SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; PNS = PNS_command_line; -- cgit v1.2.1 From 9501638798e3cd2f30f8ed09818c8382100e6b04 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 24 Aug 2017 17:00:36 +0000 Subject: Mark allocator_oom_test.cc unsupported on arm & aarch64 (PR33972) The buildbots don't seem to like it. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311674 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/allocator_oom_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/asan/TestCases/Linux/allocator_oom_test.cc b/test/asan/TestCases/Linux/allocator_oom_test.cc index 33b6677de..f94475f9b 100644 --- a/test/asan/TestCases/Linux/allocator_oom_test.cc +++ b/test/asan/TestCases/Linux/allocator_oom_test.cc @@ -29,8 +29,9 @@ // RUN: | FileCheck %s --check-prefixes=CHECK-MALLOC-REALLOC,CHECK-NULL // ASan shadow memory on s390 is too large for this test. +// AArch64 bots fail on this test. // TODO(alekseys): Android lit do not run ulimit on device. -// UNSUPPORTED: s390,android +// UNSUPPORTED: s390,android,arm,aarch64 #include #include -- cgit v1.2.1 From 0b17b7e25662a35869c1f0ffd8e3fa61e5e6dea5 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Thu, 24 Aug 2017 23:43:17 +0000 Subject: Add Clang dependency to the check for Clang C++ headers. The problem is that CMake is mostly imperative and the result of processing "if (TARGET blah)" checks depends on the order of import of CMake files. In this case, "projects" folder is registered before "tools", and calling "CheckClangHeaders" [renamed to have a better name] errors out without even giving Clang a chance to be built. This, in turn, leads to libFuzzer bot failures in some circumstances on some machines (depends on whether LIT or UNIT tests are scheduled first). Differential Revision: https://reviews.llvm.org/D37126 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311733 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index 4c6568167..d1dfb74bb 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -67,8 +67,8 @@ function(clang_compile object_file source) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND SOURCE_DEPS clang compiler-rt-headers) endif() - if (TARGET CompilerRTUnitTestCheckCxx) - list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx) + if (TARGET CheckClangHeaders) + list(APPEND SOURCE_DEPS CheckClangHeaders) endif() string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath}) string(REGEX MATCH "[.](m|mm)$" is_objc ${source_rpath}) @@ -132,12 +132,10 @@ macro(clang_compiler_add_cxx_check) " false" "fi" ) - add_custom_target(CompilerRTUnitTestCheckCxx + add_custom_target(CheckClangHeaders COMMAND bash -c "${CMD}" COMMENT "Checking that just-built clang can find C++ headers..." VERBATIM) - if (TARGET clang) - ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang) - endif() + ADD_DEPENDENCIES(CheckClangHeaders clang) endif() endmacro() -- cgit v1.2.1 From 91a66eaad21db9edfd37def4fab63addfc39a5a2 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Fri, 25 Aug 2017 01:50:53 +0000 Subject: [cfi] only add cfi tests on supported arches. Differential Revision: https://reviews.llvm.org/D35101 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311745 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index fb45f2f40..0bad50e2d 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -36,11 +36,13 @@ elseif(WIN32) # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32770 add_cfi_test_suites(True False) else() - add_cfi_test_suites(False False) - add_cfi_test_suites(False True) - if (COMPILER_RT_HAS_LLD) - add_cfi_test_suites(True False) - add_cfi_test_suites(True True) + if (CFI_SUPPORTED_ARCH) + add_cfi_test_suites(False False) + add_cfi_test_suites(False True) + if (COMPILER_RT_HAS_LLD) + add_cfi_test_suites(True False) + add_cfi_test_suites(True True) + endif() endif() endif() -- cgit v1.2.1 From 3df7fc1705d67ca499eeab1585996f279aa1d125 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 25 Aug 2017 02:36:36 +0000 Subject: Revert "Add Clang dependency to the check for Clang C++ headers." This temporarily reverts commit r311733, because of bot breakage. http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_build/38139/consoleFull#-256426522e9a0fee5-ebcc-4238-a641-c5aa112c323e git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311757 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index d1dfb74bb..4c6568167 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -67,8 +67,8 @@ function(clang_compile object_file source) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND SOURCE_DEPS clang compiler-rt-headers) endif() - if (TARGET CheckClangHeaders) - list(APPEND SOURCE_DEPS CheckClangHeaders) + if (TARGET CompilerRTUnitTestCheckCxx) + list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx) endif() string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath}) string(REGEX MATCH "[.](m|mm)$" is_objc ${source_rpath}) @@ -132,10 +132,12 @@ macro(clang_compiler_add_cxx_check) " false" "fi" ) - add_custom_target(CheckClangHeaders + add_custom_target(CompilerRTUnitTestCheckCxx COMMAND bash -c "${CMD}" COMMENT "Checking that just-built clang can find C++ headers..." VERBATIM) - ADD_DEPENDENCIES(CheckClangHeaders clang) + if (TARGET clang) + ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang) + endif() endif() endmacro() -- cgit v1.2.1 From 3d2a81a38bdbbb3624da9c1fef76c9cbfd43c199 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 25 Aug 2017 08:52:28 +0000 Subject: tsan: don't pass bogus PCs to __tsan_symbolize_external See the added comment for an explanation. Reviewed in https://reviews.llvm.org/D37107 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311768 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_rtl.h | 4 ++-- lib/tsan/rtl/tsan_rtl_report.cc | 26 ++++++++++++++++++--- lib/tsan/rtl/tsan_trace.h | 2 ++ test/tsan/double_race.cc | 52 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 test/tsan/double_race.cc diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 2cf2e1684..99c4d2529 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -825,7 +825,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs, return; DCHECK_GE((int)typ, 0); DCHECK_LE((int)typ, 7); - DCHECK_EQ(GetLsb(addr, 61), addr); + DCHECK_EQ(GetLsb(addr, kEventPCBits), addr); StatInc(thr, StatEvents); u64 pos = fs.GetTracePos(); if (UNLIKELY((pos % kTracePartSize) == 0)) { @@ -837,7 +837,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs, } Event *trace = (Event*)GetThreadTrace(fs.tid()); Event *evp = &trace[pos]; - Event ev = (u64)addr | ((u64)typ << 61); + Event ev = (u64)addr | ((u64)typ << kEventPCBits); *evp = ev; } diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index 85a982941..c1d2cc4b5 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -406,8 +406,8 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, Event *events = (Event*)GetThreadTrace(tid); for (uptr i = ebegin; i <= eend; i++) { Event ev = events[i]; - EventType typ = (EventType)(ev >> 61); - uptr pc = (uptr)(ev & ((1ull << 61) - 1)); + EventType typ = (EventType)(ev >> kEventPCBits); + uptr pc = (uptr)(ev & ((1ull << kEventPCBits) - 1)); DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc); if (typ == EventTypeMop) { stack[pos] = pc; @@ -634,7 +634,27 @@ void ReportRace(ThreadState *thr) { const uptr kMop = 2; VarSizeStackTrace traces[kMop]; uptr tags[kMop] = {kExternalTagNone}; - const uptr toppc = TraceTopPC(thr); + uptr toppc = TraceTopPC(thr); + if (toppc >> kEventPCBits) { + // This is a work-around for a known issue. + // The scenario where this happens is rather elaborate and requires + // an instrumented __sanitizer_report_error_summary callback and + // a __tsan_symbolize_external callback and a race during a range memory + // access larger than 8 bytes. MemoryAccessRange adds the current PC to + // the trace and starts processing memory accesses. A first memory access + // triggers a race, we report it and call the instrumented + // __sanitizer_report_error_summary, which adds more stuff to the trace + // since it is intrumented. Then a second memory access in MemoryAccessRange + // also triggers a race and we get here and call TraceTopPC to get the + // current PC, however now it contains some unrelated events from the + // callback. Most likely, TraceTopPC will now return a EventTypeFuncExit + // event. Later we subtract -1 from it (in GetPreviousInstructionPc) + // and the resulting PC has kExternalPCBit set, so we pass it to + // __tsan_symbolize_external. __tsan_symbolize_external is within its rights + // to crash since the PC is completely bogus. + // test/tsan/double_race.cc contains a test case for this. + toppc = 0; + } ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]); if (IsFiredSuppression(ctx, typ, traces[0])) return; diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h index 96a18ac41..9aef375cb 100644 --- a/lib/tsan/rtl/tsan_trace.h +++ b/lib/tsan/rtl/tsan_trace.h @@ -41,6 +41,8 @@ enum EventType { // u64 addr : 61; // Associated pc. typedef u64 Event; +const uptr kEventPCBits = 61; + struct TraceHeader { #if !SANITIZER_GO BufferedStackTrace stack0; // Start stack for the trace. diff --git a/test/tsan/double_race.cc b/test/tsan/double_race.cc new file mode 100644 index 000000000..76b017428 --- /dev/null +++ b/test/tsan/double_race.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "test.h" +#include + +// A reproducer for a known issue. +// See reference to double_race.cc in tsan_rtl_report.cc for an explanation. + +char buf[16]; +volatile int nreport; + +void __sanitizer_report_error_summary(const char *summary) { + nreport++; +} + +const int kEventPCBits = 61; + +extern "C" bool __tsan_symbolize_external(unsigned long pc, char *func_buf, + unsigned long func_siz, + char *file_buf, + unsigned long file_siz, int *line, + int *col) { + if (pc >> kEventPCBits) { + printf("bad PC passed to __tsan_symbolize_external: %lx\n", pc); + _exit(1); + } + return true; +} + +void *Thread(void *arg) { + barrier_wait(&barrier); + memset(buf, 2, sizeof(buf)); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t t; + pthread_create(&t, 0, Thread, 0); + memset(buf, 1, sizeof(buf)); + barrier_wait(&barrier); + pthread_join(t, 0); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 8 at {{.*}} by thread T1: +// CHECK: #0 memset +// CHECK: #1 Thread +// CHECK-NOT: bad PC passed to __tsan_symbolize_external +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 8 at {{.*}} by thread T1: +// CHECK: #0 Thread -- cgit v1.2.1 From 809c05a0ca406262e02bf5ec2dd78ae1f44009da Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 25 Aug 2017 15:18:48 +0000 Subject: tsan: fix darwin build Runtime hooks do not seem to work on darwin. The test failed on builder: http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/34882/consoleFull#7286766538254eaf0-7326-4999-85b0-388101f2d404 Move the test to Linux dir. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311776 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Linux/double_race.cc | 52 ++++++++++++++++++++++++++++++++++++++++++ test/tsan/double_race.cc | 52 ------------------------------------------ 2 files changed, 52 insertions(+), 52 deletions(-) create mode 100644 test/tsan/Linux/double_race.cc delete mode 100644 test/tsan/double_race.cc diff --git a/test/tsan/Linux/double_race.cc b/test/tsan/Linux/double_race.cc new file mode 100644 index 000000000..2b4af35a2 --- /dev/null +++ b/test/tsan/Linux/double_race.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "../test.h" +#include + +// A reproducer for a known issue. +// See reference to double_race.cc in tsan_rtl_report.cc for an explanation. + +char buf[16]; +volatile int nreport; + +void __sanitizer_report_error_summary(const char *summary) { + nreport++; +} + +const int kEventPCBits = 61; + +extern "C" bool __tsan_symbolize_external(unsigned long pc, char *func_buf, + unsigned long func_siz, + char *file_buf, + unsigned long file_siz, int *line, + int *col) { + if (pc >> kEventPCBits) { + printf("bad PC passed to __tsan_symbolize_external: %lx\n", pc); + _exit(1); + } + return true; +} + +void *Thread(void *arg) { + barrier_wait(&barrier); + memset(buf, 2, sizeof(buf)); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t t; + pthread_create(&t, 0, Thread, 0); + memset(buf, 1, sizeof(buf)); + barrier_wait(&barrier); + pthread_join(t, 0); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 8 at {{.*}} by thread T1: +// CHECK: #0 memset +// CHECK: #1 Thread +// CHECK-NOT: bad PC passed to __tsan_symbolize_external +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 8 at {{.*}} by thread T1: +// CHECK: #0 Thread diff --git a/test/tsan/double_race.cc b/test/tsan/double_race.cc deleted file mode 100644 index 76b017428..000000000 --- a/test/tsan/double_race.cc +++ /dev/null @@ -1,52 +0,0 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -#include "test.h" -#include - -// A reproducer for a known issue. -// See reference to double_race.cc in tsan_rtl_report.cc for an explanation. - -char buf[16]; -volatile int nreport; - -void __sanitizer_report_error_summary(const char *summary) { - nreport++; -} - -const int kEventPCBits = 61; - -extern "C" bool __tsan_symbolize_external(unsigned long pc, char *func_buf, - unsigned long func_siz, - char *file_buf, - unsigned long file_siz, int *line, - int *col) { - if (pc >> kEventPCBits) { - printf("bad PC passed to __tsan_symbolize_external: %lx\n", pc); - _exit(1); - } - return true; -} - -void *Thread(void *arg) { - barrier_wait(&barrier); - memset(buf, 2, sizeof(buf)); - return 0; -} - -int main() { - barrier_init(&barrier, 2); - pthread_t t; - pthread_create(&t, 0, Thread, 0); - memset(buf, 1, sizeof(buf)); - barrier_wait(&barrier); - pthread_join(t, 0); - return 0; -} - -// CHECK: WARNING: ThreadSanitizer: data race -// CHECK: Write of size 8 at {{.*}} by thread T1: -// CHECK: #0 memset -// CHECK: #1 Thread -// CHECK-NOT: bad PC passed to __tsan_symbolize_external -// CHECK: WARNING: ThreadSanitizer: data race -// CHECK: Write of size 8 at {{.*}} by thread T1: -// CHECK: #0 Thread -- cgit v1.2.1 From 3518c5ed168302e729f32e59e7406e733eabbff7 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 25 Aug 2017 19:29:47 +0000 Subject: [sanitizer-coverage] extend fsanitize-coverage=pc-table with flags for every PC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311794 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerTracePC.cpp | 17 +++++++++-------- lib/fuzzer/FuzzerTracePC.h | 8 ++++++-- test/fuzzer/InitializeTest.cpp | 1 + .../TestCases/sanitizer_coverage_inline8bit_counter.cc | 17 ++++++++++++----- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 6513b4f64..2df850b2c 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -70,9 +70,9 @@ void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { NumInline8bitCounters += Stop - Start; } -void TracePC::HandlePCsInit(const uint8_t *Start, const uint8_t *Stop) { - const uintptr_t *B = reinterpret_cast(Start); - const uintptr_t *E = reinterpret_cast(Stop); +void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) { + const PCTableEntry *B = reinterpret_cast(Start); + const PCTableEntry *E = reinterpret_cast(Stop); if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return; assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0])); ModulePCTable[NumPCTables++] = {B, E}; @@ -157,7 +157,7 @@ void TracePC::UpdateObservedPCs() { (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); for (size_t j = 0; j < Size; j++) if (Beg[j]) - Observe(ModulePCTable[i].Start[j]); + Observe(ModulePCTable[i].Start[j].PC); } } else if (NumGuards == NumPCsInPCTables) { size_t GuardIdx = 1; @@ -168,7 +168,7 @@ void TracePC::UpdateObservedPCs() { (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); for (size_t j = 0; j < Size; j++, GuardIdx++) if (Counters()[GuardIdx]) - Observe(ModulePCTable[i].Start[j]); + Observe(ModulePCTable[i].Start[j].PC); } } } @@ -240,9 +240,9 @@ void TracePC::PrintCoverage() { for (size_t i = 0; i < NumPCTables; i++) { auto &M = ModulePCTable[i]; assert(M.Start < M.Stop); - auto ModuleName = GetModuleName(*M.Start); + auto ModuleName = GetModuleName(M.Start->PC); for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) { - auto PC = *Ptr; + auto PC = Ptr->PC; auto VisualizePC = GetNextInstructionPc(PC); bool IsObserved = ObservedPCs.count(PC); std::string FileStr = DescribePC("%s", VisualizePC); @@ -388,7 +388,8 @@ void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { } ATTRIBUTE_INTERFACE -void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, const uint8_t *pcs_end) { +void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, + const uintptr_t *pcs_end) { fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end); } diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 56f1820f7..0c9d4b69b 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -75,7 +75,7 @@ class TracePC { void HandleInit(uint32_t *Start, uint32_t *Stop); void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); - void HandlePCsInit(const uint8_t *Start, const uint8_t *Stop); + void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); @@ -146,7 +146,11 @@ private: size_t NumModulesWithInline8bitCounters; // linker-initialized. size_t NumInline8bitCounters; - struct { const uintptr_t *Start, *Stop; } ModulePCTable[4096]; + struct PCTableEntry { + uintptr_t PC, PCFlags; + }; + + struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096]; size_t NumPCTables; size_t NumPCsInPCTables; diff --git a/test/fuzzer/InitializeTest.cpp b/test/fuzzer/InitializeTest.cpp index d640a8d10..a93c2a525 100644 --- a/test/fuzzer/InitializeTest.cpp +++ b/test/fuzzer/InitializeTest.cpp @@ -19,6 +19,7 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(argv0); if (Size == strlen(argv0) && !memmem(Data, Size, argv0, Size)) { fprintf(stderr, "BINGO %s\n", argv0); diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc index c071ba669..58a64d1a9 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -3,7 +3,9 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin // -// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters,pc-table 2>&1 +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters,pc-table -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// XFAIL: tsan #include #include @@ -19,13 +21,15 @@ void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { } uintptr_t FirstPC; +uintptr_t FirstPCFlag; -extern "C" void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, - const uint8_t *pcs_end) { +extern "C" void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, + const uintptr_t *pcs_end) { const uintptr_t *B = (const uintptr_t *)pcs_beg; const uintptr_t *E = (const uintptr_t *)pcs_end; - assert(B < E); - FirstPC = *B; + assert(B + 1 < E); + FirstPC = B[0]; + FirstPCFlag = B[1]; } @@ -33,4 +37,7 @@ int main() { assert(first_counter); assert(*first_counter == 1); assert(FirstPC == (uintptr_t)&main); + assert(FirstPCFlag == 1); + fprintf(stderr, "PASS\n"); + // CHECK: PASS } -- cgit v1.2.1 From 62ddf6220c3bc9c7ecc53bceec6d4548827a79e3 Mon Sep 17 00:00:00 2001 From: Max Moroz Date: Fri, 25 Aug 2017 19:36:30 +0000 Subject: [compiler-rt] Test commit: remove some trailing white spaces. Summary: [compiler-rt] Test commit: remove some trailing white spaces. Reviewers: Dor1s Reviewed By: Dor1s Subscribers: dberris Differential Revision: https://reviews.llvm.org/D37161 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311796 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/BlocksRuntime/Block.h | 2 +- lib/BlocksRuntime/Block_private.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/BlocksRuntime/Block.h b/lib/BlocksRuntime/Block.h index 55cdd01a9..e6cb142fd 100644 --- a/lib/BlocksRuntime/Block.h +++ b/lib/BlocksRuntime/Block.h @@ -27,7 +27,7 @@ #if !defined(BLOCK_EXPORT) # if defined(__cplusplus) -# define BLOCK_EXPORT extern "C" +# define BLOCK_EXPORT extern "C" # else # define BLOCK_EXPORT extern # endif diff --git a/lib/BlocksRuntime/Block_private.h b/lib/BlocksRuntime/Block_private.h index 8ae821815..91d8d8a98 100644 --- a/lib/BlocksRuntime/Block_private.h +++ b/lib/BlocksRuntime/Block_private.h @@ -27,7 +27,7 @@ #if !defined(BLOCK_EXPORT) # if defined(__cplusplus) -# define BLOCK_EXPORT extern "C" +# define BLOCK_EXPORT extern "C" # else # define BLOCK_EXPORT extern # endif -- cgit v1.2.1 From 70c68ad58bdc2727782b78eaf06347c77120219e Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 25 Aug 2017 20:09:25 +0000 Subject: [libFuzzer] add -print_funcs=1 (on bey default): print newly discovered functions during fuzzing git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311797 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerDriver.cpp | 1 + lib/fuzzer/FuzzerFlags.def | 1 + lib/fuzzer/FuzzerLoop.cpp | 1 + lib/fuzzer/FuzzerOptions.h | 1 + lib/fuzzer/FuzzerTracePC.cpp | 19 +++++++++++++------ lib/fuzzer/FuzzerTracePC.h | 3 +++ test/fuzzer/PrintFuncTest.cpp | 39 +++++++++++++++++++++++++++++++++++++++ test/fuzzer/print-func.test | 10 ++++++++++ 8 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 test/fuzzer/PrintFuncTest.cpp create mode 100644 test/fuzzer/print-func.test diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 17891d29c..d0d0f7dd0 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -603,6 +603,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.SaveArtifacts = !DoPlainRun || Flags.minimize_crash_internal_step; Options.PrintNewCovPcs = Flags.print_pcs; + Options.PrintNewCovFuncs = Flags.print_funcs; Options.PrintFinalStats = Flags.print_final_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index 2887fd24d..6968c770a 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -91,6 +91,7 @@ FUZZER_FLAG_STRING(exact_artifact_path, "and will not use checksum in the file name. Do not " "use the same path for several parallel processes.") FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") +FUZZER_FLAG_INT(print_funcs, 1, "If 1, print out newly covered functions.") FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") FUZZER_FLAG_INT(print_corpus_stats, 0, "If 1, print statistics on corpus elements at exit.") diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 234945932..d2d096af4 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -626,6 +626,7 @@ void Fuzzer::MutateAndTestOne() { void Fuzzer::Loop() { TPC.SetPrintNewPCs(Options.PrintNewCovPcs); + TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs); system_clock::time_point LastCorpusReload = system_clock::now(); if (Options.DoCrossOver) MD.SetCorpus(&Corpus); diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index 9500235e2..d38724209 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -47,6 +47,7 @@ struct FuzzingOptions { bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; bool PrintNewCovPcs = false; + bool PrintNewCovFuncs = false; bool PrintFinalStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 2df850b2c..812a6190a 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -143,11 +143,18 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { } void TracePC::UpdateObservedPCs() { - auto Observe = [&](uintptr_t PC) { - bool Inserted = ObservedPCs.insert(PC).second; - if (Inserted && DoPrintNewPCs) + auto ObservePC = [&](uintptr_t PC) { + if (ObservedPCs.insert(PC).second && DoPrintNewPCs) PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); }; + + auto Observe = [&](const PCTableEntry &TE) { + if (TE.PCFlags & 1) + if (ObservedFuncs.insert(TE.PC).second && DoPrintNewFuncs) + PrintPC("\tNEW_FUNC: %p %F %L\n", "\tNEW_PC: %p\n", TE.PC + 1); + ObservePC(TE.PC); + }; + if (NumPCsInPCTables) { if (NumInline8bitCounters == NumPCsInPCTables) { for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { @@ -157,7 +164,7 @@ void TracePC::UpdateObservedPCs() { (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); for (size_t j = 0; j < Size; j++) if (Beg[j]) - Observe(ModulePCTable[i].Start[j].PC); + Observe(ModulePCTable[i].Start[j]); } } else if (NumGuards == NumPCsInPCTables) { size_t GuardIdx = 1; @@ -168,7 +175,7 @@ void TracePC::UpdateObservedPCs() { (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); for (size_t j = 0; j < Size; j++, GuardIdx++) if (Counters()[GuardIdx]) - Observe(ModulePCTable[i].Start[j].PC); + Observe(ModulePCTable[i].Start[j]); } } } @@ -177,7 +184,7 @@ void TracePC::UpdateObservedPCs() { auto P = ClangCountersBegin(); for (size_t Idx = 0; Idx < NumClangCounters; Idx++) if (P[Idx]) - Observe((uintptr_t)Idx); + ObservePC((uintptr_t)Idx); } } diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 0c9d4b69b..76aa0748f 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -82,6 +82,7 @@ class TracePC { void SetUseCounters(bool UC) { UseCounters = UC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } + void SetPrintNewFuncs(bool P) { DoPrintNewFuncs = P; } void UpdateObservedPCs(); template void CollectFeatures(Callback CB) const; @@ -133,6 +134,7 @@ private: bool UseCounters = false; bool UseValueProfile = false; bool DoPrintNewPCs = false; + bool DoPrintNewFuncs = false; struct Module { uint32_t *Start, *Stop; @@ -158,6 +160,7 @@ private: uintptr_t *PCs() const; std::set ObservedPCs; + std::set ObservedFuncs; ValueBitMap ValueProfileMap; uintptr_t InitialStack; diff --git a/test/fuzzer/PrintFuncTest.cpp b/test/fuzzer/PrintFuncTest.cpp new file mode 100644 index 000000000..d41b46239 --- /dev/null +++ b/test/fuzzer/PrintFuncTest.cpp @@ -0,0 +1,39 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include +#include +#include +#include + +extern "C" { +__attribute__((noinline)) +void FunctionC(const uint8_t *Data, size_t Size) { + if (Size > 3 && Data[3] == 'Z') { + static bool PrintedOnce = false; + if (!PrintedOnce) { + std::cout << "BINGO\n"; + PrintedOnce = true; + } + } +} + +__attribute__((noinline)) +void FunctionB(const uint8_t *Data, size_t Size) { + if (Size > 2 && Data[2] == 'Z') + FunctionC(Data, Size); +} +__attribute__((noinline)) +void FunctionA(const uint8_t *Data, size_t Size) { + if (Size > 1 && Data[1] == 'U') + FunctionB(Data, Size); +} +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'F') + FunctionA(Data, Size); + return 0; +} + diff --git a/test/fuzzer/print-func.test b/test/fuzzer/print-func.test new file mode 100644 index 000000000..12d52cb0b --- /dev/null +++ b/test/fuzzer/print-func.test @@ -0,0 +1,10 @@ +RUN: %cpp_compiler %S/PrintFuncTest.cpp -o %t +RUN: %t -seed=1 -runs=100000 2>&1 | FileCheck %s +RUN: %t -seed=1 -runs=100000 -print_funcs=0 2>&1 | FileCheck %s --check-prefix=NO +CHECK: NEW_FUNC: {{.*}} FunctionA +CHECK: NEW_FUNC: {{.*}} FunctionB +CHECK: NEW_FUNC: {{.*}} FunctionC +CHECK: BINGO + +NO-NOT: NEW_FUNC +NO: BINGO -- cgit v1.2.1 From 61a32bfc5761d8c99fa4c81ed42f5768863e735a Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 25 Aug 2017 20:20:46 +0000 Subject: [libFuzzer] prepare tests for switching from -fsanitize-coverage=trace-pc-guard to -fsanitize-coverage=inline-8bit-counters git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311798 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerFlags.def | 3 ++- test/fuzzer/dump_coverage.test | 8 ++++---- test/fuzzer/fuzzer.test | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index 6968c770a..df52377bf 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -97,7 +97,8 @@ FUZZER_FLAG_INT(print_corpus_stats, 0, "If 1, print statistics on corpus elements at exit.") FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" " at exit.") -FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a" +FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated." + " If 1, dump coverage information as a" " .sancov file at exit.") FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") diff --git a/test/fuzzer/dump_coverage.test b/test/fuzzer/dump_coverage.test index a733355ee..b240089ce 100644 --- a/test/fuzzer/dump_coverage.test +++ b/test/fuzzer/dump_coverage.test @@ -1,8 +1,8 @@ -RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest +RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/NullDerefTest.cpp -o %t-NullDerefTest RUN: rm -rf %t_workdir && mkdir -p %t_workdir RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s diff --git a/test/fuzzer/fuzzer.test b/test/fuzzer/fuzzer.test index e506fcbee..29bc8f0ce 100644 --- a/test/fuzzer/fuzzer.test +++ b/test/fuzzer/fuzzer.test @@ -8,7 +8,7 @@ RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest -RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -o %t-NotinstrumentedTest-NoCoverage +RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fsanitize-coverage=0 -o %t-NotinstrumentedTest-NoCoverage RUN: %cpp_compiler %S/NullDerefOnEmptyTest.cpp -o %t-NullDerefOnEmptyTest RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -- cgit v1.2.1 From 01e6fcc93ee0576ece59a981a8b73771dbfaeefd Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 25 Aug 2017 21:18:29 +0000 Subject: [SanitizeCoverage] Enable stack-depth coverage for -fsanitize=fuzzer Summary: - Don't sanitize __sancov_lowest_stack. - Don't instrument leaf functions. - Add CoverageStackDepth to Fuzzer and FuzzerNoLink. Reviewers: vitalybuka, kcc Reviewed By: kcc Subscribers: cfe-commits, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D37156 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311801 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/deep-recursion.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 23b7af1df..d3294d9a7 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,4 +1,4 @@ # Test that we can find a stack overflow -RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From fe25f5a544bd7a8de0d9c98a685f2c482f2443a3 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 25 Aug 2017 22:01:21 +0000 Subject: Revert "[SanitizeCoverage] Enable stack-depth coverage for -fsanitize=fuzzer" This reverts r311801 due to a bot failure. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311803 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/deep-recursion.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index d3294d9a7..23b7af1df 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,4 +1,4 @@ # Test that we can find a stack overflow -RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t +RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 27fb0f25514625a8adb42338015e635bd6ef0626 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 26 Aug 2017 01:13:33 +0000 Subject: Automatically pick up new sanitizers in cmake. Change the default of COMPILER_RT_SANITIZERS_TO_BUILD to "all" in order to automatically pick up new sanitizers in existing build trees. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311824 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index d38e3f3b6..764488b83 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -471,7 +471,7 @@ else() endif() set(ALL_SANITIZERS asan;dfsan;msan;tsan;safestack;cfi;esan;scudo) -set(COMPILER_RT_SANITIZERS_TO_BUILD ${ALL_SANITIZERS} CACHE STRING +set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") -- cgit v1.2.1 From 740573d1259e500ea7f323d213d476784c305372 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sat, 26 Aug 2017 17:17:37 +0000 Subject: [libFuzzer] Use custom allocators for STL containers in libFuzzer Avoids ODR violations causing spurious ASAN container overflow warnings. Differential Revision: https://reviews.llvm.org/D37086 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311830 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 12 ++++++------ lib/fuzzer/FuzzerDefs.h | 17 +++++++++++++++-- lib/fuzzer/FuzzerDictionary.h | 2 +- lib/fuzzer/FuzzerDriver.cpp | 32 ++++++++++++++++---------------- lib/fuzzer/FuzzerIO.cpp | 4 ++-- lib/fuzzer/FuzzerIO.h | 4 ++-- lib/fuzzer/FuzzerIOPosix.cpp | 2 +- lib/fuzzer/FuzzerIOWindows.cpp | 2 +- lib/fuzzer/FuzzerInternal.h | 8 ++++---- lib/fuzzer/FuzzerLoop.cpp | 2 +- lib/fuzzer/FuzzerMerge.cpp | 14 +++++++------- lib/fuzzer/FuzzerMerge.h | 8 ++++---- lib/fuzzer/FuzzerMutate.cpp | 4 ++-- lib/fuzzer/FuzzerMutate.h | 14 +++++++------- lib/fuzzer/FuzzerTracePC.cpp | 2 +- lib/fuzzer/FuzzerUtil.cpp | 2 +- lib/fuzzer/FuzzerUtil.h | 4 ++-- lib/fuzzer/tests/FuzzerUnittest.cpp | 20 ++++++++++---------- 18 files changed, 83 insertions(+), 70 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index bae0aea78..844a66b25 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -35,7 +35,7 @@ struct InputInfo { size_t NumSuccessfullMutations = 0; bool MayDeleteFile = false; bool Reduced = false; - std::vector UniqFeatureSet; + fuzzer::vector UniqFeatureSet; }; class InputCorpus { @@ -71,7 +71,7 @@ class InputCorpus { bool empty() const { return Inputs.empty(); } const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, - const std::vector &FeatureSet) { + const fuzzer::vector &FeatureSet) { assert(!U.empty()); if (FeatureDebug) Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); @@ -100,7 +100,7 @@ class InputCorpus { } // Debug-only - void PrintFeatureSet(const std::vector &FeatureSet) { + void PrintFeatureSet(const fuzzer::vector &FeatureSet) { if (!FeatureDebug) return; Printf("{"); for (uint32_t Feature: FeatureSet) @@ -256,11 +256,11 @@ private: } std::piecewise_constant_distribution CorpusDistribution; - std::vector Intervals; - std::vector Weights; + fuzzer::vector Intervals; + fuzzer::vector Weights; std::unordered_set Hashes; - std::vector Inputs; + fuzzer::vector Inputs; size_t NumAddedFeatures = 0; size_t NumUpdatedFeatures = 0; diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index bbb44514a..5e5d3afa2 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include // Platform detection. #ifdef __linux__ @@ -102,8 +104,19 @@ struct ExternalFunctions; // Global interface to functions that may or may not be available. extern ExternalFunctions *EF; -typedef std::vector Unit; -typedef std::vector UnitVector; +// We are using a custom allocator to give a different symbol name to STL +// containers in order to avoid ODR violations. +template +class fuzzer_allocator: public std::allocator {}; + +template +using vector = std::vector>; + +template +using set = std::set, fuzzer_allocator>; + +typedef fuzzer::vector Unit; +typedef fuzzer::vector UnitVector; typedef int (*UserCallback)(const uint8_t *Data, size_t Size); int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h index 84cee87b8..01a091e3e 100644 --- a/lib/fuzzer/FuzzerDictionary.h +++ b/lib/fuzzer/FuzzerDictionary.h @@ -120,7 +120,7 @@ private: bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // Parses the dictionary file, fills Units, returns true iff all lines // were parsed succesfully. -bool ParseDictionaryFile(const std::string &Text, std::vector *Units); +bool ParseDictionaryFile(const std::string &Text, fuzzer::vector *Units); } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index d0d0f7dd0..1bae8702e 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -74,7 +74,7 @@ static const FlagDescription FlagDescriptions [] { static const size_t kNumFlags = sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); -static std::vector *Inputs; +static fuzzer::vector *Inputs; static std::string *ProgName; static void PrintHelp() { @@ -175,7 +175,7 @@ static bool ParseOneFlag(const char *Param) { } // We don't use any library to minimize dependencies. -static void ParseFlags(const std::vector &Args) { +static void ParseFlags(const fuzzer::vector &Args) { for (size_t F = 0; F < kNumFlags; F++) { if (FlagDescriptions[F].IntFlag) *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; @@ -185,7 +185,7 @@ static void ParseFlags(const std::vector &Args) { if (FlagDescriptions[F].StrFlag) *FlagDescriptions[F].StrFlag = nullptr; } - Inputs = new std::vector; + Inputs = new fuzzer::vector; for (size_t A = 1; A < Args.size(); A++) { if (ParseOneFlag(Args[A].c_str())) { if (Flags.ignore_remaining_args) @@ -225,7 +225,7 @@ static void WorkerThread(const std::string &Cmd, std::atomic *Counter, } } -std::string CloneArgsWithoutX(const std::vector &Args, +std::string CloneArgsWithoutX(const fuzzer::vector &Args, const char *X1, const char *X2) { std::string Cmd; for (auto &S : Args) { @@ -236,12 +236,12 @@ std::string CloneArgsWithoutX(const std::vector &Args, return Cmd; } -static int RunInMultipleProcesses(const std::vector &Args, +static int RunInMultipleProcesses(const fuzzer::vector &Args, unsigned NumWorkers, unsigned NumJobs) { std::atomic Counter(0); std::atomic HasErrors(false); std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); - std::vector V; + fuzzer::vector V; std::thread Pulse(PulseThread); Pulse.detach(); for (unsigned i = 0; i < NumWorkers; i++) @@ -294,7 +294,7 @@ static std::string GetDedupTokenFromFile(const std::string &Path) { return S.substr(Beg, End - Beg); } -int CleanseCrashInput(const std::vector &Args, +int CleanseCrashInput(const fuzzer::vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1 || !Flags.exact_artifact_path) { Printf("ERROR: -cleanse_crash should be given one input file and" @@ -322,7 +322,7 @@ int CleanseCrashInput(const std::vector &Args, auto U = FileToVector(CurrentFilePath); size_t Size = U.size(); - const std::vector ReplacementBytes = {' ', 0xff}; + const fuzzer::vector ReplacementBytes = {' ', 0xff}; for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { bool Changed = false; for (size_t Idx = 0; Idx < Size; Idx++) { @@ -354,7 +354,7 @@ int CleanseCrashInput(const std::vector &Args, return 0; } -int MinimizeCrashInput(const std::vector &Args, +int MinimizeCrashInput(const fuzzer::vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1) { Printf("ERROR: -minimize_crash should be given one input file\n"); @@ -456,17 +456,17 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } -int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, +int AnalyzeDictionary(Fuzzer *F, const fuzzer::vector& Dict, UnitVector& Corpus) { Printf("Started dictionary minimization (up to %d tests)\n", Dict.size() * Corpus.size() * 2); // Scores and usage count for each dictionary unit. - std::vector Scores(Dict.size()); - std::vector Usages(Dict.size()); + fuzzer::vector Scores(Dict.size()); + fuzzer::vector Usages(Dict.size()); - std::vector InitialFeatures; - std::vector ModifiedFeatures; + fuzzer::vector InitialFeatures; + fuzzer::vector ModifiedFeatures; for (auto &C : Corpus) { // Get coverage for the testcase without modifications. F->ExecuteCallback(C.data(), C.size()); @@ -531,7 +531,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { EF = new ExternalFunctions(); if (EF->LLVMFuzzerInitialize) EF->LLVMFuzzerInitialize(argc, argv); - const std::vector Args(*argv, *argv + *argc); + const fuzzer::vector Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); if (Argv0 != *ProgName) { @@ -593,7 +593,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.ArtifactPrefix = Flags.artifact_prefix; if (Flags.exact_artifact_path) Options.ExactArtifactPath = Flags.exact_artifact_path; - std::vector Dictionary; + fuzzer::vector Dictionary; if (Flags.dict) if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) return 1; diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index 1a06d4420..eeb104807 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -68,10 +68,10 @@ void WriteToFile(const Unit &U, const std::string &Path) { fclose(Out); } -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, +void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError) { long E = Epoch ? *Epoch : 0; - std::vector Files; + fuzzer::vector Files; ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); size_t NumLoaded = 0; for (size_t i = 0; i < Files.size(); i++) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 3b66a52d1..a404dffc4 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -27,7 +27,7 @@ void CopyFileToErr(const std::string &Path); void WriteToFile(const Unit &U, const std::string &Path); -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, +void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError); // Returns "Dir/FileName" or equivalent for the current OS. @@ -55,7 +55,7 @@ void RawPrint(const char *Str); bool IsFile(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir); + fuzzer::vector *V, bool TopDir); char GetSeparator(); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index c5ebdbac4..d283597ad 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -33,7 +33,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { + fuzzer::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp index 742520267..063d4f9f7 100644 --- a/lib/fuzzer/FuzzerIOWindows.cpp +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -73,7 +73,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { + fuzzer::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 1d68c0190..a2af3a2f5 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -69,9 +69,9 @@ public: InputInfo *II = nullptr); // Merge Corpora[1:] into Corpora[0]. - void Merge(const std::vector &Corpora); - void CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, + void Merge(const fuzzer::vector &Corpora); + void CrashResistantMerge(const fuzzer::vector &Args, + const fuzzer::vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull); void CrashResistantMergeInternalStep(const std::string &ControlFilePath); @@ -139,7 +139,7 @@ private: size_t MaxMutationLen = 0; size_t TmpMaxMutationLen = 0; - std::vector UniqFeatureSetTmp; + fuzzer::vector UniqFeatureSetTmp; // Need to know our own thread. static thread_local bool IsMyThread; diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d2d096af4..d9189123a 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -350,7 +350,7 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { void Fuzzer::RereadOutputCorpus(size_t MaxSize) { if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; - std::vector AdditionalCorpus; + fuzzer::vector AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, &EpochOfLastReadOfOutputCorpus, MaxSize, /*ExitOnError*/ false); diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index 616c0999a..a67a83490 100644 --- a/lib/fuzzer/FuzzerMerge.cpp +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -74,7 +74,7 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { size_t ExpectedStartMarker = 0; const size_t kInvalidStartMarker = -1; size_t LastSeenStartMarker = kInvalidStartMarker; - std::vector TmpFeatures; + fuzzer::vector TmpFeatures; while (std::getline(IS, Line, '\n')) { std::istringstream ISS1(Line); std::string Marker; @@ -123,7 +123,7 @@ size_t Merger::ApproximateMemoryConsumption() const { // Decides which files need to be merged (add thost to NewFiles). // Returns the number of new features added. size_t Merger::Merge(const std::set &InitialFeatures, - std::vector *NewFiles) { + fuzzer::vector *NewFiles) { NewFiles->clear(); assert(NumFilesInFirstCorpus <= Files.size()); std::set AllFeatures(InitialFeatures); @@ -138,7 +138,7 @@ size_t Merger::Merge(const std::set &InitialFeatures, // Remove all features that we already know from all other inputs. for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { auto &Cur = Files[i].Features; - std::vector Tmp; + fuzzer::vector Tmp; std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); Cur.swap(Tmp); @@ -252,15 +252,15 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { } // Outer process. Does not call the target code and thus sohuld not fail. -void Fuzzer::CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, +void Fuzzer::CrashResistantMerge(const fuzzer::vector &Args, + const fuzzer::vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull) { if (Corpora.size() <= 1) { Printf("Merge requires two or more corpus dirs\n"); return; } - std::vector AllFiles; + fuzzer::vector AllFiles; ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); size_t NumFilesInFirstCorpus = AllFiles.size(); for (size_t i = 1; i < Corpora.size(); i++) @@ -318,7 +318,7 @@ void Fuzzer::CrashResistantMerge(const std::vector &Args, std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); M.PrintSummary(SummaryOut); } - std::vector NewFiles; + fuzzer::vector NewFiles; std::set InitialFeatures; if (CoverageSummaryInputPathOrNull) { std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); diff --git a/lib/fuzzer/FuzzerMerge.h b/lib/fuzzer/FuzzerMerge.h index dd4c37b6e..dd0ad8db1 100644 --- a/lib/fuzzer/FuzzerMerge.h +++ b/lib/fuzzer/FuzzerMerge.h @@ -52,11 +52,11 @@ namespace fuzzer { struct MergeFileInfo { std::string Name; size_t Size = 0; - std::vector Features; + fuzzer::vector Features; }; struct Merger { - std::vector Files; + fuzzer::vector Files; size_t NumFilesInFirstCorpus = 0; size_t FirstNotProcessedFile = 0; std::string LastFailure; @@ -67,8 +67,8 @@ struct Merger { void PrintSummary(std::ostream &OS); std::set ParseSummary(std::istream &IS); size_t Merge(const std::set &InitialFeatures, - std::vector *NewFiles); - size_t Merge(std::vector *NewFiles) { + fuzzer::vector *NewFiles); + size_t Merge(fuzzer::vector *NewFiles) { return Merge(std::set{}, NewFiles); } size_t ApproximateMemoryConsumption() const; diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp index 5998ef9d3..439ea6741 100644 --- a/lib/fuzzer/FuzzerMutate.cpp +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -466,7 +466,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { } void MutationDispatcher::PrintRecommendedDictionary() { - std::vector V; + fuzzer::vector V; for (auto &DE : PersistentAutoDictionary) if (!ManualDictionary.ContainsWord(DE.GetW())) V.push_back(DE); @@ -506,7 +506,7 @@ size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, // Mutates Data in place, returns new size. size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators) { + const fuzzer::vector &Mutators) { assert(MaxSize > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h index 84b04c0db..d1613b22b 100644 --- a/lib/fuzzer/FuzzerMutate.h +++ b/lib/fuzzer/FuzzerMutate.h @@ -96,7 +96,7 @@ private: size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators); + const fuzzer::vector &Mutators); size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, size_t ToSize, size_t MaxToSize); @@ -128,21 +128,21 @@ private: // entries that led to successfull discoveries in the past mutations. Dictionary PersistentAutoDictionary; - std::vector CurrentMutatorSequence; - std::vector CurrentDictionaryEntrySequence; + fuzzer::vector CurrentMutatorSequence; + fuzzer::vector CurrentDictionaryEntrySequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; size_t CmpDictionaryEntriesDequeIdx = 0; const InputCorpus *Corpus = nullptr; - std::vector MutateInPlaceHere; + fuzzer::vector MutateInPlaceHere; // CustomCrossOver needs its own buffer as a custom implementation may call // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. - std::vector CustomCrossOverInPlaceHere; + fuzzer::vector CustomCrossOverInPlaceHere; - std::vector Mutators; - std::vector DefaultMutators; + fuzzer::vector Mutators; + fuzzer::vector DefaultMutators; }; } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 812a6190a..3d348f8f9 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -270,7 +270,7 @@ void TracePC::PrintCoverage() { void TracePC::DumpCoverage() { if (EF->__sanitizer_dump_coverage) { - std::vector PCsCopy(GetNumPCs()); + fuzzer::vector PCsCopy(GetNumPCs()); for (size_t i = 0; i < GetNumPCs(); i++) PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp index f5a777374..2c46d1b25 100644 --- a/lib/fuzzer/FuzzerUtil.cpp +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -124,7 +124,7 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { return true; } -bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { +bool ParseDictionaryFile(const std::string &Text, fuzzer::vector *Units) { if (Text.empty()) { Printf("ParseDictionaryFile: file does not exist or is empty\n"); return false; diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index 9c90040b0..c5bfb14e8 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -57,10 +57,10 @@ FILE *OpenProcessPipe(const char *Command, const char *Mode); const void *SearchMemory(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -std::string CloneArgsWithoutX(const std::vector &Args, +std::string CloneArgsWithoutX(const fuzzer::vector &Args, const char *X1, const char *X2); -inline std::string CloneArgsWithoutX(const std::vector &Args, +inline std::string CloneArgsWithoutX(const fuzzer::vector &Args, const char *X) { return CloneArgsWithoutX(Args, X, X); } diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index 858e61d75..feafc8ffd 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -526,7 +526,7 @@ TEST(FuzzerDictionary, ParseOneDictionaryEntry) { } TEST(FuzzerDictionary, ParseDictionaryFile) { - std::vector Units; + fuzzer::vector Units; EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); EXPECT_FALSE(ParseDictionaryFile("", &Units)); EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); @@ -538,11 +538,11 @@ TEST(FuzzerDictionary, ParseDictionaryFile) { EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); EXPECT_EQ(Units.size(), 0U); EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); - EXPECT_EQ(Units, std::vector({Unit({'a', 'a'})})); + EXPECT_EQ(Units, fuzzer::vector({Unit({'a', 'a'})})); EXPECT_TRUE( ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); EXPECT_EQ(Units, - std::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); + fuzzer::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); } TEST(FuzzerUtil, Base64) { @@ -566,7 +566,7 @@ TEST(Corpus, Distribution) { for (size_t i = 0; i < N; i++) C->AddToCorpus(Unit{ static_cast(i) }, 1, false, {}); - std::vector Hist(N); + fuzzer::vector Hist(N); for (size_t i = 0; i < N * TriesPerUnit; i++) { Hist[C->ChooseUnitIdxToMutate(Rand)]++; } @@ -596,21 +596,21 @@ TEST(Merge, Bad) { } } -void EQ(const std::vector &A, const std::vector &B) { +void EQ(const fuzzer::vector &A, const fuzzer::vector &B) { EXPECT_EQ(A, B); } -void EQ(const std::vector &A, const std::vector &B) { +void EQ(const fuzzer::vector &A, const fuzzer::vector &B) { std::set a(A.begin(), A.end()); std::set b(B.begin(), B.end()); EXPECT_EQ(a, b); } static void Merge(const std::string &Input, - const std::vector Result, + const fuzzer::vector Result, size_t NumNewFeatures) { Merger M; - std::vector NewFiles; + fuzzer::vector NewFiles; EXPECT_TRUE(M.Parse(Input, true)); std::stringstream SS; M.PrintSummary(SS); @@ -658,7 +658,7 @@ TEST(Merge, Good) { EQ(M.Files[1].Features, {4, 5, 6}); - std::vector NewFiles; + fuzzer::vector NewFiles; EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" "STARTED 0 1000\nDONE 0 1 2 3\n" @@ -739,7 +739,7 @@ TEST(Fuzzer, ForEachNonZeroByte) { 0, 0, 0, 0, 0, 0, 0, 8, 9, 9, 9, 9, 9, 9, 9, 9, }; - typedef std::vector > Vec; + typedef fuzzer::vector > Vec; Vec Res, Expected; auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) { Res.push_back({FirstFeature + Idx, V}); -- cgit v1.2.1 From 422f200cdfd54bee317d925981b24b177bd46297 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sat, 26 Aug 2017 17:50:35 +0000 Subject: Revert "[libFuzzer] Use custom allocators for STL containers in libFuzzer" This reverts commit 3539efc2f2218dba2bcbd645d0fe276f2b5cf588. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311831 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 12 ++++++------ lib/fuzzer/FuzzerDefs.h | 17 ++--------------- lib/fuzzer/FuzzerDictionary.h | 2 +- lib/fuzzer/FuzzerDriver.cpp | 32 ++++++++++++++++---------------- lib/fuzzer/FuzzerIO.cpp | 4 ++-- lib/fuzzer/FuzzerIO.h | 4 ++-- lib/fuzzer/FuzzerIOPosix.cpp | 2 +- lib/fuzzer/FuzzerIOWindows.cpp | 2 +- lib/fuzzer/FuzzerInternal.h | 8 ++++---- lib/fuzzer/FuzzerLoop.cpp | 2 +- lib/fuzzer/FuzzerMerge.cpp | 14 +++++++------- lib/fuzzer/FuzzerMerge.h | 8 ++++---- lib/fuzzer/FuzzerMutate.cpp | 4 ++-- lib/fuzzer/FuzzerMutate.h | 14 +++++++------- lib/fuzzer/FuzzerTracePC.cpp | 2 +- lib/fuzzer/FuzzerUtil.cpp | 2 +- lib/fuzzer/FuzzerUtil.h | 4 ++-- lib/fuzzer/tests/FuzzerUnittest.cpp | 20 ++++++++++---------- 18 files changed, 70 insertions(+), 83 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index 844a66b25..bae0aea78 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -35,7 +35,7 @@ struct InputInfo { size_t NumSuccessfullMutations = 0; bool MayDeleteFile = false; bool Reduced = false; - fuzzer::vector UniqFeatureSet; + std::vector UniqFeatureSet; }; class InputCorpus { @@ -71,7 +71,7 @@ class InputCorpus { bool empty() const { return Inputs.empty(); } const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, - const fuzzer::vector &FeatureSet) { + const std::vector &FeatureSet) { assert(!U.empty()); if (FeatureDebug) Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); @@ -100,7 +100,7 @@ class InputCorpus { } // Debug-only - void PrintFeatureSet(const fuzzer::vector &FeatureSet) { + void PrintFeatureSet(const std::vector &FeatureSet) { if (!FeatureDebug) return; Printf("{"); for (uint32_t Feature: FeatureSet) @@ -256,11 +256,11 @@ private: } std::piecewise_constant_distribution CorpusDistribution; - fuzzer::vector Intervals; - fuzzer::vector Weights; + std::vector Intervals; + std::vector Weights; std::unordered_set Hashes; - fuzzer::vector Inputs; + std::vector Inputs; size_t NumAddedFeatures = 0; size_t NumUpdatedFeatures = 0; diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index 5e5d3afa2..bbb44514a 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -18,8 +18,6 @@ #include #include #include -#include -#include // Platform detection. #ifdef __linux__ @@ -104,19 +102,8 @@ struct ExternalFunctions; // Global interface to functions that may or may not be available. extern ExternalFunctions *EF; -// We are using a custom allocator to give a different symbol name to STL -// containers in order to avoid ODR violations. -template -class fuzzer_allocator: public std::allocator {}; - -template -using vector = std::vector>; - -template -using set = std::set, fuzzer_allocator>; - -typedef fuzzer::vector Unit; -typedef fuzzer::vector UnitVector; +typedef std::vector Unit; +typedef std::vector UnitVector; typedef int (*UserCallback)(const uint8_t *Data, size_t Size); int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h index 01a091e3e..84cee87b8 100644 --- a/lib/fuzzer/FuzzerDictionary.h +++ b/lib/fuzzer/FuzzerDictionary.h @@ -120,7 +120,7 @@ private: bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // Parses the dictionary file, fills Units, returns true iff all lines // were parsed succesfully. -bool ParseDictionaryFile(const std::string &Text, fuzzer::vector *Units); +bool ParseDictionaryFile(const std::string &Text, std::vector *Units); } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 1bae8702e..d0d0f7dd0 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -74,7 +74,7 @@ static const FlagDescription FlagDescriptions [] { static const size_t kNumFlags = sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); -static fuzzer::vector *Inputs; +static std::vector *Inputs; static std::string *ProgName; static void PrintHelp() { @@ -175,7 +175,7 @@ static bool ParseOneFlag(const char *Param) { } // We don't use any library to minimize dependencies. -static void ParseFlags(const fuzzer::vector &Args) { +static void ParseFlags(const std::vector &Args) { for (size_t F = 0; F < kNumFlags; F++) { if (FlagDescriptions[F].IntFlag) *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; @@ -185,7 +185,7 @@ static void ParseFlags(const fuzzer::vector &Args) { if (FlagDescriptions[F].StrFlag) *FlagDescriptions[F].StrFlag = nullptr; } - Inputs = new fuzzer::vector; + Inputs = new std::vector; for (size_t A = 1; A < Args.size(); A++) { if (ParseOneFlag(Args[A].c_str())) { if (Flags.ignore_remaining_args) @@ -225,7 +225,7 @@ static void WorkerThread(const std::string &Cmd, std::atomic *Counter, } } -std::string CloneArgsWithoutX(const fuzzer::vector &Args, +std::string CloneArgsWithoutX(const std::vector &Args, const char *X1, const char *X2) { std::string Cmd; for (auto &S : Args) { @@ -236,12 +236,12 @@ std::string CloneArgsWithoutX(const fuzzer::vector &Args, return Cmd; } -static int RunInMultipleProcesses(const fuzzer::vector &Args, +static int RunInMultipleProcesses(const std::vector &Args, unsigned NumWorkers, unsigned NumJobs) { std::atomic Counter(0); std::atomic HasErrors(false); std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); - fuzzer::vector V; + std::vector V; std::thread Pulse(PulseThread); Pulse.detach(); for (unsigned i = 0; i < NumWorkers; i++) @@ -294,7 +294,7 @@ static std::string GetDedupTokenFromFile(const std::string &Path) { return S.substr(Beg, End - Beg); } -int CleanseCrashInput(const fuzzer::vector &Args, +int CleanseCrashInput(const std::vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1 || !Flags.exact_artifact_path) { Printf("ERROR: -cleanse_crash should be given one input file and" @@ -322,7 +322,7 @@ int CleanseCrashInput(const fuzzer::vector &Args, auto U = FileToVector(CurrentFilePath); size_t Size = U.size(); - const fuzzer::vector ReplacementBytes = {' ', 0xff}; + const std::vector ReplacementBytes = {' ', 0xff}; for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { bool Changed = false; for (size_t Idx = 0; Idx < Size; Idx++) { @@ -354,7 +354,7 @@ int CleanseCrashInput(const fuzzer::vector &Args, return 0; } -int MinimizeCrashInput(const fuzzer::vector &Args, +int MinimizeCrashInput(const std::vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1) { Printf("ERROR: -minimize_crash should be given one input file\n"); @@ -456,17 +456,17 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } -int AnalyzeDictionary(Fuzzer *F, const fuzzer::vector& Dict, +int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, UnitVector& Corpus) { Printf("Started dictionary minimization (up to %d tests)\n", Dict.size() * Corpus.size() * 2); // Scores and usage count for each dictionary unit. - fuzzer::vector Scores(Dict.size()); - fuzzer::vector Usages(Dict.size()); + std::vector Scores(Dict.size()); + std::vector Usages(Dict.size()); - fuzzer::vector InitialFeatures; - fuzzer::vector ModifiedFeatures; + std::vector InitialFeatures; + std::vector ModifiedFeatures; for (auto &C : Corpus) { // Get coverage for the testcase without modifications. F->ExecuteCallback(C.data(), C.size()); @@ -531,7 +531,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { EF = new ExternalFunctions(); if (EF->LLVMFuzzerInitialize) EF->LLVMFuzzerInitialize(argc, argv); - const fuzzer::vector Args(*argv, *argv + *argc); + const std::vector Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); if (Argv0 != *ProgName) { @@ -593,7 +593,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.ArtifactPrefix = Flags.artifact_prefix; if (Flags.exact_artifact_path) Options.ExactArtifactPath = Flags.exact_artifact_path; - fuzzer::vector Dictionary; + std::vector Dictionary; if (Flags.dict) if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) return 1; diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index eeb104807..1a06d4420 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -68,10 +68,10 @@ void WriteToFile(const Unit &U, const std::string &Path) { fclose(Out); } -void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector *V, +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError) { long E = Epoch ? *Epoch : 0; - fuzzer::vector Files; + std::vector Files; ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); size_t NumLoaded = 0; for (size_t i = 0; i < Files.size(); i++) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index a404dffc4..3b66a52d1 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -27,7 +27,7 @@ void CopyFileToErr(const std::string &Path); void WriteToFile(const Unit &U, const std::string &Path); -void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector *V, +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError); // Returns "Dir/FileName" or equivalent for the current OS. @@ -55,7 +55,7 @@ void RawPrint(const char *Str); bool IsFile(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - fuzzer::vector *V, bool TopDir); + std::vector *V, bool TopDir); char GetSeparator(); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index d283597ad..c5ebdbac4 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -33,7 +33,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - fuzzer::vector *V, bool TopDir) { + std::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp index 063d4f9f7..742520267 100644 --- a/lib/fuzzer/FuzzerIOWindows.cpp +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -73,7 +73,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - fuzzer::vector *V, bool TopDir) { + std::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index a2af3a2f5..1d68c0190 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -69,9 +69,9 @@ public: InputInfo *II = nullptr); // Merge Corpora[1:] into Corpora[0]. - void Merge(const fuzzer::vector &Corpora); - void CrashResistantMerge(const fuzzer::vector &Args, - const fuzzer::vector &Corpora, + void Merge(const std::vector &Corpora); + void CrashResistantMerge(const std::vector &Args, + const std::vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull); void CrashResistantMergeInternalStep(const std::string &ControlFilePath); @@ -139,7 +139,7 @@ private: size_t MaxMutationLen = 0; size_t TmpMaxMutationLen = 0; - fuzzer::vector UniqFeatureSetTmp; + std::vector UniqFeatureSetTmp; // Need to know our own thread. static thread_local bool IsMyThread; diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d9189123a..d2d096af4 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -350,7 +350,7 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { void Fuzzer::RereadOutputCorpus(size_t MaxSize) { if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; - fuzzer::vector AdditionalCorpus; + std::vector AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, &EpochOfLastReadOfOutputCorpus, MaxSize, /*ExitOnError*/ false); diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index a67a83490..616c0999a 100644 --- a/lib/fuzzer/FuzzerMerge.cpp +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -74,7 +74,7 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { size_t ExpectedStartMarker = 0; const size_t kInvalidStartMarker = -1; size_t LastSeenStartMarker = kInvalidStartMarker; - fuzzer::vector TmpFeatures; + std::vector TmpFeatures; while (std::getline(IS, Line, '\n')) { std::istringstream ISS1(Line); std::string Marker; @@ -123,7 +123,7 @@ size_t Merger::ApproximateMemoryConsumption() const { // Decides which files need to be merged (add thost to NewFiles). // Returns the number of new features added. size_t Merger::Merge(const std::set &InitialFeatures, - fuzzer::vector *NewFiles) { + std::vector *NewFiles) { NewFiles->clear(); assert(NumFilesInFirstCorpus <= Files.size()); std::set AllFeatures(InitialFeatures); @@ -138,7 +138,7 @@ size_t Merger::Merge(const std::set &InitialFeatures, // Remove all features that we already know from all other inputs. for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { auto &Cur = Files[i].Features; - fuzzer::vector Tmp; + std::vector Tmp; std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); Cur.swap(Tmp); @@ -252,15 +252,15 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { } // Outer process. Does not call the target code and thus sohuld not fail. -void Fuzzer::CrashResistantMerge(const fuzzer::vector &Args, - const fuzzer::vector &Corpora, +void Fuzzer::CrashResistantMerge(const std::vector &Args, + const std::vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull) { if (Corpora.size() <= 1) { Printf("Merge requires two or more corpus dirs\n"); return; } - fuzzer::vector AllFiles; + std::vector AllFiles; ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); size_t NumFilesInFirstCorpus = AllFiles.size(); for (size_t i = 1; i < Corpora.size(); i++) @@ -318,7 +318,7 @@ void Fuzzer::CrashResistantMerge(const fuzzer::vector &Args, std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); M.PrintSummary(SummaryOut); } - fuzzer::vector NewFiles; + std::vector NewFiles; std::set InitialFeatures; if (CoverageSummaryInputPathOrNull) { std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); diff --git a/lib/fuzzer/FuzzerMerge.h b/lib/fuzzer/FuzzerMerge.h index dd0ad8db1..dd4c37b6e 100644 --- a/lib/fuzzer/FuzzerMerge.h +++ b/lib/fuzzer/FuzzerMerge.h @@ -52,11 +52,11 @@ namespace fuzzer { struct MergeFileInfo { std::string Name; size_t Size = 0; - fuzzer::vector Features; + std::vector Features; }; struct Merger { - fuzzer::vector Files; + std::vector Files; size_t NumFilesInFirstCorpus = 0; size_t FirstNotProcessedFile = 0; std::string LastFailure; @@ -67,8 +67,8 @@ struct Merger { void PrintSummary(std::ostream &OS); std::set ParseSummary(std::istream &IS); size_t Merge(const std::set &InitialFeatures, - fuzzer::vector *NewFiles); - size_t Merge(fuzzer::vector *NewFiles) { + std::vector *NewFiles); + size_t Merge(std::vector *NewFiles) { return Merge(std::set{}, NewFiles); } size_t ApproximateMemoryConsumption() const; diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp index 439ea6741..5998ef9d3 100644 --- a/lib/fuzzer/FuzzerMutate.cpp +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -466,7 +466,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { } void MutationDispatcher::PrintRecommendedDictionary() { - fuzzer::vector V; + std::vector V; for (auto &DE : PersistentAutoDictionary) if (!ManualDictionary.ContainsWord(DE.GetW())) V.push_back(DE); @@ -506,7 +506,7 @@ size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, // Mutates Data in place, returns new size. size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const fuzzer::vector &Mutators) { + const std::vector &Mutators) { assert(MaxSize > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h index d1613b22b..84b04c0db 100644 --- a/lib/fuzzer/FuzzerMutate.h +++ b/lib/fuzzer/FuzzerMutate.h @@ -96,7 +96,7 @@ private: size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const fuzzer::vector &Mutators); + const std::vector &Mutators); size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, size_t ToSize, size_t MaxToSize); @@ -128,21 +128,21 @@ private: // entries that led to successfull discoveries in the past mutations. Dictionary PersistentAutoDictionary; - fuzzer::vector CurrentMutatorSequence; - fuzzer::vector CurrentDictionaryEntrySequence; + std::vector CurrentMutatorSequence; + std::vector CurrentDictionaryEntrySequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; size_t CmpDictionaryEntriesDequeIdx = 0; const InputCorpus *Corpus = nullptr; - fuzzer::vector MutateInPlaceHere; + std::vector MutateInPlaceHere; // CustomCrossOver needs its own buffer as a custom implementation may call // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. - fuzzer::vector CustomCrossOverInPlaceHere; + std::vector CustomCrossOverInPlaceHere; - fuzzer::vector Mutators; - fuzzer::vector DefaultMutators; + std::vector Mutators; + std::vector DefaultMutators; }; } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 3d348f8f9..812a6190a 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -270,7 +270,7 @@ void TracePC::PrintCoverage() { void TracePC::DumpCoverage() { if (EF->__sanitizer_dump_coverage) { - fuzzer::vector PCsCopy(GetNumPCs()); + std::vector PCsCopy(GetNumPCs()); for (size_t i = 0; i < GetNumPCs(); i++) PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp index 2c46d1b25..f5a777374 100644 --- a/lib/fuzzer/FuzzerUtil.cpp +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -124,7 +124,7 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { return true; } -bool ParseDictionaryFile(const std::string &Text, fuzzer::vector *Units) { +bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { if (Text.empty()) { Printf("ParseDictionaryFile: file does not exist or is empty\n"); return false; diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index c5bfb14e8..9c90040b0 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -57,10 +57,10 @@ FILE *OpenProcessPipe(const char *Command, const char *Mode); const void *SearchMemory(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -std::string CloneArgsWithoutX(const fuzzer::vector &Args, +std::string CloneArgsWithoutX(const std::vector &Args, const char *X1, const char *X2); -inline std::string CloneArgsWithoutX(const fuzzer::vector &Args, +inline std::string CloneArgsWithoutX(const std::vector &Args, const char *X) { return CloneArgsWithoutX(Args, X, X); } diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index feafc8ffd..858e61d75 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -526,7 +526,7 @@ TEST(FuzzerDictionary, ParseOneDictionaryEntry) { } TEST(FuzzerDictionary, ParseDictionaryFile) { - fuzzer::vector Units; + std::vector Units; EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); EXPECT_FALSE(ParseDictionaryFile("", &Units)); EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); @@ -538,11 +538,11 @@ TEST(FuzzerDictionary, ParseDictionaryFile) { EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); EXPECT_EQ(Units.size(), 0U); EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); - EXPECT_EQ(Units, fuzzer::vector({Unit({'a', 'a'})})); + EXPECT_EQ(Units, std::vector({Unit({'a', 'a'})})); EXPECT_TRUE( ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); EXPECT_EQ(Units, - fuzzer::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); + std::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); } TEST(FuzzerUtil, Base64) { @@ -566,7 +566,7 @@ TEST(Corpus, Distribution) { for (size_t i = 0; i < N; i++) C->AddToCorpus(Unit{ static_cast(i) }, 1, false, {}); - fuzzer::vector Hist(N); + std::vector Hist(N); for (size_t i = 0; i < N * TriesPerUnit; i++) { Hist[C->ChooseUnitIdxToMutate(Rand)]++; } @@ -596,21 +596,21 @@ TEST(Merge, Bad) { } } -void EQ(const fuzzer::vector &A, const fuzzer::vector &B) { +void EQ(const std::vector &A, const std::vector &B) { EXPECT_EQ(A, B); } -void EQ(const fuzzer::vector &A, const fuzzer::vector &B) { +void EQ(const std::vector &A, const std::vector &B) { std::set a(A.begin(), A.end()); std::set b(B.begin(), B.end()); EXPECT_EQ(a, b); } static void Merge(const std::string &Input, - const fuzzer::vector Result, + const std::vector Result, size_t NumNewFeatures) { Merger M; - fuzzer::vector NewFiles; + std::vector NewFiles; EXPECT_TRUE(M.Parse(Input, true)); std::stringstream SS; M.PrintSummary(SS); @@ -658,7 +658,7 @@ TEST(Merge, Good) { EQ(M.Files[1].Features, {4, 5, 6}); - fuzzer::vector NewFiles; + std::vector NewFiles; EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" "STARTED 0 1000\nDONE 0 1 2 3\n" @@ -739,7 +739,7 @@ TEST(Fuzzer, ForEachNonZeroByte) { 0, 0, 0, 0, 0, 0, 0, 8, 9, 9, 9, 9, 9, 9, 9, 9, }; - typedef fuzzer::vector > Vec; + typedef std::vector > Vec; Vec Res, Expected; auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) { Res.push_back({FirstFeature + Idx, V}); -- cgit v1.2.1 From 7cbce19925c4686ac96ff7e4ae38b42642dcdc3e Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Sun, 27 Aug 2017 07:44:41 +0000 Subject: [cmake] Remove i686 target that is duplicate to i386 Remove the explicit i686 target that is completely duplicate to the i386 target, with the latter being used more commonly. 1. The runtime built for i686 will be identical to the one built for i386. 2. Supporting both -i386 and -i686 suffixes causes unnecessary confusion on the clang end which has to expect either of them. 3. The checks are based on wrong assumption that __i686__ is defined for all newer x86 CPUs. In fact, it is only declared when -march=i686 is explicitly used. It is not available when a more specific (or newer) -march is used. Curious enough, if CFLAGS contain -march=i686, the runtime will be built both for i386 and i686. For any other value, only i386 variant will be built. Differential Revision: https://reviews.llvm.org/D26764 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311842 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 3 --- cmake/base-config-ix.cmake | 4 ---- cmake/builtin-config-ix.cmake | 3 ++- cmake/config-ix.cmake | 2 +- lib/asan/CMakeLists.txt | 4 ++-- lib/asan/scripts/asan_device_setup | 2 +- lib/builtins/CMakeLists.txt | 8 +------- lib/ubsan/CMakeLists.txt | 2 +- test/asan/CMakeLists.txt | 2 +- test/asan/lit.cfg | 7 +------ test/lit.common.cfg | 2 +- test/lsan/TestCases/Linux/use_tls_dynamic.cc | 2 +- test/sanitizer_common/lit.common.cfg | 2 +- test/scudo/random_shuffle.cpp | 2 +- 14 files changed, 14 insertions(+), 31 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 3b3a0c153..36df49fcc 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -163,7 +163,6 @@ macro(detect_target_arch) check_symbol_exists(__arm__ "" __ARM) check_symbol_exists(__aarch64__ "" __AARCH64) check_symbol_exists(__x86_64__ "" __X86_64) - check_symbol_exists(__i686__ "" __I686) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) @@ -176,8 +175,6 @@ macro(detect_target_arch) add_default_target_arch(aarch64) elseif(__X86_64) add_default_target_arch(x86_64) - elseif(__I686) - add_default_target_arch(i686) elseif(__I386) add_default_target_arch(i386) elseif(__MIPS64) # must be checked before __MIPS diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index f9904fbd1..55f322538 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -139,10 +139,6 @@ macro(test_targets) elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64") if(NOT MSVC) test_target_arch(x86_64 "" "-m64") - # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may - # target different variant than "$CMAKE_C_COMPILER -m32". This part should - # be gone after we resolve PR14109. - test_target_arch(i686 __i686__ "-m32") test_target_arch(i386 __i386__ "-m32") else() if (CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 20bc68476..540ec0792 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -25,7 +25,8 @@ int foo(int x, int y) { set(ARM64 aarch64) set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) -set(X86 i386 i686) +set(ARM32 arm armhf) +set(X86 i386) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 764488b83..4ba284e69 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -174,7 +174,7 @@ endmacro() set(ARM64 aarch64) set(ARM32 arm armhf) -set(X86 i386 i686) +set(X86 i386) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index c6005da6a..bdf92f838 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -169,7 +169,7 @@ else() PARENT_TARGET asan) foreach(arch ${ASAN_SUPPORTED_ARCH}) - if (UNIX AND NOT ${arch} MATCHES "i386|i686") + if (UNIX AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch} LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch} EXTRA asan.syms.extra) @@ -218,7 +218,7 @@ else() DEFS ${ASAN_DYNAMIC_DEFINITIONS} PARENT_TARGET asan) - if (UNIX AND NOT ${arch} MATCHES "i386|i686") + if (UNIX AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_symbols(clang_rt.asan_cxx ARCHS ${arch}) add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 5a4f7c47c..ac286d103 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -95,7 +95,7 @@ function get_device_arch { # OUT OUT64 local _ARCH= local _ARCH64= if [[ $_ABI == x86* ]]; then - _ARCH=i686 + _ARCH=i386 elif [[ $_ABI == armeabi* ]]; then _ARCH=arm elif [[ $_ABI == arm64-v8a* ]]; then diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 6b25c96ce..650e9f918 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -271,9 +271,6 @@ if (NOT MSVC) i386/chkstk.S i386/chkstk2.S) endif() - - set(i686_SOURCES - ${i386_SOURCES}) else () # MSVC # Use C versions of functions when building on MSVC # MSVC's assembler takes Intel syntax, not AT&T syntax. @@ -285,7 +282,6 @@ else () # MSVC ${GENERIC_SOURCES}) set(x86_64h_SOURCES ${x86_64_SOURCES}) set(i386_SOURCES ${GENERIC_SOURCES}) - set(i686_SOURCES ${i386_SOURCES}) endif () # if (NOT MSVC) set(arm_SOURCES @@ -493,9 +489,7 @@ else () # NOTE: some architectures (e.g. i386) have multiple names. Ensure that # we catch them all. set(_arch ${arch}) - if("${arch}" STREQUAL "i686") - set(_arch "i386|i686") - elseif("${arch}" STREQUAL "armv6m") + if("${arch}" STREQUAL "armv6m") set(_arch "arm|armv6m") elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$") set(_arch "arm") diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index caa77c2a7..457d9e505 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -178,7 +178,7 @@ else() if (UNIX) set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) - list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386) add_sanitizer_rt_symbols(clang_rt.ubsan_standalone ARCHS ${ARCHS_FOR_SYMBOLS} PARENT_TARGET ubsan diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 8bfc15b5c..19d9c88cf 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -18,7 +18,7 @@ if (SHADOW_MAPPING_UNRELIABLE) endif() macro(get_bits_for_arch arch bits) - if (${arch} MATCHES "i386|i686|arm|mips|mipsel") + if (${arch} MATCHES "i386|arm|mips|mipsel") set(${bits} 32) elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el|s390x") set(${bits} 64) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index e25dd297a..c7c5036b6 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -121,16 +121,11 @@ else: def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " -# Clang driver link 'x86' (i686) architecture to 'i386'. -target_arch = config.target_arch -if (target_arch == "i686"): - target_arch = "i386" - config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) ) config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) -config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % target_arch)) +config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch)) if config.asan_dynamic: config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) ) config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) ) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 6080edca4..4f23ab285 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -135,7 +135,7 @@ config.substitutions.append( ("%expect_crash ", config.expect_crash) ) target_arch = getattr(config, 'target_arch', None) if target_arch: config.available_features.add(target_arch + '-target-arch') - if target_arch in ['x86_64', 'i386', 'i686']: + if target_arch in ['x86_64', 'i386']: config.available_features.add('x86-target-arch') config.available_features.add(target_arch + '-' + config.host_os.lower()) diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index d60dec08f..f5df231ba 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: %env_lsan_opts="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux,arm +// UNSUPPORTED: i386-linux,arm #ifndef BUILD_DSO #include diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index da720a850..307a33ae7 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -26,7 +26,7 @@ config.available_features.add(config.tool_name) if config.target_arch not in ['arm', 'armhf', 'aarch64']: config.available_features.add('stable-runtime') -if config.host_os == 'Linux' and config.tool_name == "lsan" and (config.target_arch == 'i386' or config.target_arch == 'i686'): +if config.host_os == 'Linux' and config.tool_name == "lsan" and config.target_arch == 'i386': config.available_features.add("lsan-x86") if config.host_os == 'Darwin': diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 05a432615..c98d431e4 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux +// UNSUPPORTED: i386-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From cc44d7c1f1d3e45e338faf2ecc4fb43c58dda330 Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Sun, 27 Aug 2017 20:37:06 +0000 Subject: Revert r311842 - [cmake] Remove i686 target that is duplicate to i386 The required change in clang is being reverted because of the Android build bot failure. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311859 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 3 +++ cmake/base-config-ix.cmake | 4 ++++ cmake/builtin-config-ix.cmake | 3 +-- cmake/config-ix.cmake | 2 +- lib/asan/CMakeLists.txt | 4 ++-- lib/asan/scripts/asan_device_setup | 2 +- lib/builtins/CMakeLists.txt | 8 +++++++- lib/ubsan/CMakeLists.txt | 2 +- test/asan/CMakeLists.txt | 2 +- test/asan/lit.cfg | 7 ++++++- test/lit.common.cfg | 2 +- test/lsan/TestCases/Linux/use_tls_dynamic.cc | 2 +- test/sanitizer_common/lit.common.cfg | 2 +- test/scudo/random_shuffle.cpp | 2 +- 14 files changed, 31 insertions(+), 14 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 36df49fcc..3b3a0c153 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -163,6 +163,7 @@ macro(detect_target_arch) check_symbol_exists(__arm__ "" __ARM) check_symbol_exists(__aarch64__ "" __AARCH64) check_symbol_exists(__x86_64__ "" __X86_64) + check_symbol_exists(__i686__ "" __I686) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) @@ -175,6 +176,8 @@ macro(detect_target_arch) add_default_target_arch(aarch64) elseif(__X86_64) add_default_target_arch(x86_64) + elseif(__I686) + add_default_target_arch(i686) elseif(__I386) add_default_target_arch(i386) elseif(__MIPS64) # must be checked before __MIPS diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 55f322538..f9904fbd1 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -139,6 +139,10 @@ macro(test_targets) elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64") if(NOT MSVC) test_target_arch(x86_64 "" "-m64") + # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may + # target different variant than "$CMAKE_C_COMPILER -m32". This part should + # be gone after we resolve PR14109. + test_target_arch(i686 __i686__ "-m32") test_target_arch(i386 __i386__ "-m32") else() if (CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 540ec0792..20bc68476 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -25,8 +25,7 @@ int foo(int x, int y) { set(ARM64 aarch64) set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) -set(ARM32 arm armhf) -set(X86 i386) +set(X86 i386 i686) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 4ba284e69..764488b83 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -174,7 +174,7 @@ endmacro() set(ARM64 aarch64) set(ARM32 arm armhf) -set(X86 i386) +set(X86 i386 i686) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index bdf92f838..c6005da6a 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -169,7 +169,7 @@ else() PARENT_TARGET asan) foreach(arch ${ASAN_SUPPORTED_ARCH}) - if (UNIX AND NOT ${arch} STREQUAL "i386") + if (UNIX AND NOT ${arch} MATCHES "i386|i686") add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch} LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch} EXTRA asan.syms.extra) @@ -218,7 +218,7 @@ else() DEFS ${ASAN_DYNAMIC_DEFINITIONS} PARENT_TARGET asan) - if (UNIX AND NOT ${arch} STREQUAL "i386") + if (UNIX AND NOT ${arch} MATCHES "i386|i686") add_sanitizer_rt_symbols(clang_rt.asan_cxx ARCHS ${arch}) add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index ac286d103..5a4f7c47c 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -95,7 +95,7 @@ function get_device_arch { # OUT OUT64 local _ARCH= local _ARCH64= if [[ $_ABI == x86* ]]; then - _ARCH=i386 + _ARCH=i686 elif [[ $_ABI == armeabi* ]]; then _ARCH=arm elif [[ $_ABI == arm64-v8a* ]]; then diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 650e9f918..6b25c96ce 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -271,6 +271,9 @@ if (NOT MSVC) i386/chkstk.S i386/chkstk2.S) endif() + + set(i686_SOURCES + ${i386_SOURCES}) else () # MSVC # Use C versions of functions when building on MSVC # MSVC's assembler takes Intel syntax, not AT&T syntax. @@ -282,6 +285,7 @@ else () # MSVC ${GENERIC_SOURCES}) set(x86_64h_SOURCES ${x86_64_SOURCES}) set(i386_SOURCES ${GENERIC_SOURCES}) + set(i686_SOURCES ${i386_SOURCES}) endif () # if (NOT MSVC) set(arm_SOURCES @@ -489,7 +493,9 @@ else () # NOTE: some architectures (e.g. i386) have multiple names. Ensure that # we catch them all. set(_arch ${arch}) - if("${arch}" STREQUAL "armv6m") + if("${arch}" STREQUAL "i686") + set(_arch "i386|i686") + elseif("${arch}" STREQUAL "armv6m") set(_arch "arm|armv6m") elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$") set(_arch "arm") diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 457d9e505..caa77c2a7 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -178,7 +178,7 @@ else() if (UNIX) set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) - list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) add_sanitizer_rt_symbols(clang_rt.ubsan_standalone ARCHS ${ARCHS_FOR_SYMBOLS} PARENT_TARGET ubsan diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 19d9c88cf..8bfc15b5c 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -18,7 +18,7 @@ if (SHADOW_MAPPING_UNRELIABLE) endif() macro(get_bits_for_arch arch bits) - if (${arch} MATCHES "i386|arm|mips|mipsel") + if (${arch} MATCHES "i386|i686|arm|mips|mipsel") set(${bits} 32) elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el|s390x") set(${bits} 64) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index c7c5036b6..e25dd297a 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -121,11 +121,16 @@ else: def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " +# Clang driver link 'x86' (i686) architecture to 'i386'. +target_arch = config.target_arch +if (target_arch == "i686"): + target_arch = "i386" + config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) ) config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) -config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch)) +config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % target_arch)) if config.asan_dynamic: config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) ) config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) ) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 4f23ab285..6080edca4 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -135,7 +135,7 @@ config.substitutions.append( ("%expect_crash ", config.expect_crash) ) target_arch = getattr(config, 'target_arch', None) if target_arch: config.available_features.add(target_arch + '-target-arch') - if target_arch in ['x86_64', 'i386']: + if target_arch in ['x86_64', 'i386', 'i686']: config.available_features.add('x86-target-arch') config.available_features.add(target_arch + '-' + config.host_os.lower()) diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index f5df231ba..d60dec08f 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: %env_lsan_opts="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,arm +// UNSUPPORTED: i386-linux,i686-linux,arm #ifndef BUILD_DSO #include diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index 307a33ae7..da720a850 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -26,7 +26,7 @@ config.available_features.add(config.tool_name) if config.target_arch not in ['arm', 'armhf', 'aarch64']: config.available_features.add('stable-runtime') -if config.host_os == 'Linux' and config.tool_name == "lsan" and config.target_arch == 'i386': +if config.host_os == 'Linux' and config.tool_name == "lsan" and (config.target_arch == 'i386' or config.target_arch == 'i686'): config.available_features.add("lsan-x86") if config.host_os == 'Darwin': diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index c98d431e4..05a432615 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From fe253ee56618ac233dc0516daea8775b58f456d8 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 27 Aug 2017 23:20:09 +0000 Subject: [libFuzzer] Use custom allocators for STL containers in libFuzzer. Avoids ODR violations causing spurious ASAN warnings. Differential Revision: https://reviews.llvm.org/D37086 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311866 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 12 ++++++------ lib/fuzzer/FuzzerDefs.h | 21 +++++++++++++++++++-- lib/fuzzer/FuzzerDictionary.h | 2 +- lib/fuzzer/FuzzerDriver.cpp | 34 +++++++++++++++++----------------- lib/fuzzer/FuzzerIO.cpp | 4 ++-- lib/fuzzer/FuzzerIO.h | 4 ++-- lib/fuzzer/FuzzerIOPosix.cpp | 2 +- lib/fuzzer/FuzzerIOWindows.cpp | 2 +- lib/fuzzer/FuzzerInternal.h | 8 ++++---- lib/fuzzer/FuzzerLoop.cpp | 4 ++-- lib/fuzzer/FuzzerMerge.cpp | 30 +++++++++++++++--------------- lib/fuzzer/FuzzerMerge.h | 16 ++++++++-------- lib/fuzzer/FuzzerMutate.cpp | 4 ++-- lib/fuzzer/FuzzerMutate.h | 14 +++++++------- lib/fuzzer/FuzzerTracePC.cpp | 6 +++--- lib/fuzzer/FuzzerTracePC.h | 4 ++-- lib/fuzzer/FuzzerUtil.cpp | 2 +- lib/fuzzer/FuzzerUtil.h | 4 ++-- lib/fuzzer/tests/FuzzerUnittest.cpp | 32 ++++++++++++++++++-------------- 19 files changed, 113 insertions(+), 92 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index bae0aea78..2384d5082 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -35,7 +35,7 @@ struct InputInfo { size_t NumSuccessfullMutations = 0; bool MayDeleteFile = false; bool Reduced = false; - std::vector UniqFeatureSet; + Vector UniqFeatureSet; }; class InputCorpus { @@ -71,7 +71,7 @@ class InputCorpus { bool empty() const { return Inputs.empty(); } const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, - const std::vector &FeatureSet) { + const Vector &FeatureSet) { assert(!U.empty()); if (FeatureDebug) Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); @@ -100,7 +100,7 @@ class InputCorpus { } // Debug-only - void PrintFeatureSet(const std::vector &FeatureSet) { + void PrintFeatureSet(const Vector &FeatureSet) { if (!FeatureDebug) return; Printf("{"); for (uint32_t Feature: FeatureSet) @@ -256,11 +256,11 @@ private: } std::piecewise_constant_distribution CorpusDistribution; - std::vector Intervals; - std::vector Weights; + Vector Intervals; + Vector Weights; std::unordered_set Hashes; - std::vector Inputs; + Vector Inputs; size_t NumAddedFeatures = 0; size_t NumUpdatedFeatures = 0; diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index bbb44514a..7ea54a920 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include // Platform detection. #ifdef __linux__ @@ -102,8 +104,23 @@ struct ExternalFunctions; // Global interface to functions that may or may not be available. extern ExternalFunctions *EF; -typedef std::vector Unit; -typedef std::vector UnitVector; +// We are using a custom allocator to give a different symbol name to STL +// containers in order to avoid ODR violations. +template + class fuzzer_allocator: public std::allocator { + public: + template + struct rebind { typedef fuzzer_allocator other; }; + }; + +template +using Vector = std::vector>; + +template +using Set = std::set, fuzzer_allocator>; + +typedef Vector Unit; +typedef Vector UnitVector; typedef int (*UserCallback)(const uint8_t *Data, size_t Size); int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); diff --git a/lib/fuzzer/FuzzerDictionary.h b/lib/fuzzer/FuzzerDictionary.h index 84cee87b8..daf7d003e 100644 --- a/lib/fuzzer/FuzzerDictionary.h +++ b/lib/fuzzer/FuzzerDictionary.h @@ -120,7 +120,7 @@ private: bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // Parses the dictionary file, fills Units, returns true iff all lines // were parsed succesfully. -bool ParseDictionaryFile(const std::string &Text, std::vector *Units); +bool ParseDictionaryFile(const std::string &Text, Vector *Units); } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index d0d0f7dd0..1ed709237 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -74,7 +74,7 @@ static const FlagDescription FlagDescriptions [] { static const size_t kNumFlags = sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); -static std::vector *Inputs; +static Vector *Inputs; static std::string *ProgName; static void PrintHelp() { @@ -175,7 +175,7 @@ static bool ParseOneFlag(const char *Param) { } // We don't use any library to minimize dependencies. -static void ParseFlags(const std::vector &Args) { +static void ParseFlags(const Vector &Args) { for (size_t F = 0; F < kNumFlags; F++) { if (FlagDescriptions[F].IntFlag) *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; @@ -185,7 +185,7 @@ static void ParseFlags(const std::vector &Args) { if (FlagDescriptions[F].StrFlag) *FlagDescriptions[F].StrFlag = nullptr; } - Inputs = new std::vector; + Inputs = new Vector; for (size_t A = 1; A < Args.size(); A++) { if (ParseOneFlag(Args[A].c_str())) { if (Flags.ignore_remaining_args) @@ -225,7 +225,7 @@ static void WorkerThread(const std::string &Cmd, std::atomic *Counter, } } -std::string CloneArgsWithoutX(const std::vector &Args, +std::string CloneArgsWithoutX(const Vector &Args, const char *X1, const char *X2) { std::string Cmd; for (auto &S : Args) { @@ -236,12 +236,12 @@ std::string CloneArgsWithoutX(const std::vector &Args, return Cmd; } -static int RunInMultipleProcesses(const std::vector &Args, +static int RunInMultipleProcesses(const Vector &Args, unsigned NumWorkers, unsigned NumJobs) { std::atomic Counter(0); std::atomic HasErrors(false); std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); - std::vector V; + Vector V; std::thread Pulse(PulseThread); Pulse.detach(); for (unsigned i = 0; i < NumWorkers; i++) @@ -294,7 +294,7 @@ static std::string GetDedupTokenFromFile(const std::string &Path) { return S.substr(Beg, End - Beg); } -int CleanseCrashInput(const std::vector &Args, +int CleanseCrashInput(const Vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1 || !Flags.exact_artifact_path) { Printf("ERROR: -cleanse_crash should be given one input file and" @@ -322,7 +322,7 @@ int CleanseCrashInput(const std::vector &Args, auto U = FileToVector(CurrentFilePath); size_t Size = U.size(); - const std::vector ReplacementBytes = {' ', 0xff}; + const Vector ReplacementBytes = {' ', 0xff}; for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { bool Changed = false; for (size_t Idx = 0; Idx < Size; Idx++) { @@ -354,7 +354,7 @@ int CleanseCrashInput(const std::vector &Args, return 0; } -int MinimizeCrashInput(const std::vector &Args, +int MinimizeCrashInput(const Vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1) { Printf("ERROR: -minimize_crash should be given one input file\n"); @@ -456,17 +456,17 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } -int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, +int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, UnitVector& Corpus) { Printf("Started dictionary minimization (up to %d tests)\n", Dict.size() * Corpus.size() * 2); // Scores and usage count for each dictionary unit. - std::vector Scores(Dict.size()); - std::vector Usages(Dict.size()); + Vector Scores(Dict.size()); + Vector Usages(Dict.size()); - std::vector InitialFeatures; - std::vector ModifiedFeatures; + Vector InitialFeatures; + Vector ModifiedFeatures; for (auto &C : Corpus) { // Get coverage for the testcase without modifications. F->ExecuteCallback(C.data(), C.size()); @@ -477,7 +477,7 @@ int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, }); for (size_t i = 0; i < Dict.size(); ++i) { - auto Data = C; + Vector Data = C; auto StartPos = std::search(Data.begin(), Data.end(), Dict[i].begin(), Dict[i].end()); // Skip dictionary unit, if the testcase does not contain it. @@ -531,7 +531,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { EF = new ExternalFunctions(); if (EF->LLVMFuzzerInitialize) EF->LLVMFuzzerInitialize(argc, argv); - const std::vector Args(*argv, *argv + *argc); + const Vector Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); if (Argv0 != *ProgName) { @@ -593,7 +593,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.ArtifactPrefix = Flags.artifact_prefix; if (Flags.exact_artifact_path) Options.ExactArtifactPath = Flags.exact_artifact_path; - std::vector Dictionary; + Vector Dictionary; if (Flags.dict) if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) return 1; diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index 1a06d4420..b3adfacf3 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -68,10 +68,10 @@ void WriteToFile(const Unit &U, const std::string &Path) { fclose(Out); } -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, +void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, size_t MaxSize, bool ExitOnError) { long E = Epoch ? *Epoch : 0; - std::vector Files; + Vector Files; ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); size_t NumLoaded = 0; for (size_t i = 0; i < Files.size(); i++) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 3b66a52d1..8ed0e003d 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -27,7 +27,7 @@ void CopyFileToErr(const std::string &Path); void WriteToFile(const Unit &U, const std::string &Path); -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, +void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, size_t MaxSize, bool ExitOnError); // Returns "Dir/FileName" or equivalent for the current OS. @@ -55,7 +55,7 @@ void RawPrint(const char *Str); bool IsFile(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir); + Vector *V, bool TopDir); char GetSeparator(); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index c5ebdbac4..d642b3424 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -33,7 +33,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { + Vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp index 742520267..74853646b 100644 --- a/lib/fuzzer/FuzzerIOWindows.cpp +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -73,7 +73,7 @@ bool IsFile(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { + Vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 1d68c0190..567c6e6a2 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -69,9 +69,9 @@ public: InputInfo *II = nullptr); // Merge Corpora[1:] into Corpora[0]. - void Merge(const std::vector &Corpora); - void CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, + void Merge(const Vector &Corpora); + void CrashResistantMerge(const Vector &Args, + const Vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull); void CrashResistantMergeInternalStep(const std::string &ControlFilePath); @@ -139,7 +139,7 @@ private: size_t MaxMutationLen = 0; size_t TmpMaxMutationLen = 0; - std::vector UniqFeatureSetTmp; + Vector UniqFeatureSetTmp; // Need to know our own thread. static thread_local bool IsMyThread; diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d2d096af4..dd828917f 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -327,7 +327,7 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { void Fuzzer::CheckExitOnSrcPosOrItem() { if (!Options.ExitOnSrcPos.empty()) { - static auto *PCsSet = new std::set; + static auto *PCsSet = new Set; auto HandlePC = [&](uintptr_t PC) { if (!PCsSet->insert(PC).second) return; std::string Descr = DescribePC("%F %L", PC + 1); @@ -350,7 +350,7 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { void Fuzzer::RereadOutputCorpus(size_t MaxSize) { if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; - std::vector AdditionalCorpus; + Vector AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, &EpochOfLastReadOfOutputCorpus, MaxSize, /*ExitOnError*/ false); diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index 616c0999a..6f111a5e4 100644 --- a/lib/fuzzer/FuzzerMerge.cpp +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -74,7 +74,7 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { size_t ExpectedStartMarker = 0; const size_t kInvalidStartMarker = -1; size_t LastSeenStartMarker = kInvalidStartMarker; - std::vector TmpFeatures; + Vector TmpFeatures; while (std::getline(IS, Line, '\n')) { std::istringstream ISS1(Line); std::string Marker; @@ -122,11 +122,11 @@ size_t Merger::ApproximateMemoryConsumption() const { // Decides which files need to be merged (add thost to NewFiles). // Returns the number of new features added. -size_t Merger::Merge(const std::set &InitialFeatures, - std::vector *NewFiles) { +size_t Merger::Merge(const Set &InitialFeatures, + Vector *NewFiles) { NewFiles->clear(); assert(NumFilesInFirstCorpus <= Files.size()); - std::set AllFeatures(InitialFeatures); + Set AllFeatures(InitialFeatures); // What features are in the initial corpus? for (size_t i = 0; i < NumFilesInFirstCorpus; i++) { @@ -138,7 +138,7 @@ size_t Merger::Merge(const std::set &InitialFeatures, // Remove all features that we already know from all other inputs. for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { auto &Cur = Files[i].Features; - std::vector Tmp; + Vector Tmp; std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); Cur.swap(Tmp); @@ -178,16 +178,16 @@ void Merger::PrintSummary(std::ostream &OS) { } } -std::set Merger::AllFeatures() const { - std::set S; +Set Merger::AllFeatures() const { + Set S; for (auto &File : Files) S.insert(File.Features.begin(), File.Features.end()); return S; } -std::set Merger::ParseSummary(std::istream &IS) { +Set Merger::ParseSummary(std::istream &IS) { std::string Line, Tmp; - std::set Res; + Set Res; while (std::getline(IS, Line, '\n')) { size_t N; std::istringstream ISS1(Line); @@ -235,7 +235,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { TPC.ResetMaps(); ExecuteCallback(U.data(), U.size()); // Collect coverage. - std::set Features; + Set Features; TPC.CollectFeatures([&](size_t Feature) -> bool { Features.insert(Feature); return true; @@ -252,15 +252,15 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { } // Outer process. Does not call the target code and thus sohuld not fail. -void Fuzzer::CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, +void Fuzzer::CrashResistantMerge(const Vector &Args, + const Vector &Corpora, const char *CoverageSummaryInputPathOrNull, const char *CoverageSummaryOutputPathOrNull) { if (Corpora.size() <= 1) { Printf("Merge requires two or more corpus dirs\n"); return; } - std::vector AllFiles; + Vector AllFiles; ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); size_t NumFilesInFirstCorpus = AllFiles.size(); for (size_t i = 1; i < Corpora.size(); i++) @@ -318,8 +318,8 @@ void Fuzzer::CrashResistantMerge(const std::vector &Args, std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); M.PrintSummary(SummaryOut); } - std::vector NewFiles; - std::set InitialFeatures; + Vector NewFiles; + Set InitialFeatures; if (CoverageSummaryInputPathOrNull) { std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); InitialFeatures = M.ParseSummary(SummaryIn); diff --git a/lib/fuzzer/FuzzerMerge.h b/lib/fuzzer/FuzzerMerge.h index dd4c37b6e..e54885a1e 100644 --- a/lib/fuzzer/FuzzerMerge.h +++ b/lib/fuzzer/FuzzerMerge.h @@ -52,11 +52,11 @@ namespace fuzzer { struct MergeFileInfo { std::string Name; size_t Size = 0; - std::vector Features; + Vector Features; }; struct Merger { - std::vector Files; + Vector Files; size_t NumFilesInFirstCorpus = 0; size_t FirstNotProcessedFile = 0; std::string LastFailure; @@ -65,14 +65,14 @@ struct Merger { bool Parse(const std::string &Str, bool ParseCoverage); void ParseOrExit(std::istream &IS, bool ParseCoverage); void PrintSummary(std::ostream &OS); - std::set ParseSummary(std::istream &IS); - size_t Merge(const std::set &InitialFeatures, - std::vector *NewFiles); - size_t Merge(std::vector *NewFiles) { - return Merge(std::set{}, NewFiles); + Set ParseSummary(std::istream &IS); + size_t Merge(const Set &InitialFeatures, + Vector *NewFiles); + size_t Merge(Vector *NewFiles) { + return Merge(Set{}, NewFiles); } size_t ApproximateMemoryConsumption() const; - std::set AllFeatures() const; + Set AllFeatures() const; }; } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp index 5998ef9d3..9ee5299f1 100644 --- a/lib/fuzzer/FuzzerMutate.cpp +++ b/lib/fuzzer/FuzzerMutate.cpp @@ -466,7 +466,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { } void MutationDispatcher::PrintRecommendedDictionary() { - std::vector V; + Vector V; for (auto &DE : PersistentAutoDictionary) if (!ManualDictionary.ContainsWord(DE.GetW())) V.push_back(DE); @@ -506,7 +506,7 @@ size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, // Mutates Data in place, returns new size. size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators) { + Vector &Mutators) { assert(MaxSize > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h index 84b04c0db..4aa58af99 100644 --- a/lib/fuzzer/FuzzerMutate.h +++ b/lib/fuzzer/FuzzerMutate.h @@ -96,7 +96,7 @@ private: size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators); + Vector &Mutators); size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, size_t ToSize, size_t MaxToSize); @@ -128,21 +128,21 @@ private: // entries that led to successfull discoveries in the past mutations. Dictionary PersistentAutoDictionary; - std::vector CurrentMutatorSequence; - std::vector CurrentDictionaryEntrySequence; + Vector CurrentMutatorSequence; + Vector CurrentDictionaryEntrySequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; size_t CmpDictionaryEntriesDequeIdx = 0; const InputCorpus *Corpus = nullptr; - std::vector MutateInPlaceHere; + Vector MutateInPlaceHere; // CustomCrossOver needs its own buffer as a custom implementation may call // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. - std::vector CustomCrossOverInPlaceHere; + Vector CustomCrossOverInPlaceHere; - std::vector Mutators; - std::vector DefaultMutators; + Vector Mutators; + Vector DefaultMutators; }; } // namespace fuzzer diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 812a6190a..831316aa3 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -221,8 +221,8 @@ void TracePC::PrintCoverage() { Printf("COVERAGE:\n"); std::string LastFunctionName = ""; std::string LastFileStr = ""; - std::set UncoveredLines; - std::set CoveredLines; + Set UncoveredLines; + Set CoveredLines; auto FunctionEndCallback = [&](const std::string &CurrentFunc, const std::string &CurrentFile) { @@ -270,7 +270,7 @@ void TracePC::PrintCoverage() { void TracePC::DumpCoverage() { if (EF->__sanitizer_dump_coverage) { - std::vector PCsCopy(GetNumPCs()); + Vector PCsCopy(GetNumPCs()); for (size_t i = 0; i < GetNumPCs(); i++) PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 76aa0748f..9c23ef6b5 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -159,8 +159,8 @@ private: uint8_t *Counters() const; uintptr_t *PCs() const; - std::set ObservedPCs; - std::set ObservedFuncs; + Set ObservedPCs; + Set ObservedFuncs; ValueBitMap ValueProfileMap; uintptr_t InitialStack; diff --git a/lib/fuzzer/FuzzerUtil.cpp b/lib/fuzzer/FuzzerUtil.cpp index f5a777374..65f0e1747 100644 --- a/lib/fuzzer/FuzzerUtil.cpp +++ b/lib/fuzzer/FuzzerUtil.cpp @@ -124,7 +124,7 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { return true; } -bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { +bool ParseDictionaryFile(const std::string &Text, Vector *Units) { if (Text.empty()) { Printf("ParseDictionaryFile: file does not exist or is empty\n"); return false; diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h index 9c90040b0..6cebd7cd7 100644 --- a/lib/fuzzer/FuzzerUtil.h +++ b/lib/fuzzer/FuzzerUtil.h @@ -57,10 +57,10 @@ FILE *OpenProcessPipe(const char *Command, const char *Mode); const void *SearchMemory(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -std::string CloneArgsWithoutX(const std::vector &Args, +std::string CloneArgsWithoutX(const Vector &Args, const char *X1, const char *X2); -inline std::string CloneArgsWithoutX(const std::vector &Args, +inline std::string CloneArgsWithoutX(const Vector &Args, const char *X) { return CloneArgsWithoutX(Args, X, X); } diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index 858e61d75..f3e822636 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -72,7 +72,7 @@ TEST(Fuzzer, CrossOver) { { 0, 5, 6, 7, 1, 2 } }; for (size_t Len = 1; Len < 8; Len++) { - std::set FoundUnits, ExpectedUnitsWitThisLength; + Set FoundUnits, ExpectedUnitsWitThisLength; for (int Iter = 0; Iter < 3000; Iter++) { C.resize(Len); size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(), @@ -526,7 +526,7 @@ TEST(FuzzerDictionary, ParseOneDictionaryEntry) { } TEST(FuzzerDictionary, ParseDictionaryFile) { - std::vector Units; + Vector Units; EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); EXPECT_FALSE(ParseDictionaryFile("", &Units)); EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); @@ -538,11 +538,11 @@ TEST(FuzzerDictionary, ParseDictionaryFile) { EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); EXPECT_EQ(Units.size(), 0U); EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); - EXPECT_EQ(Units, std::vector({Unit({'a', 'a'})})); + EXPECT_EQ(Units, Vector({Unit({'a', 'a'})})); EXPECT_TRUE( ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); EXPECT_EQ(Units, - std::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); + Vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); } TEST(FuzzerUtil, Base64) { @@ -566,7 +566,7 @@ TEST(Corpus, Distribution) { for (size_t i = 0; i < N; i++) C->AddToCorpus(Unit{ static_cast(i) }, 1, false, {}); - std::vector Hist(N); + Vector Hist(N); for (size_t i = 0; i < N * TriesPerUnit; i++) { Hist[C->ChooseUnitIdxToMutate(Rand)]++; } @@ -596,21 +596,21 @@ TEST(Merge, Bad) { } } -void EQ(const std::vector &A, const std::vector &B) { +void EQ(const Vector &A, const Vector &B) { EXPECT_EQ(A, B); } -void EQ(const std::vector &A, const std::vector &B) { - std::set a(A.begin(), A.end()); - std::set b(B.begin(), B.end()); +void EQ(const Vector &A, const Vector &B) { + Set a(A.begin(), A.end()); + Set b(B.begin(), B.end()); EXPECT_EQ(a, b); } static void Merge(const std::string &Input, - const std::vector Result, + const Vector Result, size_t NumNewFeatures) { Merger M; - std::vector NewFiles; + Vector NewFiles; EXPECT_TRUE(M.Parse(Input, true)); std::stringstream SS; M.PrintSummary(SS); @@ -658,7 +658,7 @@ TEST(Merge, Good) { EQ(M.Files[1].Features, {4, 5, 6}); - std::vector NewFiles; + Vector NewFiles; EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" "STARTED 0 1000\nDONE 0 1 2 3\n" @@ -693,7 +693,11 @@ TEST(Merge, Good) { "", true)); EQ(M.Files[0].Features, {4, 5, 6}); EQ(M.Files[1].Features, {1, 3, 6}); - EXPECT_EQ(3U, M.Merge({1, 2, 3}, &NewFiles)); + Set InitialFeatures; + InitialFeatures.insert(1); + InitialFeatures.insert(2); + InitialFeatures.insert(3); + EXPECT_EQ(3U, M.Merge(InitialFeatures, &NewFiles)); EQ(NewFiles, {"B"}); } @@ -739,7 +743,7 @@ TEST(Fuzzer, ForEachNonZeroByte) { 0, 0, 0, 0, 0, 0, 0, 8, 9, 9, 9, 9, 9, 9, 9, 9, }; - typedef std::vector > Vec; + typedef Vector > Vec; Vec Res, Expected; auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) { Res.push_back({FirstFeature + Idx, V}); -- cgit v1.2.1 From 26676b9c57b4e21dc89f668c54e7eab5d31f9bb8 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 28 Aug 2017 00:45:12 +0000 Subject: [asan] Move __asan_handle_no_return to public header Heretofore asan_handle_no_return was used only by interceptors, i.e. code private to the ASan runtime. However, on systems without interceptors, code like libc++abi is built with -fsanitize=address itself and should call asan_handle_no_return directly from __cxa_throw so that no interceptor is required. Patch by Roland McGrath Differential Revision: https://reviews.llvm.org/D36811 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311869 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/asan_interface.h | 4 ++++ lib/asan/tests/asan_interface_test.cc | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h index 97ba0ceb0..e689a730e 100644 --- a/include/sanitizer/asan_interface.h +++ b/include/sanitizer/asan_interface.h @@ -144,6 +144,10 @@ extern "C" { void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, void **end); + // Performs cleanup before a [[noreturn]] function. Must be called + // before things like _exit and execl to avoid false positives on stack. + void __asan_handle_no_return(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc index 7d3e520d8..03351e02b 100644 --- a/lib/asan/tests/asan_interface_test.cc +++ b/lib/asan/tests/asan_interface_test.cc @@ -423,3 +423,11 @@ TEST(AddressSanitizerInterface, GetOwnershipStressTest) { free(pointers[i]); } +TEST(AddressSanitizerInterface, HandleNoReturnTest) { + char array[40]; + __asan_poison_memory_region(array, sizeof(array)); + BAD_ACCESS(array, 20); + __asan_handle_no_return(); + // It unpoisons the whole thread stack. + GOOD_ACCESS(array, 20); +} -- cgit v1.2.1 From 5824d872dfe59e2a65e2b6a8e4d69b2d06d6d001 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 28 Aug 2017 03:58:23 +0000 Subject: [XRay][compiler-rt] Return the pointer associated with the function instead of the sled Summary: XRay has erroneously been returning the address of the first sled in the instrumentation map for a function id instead of the (runtime-relocated) functison address. This causes confusion and issues for applications where: - The first sled in the function may not be an entry sled (due to re-ordering or some other reason). - The caller attempts to find a symbol associated with the pointer at runtime, because the sled may not be exactly where the function's known address is (in case of inlined functions or those that have an external definition for symbols). This fixes http://llvm.org/PR34340. Reviewers: eizan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37202 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311871 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_interface.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 694d34c01..7ad6a9b84 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -331,7 +331,7 @@ uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); if (FuncId <= 0 || static_cast(FuncId) > XRayInstrMap.Functions) return 0; - return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Address + return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Function // On PPC, function entries are always aligned to 16 bytes. The beginning of a // sled might be a local entry, which is always +8 based on the global entry. // Always return the global entry. -- cgit v1.2.1 From d74a5ec19dabe0cb290087d973d54291cfa68ad1 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 28 Aug 2017 15:20:02 +0000 Subject: [sanitizer] Re-introduce kUseSeparateSizeClassForBatch for the 32-bit Primary Summary: Currently `TransferBatch` are located within the same memory regions as "regular" chunks. This is not ideal for security: they make for an interesting target to overwrite, and are not protected by the frontend (namely, Scudo). To solve this, we re-introduce `kUseSeparateSizeClassForBatch` for the 32-bit Primary allowing for `TransferBatch` to end up in their own memory region. Currently only Scudo would use this new feature, the default behavior remains unchanged. The separate `kBatchClassID` was used for a brief period of time previously but removed when the 64-bit ended up using the "free array". Reviewers: alekseyshl, kcc, eugenis Reviewed By: alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37082 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311891 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 96 ++++++++++++---------- .../sanitizer_allocator_primary32.h | 15 ++-- .../sanitizer_allocator_size_class_map.h | 30 +++++-- .../tests/sanitizer_allocator_test.cc | 17 ++++ lib/scudo/scudo_allocator.h | 27 +++--- 5 files changed, 114 insertions(+), 71 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h index ec0742c20..1b3c2c0c1 100644 --- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -26,9 +26,6 @@ struct SizeClassAllocatorLocalCache template struct SizeClassAllocator64LocalCache { typedef SizeClassAllocator Allocator; - static const uptr kNumClasses = SizeClassAllocator::kNumClasses; - typedef typename Allocator::SizeClassMapT SizeClassMap; - typedef typename Allocator::CompactPtrT CompactPtrT; void Init(AllocatorGlobalStats *s) { stats_.Init(); @@ -76,14 +73,18 @@ struct SizeClassAllocator64LocalCache { } void Drain(SizeClassAllocator *allocator) { - for (uptr class_id = 0; class_id < kNumClasses; class_id++) { - PerClass *c = &per_class_[class_id]; + for (uptr i = 0; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; while (c->count > 0) - Drain(c, allocator, class_id, c->count); + Drain(c, allocator, i, c->count); } } - // private: + private: + typedef typename Allocator::SizeClassMapT SizeClassMap; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + typedef typename Allocator::CompactPtrT CompactPtrT; + struct PerClass { u32 count; u32 max_count; @@ -94,7 +95,7 @@ struct SizeClassAllocator64LocalCache { AllocatorStats stats_; void InitCache() { - if (per_class_[1].max_count) + if (LIKELY(per_class_[1].max_count)) return; for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; @@ -130,7 +131,6 @@ template struct SizeClassAllocator32LocalCache { typedef SizeClassAllocator Allocator; typedef typename Allocator::TransferBatch TransferBatch; - static const uptr kNumClasses = SizeClassAllocator::kNumClasses; void Init(AllocatorGlobalStats *s) { stats_.Init(); @@ -138,6 +138,21 @@ struct SizeClassAllocator32LocalCache { s->Register(&stats_); } + // Returns a TransferBatch suitable for class_id. + TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, + TransferBatch *b) { + if (uptr batch_class_id = per_class_[class_id].batch_class_id) + return (TransferBatch*)Allocate(allocator, batch_class_id); + return b; + } + + // Destroys TransferBatch b. + void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, + TransferBatch *b) { + if (uptr batch_class_id = per_class_[class_id].batch_class_id) + Deallocate(allocator, batch_class_id, b); + } + void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) { Drain(allocator); if (s) @@ -173,66 +188,57 @@ struct SizeClassAllocator32LocalCache { } void Drain(SizeClassAllocator *allocator) { - for (uptr class_id = 0; class_id < kNumClasses; class_id++) { - PerClass *c = &per_class_[class_id]; + for (uptr i = 0; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; while (c->count > 0) - Drain(allocator, class_id); + Drain(allocator, i); } } - // private: - typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap; + private: + typedef typename Allocator::SizeClassMapT SizeClassMap; + static const uptr kBatchClassID = SizeClassMap::kBatchClassID; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + // If kUseSeparateSizeClassForBatch is true, all TransferBatch objects are + // allocated from kBatchClassID size class (except for those that are needed + // for kBatchClassID itself). The goal is to have TransferBatches in a totally + // different region of RAM to improve security. + static const bool kUseSeparateSizeClassForBatch = + Allocator::kUseSeparateSizeClassForBatch; + struct PerClass { uptr count; uptr max_count; uptr class_size; - uptr class_id_for_transfer_batch; + uptr batch_class_id; void *batch[2 * TransferBatch::kMaxNumCached]; }; PerClass per_class_[kNumClasses]; AllocatorStats stats_; void InitCache() { - if (per_class_[1].max_count) + if (LIKELY(per_class_[1].max_count)) return; - // TransferBatch class is declared in SizeClassAllocator. - uptr class_id_for_transfer_batch = - SizeClassMap::ClassID(sizeof(TransferBatch)); + const uptr batch_class_id = SizeClassMap::ClassID(sizeof(TransferBatch)); for (uptr i = 0; i < kNumClasses; i++) { PerClass *c = &per_class_[i]; uptr max_cached = TransferBatch::MaxCached(i); c->max_count = 2 * max_cached; c->class_size = Allocator::ClassIdToSize(i); - // We transfer chunks between central and thread-local free lists in - // batches. For small size classes we allocate batches separately. For - // large size classes we may use one of the chunks to store the batch. - // sizeof(TransferBatch) must be a power of 2 for more efficient - // allocation. - c->class_id_for_transfer_batch = (c->class_size < + // Precompute the class id to use to store batches for the current class + // id. 0 means the class size is large enough to store a batch within one + // of the chunks. If using a separate size class, it will always be + // kBatchClassID, except for kBatchClassID itself. + if (kUseSeparateSizeClassForBatch) { + c->batch_class_id = (i == kBatchClassID) ? 0 : kBatchClassID; + } else { + c->batch_class_id = (c->class_size < TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ? - class_id_for_transfer_batch : 0; + batch_class_id : 0; + } } } - // Returns a TransferBatch suitable for class_id. - // For small size classes allocates the batch from the allocator. - // For large size classes simply returns b. - TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, - TransferBatch *b) { - if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch) - return (TransferBatch*)Allocate(allocator, batch_class_id); - return b; - } - - // Destroys TransferBatch b. - // For small size classes deallocates b to the allocator. - // Does notthing for large size classes. - void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, - TransferBatch *b) { - if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch) - Deallocate(allocator, batch_class_id, b); - } - NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) { InitCache(); PerClass *c = &per_class_[class_id]; diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index e85821543..8f8a71d67 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -41,6 +41,7 @@ template struct SizeClassAllocator32LocalCache; struct SizeClassAllocator32FlagMasks { // Bit masks. enum { kRandomShuffleChunks = 1, + kUseSeparateSizeClassForBatch = 2, }; }; @@ -55,8 +56,10 @@ class SizeClassAllocator32 { typedef typename Params::ByteMap ByteMap; typedef typename Params::MapUnmapCallback MapUnmapCallback; - static const bool kRandomShuffleChunks = - Params::kFlags & SizeClassAllocator32FlagMasks::kRandomShuffleChunks; + static const bool kRandomShuffleChunks = Params::kFlags & + SizeClassAllocator32FlagMasks::kRandomShuffleChunks; + static const bool kUseSeparateSizeClassForBatch = Params::kFlags & + SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch; struct TransferBatch { static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2; @@ -94,11 +97,11 @@ class SizeClassAllocator32 { static const uptr kBatchSize = sizeof(TransferBatch); COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0); - COMPILER_CHECK(sizeof(TransferBatch) == - SizeClassMap::kMaxNumCachedHint * sizeof(uptr)); + COMPILER_CHECK(kBatchSize == SizeClassMap::kMaxNumCachedHint * sizeof(uptr)); static uptr ClassIdToSize(uptr class_id) { - return SizeClassMap::Size(class_id); + return (class_id == SizeClassMap::kBatchClassID) ? + kBatchSize : SizeClassMap::Size(class_id); } typedef SizeClassAllocator32 ThisT; @@ -161,9 +164,9 @@ class SizeClassAllocator32 { NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, TransferBatch *b) { CHECK_LT(class_id, kNumClasses); + CHECK_GT(b->Count(), 0); SizeClassInfo *sci = GetSizeClassInfo(class_id); SpinMutexLock l(&sci->mutex); - CHECK_GT(b->Count(), 0); sci->free_list.push_front(b); } diff --git a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h index 7151a4636..2bd83b2eb 100644 --- a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h +++ b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h @@ -134,8 +134,9 @@ class SizeClassMap { static const uptr kMaxSize = 1UL << kMaxSizeLog; static const uptr kNumClasses = - kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1; + kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1 + 1; static const uptr kLargestClassID = kNumClasses - 2; + static const uptr kBatchClassID = kNumClasses - 1; COMPILER_CHECK(kNumClasses >= 16 && kNumClasses <= 256); static const uptr kNumClassesRounded = kNumClasses <= 32 ? 32 : @@ -143,6 +144,11 @@ class SizeClassMap { kNumClasses <= 128 ? 128 : 256; static uptr Size(uptr class_id) { + // Estimate the result for kBatchClassID because this class does not know + // the exact size of TransferBatch. It's OK since we are using the actual + // sizeof(TransferBatch) where it matters. + if (UNLIKELY(class_id == kBatchClassID)) + return kMaxNumCachedHint * sizeof(uptr); if (class_id <= kMidClass) return kMinSize * class_id; class_id -= kMidClass; @@ -151,9 +157,10 @@ class SizeClassMap { } static uptr ClassID(uptr size) { + if (UNLIKELY(size > kMaxSize)) + return 0; if (size <= kMidSize) return (size + kMinSize - 1) >> kMinSizeLog; - if (size > kMaxSize) return 0; uptr l = MostSignificantSetBitIndex(size); uptr hbits = (size >> (l - S)) & M; uptr lbits = size & ((1 << (l - S)) - 1); @@ -162,7 +169,13 @@ class SizeClassMap { } static uptr MaxCachedHint(uptr class_id) { - if (class_id == 0) return 0; + // Estimate the result for kBatchClassID because this class does not know + // the exact size of TransferBatch. We need to cache fewer batches than user + // chunks, so this number can be small. + if (UNLIKELY(class_id == kBatchClassID)) + return 16; + if (UNLIKELY(class_id == 0)) + return 0; uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id); return Max(1, Min(kMaxNumCachedHint, n)); } @@ -178,6 +191,8 @@ class SizeClassMap { uptr p = prev_s ? (d * 100 / prev_s) : 0; uptr l = s ? MostSignificantSetBitIndex(s) : 0; uptr cached = MaxCachedHint(i) * s; + if (i == kBatchClassID) + d = p = l = 0; Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd " "cached: %zd %zd; id %zd\n", i, Size(i), d, p, l, MaxCachedHint(i), cached, ClassID(s)); @@ -192,12 +207,13 @@ class SizeClassMap { // Printf("Validate: c%zd\n", c); uptr s = Size(c); CHECK_NE(s, 0U); + if (c == kBatchClassID) + continue; CHECK_EQ(ClassID(s), c); - if (c != kNumClasses - 1) + if (c < kLargestClassID) CHECK_EQ(ClassID(s + 1), c + 1); CHECK_EQ(ClassID(s - 1), c); - if (c) - CHECK_GT(Size(c), Size(c-1)); + CHECK_GT(Size(c), Size(c - 1)); } CHECK_EQ(ClassID(kMaxSize + 1), 0); @@ -207,7 +223,7 @@ class SizeClassMap { CHECK_LT(c, kNumClasses); CHECK_GE(Size(c), s); if (c > 0) - CHECK_LT(Size(c-1), s); + CHECK_LT(Size(c - 1), s); } } }; diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index 0def8ee0f..9ec967bee 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -240,6 +240,23 @@ TEST(SanitizerCommon, SizeClassAllocator32Compact) { TestSizeClassAllocator(); } +struct AP32SeparateBatches { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = kAddressSpaceSize; + static const uptr kMetadataSize = 16; + typedef DefaultSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = ::kRegionSizeLog; + typedef FlatByteMap ByteMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = + SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch; +}; +typedef SizeClassAllocator32 Allocator32SeparateBatches; + +TEST(SanitizerCommon, SizeClassAllocator32SeparateBatches) { + TestSizeClassAllocator(); +} + template void SizeClassAllocatorMetadataStress() { Allocator *a = new Allocator; diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 8ecc8cde3..a5f0ab004 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -23,10 +23,10 @@ namespace __scudo { enum AllocType : u8 { - FromMalloc = 0, // Memory block came from malloc, realloc, calloc, etc. - FromNew = 1, // Memory block came from operator new. - FromNewArray = 2, // Memory block came from operator new []. - FromMemalign = 3, // Memory block came from memalign, posix_memalign, etc. + FromMalloc = 0, // Memory block came from malloc, realloc, calloc, etc. + FromNew = 1, // Memory block came from operator new. + FromNewArray = 2, // Memory block came from operator new []. + FromMemalign = 3, // Memory block came from memalign, posix_memalign, etc. }; enum ChunkState : u8 { @@ -43,15 +43,15 @@ enum ChunkState : u8 { typedef u64 PackedHeader; struct UnpackedHeader { u64 Checksum : 16; - u64 SizeOrUnusedBytes : 19; // Size for Primary backed allocations, amount of - // unused bytes in the chunk for Secondary ones. + u64 SizeOrUnusedBytes : 19; // Size for Primary backed allocations, amount of + // unused bytes in the chunk for Secondary ones. u64 FromPrimary : 1; - u64 State : 2; // available, allocated, or quarantined - u64 AllocType : 2; // malloc, new, new[], or memalign - u64 Offset : 16; // Offset from the beginning of the backend - // allocation to the beginning of the chunk - // itself, in multiples of MinAlignment. See - // comment about its maximum value and in init(). + u64 State : 2; // available, allocated, or quarantined + u64 AllocType : 2; // malloc, new, new[], or memalign + u64 Offset : 16; // Offset from the beginning of the backend + // allocation to the beginning of the chunk + // itself, in multiples of MinAlignment. See + // comment about its maximum value and in init(). u64 Salt : 8; }; @@ -109,7 +109,8 @@ struct AP32 { typedef __scudo::ByteMap ByteMap; typedef NoOpMapUnmapCallback MapUnmapCallback; static const uptr kFlags = - SizeClassAllocator32FlagMasks::kRandomShuffleChunks; + SizeClassAllocator32FlagMasks::kRandomShuffleChunks | + SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch; }; typedef SizeClassAllocator32 PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 -- cgit v1.2.1 From 0c221230c701ff6c60cce8f6401148dba6dd9d95 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 28 Aug 2017 19:39:05 +0000 Subject: Proper dependency check for clang in compiler_rt. - Not having a dependency does not work in standalone build, as Clang does not exist. - if (TARGET clang) check is useless, as it is order-dependent, and Clang may not be registered yet. Differential Revision: https://reviews.llvm.org/D37228 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311911 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index 4c6568167..872f1a065 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -136,7 +136,7 @@ macro(clang_compiler_add_cxx_check) COMMAND bash -c "${CMD}" COMMENT "Checking that just-built clang can find C++ headers..." VERBATIM) - if (TARGET clang) + if (NOT COMPILER_RT_STANDALONE_BUILD) ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang) endif() endif() -- cgit v1.2.1 From ffb70a6cbe19bb3f97abf4562cf63dd565dea04d Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 28 Aug 2017 19:44:19 +0000 Subject: [libFuzzer] Fix libFuzzer flag propagation for standalone builds. Under the previous configurations, flags from SANITIZER_COMMON were not propagated for standalone builds. Differential Revision: https://reviews.llvm.org/D37225 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311912 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index f06f93881..4c5b73f98 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -30,11 +30,14 @@ CHECK_CXX_SOURCE_COMPILES(" } " HAS_THREAD_LOCAL) +set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS}) + if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage") - set(LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters) + list(APPEND LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters) endif() + if(NOT HAS_THREAD_LOCAL) - set(LIBFUZZER_CFLAGS "${LIBFUZZER_CFLAGS} -Dthread_local=__thread") + list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread) endif() if(APPLE) -- cgit v1.2.1 From 7ab1a1642c2e4921f593f14603efbfa1801a9af3 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 28 Aug 2017 20:10:30 +0000 Subject: [libFuzzer] Exclude a test failing on OS X. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311916 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/deep-recursion.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 23b7af1df..b99bad4c6 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,4 +1,5 @@ # Test that we can find a stack overflow +REQUIRES: linux RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 9d51100aa169fa8b8213146f5143d6c9394067a1 Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Mon, 28 Aug 2017 20:30:12 +0000 Subject: Reland r311842 - [cmake] Remove i686 target that is duplicate to i386 Remove the explicit i686 target that is completely duplicate to the i386 target, with the latter being used more commonly. 1. The runtime built for i686 will be identical to the one built for i386. 2. Supporting both -i386 and -i686 suffixes causes unnecessary confusion on the clang end which has to expect either of them. 3. The checks are based on wrong assumption that __i686__ is defined for all newer x86 CPUs. In fact, it is only declared when -march=i686 is explicitly used. It is not available when a more specific (or newer) -march is used. Curious enough, if CFLAGS contain -march=i686, the runtime will be built both for i386 and i686. For any other value, only i386 variant will be built. Differential Revision: https://reviews.llvm.org/D26764 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311924 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTUtils.cmake | 3 --- cmake/base-config-ix.cmake | 4 ---- cmake/builtin-config-ix.cmake | 3 ++- cmake/config-ix.cmake | 2 +- lib/asan/CMakeLists.txt | 4 ++-- lib/asan/scripts/asan_device_setup | 2 +- lib/builtins/CMakeLists.txt | 8 +------- lib/ubsan/CMakeLists.txt | 2 +- test/asan/CMakeLists.txt | 2 +- test/asan/lit.cfg | 7 +------ test/lit.common.cfg | 2 +- test/lsan/TestCases/Linux/use_tls_dynamic.cc | 2 +- test/sanitizer_common/lit.common.cfg | 2 +- test/scudo/random_shuffle.cpp | 2 +- 14 files changed, 14 insertions(+), 31 deletions(-) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 3b3a0c153..36df49fcc 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -163,7 +163,6 @@ macro(detect_target_arch) check_symbol_exists(__arm__ "" __ARM) check_symbol_exists(__aarch64__ "" __AARCH64) check_symbol_exists(__x86_64__ "" __X86_64) - check_symbol_exists(__i686__ "" __I686) check_symbol_exists(__i386__ "" __I386) check_symbol_exists(__mips__ "" __MIPS) check_symbol_exists(__mips64__ "" __MIPS64) @@ -176,8 +175,6 @@ macro(detect_target_arch) add_default_target_arch(aarch64) elseif(__X86_64) add_default_target_arch(x86_64) - elseif(__I686) - add_default_target_arch(i686) elseif(__I386) add_default_target_arch(i386) elseif(__MIPS64) # must be checked before __MIPS diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index f9904fbd1..55f322538 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -139,10 +139,6 @@ macro(test_targets) elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64") if(NOT MSVC) test_target_arch(x86_64 "" "-m64") - # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may - # target different variant than "$CMAKE_C_COMPILER -m32". This part should - # be gone after we resolve PR14109. - test_target_arch(i686 __i686__ "-m32") test_target_arch(i386 __i386__ "-m32") else() if (CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 20bc68476..540ec0792 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -25,7 +25,8 @@ int foo(int x, int y) { set(ARM64 aarch64) set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) -set(X86 i386 i686) +set(ARM32 arm armhf) +set(X86 i386) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 764488b83..4ba284e69 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -174,7 +174,7 @@ endmacro() set(ARM64 aarch64) set(ARM32 arm armhf) -set(X86 i386 i686) +set(X86 i386) set(X86_64 x86_64) set(MIPS32 mips mipsel) set(MIPS64 mips64 mips64el) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index c6005da6a..bdf92f838 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -169,7 +169,7 @@ else() PARENT_TARGET asan) foreach(arch ${ASAN_SUPPORTED_ARCH}) - if (UNIX AND NOT ${arch} MATCHES "i386|i686") + if (UNIX AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch} LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch} EXTRA asan.syms.extra) @@ -218,7 +218,7 @@ else() DEFS ${ASAN_DYNAMIC_DEFINITIONS} PARENT_TARGET asan) - if (UNIX AND NOT ${arch} MATCHES "i386|i686") + if (UNIX AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_symbols(clang_rt.asan_cxx ARCHS ${arch}) add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 5a4f7c47c..ac286d103 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -95,7 +95,7 @@ function get_device_arch { # OUT OUT64 local _ARCH= local _ARCH64= if [[ $_ABI == x86* ]]; then - _ARCH=i686 + _ARCH=i386 elif [[ $_ABI == armeabi* ]]; then _ARCH=arm elif [[ $_ABI == arm64-v8a* ]]; then diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 6b25c96ce..650e9f918 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -271,9 +271,6 @@ if (NOT MSVC) i386/chkstk.S i386/chkstk2.S) endif() - - set(i686_SOURCES - ${i386_SOURCES}) else () # MSVC # Use C versions of functions when building on MSVC # MSVC's assembler takes Intel syntax, not AT&T syntax. @@ -285,7 +282,6 @@ else () # MSVC ${GENERIC_SOURCES}) set(x86_64h_SOURCES ${x86_64_SOURCES}) set(i386_SOURCES ${GENERIC_SOURCES}) - set(i686_SOURCES ${i386_SOURCES}) endif () # if (NOT MSVC) set(arm_SOURCES @@ -493,9 +489,7 @@ else () # NOTE: some architectures (e.g. i386) have multiple names. Ensure that # we catch them all. set(_arch ${arch}) - if("${arch}" STREQUAL "i686") - set(_arch "i386|i686") - elseif("${arch}" STREQUAL "armv6m") + if("${arch}" STREQUAL "armv6m") set(_arch "arm|armv6m") elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$") set(_arch "arm") diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index caa77c2a7..457d9e505 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -178,7 +178,7 @@ else() if (UNIX) set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) - list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386) add_sanitizer_rt_symbols(clang_rt.ubsan_standalone ARCHS ${ARCHS_FOR_SYMBOLS} PARENT_TARGET ubsan diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 8bfc15b5c..19d9c88cf 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -18,7 +18,7 @@ if (SHADOW_MAPPING_UNRELIABLE) endif() macro(get_bits_for_arch arch bits) - if (${arch} MATCHES "i386|i686|arm|mips|mipsel") + if (${arch} MATCHES "i386|arm|mips|mipsel") set(${bits} 32) elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el|s390x") set(${bits} 64) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index e25dd297a..c7c5036b6 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -121,16 +121,11 @@ else: def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " -# Clang driver link 'x86' (i686) architecture to 'i386'. -target_arch = config.target_arch -if (target_arch == "i686"): - target_arch = "i386" - config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) ) config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) -config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % target_arch)) +config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch)) if config.asan_dynamic: config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) ) config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) ) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 6080edca4..4f23ab285 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -135,7 +135,7 @@ config.substitutions.append( ("%expect_crash ", config.expect_crash) ) target_arch = getattr(config, 'target_arch', None) if target_arch: config.available_features.add(target_arch + '-target-arch') - if target_arch in ['x86_64', 'i386', 'i686']: + if target_arch in ['x86_64', 'i386']: config.available_features.add('x86-target-arch') config.available_features.add(target_arch + '-' + config.host_os.lower()) diff --git a/test/lsan/TestCases/Linux/use_tls_dynamic.cc b/test/lsan/TestCases/Linux/use_tls_dynamic.cc index d60dec08f..f5df231ba 100644 --- a/test/lsan/TestCases/Linux/use_tls_dynamic.cc +++ b/test/lsan/TestCases/Linux/use_tls_dynamic.cc @@ -5,7 +5,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s // RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1 // RUN: %env_lsan_opts="" %run %t 2>&1 -// UNSUPPORTED: i386-linux,i686-linux,arm +// UNSUPPORTED: i386-linux,arm #ifndef BUILD_DSO #include diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index da720a850..307a33ae7 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -26,7 +26,7 @@ config.available_features.add(config.tool_name) if config.target_arch not in ['arm', 'armhf', 'aarch64']: config.available_features.add('stable-runtime') -if config.host_os == 'Linux' and config.tool_name == "lsan" and (config.target_arch == 'i386' or config.target_arch == 'i686'): +if config.host_os == 'Linux' and config.tool_name == "lsan" and config.target_arch == 'i386': config.available_features.add("lsan-x86") if config.host_os == 'Darwin': diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 05a432615..c98d431e4 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,7 +7,7 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux +// UNSUPPORTED: i386-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From 45ead6c7c9164063fcf7f45f94f932c5d935b5e0 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 28 Aug 2017 21:03:23 +0000 Subject: Add NetBSD specific version of sanitizer_platform_limits_posix Summary: NetBSD is an Open-Source POSIX-like BSD Operating System. Part of the code inspired by the original work on libsanitizer in GCC 5.4 by Christos Zoulas. Sponsored by Reviewers: joerg, kcc, vitalybuka, filcab, fjricci Reviewed By: kcc Subscribers: llvm-commits, kubamracek, mgorny, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37193 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311933 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 2 + lib/sanitizer_common/sanitizer_linux.h | 3 +- .../sanitizer_platform_interceptors.h | 1 + .../sanitizer_platform_limits_netbsd.cc | 359 +++++++++++++ .../sanitizer_platform_limits_netbsd.h | 568 +++++++++++++++++++++ .../sanitizer_platform_limits_posix.h | 4 + lib/sanitizer_common/sanitizer_posix.h | 1 + lib/sanitizer_common/sanitizer_posix_libcdep.cc | 2 + 8 files changed, 939 insertions(+), 1 deletion(-) create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_netbsd.h diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index eb053929a..3b77adc75 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -18,6 +18,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_mac.cc sanitizer_persistent_allocator.cc sanitizer_platform_limits_linux.cc + sanitizer_platform_limits_netbsd.cc sanitizer_platform_limits_posix.cc sanitizer_posix.cc sanitizer_printf.cc @@ -118,6 +119,7 @@ set(SANITIZER_HEADERS sanitizer_placement_new.h sanitizer_platform.h sanitizer_platform_interceptors.h + sanitizer_platform_limits_netbsd.h sanitizer_platform_limits_posix.h sanitizer_posix.h sanitizer_procmaps.h diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index 2d15525ee..cbe2f17f4 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -17,8 +17,9 @@ #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" -#include "sanitizer_posix.h" +#include "sanitizer_platform_limits_netbsd.h" #include "sanitizer_platform_limits_posix.h" +#include "sanitizer_posix.h" struct link_map; // Opaque type returned by dlopen(). diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 276b5c490..5d6ea6a66 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -33,6 +33,7 @@ #endif #if SI_POSIX +# include "sanitizer_platform_limits_netbsd.h" # include "sanitizer_platform_limits_posix.h" #endif diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc new file mode 100644 index 000000000..3be1d371f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -0,0 +1,359 @@ +//===-- sanitizer_platform_limits_netbsd.cc -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_netbsd.h" + +namespace __sanitizer { +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sigevent_sz = sizeof(struct sigevent); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz = sizeof(ucontext_t); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timex_sz = sizeof(struct timex); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); + +uptr sig_ign = (uptr)SIG_IGN; +uptr sig_dfl = (uptr)SIG_DFL; +uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +// ioctl arguments +unsigned struct_ifreq_sz = sizeof(struct ifreq); +unsigned struct_termios_sz = sizeof(struct termios); +unsigned struct_winsize_sz = sizeof(struct winsize); +unsigned struct_mtget_sz = sizeof(struct mtget); +unsigned struct_mtop_sz = sizeof(struct mtop); +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, _key); +CHECK_SIZE_AND_OFFSET(ipc_perm, _seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#endif // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h new file mode 100644 index 000000000..fe12cd2a5 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -0,0 +1,568 @@ +//===-- sanitizer_platform_limits_netbsd.h --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_NETBSD_H +#define SANITIZER_PLATFORM_LIMITS_NETBSD_H + +#if SANITIZER_NETBSD + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ + ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) + +#if defined(__x86_64__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 608) +#elif defined(__i386__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 324) +#endif + +namespace __sanitizer { +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +extern unsigned ucontext_t_sz; + +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { + u64 aio_offset; + uptr aio_buf; + long aio_nbytes; + u32 aio_fildes; + u32 aio_lio_opcode; + long aio_reqprio; +#if SANITIZER_WORDSIZE == 64 + u8 aio_sigevent[32]; +#else + u8 aio_sigevent[20]; +#endif + u32 _state; + u32 _errno; + long _retval; +}; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; +}; + +struct __sanitizer_sem_t { + uptr data[5]; +}; + +struct __sanitizer_ipc_perm { + u32 uid; + u32 gid; + u32 cuid; + u32 cgid; + u32 mode; + unsigned short _seq; + long _key; +}; + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; + u32 shm_lpid; + u32 shm_cpid; + unsigned int shm_nattch; + u64 shm_atime; + u64 shm_dtime; + u64 shm_ctime; + void *_shm_internal; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; + unsigned int ifa_addrflags; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +typedef long long __sanitizer_time_t; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { + u64 d_fileno; + u16 d_reclen; + // more fields that we don't care about +}; + +typedef int __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; + +typedef u32 __sanitizer___kernel_uid_t; +typedef u32 __sanitizer___kernel_gid_t; +typedef u64 __sanitizer___kernel_off_t; +typedef struct { + u32 fds_bits[8]; +} __sanitizer___kernel_fd_set; + +typedef struct { + unsigned int pta_magic; + int pta_flags; + void *pta_private; +} __sanitizer_pthread_attr_t; + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +struct __sanitizer_sigaction { + union { + void (*handler)(int sig); + void (*sigaction)(int sig, void *siginfo, void *uctx); + }; + __sanitizer_sigset_t sa_mask; + int sa_flags; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, void *info, void *ctx); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; + +extern uptr sig_ign; +extern uptr sig_dfl; +extern uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + uptr gl_matchc; + uptr gl_offs; + int gl_flags; + char **gl_pathv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; + +extern unsigned path_max; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char *we_strings; + uptr we_nbytes; +}; + +typedef void __sanitizer_FILE; +#define SANITIZER_HAS_STRUCT_FILE 0 + +extern int shmctl_ipc_stat; + +// This simplifies generic code +#define struct_shminfo_sz -1 +#define struct_shm_info_sz -1 +#define shmctl_shm_stat -1 +#define shmctl_ipc_info -1 +#define shmctl_shm_info -1 + +extern unsigned struct_utmp_sz; +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; + +#define IOC_NRBITS 8 +#define IOC_TYPEBITS 8 +#define IOC_SIZEBITS 14 +#define IOC_DIRBITS 2 +#define IOC_NONE 0U +#define IOC_WRITE 1U +#define IOC_READ 2U +#define IOC_NRMASK ((1 << IOC_NRBITS) - 1) +#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) +#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) +#undef IOC_DIRMASK +#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) +#define IOC_NRSHIFT 0 +#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) +#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) +#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) +#define EVIOC_EV_MAX 0x1f +#define EVIOC_ABS_MAX 0x3f + +#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) +#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) +#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) +#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) + +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +extern unsigned struct_arpreq_sz; + +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; +} // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +#endif // SANITIZER_NETBSD + +#endif diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 63dcd2a6d..45b9d8e24 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -15,6 +15,8 @@ #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC + #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" @@ -1485,4 +1487,6 @@ struct __sanitizer_cookie_io_functions_t { COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC + #endif diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index e7d37cbf0..0c7445fe5 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -16,6 +16,7 @@ // ----------- ATTENTION ------------- // This header should NOT include any other headers from sanitizer runtime. #include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_netbsd.h" #include "sanitizer_platform_limits_posix.h" #if !SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index e113fb109..13062f000 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -18,7 +18,9 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_platform_limits_netbsd.h" #include "sanitizer_platform_limits_posix.h" + #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" -- cgit v1.2.1 From 1cca2c591777ea1905f4a38165fafd5d6cd1057c Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Mon, 28 Aug 2017 21:41:04 +0000 Subject: Add NetBSD ASAN shadow mapping for x86-64 Summary: The maximal virtual address on NetBSD/amd64 is 0x7f7ffffff000. Define shadow offset 0x400000000000 (1ULL << 46). Sponsored by Reviewers: joerg, vitalybuka, filcab, fjricci, kcc, eugenis, pcc Reviewed By: kcc Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36587 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311937 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_mapping.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index 408b3427a..fcd95114e 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -115,6 +115,13 @@ // || `[0x40000000, 0x47ffffff]` || LowShadow || // || `[0x00000000, 0x3fffffff]` || LowMem || // +// Shadow mapping on NetBSD/x86-64 with SHADOW_OFFSET == 0x400000000000: +// || `[0x4feffffffe01, 0x7f7ffffff000]` || HighMem || +// || `[0x49fdffffffc0, 0x4feffffffe00]` || HighShadow || +// || `[0x480000000000, 0x49fdffffffbf]` || ShadowGap || +// || `[0x400000000000, 0x47ffffffffff]` || LowShadow || +// || `[0x000000000000, 0x3fffffffffff]` || LowMem || +// // Default Windows/i386 mapping: // (the exact location of HighShadow/HighMem may vary depending // on WoW64, /LARGEADDRESSAWARE, etc). @@ -140,6 +147,7 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 +static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #define SHADOW_SCALE kDefaultShadowScale @@ -179,6 +187,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET kSystemZ_ShadowOffset64 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset64 +# elif SANITIZER_NETBSD +# define SHADOW_OFFSET kNetBSD_ShadowOffset64 # elif SANITIZER_MAC # define SHADOW_OFFSET kDefaultShadowOffset64 # elif defined(__mips64) -- cgit v1.2.1 From ebae6acb2bfef45b621788fba5e98a384a2477d6 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 28 Aug 2017 22:52:22 +0000 Subject: [libFuzzer] allow -print_funcs=N: N is the max number of new covered function printed git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311945 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerFlags.def | 3 ++- lib/fuzzer/FuzzerOptions.h | 2 +- lib/fuzzer/FuzzerTracePC.cpp | 10 ++++++++-- lib/fuzzer/FuzzerTracePC.h | 4 ++-- test/fuzzer/print-func.test | 6 +++--- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index df52377bf..790b5783d 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -91,7 +91,8 @@ FUZZER_FLAG_STRING(exact_artifact_path, "and will not use checksum in the file name. Do not " "use the same path for several parallel processes.") FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") -FUZZER_FLAG_INT(print_funcs, 1, "If 1, print out newly covered functions.") +FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of " + "newly covered functions.") FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") FUZZER_FLAG_INT(print_corpus_stats, 0, "If 1, print statistics on corpus elements at exit.") diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index d38724209..bfac3b685 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -47,7 +47,7 @@ struct FuzzingOptions { bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; bool PrintNewCovPcs = false; - bool PrintNewCovFuncs = false; + int PrintNewCovFuncs = 0; bool PrintFinalStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 831316aa3..78f0d4171 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -143,6 +143,7 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { } void TracePC::UpdateObservedPCs() { + Vector CoveredFuncs; auto ObservePC = [&](uintptr_t PC) { if (ObservedPCs.insert(PC).second && DoPrintNewPCs) PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); @@ -150,8 +151,8 @@ void TracePC::UpdateObservedPCs() { auto Observe = [&](const PCTableEntry &TE) { if (TE.PCFlags & 1) - if (ObservedFuncs.insert(TE.PC).second && DoPrintNewFuncs) - PrintPC("\tNEW_FUNC: %p %F %L\n", "\tNEW_PC: %p\n", TE.PC + 1); + if (ObservedFuncs.insert(TE.PC).second && NumPrintNewFuncs) + CoveredFuncs.push_back(TE.PC); ObservePC(TE.PC); }; @@ -186,6 +187,11 @@ void TracePC::UpdateObservedPCs() { if (P[Idx]) ObservePC((uintptr_t)Idx); } + + for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) { + Printf("\tNEW_FUNC[%zd/%zd]: ", i, CoveredFuncs.size()); + PrintPC("%p %F %L\n", "%p\n", CoveredFuncs[i] + 1); + } } inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 9c23ef6b5..54172608d 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -82,7 +82,7 @@ class TracePC { void SetUseCounters(bool UC) { UseCounters = UC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } - void SetPrintNewFuncs(bool P) { DoPrintNewFuncs = P; } + void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; } void UpdateObservedPCs(); template void CollectFeatures(Callback CB) const; @@ -134,7 +134,7 @@ private: bool UseCounters = false; bool UseValueProfile = false; bool DoPrintNewPCs = false; - bool DoPrintNewFuncs = false; + size_t NumPrintNewFuncs = 0; struct Module { uint32_t *Start, *Stop; diff --git a/test/fuzzer/print-func.test b/test/fuzzer/print-func.test index 12d52cb0b..930e9992a 100644 --- a/test/fuzzer/print-func.test +++ b/test/fuzzer/print-func.test @@ -1,9 +1,9 @@ RUN: %cpp_compiler %S/PrintFuncTest.cpp -o %t RUN: %t -seed=1 -runs=100000 2>&1 | FileCheck %s RUN: %t -seed=1 -runs=100000 -print_funcs=0 2>&1 | FileCheck %s --check-prefix=NO -CHECK: NEW_FUNC: {{.*}} FunctionA -CHECK: NEW_FUNC: {{.*}} FunctionB -CHECK: NEW_FUNC: {{.*}} FunctionC +CHECK: NEW_FUNC{{.*}} FunctionA +CHECK: NEW_FUNC{{.*}} FunctionB +CHECK: NEW_FUNC{{.*}} FunctionC CHECK: BINGO NO-NOT: NEW_FUNC -- cgit v1.2.1 From 886bbfa61b2327865e1ccd9916554de6e026bc5d Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Tue, 29 Aug 2017 01:03:13 +0000 Subject: Shorten filenames of tests (-with-calls to -calls) Summary: The NetBSD's 8(beta) versions of kernel functions to retrieve program name (vnode to path translator) and process memory map have internal limit of processing filenames with maximum of 31 characters. Filenames like Asan-x86_64-with-calls-Noinst-Test break this limit and affect tests. Rename "-with-calls" to "-calls". This changes fixes all issues for the Address Sanitizer test target (check-asan) on the current NetBSD support caused by long filenames. Sponsored by Reviewers: joerg, vitalybuka, filcab, fjricci, kcc Reviewed By: vitalybuka Subscribers: kubamracek, mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37149 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311966 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 983cf9f90..f8b9f4584 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -265,7 +265,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) FOLDER "Compiler-RT Runtime tests") add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-inline") - add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-with-calls" + add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-calls" CFLAGS -mllvm -asan-instrumentation-with-call-threshold=0) endforeach() endif() -- cgit v1.2.1 From 895df3ed0da58642a4b690506e1c250d0bde2836 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 29 Aug 2017 02:05:01 +0000 Subject: [libFuzzer] refactoring: move reading the seed corpus closer to where it's consumed; NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311972 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerDriver.cpp | 38 ++++++++++++-------------------------- lib/fuzzer/FuzzerInternal.h | 3 ++- lib/fuzzer/FuzzerLoop.cpp | 31 +++++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 1ed709237..804f426e9 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -558,8 +558,6 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { if (Flags.workers > 0 && Flags.jobs > 0) return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); - const size_t kMaxSaneLen = 1 << 20; - const size_t kMinDefaultLen = 4096; FuzzingOptions Options; Options.Verbosity = Flags.verbosity; Options.MaxLen = Flags.max_len; @@ -702,8 +700,10 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { } if (Flags.merge) { + const size_t kDefaultMaxMergeLen = 1 << 20; if (Options.MaxLen == 0) - F->SetMaxInputLen(kMaxSaneLen); + F->SetMaxInputLen(kDefaultMaxMergeLen); + if (Flags.merge_control_file) F->CrashResistantMergeInternalStep(Flags.merge_control_file); else @@ -713,16 +713,16 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); } - size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; - - UnitVector InitialCorpus; - for (auto &Inp : *Inputs) { - Printf("Loading corpus dir: %s\n", Inp.c_str()); - ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, - TemporaryMaxLen, /*ExitOnError=*/false); - } if (Flags.analyze_dict) { + size_t MaxLen = INT_MAX; // Large max length. + UnitVector InitialCorpus; + for (auto &Inp : *Inputs) { + Printf("Loading corpus dir: %s\n", Inp.c_str()); + ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, + MaxLen, /*ExitOnError=*/false); + } + if (Dictionary.empty() || Inputs->empty()) { Printf("ERROR: can't analyze dict without dict and corpus provided\n"); return 1; @@ -735,21 +735,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); } - if (Options.MaxLen == 0) { - size_t MaxLen = 0; - for (auto &U : InitialCorpus) - MaxLen = std::max(U.size(), MaxLen); - F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); - } - - if (InitialCorpus.empty()) { - InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. - if (Options.Verbosity) - Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); - } - F->ShuffleAndMinimize(&InitialCorpus); - InitialCorpus.clear(); // Don't need this memory any more. - F->Loop(); + F->Loop(*Inputs); if (Flags.verbosity) Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 567c6e6a2..70136a30b 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -35,7 +35,8 @@ public: Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, FuzzingOptions Options); ~Fuzzer(); - void Loop(); + void Loop(const Vector &CorpusDirs); + void ReadAndExecuteSeedCorpora(const Vector &CorpusDirs); void MinimizeCrashLoop(const Unit &U); void ShuffleAndMinimize(UnitVector *V); void RereadOutputCorpus(size_t MaxSize); diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index dd828917f..84ea2d6e8 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -380,7 +380,8 @@ void Fuzzer::ShuffleCorpus(UnitVector *V) { } void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { - Printf("#0\tREAD units: %zd\n", InitialCorpus->size()); + Printf("#0\tREAD units: %zd; rss: %zdMb\n", InitialCorpus->size(), + GetPeakRSSMb()); if (Options.ShuffleAtStartUp) ShuffleCorpus(InitialCorpus); @@ -624,7 +625,33 @@ void Fuzzer::MutateAndTestOne() { } } -void Fuzzer::Loop() { +void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { + const size_t kMaxSaneLen = 1 << 20; + const size_t kMinDefaultLen = 4096; + size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; + UnitVector InitialCorpus; + for (auto &Inp : CorpusDirs) { + Printf("Loading corpus dir: %s\n", Inp.c_str()); + ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, + TemporaryMaxLen, /*ExitOnError=*/false); + } + if (Options.MaxLen == 0) { + size_t MaxLen = 0; + for (auto &U : InitialCorpus) + MaxLen = std::max(U.size(), MaxLen); + SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); + } + + if (InitialCorpus.empty()) { + InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. + if (Options.Verbosity) + Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); + } + ShuffleAndMinimize(&InitialCorpus); +} + +void Fuzzer::Loop(const Vector &CorpusDirs) { + ReadAndExecuteSeedCorpora(CorpusDirs); TPC.SetPrintNewPCs(Options.PrintNewCovPcs); TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs); system_clock::time_point LastCorpusReload = system_clock::now(); -- cgit v1.2.1 From fedf302bebe6d9e3f819d5a2492b45953ec10e90 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 29 Aug 2017 12:21:45 +0000 Subject: [XRay][compiler-rt][NFC] Refactor global TLS variables behind an accessor function. Summary: This change hides all the initialization of thread_local variables used by the XRay FDR mode implementation behind a function call. This makes initialization of thread-local data to be done lazily, instead of eagerly when they're done as globals. It also gives us an isolation mechanism if/when we want to change the TLS implementation from using the C++ thread_local keyword, for something more ad-hoc (potentialy using pthread directly) on some platforms or set-ups where we cannot use the C++ thread_local variables. Reviewers: kpw, eizan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37248 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@311997 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 11 +- lib/xray/xray_fdr_logging_impl.h | 230 ++++++++++++++++++++++----------------- 2 files changed, 135 insertions(+), 106 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 21a09bf12..dee0e23ee 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -223,7 +223,8 @@ void fdrLoggingHandleCustomEvent(void *Event, (void)Once; } int32_t ReducedEventSize = static_cast(EventSize); - if (!isLogInitializedAndReady(*LocalBQ, TSC, CPU, clock_gettime)) + auto &TLD = getThreadLocalData(); + if (!isLogInitializedAndReady(TLD.LocalBQ, TSC, CPU, clock_gettime)) return; // Here we need to prepare the log to handle: @@ -231,7 +232,7 @@ void fdrLoggingHandleCustomEvent(void *Event, // - The additional data we're going to write. Currently, that's the size of // the event we're going to dump into the log as free-form bytes. if (!prepareBuffer(clock_gettime, MetadataRecSize + EventSize)) { - LocalBQ = nullptr; + TLD.LocalBQ = nullptr; return; } @@ -246,9 +247,9 @@ void fdrLoggingHandleCustomEvent(void *Event, constexpr auto TSCSize = sizeof(std::get<0>(TSC_CPU)); std::memcpy(&CustomEvent.Data, &ReducedEventSize, sizeof(int32_t)); std::memcpy(&CustomEvent.Data[sizeof(int32_t)], &TSC, TSCSize); - std::memcpy(RecordPtr, &CustomEvent, sizeof(CustomEvent)); - RecordPtr += sizeof(CustomEvent); - std::memcpy(RecordPtr, Event, ReducedEventSize); + std::memcpy(TLD.RecordPtr, &CustomEvent, sizeof(CustomEvent)); + TLD.RecordPtr += sizeof(CustomEvent); + std::memcpy(TLD.RecordPtr, Event, ReducedEventSize); endBufferIfFull(); } diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index ce4f6cd53..ce81e4364 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -104,36 +104,38 @@ static void processFunctionHook(int32_t FuncId, XRayEntryType Entry, __sanitizer::atomic_sint32_t &LoggingStatus, const std::shared_ptr &BQ); -//-----------------------------------------------------------------------------| -// The rest of the file is implementation. | -//-----------------------------------------------------------------------------| -// Functions are implemented in the header for inlining since we don't want | -// to grow the stack when we've hijacked the binary for logging. | -//-----------------------------------------------------------------------------| - -namespace { - -thread_local BufferQueue::Buffer Buffer; -thread_local char *RecordPtr = nullptr; - -// The number of FunctionEntry records immediately preceding RecordPtr. -thread_local uint8_t NumConsecutiveFnEnters = 0; +// Group together thread-local-data in a struct, then hide it behind a function +// call so that it can be initialized on first use instead of as a global. +struct ThreadLocalData { + BufferQueue::Buffer Buffer; + char *RecordPtr = nullptr; + // The number of FunctionEntry records immediately preceding RecordPtr. + uint8_t NumConsecutiveFnEnters = 0; + + // The number of adjacent, consecutive pairs of FunctionEntry, Tail Exit + // records preceding RecordPtr. + uint8_t NumTailCalls = 0; + + // We use a thread_local variable to keep track of which CPUs we've already + // run, and the TSC times for these CPUs. This allows us to stop repeating the + // CPU field in the function records. + // + // We assume that we'll support only 65536 CPUs for x86_64. + uint16_t CurrentCPU = std::numeric_limits::max(); + uint64_t LastTSC = 0; + uint64_t LastFunctionEntryTSC = 0; + + // Make sure a thread that's ever called handleArg0 has a thread-local + // live reference to the buffer queue for this particular instance of + // FDRLogging, and that we're going to clean it up when the thread exits. + std::shared_ptr LocalBQ = nullptr; +}; -// The number of adjacent, consecutive pairs of FunctionEntry, Tail Exit -// records preceding RecordPtr. -thread_local uint8_t NumTailCalls = 0; +// Forward-declare, defined later. +static ThreadLocalData &getThreadLocalData(); -constexpr auto MetadataRecSize = sizeof(MetadataRecord); -constexpr auto FunctionRecSize = sizeof(FunctionRecord); - -// We use a thread_local variable to keep track of which CPUs we've already -// run, and the TSC times for these CPUs. This allows us to stop repeating the -// CPU field in the function records. -// -// We assume that we'll support only 65536 CPUs for x86_64. -thread_local uint16_t CurrentCPU = std::numeric_limits::max(); -thread_local uint64_t LastTSC = 0; -thread_local uint64_t LastFunctionEntryTSC = 0; +static constexpr auto MetadataRecSize = sizeof(MetadataRecord); +static constexpr auto FunctionRecSize = sizeof(FunctionRecord); class ThreadExitBufferCleanup { std::shared_ptr &Buffers; @@ -146,6 +148,8 @@ public: Buffer(Buffer) {} ~ThreadExitBufferCleanup() noexcept XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); + auto &RecordPtr = TLD.RecordPtr; if (RecordPtr == nullptr) return; @@ -166,19 +170,27 @@ public: } }; -// Make sure a thread that's ever called handleArg0 has a thread-local -// live reference to the buffer queue for this particular instance of -// FDRLogging, and that we're going to clean it up when the thread exits. -thread_local std::shared_ptr* LocalBQ = - new std::shared_ptr(); -thread_local ThreadExitBufferCleanup Cleanup(*LocalBQ, Buffer); +static ThreadLocalData &getThreadLocalData() { + thread_local ThreadLocalData TLD; + thread_local ThreadExitBufferCleanup Cleanup(TLD.LocalBQ, TLD.Buffer); + return TLD; +} + +//-----------------------------------------------------------------------------| +// The rest of the file is implementation. | +//-----------------------------------------------------------------------------| +// Functions are implemented in the header for inlining since we don't want | +// to grow the stack when we've hijacked the binary for logging. | +//-----------------------------------------------------------------------------| + +namespace { class RecursionGuard { - bool &Running; + volatile bool &Running; const bool Valid; public: - explicit RecursionGuard(bool &R) : Running(R), Valid(!R) { + explicit RecursionGuard(volatile bool &R) : Running(R), Valid(!R) { if (Valid) Running = true; } @@ -238,24 +250,29 @@ inline void writeNewBufferPreamble(pid_t Tid, timespec TS, } std::memcpy(MemPtr, Records, sizeof(MetadataRecord) * InitRecordsCount); MemPtr += sizeof(MetadataRecord) * InitRecordsCount; - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + auto &TLD = getThreadLocalData(); + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; } inline void setupNewBuffer(int (*wall_clock_reader)( clockid_t, struct timespec *)) XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); + auto &Buffer = TLD.Buffer; + auto &RecordPtr = TLD.RecordPtr; RecordPtr = static_cast(Buffer.Buffer); pid_t Tid = syscall(SYS_gettid); timespec TS{0, 0}; // This is typically clock_gettime, but callers have injection ability. wall_clock_reader(CLOCK_MONOTONIC, &TS); writeNewBufferPreamble(Tid, TS, RecordPtr); - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; } inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, char *&MemPtr) XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); MetadataRecord NewCPUId; NewCPUId.Type = uint8_t(RecordType::Metadata); NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId); @@ -268,32 +285,34 @@ inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC, std::memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC)); std::memcpy(MemPtr, &NewCPUId, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; } inline void writeNewCPUIdMetadata(uint16_t CPU, uint64_t TSC) XRAY_NEVER_INSTRUMENT { - writeNewCPUIdMetadata(CPU, TSC, RecordPtr); + writeNewCPUIdMetadata(CPU, TSC, getThreadLocalData().RecordPtr); } inline void writeEOBMetadata(char *&MemPtr) XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); MetadataRecord EOBMeta; EOBMeta.Type = uint8_t(RecordType::Metadata); EOBMeta.RecordKind = uint8_t(MetadataRecord::RecordKinds::EndOfBuffer); // For now we don't write any bytes into the Data field. std::memcpy(MemPtr, &EOBMeta, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; } inline void writeEOBMetadata() XRAY_NEVER_INSTRUMENT { - writeEOBMetadata(RecordPtr); + writeEOBMetadata(getThreadLocalData().RecordPtr); } inline void writeTSCWrapMetadata(uint64_t TSC, char *&MemPtr) XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); MetadataRecord TSCWrap; TSCWrap.Type = uint8_t(RecordType::Metadata); TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap); @@ -304,12 +323,12 @@ inline void writeTSCWrapMetadata(uint64_t TSC, std::memcpy(&TSCWrap.Data, &TSC, sizeof(TSC)); std::memcpy(MemPtr, &TSCWrap, sizeof(MetadataRecord)); MemPtr += sizeof(MetadataRecord); - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; } inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { - writeTSCWrapMetadata(TSC, RecordPtr); + writeTSCWrapMetadata(TSC, getThreadLocalData().RecordPtr); } inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, @@ -324,36 +343,37 @@ inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, FuncRecord.FuncId = FuncId & ~(0x0F << 28); FuncRecord.TSCDelta = TSCDelta; + auto &TLD = getThreadLocalData(); switch (EntryType) { case XRayEntryType::ENTRY: - ++NumConsecutiveFnEnters; + ++TLD.NumConsecutiveFnEnters; FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); break; case XRayEntryType::LOG_ARGS_ENTRY: // We should not rewind functions with logged args. - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter); break; case XRayEntryType::EXIT: // If we've decided to log the function exit, we will never erase the log // before it. - NumConsecutiveFnEnters = 0; - NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit); break; case XRayEntryType::TAIL: // If we just entered the function we're tail exiting from or erased every // invocation since then, this function entry tail pair is a candidate to // be erased when the child function exits. - if (NumConsecutiveFnEnters > 0) { - ++NumTailCalls; - NumConsecutiveFnEnters = 0; + if (TLD.NumConsecutiveFnEnters > 0) { + ++TLD.NumTailCalls; + TLD.NumConsecutiveFnEnters = 0; } else { // We will never be able to erase this tail call since we have logged // something in between the function entry and tail exit. - NumTailCalls = 0; - NumConsecutiveFnEnters = 0; + TLD.NumTailCalls = 0; + TLD.NumConsecutiveFnEnters = 0; } FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionTailExit); @@ -391,20 +411,21 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, using AlignedFuncStorage = std::aligned_storage::type; - RecordPtr -= FunctionRecSize; + auto &TLD = getThreadLocalData(); + TLD.RecordPtr -= FunctionRecSize; AlignedFuncStorage AlignedFuncRecordBuffer; const auto &FuncRecord = *reinterpret_cast( - std::memcpy(&AlignedFuncRecordBuffer, RecordPtr, FunctionRecSize)); + std::memcpy(&AlignedFuncRecordBuffer, TLD.RecordPtr, FunctionRecSize)); assert(FuncRecord.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && "Expected to find function entry recording when rewinding."); assert(FuncRecord.FuncId == (FuncId & ~(0x0F << 28)) && "Expected matching function id when rewinding Exit"); - --NumConsecutiveFnEnters; + --TLD.NumConsecutiveFnEnters; LastTSC -= FuncRecord.TSCDelta; // We unwound one call. Update the state and return without writing a log. - if (NumConsecutiveFnEnters != 0) { + if (TLD.NumConsecutiveFnEnters != 0) { LastFunctionEntryTSC -= FuncRecord.TSCDelta; return; } @@ -414,8 +435,8 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, // exited from via this exit. LastFunctionEntryTSC = 0; auto RewindingTSC = LastTSC; - auto RewindingRecordPtr = RecordPtr - FunctionRecSize; - while (NumTailCalls > 0) { + auto RewindingRecordPtr = TLD.RecordPtr - FunctionRecSize; + while (TLD.NumTailCalls > 0) { AlignedFuncStorage TailExitRecordBuffer; // Rewind the TSC back over the TAIL EXIT record. const auto &ExpectedTailExit = @@ -438,24 +459,25 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, // This tail call exceeded the threshold duration. It will not be erased. if ((TSC - RewindingTSC) >= thresholdTicks()) { - NumTailCalls = 0; + TLD.NumTailCalls = 0; return; } // We can erase a tail exit pair that we're exiting through since // its duration is under threshold. - --NumTailCalls; + --TLD.NumTailCalls; RewindingRecordPtr -= FunctionRecSize; RewindingTSC -= ExpectedFunctionEntry.TSCDelta; - RecordPtr -= 2 * FunctionRecSize; + TLD.RecordPtr -= 2 * FunctionRecSize; LastTSC = RewindingTSC; } } inline bool releaseThreadLocalBuffer(BufferQueue &BQArg) { - auto EC = BQArg.releaseBuffer(Buffer); + auto &TLD = getThreadLocalData(); + auto EC = BQArg.releaseBuffer(TLD.Buffer); if (EC != BufferQueue::ErrorCode::Ok) { - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + Report("Failed to release buffer at %p; error=%s\n", TLD.Buffer.Buffer, BufferQueue::getErrorString(EC)); return false; } @@ -465,12 +487,14 @@ inline bool releaseThreadLocalBuffer(BufferQueue &BQArg) { inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, struct timespec *), size_t MaxSize) XRAY_NEVER_INSTRUMENT { - char *BufferStart = static_cast(Buffer.Buffer); - if ((RecordPtr + MaxSize) > (BufferStart + Buffer.Size - MetadataRecSize)) { + auto &TLD = getThreadLocalData(); + char *BufferStart = static_cast(TLD.Buffer.Buffer); + if ((TLD.RecordPtr + MaxSize) > + (BufferStart + TLD.Buffer.Size - MetadataRecSize)) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(**LocalBQ)) + if (!releaseThreadLocalBuffer(*TLD.LocalBQ)) return false; - auto EC = (*LocalBQ)->getBuffer(Buffer); + auto EC = TLD.LocalBQ->getBuffer(TLD.Buffer); if (EC != BufferQueue::ErrorCode::Ok) { Report("Failed to acquire a buffer; error=%s\n", BufferQueue::getErrorString(EC)); @@ -489,14 +513,15 @@ inline bool isLogInitializedAndReady( // We should take the opportunity to release the buffer though. auto Status = __sanitizer::atomic_load(&LoggingStatus, __sanitizer::memory_order_acquire); + auto &TLD = getThreadLocalData(); if (Status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { - if (RecordPtr != nullptr && + if (TLD.RecordPtr != nullptr && (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) { writeEOBMetadata(); if (!releaseThreadLocalBuffer(*LBQ)) return false; - RecordPtr = nullptr; + TLD.RecordPtr = nullptr; LBQ = nullptr; return false; } @@ -507,11 +532,11 @@ inline bool isLogInitializedAndReady( writeEOBMetadata(); if (!releaseThreadLocalBuffer(*LBQ)) return false; - RecordPtr = nullptr; + TLD.RecordPtr = nullptr; } - if (Buffer.Buffer == nullptr) { - auto EC = LBQ->getBuffer(Buffer); + if (TLD.Buffer.Buffer == nullptr) { + auto EC = LBQ->getBuffer(TLD.Buffer); if (EC != BufferQueue::ErrorCode::Ok) { auto LS = __sanitizer::atomic_load(&LoggingStatus, __sanitizer::memory_order_acquire); @@ -525,10 +550,10 @@ inline bool isLogInitializedAndReady( setupNewBuffer(wall_clock_reader); } - if (CurrentCPU == std::numeric_limits::max()) { + if (TLD.CurrentCPU == std::numeric_limits::max()) { // This means this is the first CPU this thread has ever run on. We set // the current CPU and record this as the first TSC we've seen. - CurrentCPU = CPU; + TLD.CurrentCPU = CPU; writeNewCPUIdMetadata(CPU, TSC); } @@ -536,12 +561,13 @@ inline bool isLogInitializedAndReady( } // namespace __xray_fdr_internal inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { - auto BufferStart = static_cast(Buffer.Buffer); - if ((RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { + auto &TLD = getThreadLocalData(); + auto BufferStart = static_cast(TLD.Buffer.Buffer); + if ((TLD.RecordPtr + MetadataRecSize) - BufferStart == MetadataRecSize) { writeEOBMetadata(); - if (!releaseThreadLocalBuffer(**LocalBQ)) + if (!releaseThreadLocalBuffer(*TLD.LocalBQ)) return; - RecordPtr = nullptr; + TLD.RecordPtr = nullptr; } } @@ -555,19 +581,21 @@ inline void processFunctionHook( // don't want to be clobbering potentially partial writes already happening in // the thread. We use a simple thread_local latch to only allow one on-going // handleArg0 to happen at any given time. - thread_local bool Running = false; + thread_local volatile bool Running = false; RecursionGuard Guard{Running}; if (!Guard) { assert(Running == true && "RecursionGuard is buggy!"); return; } + auto &TLD = getThreadLocalData(); + // In case the reference has been cleaned up before, we make sure we // initialize it to the provided BufferQueue. - if ((*LocalBQ) == nullptr) - *LocalBQ = BQ; + if (TLD.LocalBQ == nullptr) + TLD.LocalBQ = BQ; - if (!isLogInitializedAndReady(*LocalBQ, TSC, CPU, wall_clock_reader)) + if (!isLogInitializedAndReady(TLD.LocalBQ, TSC, CPU, wall_clock_reader)) return; // Before we go setting up writing new function entries, we need to be really @@ -607,14 +635,14 @@ inline void processFunctionHook( // Buffer, set it up properly before doing any further writing. // if (!prepareBuffer(wall_clock_reader, FunctionRecSize + MetadataRecSize)) { - *LocalBQ = nullptr; + TLD.LocalBQ = nullptr; return; } // By this point, we are now ready to write at most 24 bytes (one metadata // record and one function record). - assert((RecordPtr + (MetadataRecSize + FunctionRecSize)) - - static_cast(Buffer.Buffer) >= + assert((TLD.RecordPtr + (MetadataRecSize + FunctionRecSize)) - + static_cast(TLD.Buffer.Buffer) >= static_cast(MetadataRecSize) && "Misconfigured BufferQueue provided; Buffer size not large enough."); @@ -638,36 +666,36 @@ inline void processFunctionHook( // the correct TSC delta. // uint32_t RecordTSCDelta = 0; - if (CPU != CurrentCPU) { + if (CPU != TLD.CurrentCPU) { // We've moved to a new CPU. writeNewCPUIdMetadata(CPU, TSC); } else { // If the delta is greater than the range for a uint32_t, then we write out // the TSC wrap metadata entry with the full TSC, and the TSC for the // function record be 0. - auto Delta = TSC - LastTSC; + auto Delta = TSC - TLD.LastTSC; if (Delta > (1ULL << 32) - 1) writeTSCWrapMetadata(TSC); else RecordTSCDelta = Delta; } - LastTSC = TSC; - CurrentCPU = CPU; + TLD.LastTSC = TSC; + TLD.CurrentCPU = CPU; switch (Entry) { case XRayEntryType::ENTRY: case XRayEntryType::LOG_ARGS_ENTRY: // Update the thread local state for the next invocation. - LastFunctionEntryTSC = TSC; + TLD.LastFunctionEntryTSC = TSC; break; case XRayEntryType::TAIL: break; case XRayEntryType::EXIT: // Break out and write the exit record if we can't erase any functions. - if (NumConsecutiveFnEnters == 0 || - (TSC - LastFunctionEntryTSC) >= thresholdTicks()) + if (TLD.NumConsecutiveFnEnters == 0 || + (TSC - TLD.LastFunctionEntryTSC) >= thresholdTicks()) break; - rewindRecentCall(TSC, LastTSC, LastFunctionEntryTSC, FuncId); + rewindRecentCall(TSC, TLD.LastTSC, TLD.LastFunctionEntryTSC, FuncId); return; // without writing log. case XRayEntryType::CUSTOM_EVENT: { // This is a bug in patching, so we'll report it once and move on. @@ -682,7 +710,7 @@ inline void processFunctionHook( } } - writeFunctionRecord(FuncId, RecordTSCDelta, Entry, RecordPtr); + writeFunctionRecord(FuncId, RecordTSCDelta, Entry, TLD.RecordPtr); // If we've exhausted the buffer by this time, we then release the buffer to // make sure that other threads may start using this buffer. -- cgit v1.2.1 From 79654fd7716284ec881606e177a409608e8c4ede Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 29 Aug 2017 19:48:12 +0000 Subject: [SanitizeCoverage] Enable stack-depth coverage for -fsanitize=fuzzer Summary: - Don't sanitize __sancov_lowest_stack. - Don't instrument leaf functions. - Add CoverageStackDepth to Fuzzer and FuzzerNoLink. - Disable stack depth tracking on Mac. Reviewers: vitalybuka, kcc, george.karpenkov Reviewed By: kcc Subscribers: kubamracek, cfe-commits, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D37156 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312026 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 5 +++++ lib/sanitizer_common/sanitizer_internal_defs.h | 8 ++++++++ test/fuzzer/deep-recursion.test | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 469656766..3c5f29b28 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -211,5 +211,10 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" +// Weak definition for code instrumented with -fsanitize-coverage=stack-depth +// and later linked with code containing a strong definition. +// E.g., -fsanitize=fuzzer-no-link +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; #endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 4b780917f..7ffebcb5f 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -35,6 +35,14 @@ # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) #endif +// Mac handles TLS differently +#if SANITIZER_MAC +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE +#else +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ + __attribute((tls_model("initial-exec"))) thread_local +#endif + //--------------------------- WEAK FUNCTIONS ---------------------------------// // When working with weak functions, to simplify the code and make it more // portable, when possible define a default implementation using this macro: diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index b99bad4c6..22475f912 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,5 +1,5 @@ # Test that we can find a stack overflow REQUIRES: linux -RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 440c0242b3e8488d6c6ba31e692c87fdd47fb0af Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 29 Aug 2017 20:03:51 +0000 Subject: Minimal runtime for UBSan. Summary: An implementation of ubsan runtime library suitable for use in production. Minimal attack surface. * No stack traces. * Definitely no C++ demangling. * No UBSAN_OPTIONS=log_file=/path (very suid-unfriendly). And no UBSAN_OPTIONS in general. * as simple as possible Minimal CPU and RAM overhead. * Source locations unnecessary in the presence of (split) debug info. * Values and types (as in A+B overflows T) can be reconstructed from register/stack dumps, once you know what type of error you are looking at. * above two items save 3% binary size. When UBSan is used with -ftrap-function=abort, sometimes it is hard to reason about failures. This library replaces abort with a slightly more informative message without much extra overhead. Since ubsan interface in not stable, this code must reside in compiler-rt. Reviewers: pcc, kcc Subscribers: srhines, mgorny, aprantl, krytarowski, llvm-commits Differential Revision: https://reviews.llvm.org/D36810 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312029 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 9 ++- lib/ubsan_minimal/CMakeLists.txt | 50 ++++++++++++ lib/ubsan_minimal/ubsan.syms.extra | 1 + lib/ubsan_minimal/ubsan_minimal_handlers.cc | 91 ++++++++++++++++++++++ test/ubsan_minimal/CMakeLists.txt | 23 ++++++ .../TestCases/recover-dedup-limit.cpp | 41 ++++++++++ test/ubsan_minimal/TestCases/recover-dedup.cpp | 25 ++++++ test/ubsan_minimal/TestCases/uadd-overflow.cpp | 10 +++ test/ubsan_minimal/lit.common.cfg | 35 +++++++++ test/ubsan_minimal/lit.site.cfg.in | 11 +++ 10 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 lib/ubsan_minimal/CMakeLists.txt create mode 100644 lib/ubsan_minimal/ubsan.syms.extra create mode 100644 lib/ubsan_minimal/ubsan_minimal_handlers.cc create mode 100644 test/ubsan_minimal/CMakeLists.txt create mode 100644 test/ubsan_minimal/TestCases/recover-dedup-limit.cpp create mode 100644 test/ubsan_minimal/TestCases/recover-dedup.cpp create mode 100644 test/ubsan_minimal/TestCases/uadd-overflow.cpp create mode 100644 test/ubsan_minimal/lit.common.cfg create mode 100644 test/ubsan_minimal/lit.site.cfg.in diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 4ba284e69..c53715f53 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -470,7 +470,7 @@ else() set(OS_NAME "${CMAKE_SYSTEM_NAME}") endif() -set(ALL_SANITIZERS asan;dfsan;msan;tsan;safestack;cfi;esan;scudo) +set(ALL_SANITIZERS asan;dfsan;msan;tsan;safestack;cfi;esan;scudo;ubsan_minimal) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -545,6 +545,13 @@ else() set(COMPILER_RT_HAS_UBSAN FALSE) endif() +if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND + OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Android") + set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE) +else() + set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) +endif() + if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD") set(COMPILER_RT_HAS_SAFESTACK TRUE) diff --git a/lib/ubsan_minimal/CMakeLists.txt b/lib/ubsan_minimal/CMakeLists.txt new file mode 100644 index 000000000..c75f5090a --- /dev/null +++ b/lib/ubsan_minimal/CMakeLists.txt @@ -0,0 +1,50 @@ +# Build for the undefined behavior sanitizer runtime support library. + +set(UBSAN_MINIMAL_SOURCES + ubsan_minimal_handlers.cc + ) + +include_directories(..) + +set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF UBSAN_CFLAGS) + +set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF UBSAN_STANDALONE_CFLAGS) + +add_compiler_rt_component(ubsan-minimal) + +# Common parts of UBSan runtime. +add_compiler_rt_object_libraries(RTUbsan_minimal + ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} + SOURCES ${UBSAN_MINIMAL_SOURCES} CFLAGS ${UBSAN_CFLAGS}) + + +if(COMPILER_RT_HAS_UBSAN) + # Initializer of standalone UBSan runtime. + + # Standalone UBSan runtimes. + add_compiler_rt_runtime(clang_rt.ubsan_minimal + STATIC + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_minimal + CFLAGS ${UBSAN_CFLAGS} + PARENT_TARGET ubsan-minimal) + + add_compiler_rt_runtime(clang_rt.ubsan_minimal + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_minimal + CFLAGS ${UBSAN_CFLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan-minimal) + + if (UNIX) + set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) + add_sanitizer_rt_symbols(clang_rt.ubsan_minimal + ARCHS ${ARCHS_FOR_SYMBOLS} + PARENT_TARGET ubsan-minimal + EXTRA ubsan.syms.extra) + endif() +endif() diff --git a/lib/ubsan_minimal/ubsan.syms.extra b/lib/ubsan_minimal/ubsan.syms.extra new file mode 100644 index 000000000..7f8be6944 --- /dev/null +++ b/lib/ubsan_minimal/ubsan.syms.extra @@ -0,0 +1 @@ +__ubsan_* diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc new file mode 100644 index 000000000..3ab2811c6 --- /dev/null +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +static void message(const char *msg) { + write(2, msg, strlen(msg)); +} + +static const int kMaxCallerPcs = 20; +static std::atomic caller_pcs[kMaxCallerPcs]; +// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means +// that "too many errors" has already been reported. +static std::atomic caller_pcs_sz; + +__attribute__((noinline)) +static bool report_this_error(void *caller) { + if (caller == nullptr) return false; + while (true) { + int sz = caller_pcs_sz.load(std::memory_order_relaxed); + if (sz > kMaxCallerPcs) return false; // early exit + // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg + // succeeds in order to not print it multiple times. + if (sz > 0 && sz < kMaxCallerPcs) { + void *p; + for (int i = 0; i < sz; ++i) { + p = caller_pcs[i].load(std::memory_order_relaxed); + if (p == nullptr) break; // Concurrent update. + if (p == caller) return false; + } + if (p == nullptr) continue; // FIXME: yield? + } + + if (!caller_pcs_sz.compare_exchange_strong(sz, sz + 1)) + continue; // Concurrent update! Try again from the start. + + if (sz == kMaxCallerPcs) { + message("ubsan: too many errors\n"); + return false; + } + caller_pcs[sz].store(caller, std::memory_order_relaxed); + return true; + } +} + +#if defined(__ANDROID__) +extern "C" void android_set_abort_message(const char *msg); +static void abort_with_message(const char *msg) { +#if __ANDROID_API__ >= 21 + android_set_abort_message(msg); +#endif + abort(); +} +#else +static void abort_with_message(const char *) { abort(); } +#endif + +#define INTERFACE extern "C" __attribute__((visibility("default"))) + +// FIXME: add caller pc to the error message (possibly as "ubsan: error-type +// @1234ABCD"). +#define HANDLER(name, msg) \ + INTERFACE void __ubsan_handle_##name##_minimal() { \ + if (!report_this_error(__builtin_return_address(0))) return; \ + message("ubsan: " msg "\n"); \ + } \ + \ + INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ + message("ubsan: " msg "\n"); \ + abort_with_message("ubsan: " msg); \ + } + +HANDLER(type_mismatch, "type-mismatch") +HANDLER(add_overflow, "add-overflow") +HANDLER(sub_overflow, "sub-overflow") +HANDLER(mul_overflow, "mul-overflow") +HANDLER(negate_overflow, "negate-overflow") +HANDLER(divrem_overflow, "divrem-overflow") +HANDLER(shift_out_of_bounds, "shift-out-of-bounds") +HANDLER(out_of_bounds, "out-of-bounds") +HANDLER(builtin_unreachable, "builtin-unreachable") +HANDLER(missing_return, "missing-return") +HANDLER(vla_bound_not_positive, "vla-bound-not-positive") +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(nonnull_arg, "nonnull-arg") +HANDLER(nullability_arg, "nullability-arg") +HANDLER(pointer_overflow, "pointer-overflow") +HANDLER(cfi_check_fail, "cfi-check-fail") diff --git a/test/ubsan_minimal/CMakeLists.txt b/test/ubsan_minimal/CMakeLists.txt new file mode 100644 index 000000000..8e87b76bc --- /dev/null +++ b/test/ubsan_minimal/CMakeLists.txt @@ -0,0 +1,23 @@ +set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(UBSAN_TEST_ARCH ${UBSAN_SUPPORTED_ARCH}) + +set(UBSAN_TESTSUITES) +set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND UBSAN_TEST_DEPS ubsan-minimal) +endif() + +foreach(arch ${UBSAN_TEST_ARCH}) + get_test_cc_for_arch(${arch} UBSAN_TEST_TARGET_CC UBSAN_TEST_TARGET_CFLAGS) + set(CONFIG_NAME ${arch}) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +add_lit_testsuite(check-ubsan-minimal "Running UndefinedBehaviorSanitizerMinimal tests" + ${UBSAN_TESTSUITES} + DEPENDS ${UBSAN_TEST_DEPS}) +set_target_properties(check-ubsan-minimal PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/ubsan_minimal/TestCases/recover-dedup-limit.cpp b/test/ubsan_minimal/TestCases/recover-dedup-limit.cpp new file mode 100644 index 000000000..faa2b66ad --- /dev/null +++ b/test/ubsan_minimal/TestCases/recover-dedup-limit.cpp @@ -0,0 +1,41 @@ +// RUN: %clangxx -fsanitize=signed-integer-overflow -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s + +#include + +#define OVERFLOW \ + x = 0x7FFFFFFE; \ + x += __LINE__ + +int main() { + int32_t x; + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + // CHECK-NOT: add-overflow + OVERFLOW; // CHECK: too many errors + // CHECK-NOT: add-overflow + OVERFLOW; + OVERFLOW; + OVERFLOW; +} diff --git a/test/ubsan_minimal/TestCases/recover-dedup.cpp b/test/ubsan_minimal/TestCases/recover-dedup.cpp new file mode 100644 index 000000000..744471c66 --- /dev/null +++ b/test/ubsan_minimal/TestCases/recover-dedup.cpp @@ -0,0 +1,25 @@ +// RUN: %clangxx -fsanitize=signed-integer-overflow -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s + +#include + +__attribute__((noinline)) +int f(int x, int y) { + // CHECK: mul-overflow + return x * y; +} + +__attribute__((noinline)) +int g(int x, int y) { + // CHECK: mul-overflow + return x * (y + 1); +} + +int main() { + int x = 2; + for (int i = 0; i < 10; ++i) + x = f(x, x); + x = 2; + for (int i = 0; i < 10; ++i) + x = g(x, x); + // CHECK-NOT: mul-overflow +} diff --git a/test/ubsan_minimal/TestCases/uadd-overflow.cpp b/test/ubsan_minimal/TestCases/uadd-overflow.cpp new file mode 100644 index 000000000..034575012 --- /dev/null +++ b/test/ubsan_minimal/TestCases/uadd-overflow.cpp @@ -0,0 +1,10 @@ +// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=all %s -o %t && not --crash %run %t 2>&1 | FileCheck %s + +#include + +int main() { + uint32_t k = 0x87654321; + k += 0xedcba987; + // CHECK: add-overflow +} diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg new file mode 100644 index 000000000..1bd1bbefe --- /dev/null +++ b/test/ubsan_minimal/lit.common.cfg @@ -0,0 +1,35 @@ +# -*- Python -*- + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +target_cflags = [get_required_attr(config, "target_cflags")] +clang_ubsan_cflags = ["-fsanitize-minimal-runtime"] + target_cflags +clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags + +# Define %clang and %clangxx substitutions to use in test RUN lines. +config.substitutions.append( ("%clang ", build_invocation(clang_ubsan_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +# Check that the host supports UndefinedBehaviorSanitizerMinimal tests +if config.host_os not in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']: # TODO: Windows + config.unsupported = True + +config.available_features.add('arch=' + config.target_arch) diff --git a/test/ubsan_minimal/lit.site.cfg.in b/test/ubsan_minimal/lit.site.cfg.in new file mode 100644 index 000000000..d4dd68ef2 --- /dev/null +++ b/test/ubsan_minimal/lit.site.cfg.in @@ -0,0 +1,11 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.target_cflags = "@UBSAN_TEST_TARGET_CFLAGS@" +config.target_arch = "@UBSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/lit.common.cfg") -- cgit v1.2.1 From 21ee37b2d0d672da99b525418598056ed6a7ba79 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 29 Aug 2017 20:44:41 +0000 Subject: Disable stack depth tracking on Windows. Windows doesn't support the tls_model attribute. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312032 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_internal_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 7ffebcb5f..28687c66b 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -36,7 +36,7 @@ #endif // Mac handles TLS differently -#if SANITIZER_MAC +#if SANITIZER_MAC || SANITIZER_WINDOWS # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE #else # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ -- cgit v1.2.1 From 04d0769c4c9fe8e3204424cfc5368b4a78006d03 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 29 Aug 2017 20:51:24 +0000 Subject: [libFUzzer] change the way we load the seed corpora: instead of loading all files and these executing all files, load and execute them one-by-one. This should reduce the memory usage in many cases git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312033 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerIO.h | 1 + lib/fuzzer/FuzzerIOPosix.cpp | 7 +++ lib/fuzzer/FuzzerInternal.h | 2 - lib/fuzzer/FuzzerLoop.cpp | 107 ++++++++++++++++++++++------------------- test/fuzzer/fuzzer-dirs.test | 2 +- test/fuzzer/reduce_inputs.test | 2 +- 6 files changed, 68 insertions(+), 53 deletions(-) diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 8ed0e003d..5059c11ac 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -53,6 +53,7 @@ void RawPrint(const char *Str); // Platform specific functions: bool IsFile(const std::string &Path); +size_t FileSize(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector *V, bool TopDir); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index d642b3424..2c452a7dd 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -32,6 +32,13 @@ bool IsFile(const std::string &Path) { return S_ISREG(St.st_mode); } +size_t FileSize(const std::string &Path) { + struct stat St; + if (stat(Path.c_str(), &St)) + return 0; + return St.st_size; +} + void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector *V, bool TopDir) { auto E = GetEpoch(Dir); diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 70136a30b..34fdeb821 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -38,7 +38,6 @@ public: void Loop(const Vector &CorpusDirs); void ReadAndExecuteSeedCorpora(const Vector &CorpusDirs); void MinimizeCrashLoop(const Unit &U); - void ShuffleAndMinimize(UnitVector *V); void RereadOutputCorpus(size_t MaxSize); size_t secondsSinceProcessStartUp() { @@ -103,7 +102,6 @@ private: void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); void PrintStatusForNewUnit(const Unit &U, const char *Text); - void ShuffleCorpus(UnitVector *V); void CheckExitOnSrcPosOrItem(); static void StaticDeathCallback(); diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 84ea2d6e8..97fc31cc8 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -371,39 +371,6 @@ void Fuzzer::RereadOutputCorpus(size_t MaxSize) { PrintStats("RELOAD"); } -void Fuzzer::ShuffleCorpus(UnitVector *V) { - std::shuffle(V->begin(), V->end(), MD.GetRand()); - if (Options.PreferSmall) - std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) { - return A.size() < B.size(); - }); -} - -void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { - Printf("#0\tREAD units: %zd; rss: %zdMb\n", InitialCorpus->size(), - GetPeakRSSMb()); - if (Options.ShuffleAtStartUp) - ShuffleCorpus(InitialCorpus); - - // Test the callback with empty input and never try it again. - uint8_t dummy; - ExecuteCallback(&dummy, 0); - - for (auto &U : *InitialCorpus) { - RunOne(U.data(), U.size()); - CheckExitOnSrcPosOrItem(); - TryDetectingAMemoryLeak(U.data(), U.size(), - /*DuringInitialCorpusExecution*/ true); - U.clear(); - } - PrintStats("INITED"); - if (Corpus.empty()) { - Printf("ERROR: no interesting inputs were found. " - "Is the code instrumented for coverage? Exiting.\n"); - exit(1); - } -} - void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { auto TimeOfUnit = duration_cast(UnitStopTime - UnitStartTime).count(); @@ -628,26 +595,68 @@ void Fuzzer::MutateAndTestOne() { void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { const size_t kMaxSaneLen = 1 << 20; const size_t kMinDefaultLen = 4096; - size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; - UnitVector InitialCorpus; - for (auto &Inp : CorpusDirs) { - Printf("Loading corpus dir: %s\n", Inp.c_str()); - ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, - TemporaryMaxLen, /*ExitOnError=*/false); + struct SizedFile { + std::string File; + size_t Size; + }; + Vector SizedFiles; + size_t MaxSize = 0; + size_t MinSize = -1; + size_t TotalSize = 0; + for (auto &Dir : CorpusDirs) { + Vector Files; + ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true); + Printf("INFO: % 8zd files found in %s\n", Files.size(), Dir.c_str()); + for (auto &File : Files) { + if (size_t Size = FileSize(File)) { + MaxSize = Max(Size, MaxSize); + MinSize = Min(Size, MinSize); + TotalSize += Size; + SizedFiles.push_back({File, Size}); + } + } } - if (Options.MaxLen == 0) { - size_t MaxLen = 0; - for (auto &U : InitialCorpus) - MaxLen = std::max(U.size(), MaxLen); - SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); + if (Options.MaxLen == 0) + SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); + assert(MaxInputLen > 0); + + if (SizedFiles.empty()) { + Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); + Unit U({'\n'}); // Valid ASCII input. + RunOne(U.data(), U.size()); + } else { + Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb" + " rss: %zdMb\n", + SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb()); + if (Options.ShuffleAtStartUp) + std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand()); + + if (Options.PreferSmall) + std::stable_sort( + SizedFiles.begin(), SizedFiles.end(), + [](const SizedFile &A, const SizedFile &B) { return A.Size < B.Size; }); + + // Load and execute inputs one by one. + for (auto &SF : SizedFiles) { + auto U = FileToVector(SF.File, MaxInputLen); + assert(U.size() <= MaxInputLen); + RunOne(U.data(), U.size()); + CheckExitOnSrcPosOrItem(); + TryDetectingAMemoryLeak(U.data(), U.size(), + /*DuringInitialCorpusExecution*/ true); + } } - if (InitialCorpus.empty()) { - InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. - if (Options.Verbosity) - Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); + // Test the callback with empty input and never try it again. + uint8_t dummy; + ExecuteCallback(&dummy, 0); + + PrintStats("INITED"); + if (Corpus.empty()) { + Printf("ERROR: no interesting inputs were found. " + "Is the code instrumented for coverage? Exiting.\n"); + exit(1); } - ShuffleAndMinimize(&InitialCorpus); } void Fuzzer::Loop(const Vector &CorpusDirs) { diff --git a/test/fuzzer/fuzzer-dirs.test b/test/fuzzer/fuzzer-dirs.test index ef0888f3b..9b6e4d1ee 100644 --- a/test/fuzzer/fuzzer-dirs.test +++ b/test/fuzzer/fuzzer-dirs.test @@ -6,7 +6,7 @@ RUN: echo a > %t/SUB1/a RUN: echo b > %t/SUB1/SUB2/b RUN: echo c > %t/SUB1/SUB2/SUB3/c RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS -SUBDIRS: READ units: 3 +SUBDIRS: INFO: seed corpus: files: 3 min: 2b max: 2b total: 6b RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/f64 RUN: cat %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 > %t/SUB1/f256 RUN: cat %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 > %t/SUB1/f1024 diff --git a/test/fuzzer/reduce_inputs.test b/test/fuzzer/reduce_inputs.test index 02e090ebd..94f8cc4f3 100644 --- a/test/fuzzer/reduce_inputs.test +++ b/test/fuzzer/reduce_inputs.test @@ -9,7 +9,7 @@ CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60' # Test that reduce_inputs deletes redundant files in the corpus. RUN: %t-ShrinkControlFlowSimpleTest -runs=0 %t/C 2>&1 | FileCheck %s --check-prefix=COUNT -COUNT: READ units: 4 +COUNT: seed corpus: files: 4 # a bit longer test RUN: %t-ShrinkControlFlowTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -seed=1 -runs=1000000 2>&1 | FileCheck %s -- cgit v1.2.1 From 8140e686727334160666888918bba735b197dcf3 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 29 Aug 2017 21:15:08 +0000 Subject: Disable ubsan-minimal on Darwin. Should un-break this bot: http://green.lab.llvm.org/green//job/clang-stage1-configure-RA_build/38264/consoleFull git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312036 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/ubsan_minimal/CMakeLists.txt | 2 +- test/ubsan_minimal/lit.common.cfg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index c53715f53..d5ef46e25 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -546,7 +546,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Android") + OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android") set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE) else() set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) diff --git a/lib/ubsan_minimal/CMakeLists.txt b/lib/ubsan_minimal/CMakeLists.txt index c75f5090a..adc5d184d 100644 --- a/lib/ubsan_minimal/CMakeLists.txt +++ b/lib/ubsan_minimal/CMakeLists.txt @@ -20,7 +20,7 @@ add_compiler_rt_object_libraries(RTUbsan_minimal SOURCES ${UBSAN_MINIMAL_SOURCES} CFLAGS ${UBSAN_CFLAGS}) -if(COMPILER_RT_HAS_UBSAN) +if(COMPILER_RT_HAS_UBSAN_MINIMAL) # Initializer of standalone UBSan runtime. # Standalone UBSan runtimes. diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index 1bd1bbefe..df0643cd7 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -29,7 +29,7 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags config.suffixes = ['.c', '.cc', '.cpp'] # Check that the host supports UndefinedBehaviorSanitizerMinimal tests -if config.host_os not in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']: # TODO: Windows +if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD']: # TODO: Darwin, Windows config.unsupported = True config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 730138a7ef0556eb25df17377f6d8b6824818c16 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 29 Aug 2017 21:15:33 +0000 Subject: Re-enable stack depth instrumentation on Windows. Specified tls_model attribute properly. Should compile on Windows now. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312037 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_internal_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 28687c66b..c7b401d4f 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -36,11 +36,11 @@ #endif // Mac handles TLS differently -#if SANITIZER_MAC || SANITIZER_WINDOWS +#if SANITIZER_MAC # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE #else # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ - __attribute((tls_model("initial-exec"))) thread_local + __attribute__((tls_model("initial-exec"))) thread_local #endif //--------------------------- WEAK FUNCTIONS ---------------------------------// -- cgit v1.2.1 From 25500b158196752cb12a88207ba1fe5c9a86f5b1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 29 Aug 2017 21:23:44 +0000 Subject: [asan] Add use-after-scope test which fails because of bug in clang Reviewers: kcc, eugenis Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37242 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312039 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/use-after-scope-conversion.cc | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/asan/TestCases/use-after-scope-conversion.cc diff --git a/test/asan/TestCases/use-after-scope-conversion.cc b/test/asan/TestCases/use-after-scope-conversion.cc new file mode 100644 index 000000000..99b845d07 --- /dev/null +++ b/test/asan/TestCases/use-after-scope-conversion.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_asan -O0 -fsanitize-address-use-after-scope %s -o %t + +// RUN: not %run %t 'A' 2>&1 | FileCheck %s +// RUN: not %run %t 'B' 2>&1 | FileCheck %s + +// Missing lifetime markers in test_a +// https://bugs.llvm.org/show_bug.cgi?id=34353 +// XFAIL: * + +struct B { + B() : p('B') {} + char p; +}; + +struct C { + const char *p; + explicit C(const char *c) : p(c) {} + C(const B &b) : p(&b.p) {} // NOLINT +}; + +struct A { + char p; + explicit A() : p('C') {} + const operator C() const { return C(&p); } +}; + +volatile char r; +void test_a() { + C s = A(); + r = *s.p; +} + +void test_b() { + C s = B(); + r = *s.p; +} + +int main(int argc, char **argv) { + switch (argv[1][0]) { + case 'A': + test_a(); + return 0; + case 'B': + test_b(); + return 0; + } + return 1; +} + +// CHECK: ERROR: AddressSanitizer: stack-use-after-scope -- cgit v1.2.1 From 454ce793bfd6e54f91d224a12636d2cb1db00a86 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 29 Aug 2017 21:52:56 +0000 Subject: Enable GetRandom for Fuchsia sanitizer. Summary: Adds a true implementation of GetRandom, to be used by scudo_utils.h. Reviewers: mcgrathr, phosek, kcc, vitalybuka, cryptoad Reviewed By: mcgrathr Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D37218 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312046 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_fuchsia.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 75924536a..a6abe4391 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -480,6 +480,14 @@ uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { uptr MainThreadStackBase, MainThreadStackSize; +bool GetRandom(void *buffer, uptr length, bool blocking) { + CHECK_LE(length, MX_CPRNG_DRAW_MAX_LEN); + size_t size; + CHECK_EQ(_mx_cprng_draw(buffer, length, &size), MX_OK); + CHECK_EQ(size, length); + return true; +} + } // namespace __sanitizer using namespace __sanitizer; // NOLINT -- cgit v1.2.1 From 3b8cbd95181da5c96c0f9287b197a530414f8615 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 29 Aug 2017 21:56:56 +0000 Subject: Revert "[SanitizeCoverage] Enable stack-depth coverage for -fsanitize=fuzzer" This reverts r312026 due to bot breakage. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312047 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 5 ----- lib/sanitizer_common/sanitizer_internal_defs.h | 8 -------- test/fuzzer/deep-recursion.test | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 3c5f29b28..469656766 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -211,10 +211,5 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" -// Weak definition for code instrumented with -fsanitize-coverage=stack-depth -// and later linked with code containing a strong definition. -// E.g., -fsanitize=fuzzer-no-link -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; #endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index c7b401d4f..4b780917f 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -35,14 +35,6 @@ # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) #endif -// Mac handles TLS differently -#if SANITIZER_MAC -# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE -#else -# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ - __attribute__((tls_model("initial-exec"))) thread_local -#endif - //--------------------------- WEAK FUNCTIONS ---------------------------------// // When working with weak functions, to simplify the code and make it more // portable, when possible define a default implementation using this macro: diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index 22475f912..b99bad4c6 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,5 +1,5 @@ # Test that we can find a stack overflow REQUIRES: linux -RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t +RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 20bf9b48b412e9c33b0b21952f8c8917a4d1a670 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 29 Aug 2017 22:12:31 +0000 Subject: Restore clang_rt library name on i686-android. Summary: Recent changes canonicalized clang_rt library names to refer to "i386" on all x86 targets. Android historically uses i686. This change adds a special case to keep i686 in all clang_rt libraries when targeting Android. Reviewers: hans, mgorny, beanz Subscribers: srhines, cfe-commits, llvm-commits Differential Revision: https://reviews.llvm.org/D37278 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312048 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 966377cce..64a8e0368 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -86,6 +86,14 @@ function(add_compiler_rt_component name) add_dependencies(compiler-rt ${name}) endfunction() +macro(set_output_name output name arch) + if(ANDROID AND ${arch} STREQUAL "i386") + set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}") + else() + set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}") + endif() +endmacro() + # Adds static or shared runtime for a list of architectures and operating # systems and puts it in the proper directory in the build and install trees. # add_compiler_rt_runtime( @@ -142,15 +150,15 @@ function(add_compiler_rt_runtime name type) endif() if(type STREQUAL "STATIC") set(libname "${name}-${arch}") - set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX}) + set_output_name(output_name_${libname} ${name} ${arch}) else() set(libname "${name}-dynamic-${arch}") set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS}) set(extra_link_flags_${libname} ${TARGET_${arch}_LINK_FLAGS} ${LIB_LINK_FLAGS}) if(WIN32) - set(output_name_${libname} ${name}_dynamic-${arch}${COMPILER_RT_OS_SUFFIX}) + set_output_name(output_name_${libname} ${name}_dynamic ${arch}) else() - set(output_name_${libname} ${name}-${arch}${COMPILER_RT_OS_SUFFIX}) + set_output_name(output_name_${libname} ${name} ${arch}) endif() endif() set(sources_${libname} ${LIB_SOURCES}) -- cgit v1.2.1 From 90cb6cb18af12fdec220ea83631b515e844a6c19 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 30 Aug 2017 02:24:31 +0000 Subject: Fix for TSan unit-tests: Previous refactoring has left unit-tests in a buggy state, where they were not launched at all. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312094 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/tests/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index 324b70c94..f5e4caef2 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories(../rtl) add_custom_target(TsanUnitTests) set_target_properties(TsanUnitTests PROPERTIES - FOLDER "TSan unittests") + FOLDER "Compiler-RT Tests") set(TSAN_UNITTEST_CFLAGS ${TSAN_CFLAGS} @@ -49,9 +49,11 @@ endforeach() macro(add_tsan_unittest testname) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) if(UNIX) - foreach(arch ${ASAN_TEST_ARCH}) - generate_compiler_rt_tests(TsanUnitTests ${testname} ${arch} - SOURCES ${TEST_SOURCES} + foreach(arch ${TSAN_TEST_ARCH}) + set(TsanUnitTestsObjects) + generate_compiler_rt_tests(TsanUnitTestsObjects TsanUnitTests + "${testname}-${arch}-Test" ${arch} + SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} RUNTIME ${TSAN_TEST_RUNTIME} COMPILE_DEPS ${TEST_HEADERS} ${TSAN_RTL_HEADERS} DEPS gtest tsan -- cgit v1.2.1 From e5229ff180fc2fe4d5f8a364d66609509d959d2e Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 30 Aug 2017 17:12:57 +0000 Subject: [builtins] Prevent duplicate definitions for overridden functions Summary: Some architecture-specific function overrides (for example, i386/ashrdi3.S) duplicate generic functions (in that case, ashrdi3.c). Prevent duplicate definitions by filtering out the generic files before compiling. Reviewers: compnerd, beanz Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D37166 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312140 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTDarwinUtils.cmake | 35 +++---------------------------- cmake/Modules/CompilerRTUtils.cmake | 29 +++++++++++++++++++++++++ lib/builtins/CMakeLists.txt | 12 +++++------ 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index f64697547..7fdb111fe 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -243,35 +243,6 @@ function(darwin_lipo_libs name) endif() endfunction() -# 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. -function(darwin_filter_builtin_sources output_var exclude_or_include excluded_list) - if(exclude_or_include STREQUAL "EXCLUDE") - set(filter_action GREATER) - set(filter_value -1) - elseif(exclude_or_include STREQUAL "INCLUDE") - set(filter_action LESS) - set(filter_value 0) - else() - message(FATAL_ERROR "darwin_filter_builtin_sources called without EXCLUDE|INCLUDE") - endif() - - set(intermediate ${ARGN}) - foreach (_file ${intermediate}) - get_filename_component(_name_we ${_file} NAME_WE) - list(FIND ${excluded_list} ${_name_we} _found) - if(_found ${filter_action} ${filter_value}) - list(REMOVE_ITEM intermediate ${_file}) - elseif(${_file} MATCHES ".*/.*\\.S" OR ${_file} MATCHES ".*/.*\\.c") - get_filename_component(_name ${_file} NAME) - string(REPLACE ".S" ".c" _cname "${_name}") - list(REMOVE_ITEM intermediate ${_cname}) - endif () - endforeach () - set(${output_var} ${intermediate} PARENT_SCOPE) -endfunction() - # Generates builtin libraries for all operating systems specified in ARGN. Each # OS library is constructed by lipo-ing together single-architecture libraries. macro(darwin_add_builtin_libraries) @@ -294,7 +265,7 @@ macro(darwin_add_builtin_libraries) ARCH ${arch} MIN_VERSION ${DARWIN_${os}_BUILTIN_MIN_VER}) - darwin_filter_builtin_sources(filtered_sources + filter_builtin_sources(filtered_sources EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS ${${arch}_SOURCES}) @@ -316,7 +287,7 @@ macro(darwin_add_builtin_libraries) OS ${os} ARCH ${arch}) - darwin_filter_builtin_sources(filtered_sources + filter_builtin_sources(filtered_sources EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS ${${arch}_SOURCES}) @@ -411,7 +382,7 @@ macro(darwin_add_embedded_builtin_libraries) set(x86_64_FUNCTIONS ${common_FUNCTIONS}) foreach(arch ${DARWIN_macho_embedded_ARCHS}) - darwin_filter_builtin_sources(${arch}_filtered_sources + filter_builtin_sources(${arch}_filtered_sources INCLUDE ${arch}_FUNCTIONS ${${arch}_SOURCES}) if(NOT ${arch}_filtered_sources) diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake index 36df49fcc..63b225260 100644 --- a/cmake/Modules/CompilerRTUtils.cmake +++ b/cmake/Modules/CompilerRTUtils.cmake @@ -270,3 +270,32 @@ macro(construct_compiler_rt_default_triple) set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE FALSE) endif() endmacro() + +# 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. +function(filter_builtin_sources output_var exclude_or_include excluded_list) + if(exclude_or_include STREQUAL "EXCLUDE") + set(filter_action GREATER) + set(filter_value -1) + elseif(exclude_or_include STREQUAL "INCLUDE") + set(filter_action LESS) + set(filter_value 0) + else() + message(FATAL_ERROR "filter_builtin_sources called without EXCLUDE|INCLUDE") + endif() + + set(intermediate ${ARGN}) + foreach (_file ${intermediate}) + get_filename_component(_name_we ${_file} NAME_WE) + list(FIND ${excluded_list} ${_name_we} _found) + if(_found ${filter_action} ${filter_value}) + list(REMOVE_ITEM intermediate ${_file}) + elseif(${_file} MATCHES ".*/.*\\.S" OR ${_file} MATCHES ".*/.*\\.c") + get_filename_component(_name ${_file} NAME) + string(REPLACE ".S" ".c" _cname "${_name}") + list(REMOVE_ITEM intermediate ${_cname}) + endif () + endforeach () + set(${output_var} ${intermediate} PARENT_SCOPE) +endfunction() diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 650e9f918..6128abcbf 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -235,8 +235,8 @@ if (NOT MSVC) x86_64/floatdixf.c x86_64/floatundidf.S x86_64/floatundisf.S - x86_64/floatundixf.S - ${GENERIC_SOURCES}) + x86_64/floatundixf.S) + filter_builtin_sources(x86_64_SOURCES EXCLUDE x86_64_SOURCES "${x86_64_SOURCES};${GENERIC_SOURCES}") set(x86_64h_SOURCES ${x86_64_SOURCES}) if (WIN32) @@ -262,8 +262,8 @@ if (NOT MSVC) i386/moddi3.S i386/muldi3.S i386/udivdi3.S - i386/umoddi3.S - ${GENERIC_SOURCES}) + i386/umoddi3.S) + filter_builtin_sources(i386_SOURCES EXCLUDE i386_SOURCES "${i386_SOURCES};${GENERIC_SOURCES}") if (WIN32) set(i386_SOURCES @@ -315,8 +315,8 @@ set(arm_SOURCES arm/sync_fetch_and_xor_8.S arm/udivmodsi4.S arm/udivsi3.S - arm/umodsi3.S - ${GENERIC_SOURCES}) + arm/umodsi3.S) +filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}") set(thumb1_SOURCES arm/divsi3.S -- cgit v1.2.1 From 30b8ae261ee9071c0e9ada8b35a01bd73e8dcadb Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 30 Aug 2017 19:29:11 +0000 Subject: [fuzzer] Don't enable tests when the fuzzer isn't built Should fix: http://green.lab.llvm.org/green/job/clang-stage2-coverage-R_build/1527 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312157 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ade658a2c..2e344056f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,7 +58,10 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) # CFI tests require diagnostic mode, which is implemented in UBSan. compiler_rt_test_runtime(ubsan cfi) compiler_rt_test_runtime(sanitizer_common) - compiler_rt_test_runtime(fuzzer) + + if(COMPILER_RT_BUILD_LIBFUZZER) + compiler_rt_test_runtime(fuzzer) + endif() foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) # cfi testing is gated on ubsan -- cgit v1.2.1 From e8a60882138333d030434d915725ab304674cb8c Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 30 Aug 2017 19:40:47 +0000 Subject: Add NetBSD support in test/tsan/thread_name*.cc Summary: A snipped from the documentation of thread_setname_np(3): NAME pthread_getname_np - get and set descriptive name of a thread LIBRARY POSIX Threads Library (libpthread, -lpthread) SYNOPSIS #include int pthread_getname_np(pthread_t thread, char *name, size_t len); int pthread_setname_np(pthread_t thread, const char *name, void *arg); Sponsored by Reviewers: joerg, dvyukov, eugenis, vitalybuka, kcc Reviewed By: dvyukov Subscribers: kubamracek, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37306 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312159 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/thread_name.cc | 8 ++++++-- test/tsan/thread_name2.cc | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc index 80d30b82d..17caa62ef 100644 --- a/test/tsan/thread_name.cc +++ b/test/tsan/thread_name.cc @@ -3,10 +3,14 @@ #if defined(__linux__) #define USE_PTHREAD_SETNAME_NP __GLIBC_PREREQ(2, 12) +#define tsan_pthread_setname_np pthread_setname_np #elif defined(__FreeBSD__) #include #define USE_PTHREAD_SETNAME_NP 1 -#define pthread_setname_np pthread_set_name_np +#define tasn_pthread_setname_np pthread_set_name_np +#elif defined(__NetBSD__) +#define USE_PTHREAD_SETNAME_NP 1 +#define tsan_pthread_setname_np(a, b) pthread_setname_np((a), "%s", (void *)(b)) #else #define USE_PTHREAD_SETNAME_NP 0 #endif @@ -24,7 +28,7 @@ void *Thread1(void *x) { void *Thread2(void *x) { #if USE_PTHREAD_SETNAME_NP - pthread_setname_np(pthread_self(), "Thread2"); + tsan_pthread_setname_np(pthread_self(), "Thread2"); #else AnnotateThreadName(__FILE__, __LINE__, "Thread2"); #endif diff --git a/test/tsan/thread_name2.cc b/test/tsan/thread_name2.cc index d7ed0f0d1..9ebac29dd 100644 --- a/test/tsan/thread_name2.cc +++ b/test/tsan/thread_name2.cc @@ -6,7 +6,11 @@ #if defined(__FreeBSD__) #include -#define pthread_setname_np pthread_set_name_np +#define tsan_pthread_setname_np pthread_set_name_np +#elif defined(__NetBSD__) +#define tsan_pthread_setname_np(a, b) pthread_setname_np((a), "%s", (void *)(b)) +#else +#define tsan_pthread_setname_np pthread_setname_np #endif long long Global; @@ -18,7 +22,7 @@ void *Thread1(void *x) { } void *Thread2(void *x) { - pthread_setname_np(pthread_self(), "foobar2"); + tsan_pthread_setname_np(pthread_self(), "foobar2"); Global--; barrier_wait(&barrier); return 0; @@ -29,7 +33,7 @@ int main() { pthread_t t[2]; pthread_create(&t[0], 0, Thread1, 0); pthread_create(&t[1], 0, Thread2, 0); - pthread_setname_np(t[0], "foobar1"); + tsan_pthread_setname_np(t[0], "foobar1"); barrier_wait(&barrier); pthread_join(t[0], NULL); pthread_join(t[1], NULL); -- cgit v1.2.1 From fa6658d33ea125e983be5c94395ddc6e84e4d90b Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 30 Aug 2017 19:41:30 +0000 Subject: Add NetBSD support in tsan_interceptors.cc Summary: NetBSD is a POSIX-like BSD Operating System. Sponsored by Reviewers: joerg, kcc, vitalybuka, dvyukov, eugenis Reviewed By: dvyukov Subscribers: srhines, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37305 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312160 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 47 ++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 4c24c46eb..34f49fce5 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_posix.h" @@ -39,6 +40,13 @@ using namespace __tsan; // NOLINT #define stderr __stderrp #endif +#if SANITIZER_NETBSD +#define dirfd(dirp) (*(int *)(dirp)) +#define fileno_unlocked fileno +#define stdout __sF[1] +#define stderr __sF[2] +#endif + #if SANITIZER_ANDROID #define mallopt(a, b) #endif @@ -84,19 +92,25 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) extern "C" void *pthread_self(); extern "C" void _exit(int status); extern "C" int fileno_unlocked(void *stream); +#if !SANITIZER_NETBSD extern "C" int dirfd(void *dirp); -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID +#endif +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD extern "C" int mallopt(int param, int value); #endif +#if SANITIZER_NETBSD +extern __sanitizer_FILE **__sF; +#else extern __sanitizer_FILE *stdout, *stderr; -#if !SANITIZER_FREEBSD && !SANITIZER_MAC +#endif +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD const int PTHREAD_MUTEX_RECURSIVE = 1; const int PTHREAD_MUTEX_RECURSIVE_NP = 1; #else const int PTHREAD_MUTEX_RECURSIVE = 2; const int PTHREAD_MUTEX_RECURSIVE_NP = 2; #endif -#if !SANITIZER_FREEBSD && !SANITIZER_MAC +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD const int EPOLL_CTL_ADD = 1; #endif const int SIGILL = 4; @@ -105,7 +119,7 @@ const int SIGFPE = 8; const int SIGSEGV = 11; const int SIGPIPE = 13; const int SIGTERM = 15; -#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC +#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD const int SIGBUS = 10; const int SIGSYS = 12; #else @@ -113,7 +127,9 @@ const int SIGBUS = 7; const int SIGSYS = 31; #endif void *const MAP_FAILED = (void*)-1; -#if !SANITIZER_MAC +#if SANITIZER_NETBSD +const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567; +#elif !SANITIZER_MAC const int PTHREAD_BARRIER_SERIAL_THREAD = -1; #endif const int MAP_FIXED = 0x10; @@ -138,6 +154,15 @@ struct sigaction_t { __sanitizer_sigset_t sa_mask; void (*sa_restorer)(); }; +#elif SANITIZER_NETBSD +struct sigaction_t { + union { + sighandler_t sa_handler; + sigactionhandler_t sa_sigaction; + }; + __sanitizer_sigset_t sa_mask; + int sa_flags; +}; #else struct sigaction_t { #ifdef __mips__ @@ -166,7 +191,7 @@ struct sigaction_t { const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; const sighandler_t SIG_ERR = (sighandler_t)-1; -#if SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD const int SA_SIGINFO = 0x40; const int SIG_SETMASK = 3; #elif defined(__mips__) @@ -282,7 +307,7 @@ void ScopedInterceptor::DisableIgnores() { } #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) #else # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) @@ -459,7 +484,7 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { static void LongJmp(ThreadState *thr, uptr *env) { #ifdef __powerpc__ uptr mangled_sp = env[0]; -#elif SANITIZER_FREEBSD +#elif SANITIZER_FREEBSD || SANITIZER_NETBSD uptr mangled_sp = env[2]; #elif SANITIZER_MAC # ifdef __aarch64__ @@ -1345,7 +1370,7 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { #endif TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); @@ -1926,7 +1951,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) { sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags; internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, sizeof(sigactions[sig].sa_mask)); -#if !SANITIZER_FREEBSD && !SANITIZER_MAC +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD sigactions[sig].sa_restorer = act->sa_restorer; #endif sigaction_t newact; @@ -2288,7 +2313,7 @@ struct ScopedSyscall { } }; -#if !SANITIZER_FREEBSD && !SANITIZER_MAC +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { TSAN_SYSCALL(); MemoryAccessRange(thr, pc, p, s, write); -- cgit v1.2.1 From 2546e2f317fefb7e72208520eb2289c445c5497c Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 30 Aug 2017 22:44:11 +0000 Subject: Add preliminary NetBSD support in libfuzzer Summary: This code already works and passes some number of tests. There is need to finish remaining sanitizers to get better coverage. Many tests fail due to overly long file names of executables (>31). This is a current shortcoming of the NetBSD 8(beta) kernel, as certain functions can fail (like retrieving file name of executable). Sponsored by Reviewers: joerg, kcc, vitalybuka, george.karpenkov Reviewed By: kcc Subscribers: mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37304 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312183 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/fuzzer/FuzzerDefs.h | 10 +++++++++- lib/fuzzer/FuzzerExtFunctionsWeak.cpp | 4 ++-- lib/fuzzer/FuzzerExtraCounters.cpp | 2 +- lib/fuzzer/FuzzerUtilLinux.cpp | 4 ++-- lib/fuzzer/afl/afl_driver.cpp | 8 +++++++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index d5ef46e25..d688abccb 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -588,7 +588,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux") + OS_NAME MATCHES "Darwin|Linux|NetBSD") set(COMPILER_RT_HAS_FUZZER TRUE) else() set(COMPILER_RT_HAS_FUZZER FALSE) diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index 7ea54a920..e8c92ae3f 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -25,14 +25,22 @@ #ifdef __linux__ #define LIBFUZZER_APPLE 0 #define LIBFUZZER_LINUX 1 +#define LIBFUZZER_NETBSD 0 #define LIBFUZZER_WINDOWS 0 #elif __APPLE__ #define LIBFUZZER_APPLE 1 #define LIBFUZZER_LINUX 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_WINDOWS 0 +#elif __NetBSD__ +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_NETBSD 1 #define LIBFUZZER_WINDOWS 0 #elif _WIN32 #define LIBFUZZER_APPLE 0 #define LIBFUZZER_LINUX 0 +#define LIBFUZZER_NETBSD 0 #define LIBFUZZER_WINDOWS 1 #else #error "Support for your platform has not been implemented" @@ -42,7 +50,7 @@ # define __has_attribute(x) 0 #endif -#define LIBFUZZER_POSIX LIBFUZZER_APPLE || LIBFUZZER_LINUX +#define LIBFUZZER_POSIX (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD) #ifdef __x86_64 # if __has_attribute(target) diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp index 503f0395c..5056eb8a9 100644 --- a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp +++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp @@ -13,7 +13,7 @@ // to clients right now. //===----------------------------------------------------------------------===// #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD #include "FuzzerExtFunctions.h" #include "FuzzerIO.h" @@ -51,4 +51,4 @@ ExternalFunctions::ExternalFunctions() { } // namespace fuzzer -#endif // LIBFUZZER_LINUX +#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD diff --git a/lib/fuzzer/FuzzerExtraCounters.cpp b/lib/fuzzer/FuzzerExtraCounters.cpp index 07dbe0fde..0e7a7761b 100644 --- a/lib/fuzzer/FuzzerExtraCounters.cpp +++ b/lib/fuzzer/FuzzerExtraCounters.cpp @@ -11,7 +11,7 @@ #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD __attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters; __attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters; diff --git a/lib/fuzzer/FuzzerUtilLinux.cpp b/lib/fuzzer/FuzzerUtilLinux.cpp index dfe7e6f4e..69d46b578 100644 --- a/lib/fuzzer/FuzzerUtilLinux.cpp +++ b/lib/fuzzer/FuzzerUtilLinux.cpp @@ -9,7 +9,7 @@ // Misc utils for Linux. //===----------------------------------------------------------------------===// #include "FuzzerDefs.h" -#if LIBFUZZER_LINUX +#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD #include @@ -21,4 +21,4 @@ int ExecuteCommand(const std::string &Command) { } // namespace fuzzer -#endif // LIBFUZZER_LINUX +#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index 15bceb896..f10247947 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -68,9 +68,15 @@ statistics from the file. If that fails then the process will quit. #ifdef __linux__ #define LIBFUZZER_LINUX 1 #define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 #elif __APPLE__ #define LIBFUZZER_LINUX 0 #define LIBFUZZER_APPLE 1 +#define LIBFUZZER_NETBSD 0 +#elif __NetBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 1 #else #error "Support for your platform has not been implemented" #endif @@ -119,7 +125,7 @@ size_t GetPeakRSSMb() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) return 0; - if (LIBFUZZER_LINUX) { + if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD) { // ru_maxrss is in KiB return usage.ru_maxrss >> 10; } else if (LIBFUZZER_APPLE) { -- cgit v1.2.1 From 14bcbc22b12de9c631d93d992ae926ac99a6cd10 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 30 Aug 2017 22:47:05 +0000 Subject: Add NetBSD support in lsan_interceptors.cc Summary: NetBSD is a modern POSIX-like UNIX-like Operating System derived from 4.4BSD/386BSD. Sponsored by Reviewers: joerg, vitalybuka, kcc, dvyukov Reviewed By: kcc Subscribers: llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37307 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312184 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_interceptors.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 1aaaf1671..259c138ec 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -20,6 +20,7 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" -- cgit v1.2.1 From 1c8c066ed59bb91fba7e977d421a658b24573fc5 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Wed, 30 Aug 2017 22:49:31 +0000 Subject: [SanitizeCoverage] Enable stack-depth coverage for -fsanitize=fuzzer Summary: - Don't sanitize __sancov_lowest_stack. - Don't instrument leaf functions. - Add CoverageStackDepth to Fuzzer and FuzzerNoLink. - Only enable on Linux. Reviewers: vitalybuka, kcc, george.karpenkov Reviewed By: kcc Subscribers: kubamracek, cfe-commits, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D37156 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312185 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc | 5 +++++ lib/sanitizer_common/sanitizer_internal_defs.h | 8 ++++++++ test/asan/TestCases/Darwin/interface_symbols_darwin.c | 1 + test/asan/TestCases/Linux/interface_symbols_linux.c | 1 + test/asan/TestCases/Windows/interface_symbols_windows.c | 1 + test/fuzzer/deep-recursion.test | 2 +- 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 469656766..3c5f29b28 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -211,5 +211,10 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" +// Weak definition for code instrumented with -fsanitize-coverage=stack-depth +// and later linked with code containing a strong definition. +// E.g., -fsanitize=fuzzer-no-link +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; #endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 4b780917f..e7230e43b 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -35,6 +35,14 @@ # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) #endif +// TLS is handled differently on different platforms +#if SANITIZER_LINUX +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ + __attribute__((tls_model("initial-exec"))) thread_local +#else +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE +#endif + //--------------------------- WEAK FUNCTIONS ---------------------------------// // When working with weak functions, to simplify the code and make it more // portable, when possible define a default implementation using this macro: diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c index 09af1ece5..431de435f 100644 --- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c +++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c @@ -12,6 +12,7 @@ // RUN: | grep -v "__sanitizer_weak_hook" \ // RUN: | grep -v "__sanitizer_mz" \ // RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss" \ +// RUN: | grep -v "__sancov_lowest_stack" \ // RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ // RUN: > %t.exports // diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c index 33fdd5ca1..a8b9d37cc 100644 --- a/test/asan/TestCases/Linux/interface_symbols_linux.c +++ b/test/asan/TestCases/Linux/interface_symbols_linux.c @@ -6,6 +6,7 @@ // RUN: | grep -v "__sanitizer_syscall" \ // RUN: | grep -v "__sanitizer_weak_hook" \ // RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss" \ +// RUN: | grep -v "__sancov_lowest_stack" \ // RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ // RUN: > %t.exports // diff --git a/test/asan/TestCases/Windows/interface_symbols_windows.c b/test/asan/TestCases/Windows/interface_symbols_windows.c index a08f35872..bc2f3e883 100644 --- a/test/asan/TestCases/Windows/interface_symbols_windows.c +++ b/test/asan/TestCases/Windows/interface_symbols_windows.c @@ -38,6 +38,7 @@ // IMPORT: __asan_set_seh_filter // IMPORT: __asan_unhandled_exception_filter // IMPORT: __asan_test_only_reported_buggy_pointer +// IMPORT: __sancov_lowest_stack // // RUN: cat %t.imports1 %t.imports2 %t.imports3 | sort | uniq > %t.imports-sorted // RUN: cat %t.exports | sort | uniq > %t.exports-sorted diff --git a/test/fuzzer/deep-recursion.test b/test/fuzzer/deep-recursion.test index b99bad4c6..22475f912 100644 --- a/test/fuzzer/deep-recursion.test +++ b/test/fuzzer/deep-recursion.test @@ -1,5 +1,5 @@ # Test that we can find a stack overflow REQUIRES: linux -RUN: %cpp_compiler -fsanitize-coverage=stack-depth %S/DeepRecursionTest.cpp -o %t +RUN: %cpp_compiler %S/DeepRecursionTest.cpp -o %t RUN: not %t -seed=1 -runs=100000000 2>&1 | FileCheck %s CHECK: ERROR: libFuzzer: deadly signal -- cgit v1.2.1 From 40af6632902a9baf53ce3c4439a0a0d82c6f9f8e Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 30 Aug 2017 23:02:36 +0000 Subject: Finalize ASAN/NetBSD Summary: This revision contains various cleanups. Sponsored by Reviewers: kcc, vitalybuka, joerg, eugenis Reviewed By: kcc Subscribers: emaste, srhines, llvm-commits, kubamracek, mgorny, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D37244 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312188 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_symbolize.py | 2 +- lib/sanitizer_common/sanitizer_internal_defs.h | 4 ---- test/asan/TestCases/alloca_constant_size.cc | 2 +- test/asan/TestCases/atexit_stats.cc | 2 +- test/asan/TestCases/non-executable-pc.cpp | 4 ++-- test/asan/TestCases/verbose-log-path_test.cc | 2 +- test/sanitizer_common/CMakeLists.txt | 2 +- 7 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index d53ec3571..cd5d89ba2 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -280,7 +280,7 @@ def BreakpadSymbolizerFactory(binary): def SystemSymbolizerFactory(system, addr, binary, arch): if system == 'Darwin': return DarwinSymbolizer(addr, binary, arch) - elif system == 'Linux' or system == 'FreeBSD' or system == 'NetBSD': + elif system in ['Linux', 'FreeBSD', 'NetBSD']: return Addr2LineSymbolizer(binary) diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index e7230e43b..601f230ed 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -137,10 +137,6 @@ typedef int error_t; #endif typedef int pid_t; -// WARNING: OFF_T may be different from OS type off_t, depending on the value of -// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls -// like pread and mmap, as opposed to pread64 and mmap64. -// FreeBSD, NetBSD, Mac and Linux/x86-64 are special. #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \ (SANITIZER_LINUX && defined(__x86_64__)) typedef u64 OFF_T; diff --git a/test/asan/TestCases/alloca_constant_size.cc b/test/asan/TestCases/alloca_constant_size.cc index a766ae75b..57aa31570 100644 --- a/test/asan/TestCases/alloca_constant_size.cc +++ b/test/asan/TestCases/alloca_constant_size.cc @@ -10,7 +10,7 @@ // MSVC provides _alloca instead of alloca. #if defined(_MSC_VER) && !defined(alloca) # define alloca _alloca -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__NetBSD__) #include #else #include diff --git a/test/asan/TestCases/atexit_stats.cc b/test/asan/TestCases/atexit_stats.cc index f0b5830b4..c8d97da52 100644 --- a/test/asan/TestCases/atexit_stats.cc +++ b/test/asan/TestCases/atexit_stats.cc @@ -7,7 +7,7 @@ // UNSUPPORTED: android #include -#if !defined(__APPLE__) && !defined(__FreeBSD__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) #include #endif int *p1 = (int*)malloc(900); diff --git a/test/asan/TestCases/non-executable-pc.cpp b/test/asan/TestCases/non-executable-pc.cpp index f8adee613..6ef40540b 100644 --- a/test/asan/TestCases/non-executable-pc.cpp +++ b/test/asan/TestCases/non-executable-pc.cpp @@ -2,8 +2,8 @@ // RUN: not %run %t 0 2>&1 | FileCheck %s // RUN: not %run %t n 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=NON_EXEC -// Only Linux and FreeBSD list every memory region in MemoryMappingLayout, for now. -// REQUIRES: linux || freebsd +// Not every OS lists every memory region in MemoryMappingLayout. +// REQUIRES: linux || freebsd || netbsd #include diff --git a/test/asan/TestCases/verbose-log-path_test.cc b/test/asan/TestCases/verbose-log-path_test.cc index a63c58475..3c3db0883 100644 --- a/test/asan/TestCases/verbose-log-path_test.cc +++ b/test/asan/TestCases/verbose-log-path_test.cc @@ -8,7 +8,7 @@ // RUN: %env_asan_opts=log_path=%T/asan.log:log_exe_name=1 not %run %T/verbose-log-path_test-binary 2> %t.out // RUN: FileCheck %s --check-prefix=CHECK-ERROR < %T/asan.log.verbose-log-path_test-binary.* -// FIXME: only FreeBSD and Linux have verbose log paths now. +// FIXME: only FreeBSD, NetBSD and Linux have verbose log paths now. // XFAIL: win32,android // UNSUPPORTED: ios diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index 9b4070b0f..b716f89df 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -4,7 +4,7 @@ set(SANITIZER_COMMON_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) set(SANITIZER_COMMON_TESTSUITES) set(SUPPORTED_TOOLS) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD" AND NOT ANDROID) +if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD" AND NOT ANDROID) list(APPEND SUPPORTED_TOOLS asan) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID) -- cgit v1.2.1 From 592b221805cd5d32fd351b4d98f16305378b0811 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 31 Aug 2017 00:50:12 +0000 Subject: [XRay][compiler-rt] Enable the XRay compiler-rt unit tests. Summary: Before this change we seemed to not be running the unit tests, and therefore we set out to run them. In the process of making this happen we found a divergence between the implementation and the tests. This includes changes to both the CMake files as well as the implementation and headers of the XRay runtime. We've also updated documentation on the changed functions. Reviewers: kpw, eizan Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D37290 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312202 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/CMakeLists.txt | 11 +++++------ lib/xray/tests/unit/buffer_queue_test.cc | 4 ++-- lib/xray/tests/unit/fdr_logging_test.cc | 2 -- lib/xray/xray_buffer_queue.h | 15 +++++++++------ test/xray/Unit/lit.site.cfg.in | 2 +- test/xray/lit.site.cfg.in | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index 4ea03d37a..f88024b9f 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -11,22 +11,21 @@ set(XRAY_UNITTEST_CFLAGS -I${COMPILER_RT_SOURCE_DIR}/lib/xray -I${COMPILER_RT_SOURCE_DIR}/lib) +set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) macro(add_xray_unittest testname) - set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) - # FIXME: Figure out how to run even just the unit tests on APPLE. if(UNIX AND NOT APPLE) foreach(arch ${XRAY_TEST_ARCH}) set(TEST_OBJECTS) generate_compiler_rt_tests(TEST_OBJECTS - XRayUnitTests "${testname}-${arch}" "${arch}" + XRayUnitTests "${testname}-${arch}-Test" "${arch}" SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} - DEPS gtest_main xray + DEPS gtest xray CFLAGS ${XRAY_UNITTEST_CFLAGS} - LINK_FLAGS + LINK_FLAGS -fxray-instrument + ${TARGET_LINK_FLAGS} -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} -lpthread - -L${COMPILER_RT_LIBRARY_OUTPUT_DIR} -lclang_rt.xray-${arch} -ldl -lrt) endforeach() endif() diff --git a/lib/xray/tests/unit/buffer_queue_test.cc b/lib/xray/tests/unit/buffer_queue_test.cc index ac89a8dbc..1ec7469ce 100644 --- a/lib/xray/tests/unit/buffer_queue_test.cc +++ b/lib/xray/tests/unit/buffer_queue_test.cc @@ -68,9 +68,9 @@ TEST(BufferQueueTest, ErrorsWhenFinalising) { ASSERT_NE(nullptr, Buf.Buffer); ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok); BufferQueue::Buffer OtherBuf; - ASSERT_EQ(BufferQueue::ErrorCode::AlreadyFinalized, + ASSERT_EQ(BufferQueue::ErrorCode::QueueFinalizing, Buffers.getBuffer(OtherBuf)); - ASSERT_EQ(BufferQueue::ErrorCode::AlreadyFinalized, + ASSERT_EQ(BufferQueue::ErrorCode::QueueFinalizing, Buffers.finalize()); ASSERT_EQ(Buffers.releaseBuffer(Buf), BufferQueue::ErrorCode::Ok); } diff --git a/lib/xray/tests/unit/fdr_logging_test.cc b/lib/xray/tests/unit/fdr_logging_test.cc index 0d5e99a74..edc5e3c74 100644 --- a/lib/xray/tests/unit/fdr_logging_test.cc +++ b/lib/xray/tests/unit/fdr_logging_test.cc @@ -57,7 +57,6 @@ TEST(FDRLoggingTest, Simple) { fdrLoggingHandleArg0(1, XRayEntryType::EXIT); ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED); ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED); - ASSERT_EQ(fdrLoggingReset(), XRayLogInitStatus::XRAY_LOG_UNINITIALIZED); // To do this properly, we have to close the file descriptor then re-open the // file for reading this time. @@ -98,7 +97,6 @@ TEST(FDRLoggingTest, Multiple) { } ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED); ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED); - ASSERT_EQ(fdrLoggingReset(), XRayLogInitStatus::XRAY_LOG_UNINITIALIZED); // To do this properly, we have to close the file descriptor then re-open the // file for reading this time. diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index e051695a2..bd382a26c 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -82,15 +82,18 @@ public: /// - BufferQueue is not finalising. /// /// Returns: - /// - std::errc::not_enough_memory on exceeding MaxSize. - /// - no error when we find a Buffer. - /// - std::errc::state_not_recoverable on finalising BufferQueue. + /// - ErrorCode::NotEnoughMemory on exceeding MaxSize. + /// - ErrorCode::Ok when we find a Buffer. + /// - ErrorCode::QueueFinalizing or ErrorCode::AlreadyFinalized on + /// a finalizing/finalized BufferQueue. ErrorCode getBuffer(Buffer &Buf); /// Updates |Buf| to point to nullptr, with size 0. /// /// Returns: - /// - ... + /// - ErrorCode::Ok when we successfully release the buffer. + /// - ErrorCode::UnrecognizedBuffer for when this BufferQueue does not own + /// the buffer being released. ErrorCode releaseBuffer(Buffer &Buf); bool finalizing() const { @@ -107,12 +110,12 @@ public: /// - All releaseBuffer operations will not fail. /// /// After a call to finalize succeeds, all subsequent calls to finalize will - /// fail with std::errc::state_not_recoverable. + /// fail with ErrorCode::QueueFinalizing. ErrorCode finalize(); /// Applies the provided function F to each Buffer in the queue, only if the /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a - /// releaseBuffer(...) operation. + /// releaseBuffer(...) operation). template void apply(F Fn) { __sanitizer::BlockingMutexLock G(&Mutex); for (const auto &T : Buffers) { diff --git a/test/xray/Unit/lit.site.cfg.in b/test/xray/Unit/lit.site.cfg.in index 75ea8889b..be860deaf 100644 --- a/test/xray/Unit/lit.site.cfg.in +++ b/test/xray/Unit/lit.site.cfg.in @@ -13,4 +13,4 @@ config.test_source_root = config.test_exec_root # Do not patch the XRay unit tests pre-main, and also make the error logging # verbose to get a more accurate error logging mechanism. -config.environment['XRAY_OPTIONS'] = 'patch_premain=false verbose=1' +config.environment['XRAY_OPTIONS'] = 'patch_premain=false' diff --git a/test/xray/lit.site.cfg.in b/test/xray/lit.site.cfg.in index 73c4eff6e..bc4acb6d3 100644 --- a/test/xray/lit.site.cfg.in +++ b/test/xray/lit.site.cfg.in @@ -17,4 +17,4 @@ if config.built_with_llvm: lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") # Load tool-specific config that would do the real work. -lit_config.load_config(config, "@XRAY_LIT_SOURCE_DIR@/lit.cfg") +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") -- cgit v1.2.1 From 8fd4da6e76ef4d33c9b35e6007230b23680a880b Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 31 Aug 2017 00:54:10 +0000 Subject: [ubsan] Give ubsan-minimal lit test suite a name. Otherwise llvm-lit -v prints this: PASS: :: TestCases/recover-dedup-limit.cpp (1 of 3) PASS: :: TestCases/recover-dedup.cpp (2 of 3) PASS: :: TestCases/uadd-overflow.cpp (3 of 3) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312203 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/lit.common.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index df0643cd7..45db6a6f6 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -13,6 +13,7 @@ def get_required_attr(config, attr_name): # Setup source root. config.test_source_root = os.path.dirname(__file__) +config.name = 'UBSan-Minimal-' + config.target_arch def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " -- cgit v1.2.1 From 1c3df8c3b6deb2547abd998c3f688c7d56494333 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Thu, 31 Aug 2017 10:01:36 +0000 Subject: [cmake] Fix the list of arm32 architectures This was accidentally changed in SVN r311924, which was only supposed to change the behaviour for x86. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312230 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/builtin-config-ix.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake index 540ec0792..162ead145 100644 --- a/cmake/builtin-config-ix.cmake +++ b/cmake/builtin-config-ix.cmake @@ -25,7 +25,6 @@ int foo(int x, int y) { set(ARM64 aarch64) set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k) -set(ARM32 arm armhf) set(X86 i386) set(X86_64 x86_64) set(MIPS32 mips mipsel) -- cgit v1.2.1 From 72a53283924a94115e513ffdf7a11582b60bf4b1 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 31 Aug 2017 13:23:24 +0000 Subject: Build LLVM with -Wstrict-prototypes enabled Clang 5 supports -Wstrict-prototypes. We should use it to catch any C declarations that declare a non-prototype function. rdar://33705313 Differential Revision: https://reviews.llvm.org/D36669 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312240 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/GCDAProfiling.c | 4 ++-- lib/profile/InstrProfiling.h | 6 +++--- lib/profile/InstrProfilingFile.c | 2 +- lib/profile/InstrProfilingInternal.h | 10 +++++----- lib/profile/InstrProfilingUtil.h | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index 138af6ec4..eb8a937f3 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -92,7 +92,7 @@ static int fd = -1; /* * A list of functions to write out the data. */ -typedef void (*writeout_fn)(); +typedef void (*writeout_fn)(void); struct writeout_fn_node { writeout_fn fn; @@ -105,7 +105,7 @@ static struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. */ -typedef void (*flush_fn)(); +typedef void (*flush_fn)(void); struct flush_fn_node { flush_fn fn; diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h index 945f1c4ac..a644d6a8d 100644 --- a/lib/profile/InstrProfiling.h +++ b/lib/profile/InstrProfiling.h @@ -63,8 +63,8 @@ const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); -ValueProfNode *__llvm_profile_begin_vnodes(); -ValueProfNode *__llvm_profile_end_vnodes(); +ValueProfNode *__llvm_profile_begin_vnodes(void); +ValueProfNode *__llvm_profile_end_vnodes(void); /*! * \brief Clear profile counters to zero. @@ -164,7 +164,7 @@ void __llvm_profile_initialize_file(void); * merge mode is turned on for instrumented programs with shared libs). * Side-effect: this API call will invoke malloc with dynamic memory allocation. */ -const char *__llvm_profile_get_path_prefix(); +const char *__llvm_profile_get_path_prefix(void); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index 8ae2b7d98..7ee004af6 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -86,7 +86,7 @@ COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, 0, 0, 0, PNS_unknown}; int getpid(void); -static int getCurFilenameLength(); +static int getCurFilenameLength(void); static const char *getCurFilename(char *FilenameBuf); static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } diff --git a/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h index 36490ef7d..18783a768 100644 --- a/lib/profile/InstrProfilingInternal.h +++ b/lib/profile/InstrProfilingInternal.h @@ -155,27 +155,27 @@ int lprofWriteDataImpl(ProfDataWriter *Writer, void lprofMergeValueProfData(struct ValueProfData *SrcValueProfData, __llvm_profile_data *DstData); -VPDataReaderType *lprofGetVPDataReader(); +VPDataReaderType *lprofGetVPDataReader(void); /* Internal interface used by test to reset the max number of * tracked values per value site to be \p MaxVals. */ void lprofSetMaxValsPerSite(uint32_t MaxVals); -void lprofSetupValueProfiler(); +void lprofSetupValueProfiler(void); /* Return the profile header 'signature' value associated with the current * executable or shared library. The signature value can be used to for * a profile name that is unique to this load module so that it does not * collide with profiles from other binaries. It also allows shared libraries * to dump merged profile data into its own profile file. */ -uint64_t lprofGetLoadModuleSignature(); +uint64_t lprofGetLoadModuleSignature(void); /* * Return non zero value if the profile data has already been * dumped to the file. */ -unsigned lprofProfileDumped(); -void lprofSetProfileDumped(); +unsigned lprofProfileDumped(void); +void lprofSetProfileDumped(void); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h index 969859960..fdbfd4a27 100644 --- a/lib/profile/InstrProfilingUtil.h +++ b/lib/profile/InstrProfilingUtil.h @@ -54,9 +54,9 @@ void *lprofPtrFetchAdd(void **Mem, long ByteIncr); /* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed. * Other return values mean no restore is needed. */ -int lprofSuspendSigKill(); +int lprofSuspendSigKill(void); /* Restore previously suspended SIGKILL. */ -void lprofRestoreSigKill(); +void lprofRestoreSigKill(void); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ -- cgit v1.2.1 From 907e59854ac144ef0760d4c40ca3359481d511a1 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 31 Aug 2017 15:51:23 +0000 Subject: Revert r312240 The buildbots have shown that -Wstrict-prototypes behaves differently in GCC and Clang so we should keep it disabled until Clang follows GCC's behaviour git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312246 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/GCDAProfiling.c | 4 ++-- lib/profile/InstrProfiling.h | 6 +++--- lib/profile/InstrProfilingFile.c | 2 +- lib/profile/InstrProfilingInternal.h | 10 +++++----- lib/profile/InstrProfilingUtil.h | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index eb8a937f3..138af6ec4 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -92,7 +92,7 @@ static int fd = -1; /* * A list of functions to write out the data. */ -typedef void (*writeout_fn)(void); +typedef void (*writeout_fn)(); struct writeout_fn_node { writeout_fn fn; @@ -105,7 +105,7 @@ static struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. */ -typedef void (*flush_fn)(void); +typedef void (*flush_fn)(); struct flush_fn_node { flush_fn fn; diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h index a644d6a8d..945f1c4ac 100644 --- a/lib/profile/InstrProfiling.h +++ b/lib/profile/InstrProfiling.h @@ -63,8 +63,8 @@ const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); -ValueProfNode *__llvm_profile_begin_vnodes(void); -ValueProfNode *__llvm_profile_end_vnodes(void); +ValueProfNode *__llvm_profile_begin_vnodes(); +ValueProfNode *__llvm_profile_end_vnodes(); /*! * \brief Clear profile counters to zero. @@ -164,7 +164,7 @@ void __llvm_profile_initialize_file(void); * merge mode is turned on for instrumented programs with shared libs). * Side-effect: this API call will invoke malloc with dynamic memory allocation. */ -const char *__llvm_profile_get_path_prefix(void); +const char *__llvm_profile_get_path_prefix(); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index 7ee004af6..8ae2b7d98 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -86,7 +86,7 @@ COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, 0, 0, 0, PNS_unknown}; int getpid(void); -static int getCurFilenameLength(void); +static int getCurFilenameLength(); static const char *getCurFilename(char *FilenameBuf); static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } diff --git a/lib/profile/InstrProfilingInternal.h b/lib/profile/InstrProfilingInternal.h index 18783a768..36490ef7d 100644 --- a/lib/profile/InstrProfilingInternal.h +++ b/lib/profile/InstrProfilingInternal.h @@ -155,27 +155,27 @@ int lprofWriteDataImpl(ProfDataWriter *Writer, void lprofMergeValueProfData(struct ValueProfData *SrcValueProfData, __llvm_profile_data *DstData); -VPDataReaderType *lprofGetVPDataReader(void); +VPDataReaderType *lprofGetVPDataReader(); /* Internal interface used by test to reset the max number of * tracked values per value site to be \p MaxVals. */ void lprofSetMaxValsPerSite(uint32_t MaxVals); -void lprofSetupValueProfiler(void); +void lprofSetupValueProfiler(); /* Return the profile header 'signature' value associated with the current * executable or shared library. The signature value can be used to for * a profile name that is unique to this load module so that it does not * collide with profiles from other binaries. It also allows shared libraries * to dump merged profile data into its own profile file. */ -uint64_t lprofGetLoadModuleSignature(void); +uint64_t lprofGetLoadModuleSignature(); /* * Return non zero value if the profile data has already been * dumped to the file. */ -unsigned lprofProfileDumped(void); -void lprofSetProfileDumped(void); +unsigned lprofProfileDumped(); +void lprofSetProfileDumped(); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h index fdbfd4a27..969859960 100644 --- a/lib/profile/InstrProfilingUtil.h +++ b/lib/profile/InstrProfilingUtil.h @@ -54,9 +54,9 @@ void *lprofPtrFetchAdd(void **Mem, long ByteIncr); /* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed. * Other return values mean no restore is needed. */ -int lprofSuspendSigKill(void); +int lprofSuspendSigKill(); /* Restore previously suspended SIGKILL. */ -void lprofRestoreSigKill(void); +void lprofRestoreSigKill(); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ -- cgit v1.2.1 From fcb6aa26f41fd7544842e5d45ef4a125439a04af Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 31 Aug 2017 19:17:15 +0000 Subject: [libFuzzer] tolerate missing files when loading the seed corpus git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312269 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 97fc31cc8..0354fc86e 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -638,7 +638,7 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { // Load and execute inputs one by one. for (auto &SF : SizedFiles) { - auto U = FileToVector(SF.File, MaxInputLen); + auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false); assert(U.size() <= MaxInputLen); RunOne(U.data(), U.size()); CheckExitOnSrcPosOrItem(); -- cgit v1.2.1 From c7cde8a5c61d9fe2a74e6e95b114e1022e7cccba Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 31 Aug 2017 22:26:34 +0000 Subject: [ubsan] Make check-ubsan depend on check-ubsan-minimal. Summary: This way we don't need to add check-ubsan-minimal steps to all the bots. Reviewers: vitalybuka Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D37350 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312291 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2e344056f..341618554 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,6 +71,10 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) endforeach() compiler_rt_test_runtime(profile) + + if(COMPILER_RT_HAS_UBSAN AND COMPILER_RT_HAS_UBSAN_MINIMAL) + add_dependencies(check-ubsan check-ubsan-minimal) + endif() endif() if(COMPILER_RT_BUILD_XRAY) compiler_rt_test_runtime(xray) -- cgit v1.2.1 From 9f4b0100b5010d440adc4ca02dd8f5859e841dc1 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 31 Aug 2017 23:34:01 +0000 Subject: Revert "[ubsan] Make check-ubsan depend on check-ubsan-minimal." Breaks buildbot with CMake Error at projects/compiler-rt/test/CMakeLists.txt:76 (add_dependencies): The dependency target "check-ubsan-minimal" of target "check-ubsan" does not exist. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312295 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 341618554..2e344056f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,10 +71,6 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) endforeach() compiler_rt_test_runtime(profile) - - if(COMPILER_RT_HAS_UBSAN AND COMPILER_RT_HAS_UBSAN_MINIMAL) - add_dependencies(check-ubsan check-ubsan-minimal) - endif() endif() if(COMPILER_RT_BUILD_XRAY) compiler_rt_test_runtime(xray) -- cgit v1.2.1 From dd9106706dd579555ea86010071f849c379c0993 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Fri, 1 Sep 2017 17:13:26 +0000 Subject: [libFuzzer] Enable 8-bit counters test on macOS git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312339 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/inline-8bit-counters.test | 1 - 1 file changed, 1 deletion(-) diff --git a/test/fuzzer/inline-8bit-counters.test b/test/fuzzer/inline-8bit-counters.test index 5723c70b1..76ae1f537 100644 --- a/test/fuzzer/inline-8bit-counters.test +++ b/test/fuzzer/inline-8bit-counters.test @@ -1,4 +1,3 @@ -REQUIRES: linux RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters -o %t-SimpleTest-Inline8bitCounters CHECK: INFO: Loaded 1 modules ({{.*}} inline 8-bit counters) CHECK: BINGO -- cgit v1.2.1 From 665cb4327b786b6869753488a69b9993373110ef Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 1 Sep 2017 19:45:08 +0000 Subject: [libFuzzer] use more iterations for a test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312356 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/fuzzer-customcrossover.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index 8f74cd98f..f0291996b 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -4,7 +4,7 @@ RUN: rm -rf %t/CustomCrossover RUN: mkdir -p %t/CustomCrossover RUN: echo "0123456789" > %t/CustomCrossover/digits RUN: echo "abcdefghij" > %t/CustomCrossover/chars -RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover +RUN: not %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover RUN: rm -rf %t/CustomCrossover LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover -- cgit v1.2.1 From 160179b335b9dd2c22b151e5eb0aff983db202db Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 1 Sep 2017 23:23:59 +0000 Subject: [cmake] Work around -Wunused-driver-argument warnings Fix the Darwin logic so that -msse3 is only used on macOS, and -fomit-frame-pointer is not used on armv7/armv7k/armv7s. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312390 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 8 ++++++++ cmake/Modules/CompilerRTDarwinUtils.cmake | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 64a8e0368..032b43723 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -125,8 +125,16 @@ function(add_compiler_rt_runtime name type) else() set(NO_LTO_FLAGS "") endif() + if(APPLE) foreach(os ${LIB_OS}) + # Strip out -msse3 if this isn't macOS. + message(WARNING "BEFORE: ${LIB_CFLAGS}") + list(LENGTH LIB_CFLAGS HAS_EXTRA_CFLAGS) + if(HAS_EXTRA_CFLAGS AND NOT "${os}" MATCHES "^(osx)$") + list(REMOVE_ITEM LIB_CFLAGS "-msse3") + endif() + message(WARNING "AFTER: ${LIB_CFLAGS}") if(type STREQUAL "STATIC") set(libname "${name}_${os}") else() diff --git a/cmake/Modules/CompilerRTDarwinUtils.cmake b/cmake/Modules/CompilerRTDarwinUtils.cmake index 7fdb111fe..a25540bf4 100644 --- a/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -200,10 +200,23 @@ macro(darwin_add_builtin_library name suffix) if(DARWIN_${LIB_OS}_SYSROOT) set(sysroot_flag -isysroot ${DARWIN_${LIB_OS}_SYSROOT}) endif() + + # Make a copy of the compilation flags. + set(builtin_cflags ${LIB_CFLAGS}) + + # Strip out any inappropriate flags for the target. + if("${LIB_ARCH}" MATCHES "^(armv7|armv7k|armv7s)$") + set(builtin_cflags "") + foreach(cflag "${LIB_CFLAGS}") + string(REPLACE "-fomit-frame-pointer" "" cflag "${cflag}") + list(APPEND builtin_cflags ${cflag}) + endforeach(cflag) + endif() + set_target_compile_flags(${libname} ${sysroot_flag} ${DARWIN_${LIB_OS}_BUILTIN_MIN_VER_FLAG} - ${LIB_CFLAGS}) + ${builtin_cflags}) set_property(TARGET ${libname} APPEND PROPERTY COMPILE_DEFINITIONS ${LIB_DEFS}) set_target_properties(${libname} PROPERTIES -- cgit v1.2.1 From b66aeedd0667813d305f4c4091c53d22da094c7a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 1 Sep 2017 23:49:22 +0000 Subject: [cmake] Remove accidentally committed warning messages git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312393 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 032b43723..622292ede 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -129,12 +129,10 @@ function(add_compiler_rt_runtime name type) if(APPLE) foreach(os ${LIB_OS}) # Strip out -msse3 if this isn't macOS. - message(WARNING "BEFORE: ${LIB_CFLAGS}") list(LENGTH LIB_CFLAGS HAS_EXTRA_CFLAGS) if(HAS_EXTRA_CFLAGS AND NOT "${os}" MATCHES "^(osx)$") list(REMOVE_ITEM LIB_CFLAGS "-msse3") endif() - message(WARNING "AFTER: ${LIB_CFLAGS}") if(type STREQUAL "STATIC") set(libname "${name}_${os}") else() -- cgit v1.2.1 From 712b1f9fc2d31db617f72fb4432676f6054506af Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Fri, 1 Sep 2017 23:57:34 +0000 Subject: Fix constant-logical-operand warning. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312394 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_stack.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h index 324cd3ddd..9f7b102c6 100644 --- a/lib/asan/asan_stack.h +++ b/lib/asan/asan_stack.h @@ -44,8 +44,9 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() // yields the call stack of the signal's handler and not of the code // that raised the signal (as it does on Linux). - if ((SANITIZER_FREEBSD || SANITIZER_NETBSD) && t->isInDeadlySignal()) - fast = true; +#if SANITIZER_FREEBSD || SANITIZER_NETBSD + if (t->isInDeadlySignal()) fast = true; +#endif uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); -- cgit v1.2.1 From 547f9dadc814bbf52420f4edac6ccd56b4e950b3 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 2 Sep 2017 00:09:57 +0000 Subject: (NFC) Fix the use of do{}while(0) in a macro. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312396 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index b5d22baca..08eb261aa 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -109,7 +109,7 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { #define CHECK_UNPOISONED(x, n) \ do { \ if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \ - } while (0); + } while (0) #define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \ CHECK_UNPOISONED((x), \ @@ -134,7 +134,7 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { ENSURE_MSAN_INITED(); - CHECK_UNPOISONED_STRING(path, 0) + CHECK_UNPOISONED_STRING(path, 0); SSIZE_T res = REAL(readlink)(path, buf, bufsiz); if (res > 0) __msan_unpoison(buf, res); @@ -601,7 +601,7 @@ static void UnpoisonEnviron() { INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) { ENSURE_MSAN_INITED(); - CHECK_UNPOISONED_STRING(name, 0) + CHECK_UNPOISONED_STRING(name, 0); int res = REAL(setenv)(name, value, overwrite); if (!res) UnpoisonEnviron(); return res; -- cgit v1.2.1 From ad3d7d644c42e6ec6ae448800574d837d10dde86 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 5 Sep 2017 21:08:56 +0000 Subject: [msan] Check sigset_t and sigaction arguments. Summary: Check sigset_t arguments in ppoll, sig*wait*, sigprocmask interceptors, and the entire "struct sigaction" in sigaction. This can be done because sigemptyset/sigfullset are intercepted and signal masks should be correctly marked as initialized. Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D37367 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312576 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 10 +++++ .../sanitizer_common_interceptors.inc | 10 ++--- test/msan/Linux/poll.cc | 42 +++++++++++++++++++ test/msan/sigaction.cc | 47 ++++++++++++++++++++++ test/msan/sigwait.cc | 7 +++- 5 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 test/msan/Linux/poll.cc create mode 100644 test/msan/sigaction.cc diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 08eb261aa..916e25557 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -983,11 +983,21 @@ static void SignalAction(int signo, void *si, void *uc) { cb(signo, si, uc); } +static void read_sigaction(const __sanitizer_sigaction *act) { + CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags)); + if (act->sa_flags & __sanitizer::sa_siginfo) + CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction)); + else + CHECK_UNPOISONED(&act->handler, sizeof(act->handler)); + CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask)); +} + INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { ENSURE_MSAN_INITED(); // FIXME: check that *act is unpoisoned. // That requires intercepting all of sigemptyset, sigfillset, etc. + if (act) read_sigaction(act); int res; if (flags()->wrap_signals) { SpinMutexLock lock(&sigactions_mu); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index e6f0f1129..b9c182e65 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3589,7 +3589,7 @@ INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, if (fds && nfds) read_pollfd(ctx, fds, nfds); if (timeout_ts) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz); - // FIXME: read sigmask when all of sigemptyset, etc are intercepted. + if (sigmask) COMMON_INTERCEPTOR_READ_RANGE(ctx, sigmask, sizeof(*sigmask)); int res = COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask); if (fds && nfds) write_pollfd(ctx, fds, nfds); @@ -3630,7 +3630,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig); - // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. @@ -3647,7 +3647,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info); - // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. @@ -3666,7 +3666,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout); if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); - // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. @@ -3729,7 +3729,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); - // FIXME: read sigset_t when all of sigemptyset, etc are intercepted + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. diff --git a/test/msan/Linux/poll.cc b/test/msan/Linux/poll.cc new file mode 100644 index 000000000..7870d18e0 --- /dev/null +++ b/test/msan/Linux/poll.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_msan -O0 -std=c++11 -g %s -o %t +// RUN: %run %t _ 2>&1 | FileCheck %s --check-prefix=CLEAN +// RUN: not %run %t A 2>&1 | FileCheck %s --check-prefix=A +// RUN: not %run %t B 2>&1 | FileCheck %s --check-prefix=B + +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) { + char T = argv[1][0]; + + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 1000; + int res = ppoll(nullptr, 0, &ts, nullptr); + assert(res == 0); + + if (T == 'A') { + __msan_poison(&ts.tv_sec, sizeof(ts.tv_sec)); + ppoll(nullptr, 0, &ts, nullptr); + // A: use-of-uninitialized-value + } + + // A-NOT: ==1 + // B: ==1 + fprintf(stderr, "==1\n"); + + sigset_t sig; + if (T != 'B') + sigemptyset(&sig); + ppoll(nullptr, 0, &ts, &sig); + // B: use-of-uninitialized-value + + // B-NOT: ==2 + // CLEAN: ==2 + fprintf(stderr, "==2\n"); + return 0; +} diff --git a/test/msan/sigaction.cc b/test/msan/sigaction.cc new file mode 100644 index 000000000..0c69f115f --- /dev/null +++ b/test/msan/sigaction.cc @@ -0,0 +1,47 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t +// RUN: %run %t __ +// RUN: not %run %t A_ 2>&1 | FileCheck %s +// RUN: not %run %t AH 2>&1 | FileCheck %s +// RUN: not %run %t B_ 2>&1 | FileCheck %s +// RUN: not %run %t BH 2>&1 | FileCheck %s +// RUN: not %run %t C_ 2>&1 | FileCheck %s +// RUN: not %run %t CH 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include + +#include + +void handler(int) {} +void action(int, siginfo_t *, void *) {} + +int main(int argc, char **argv) { + char T = argv[1][0]; + char H = argv[1][1]; + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + if (H == 'H') { + sa.sa_handler = handler; + } else { + sa.sa_sigaction = action; + sa.sa_flags = SA_SIGINFO; + } + + if (T == 'A') { + if (H == 'H') + __msan_poison(&sa.sa_handler, sizeof(sa.sa_handler)); + else + __msan_poison(&sa.sa_sigaction, sizeof(sa.sa_sigaction)); + } + if (T == 'B') + __msan_poison(&sa.sa_flags, sizeof(sa.sa_flags)); + if (T == 'C') + __msan_poison(&sa.sa_mask, sizeof(sa.sa_mask)); + // CHECK: use-of-uninitialized-value + int res = sigaction(SIGUSR1, &sa, nullptr); + assert(res == 0); + return 0; +} diff --git a/test/msan/sigwait.cc b/test/msan/sigwait.cc index f2e77cfd6..222fc34a1 100644 --- a/test/msan/sigwait.cc +++ b/test/msan/sigwait.cc @@ -1,16 +1,21 @@ // RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -DPOSITIVE -std=c++11 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s #include -#include #include #include #include +#include + void test_sigwait() { sigset_t s; +#ifndef POSITIVE sigemptyset(&s); sigaddset(&s, SIGUSR1); +#endif sigprocmask(SIG_BLOCK, &s, 0); + // CHECK: MemorySanitizer: use-of-uninitialized-value if (pid_t pid = fork()) { kill(pid, SIGUSR1); -- cgit v1.2.1 From efa83bbf680f0948a9879a4a5bb22a61f411ca1a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 5 Sep 2017 21:51:20 +0000 Subject: Remove ld.config.txt for Android O. ld.config.txt defines linker namespaces in a way that is incompatible with ASan. Remove the file when installing ASan on an Android O (8.0.x) device. Patch by Jiyong Park. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312581 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/scripts/asan_device_setup | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index ac286d103..ec19899a5 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -181,6 +181,17 @@ if [[ -n $ARCH64 ]]; then ASAN_RT64="libclang_rt.asan-$ARCH64-android.so" fi +RELEASE=$(adb_shell getprop ro.build.version.release) +PRE_L=0 +if echo "$RELEASE" | grep '^4\.' >&/dev/null; then + PRE_L=1 +fi +ANDROID_O=0 +if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then + # 8.0.x is for Android O + ANDROID_O=1 +fi + if [[ x$revert == xyes ]]; then echo '>> Uninstalling ASan' @@ -202,6 +213,10 @@ if [[ x$revert == xyes ]]; then adb_shell ln -s /system/bin/app_process32 /system/bin/app_process fi + if [[ ANDROID_O -eq 1 ]]; then + adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt + fi + echo '>> Restarting shell' adb_shell stop adb_shell start @@ -251,12 +266,6 @@ TMPDIROLD="$TMPDIRBASE/old" TMPDIR="$TMPDIRBASE/new" mkdir "$TMPDIROLD" -RELEASE=$(adb_shell getprop ro.build.version.release) -PRE_L=0 -if echo "$RELEASE" | grep '^4\.' >&/dev/null; then - PRE_L=1 -fi - if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then @@ -427,6 +436,11 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then adb_shell cp /system/bin/sh /system/bin/sh-from-zygote adb_shell chcon $CTX /system/bin/sh-from-zygote + if [[ ANDROID_O -eq 1 ]]; then + # For Android O, the linker namespace is temporarily disabled. + adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved + fi + if [ $ENFORCING == 1 ]; then adb_shell setenforce 1 fi -- cgit v1.2.1 From 673bb37747d5acb6bd0a73b49a998bb9b75e8857 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 5 Sep 2017 23:45:54 +0000 Subject: [libFuzzer] remporary disable an unstable test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312593 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/fuzzer-customcrossover.test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index f0291996b..942e166ea 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -4,7 +4,10 @@ RUN: rm -rf %t/CustomCrossover RUN: mkdir -p %t/CustomCrossover RUN: echo "0123456789" > %t/CustomCrossover/digits RUN: echo "abcdefghij" > %t/CustomCrossover/chars -RUN: not %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover +TODO: make this test more stable (currently, the target can be found by usual strcmp magic) +DISABLED: not %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover +RUN: echo In LLVMFuzzerCustomCrossover +RUN: echo BINGO RUN: rm -rf %t/CustomCrossover LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover -- cgit v1.2.1 From 0a1d98c7666ea56fe9544c94c21a67cdcc7b1383 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 6 Sep 2017 00:00:46 +0000 Subject: [sanitizer_common][Fuchsia] Update Fuchsia sanitizer markup Include URLs to the markup format specification in code comments. Use sanitizer markup in the sancov message about a dump just produced. Patch by Roland McGrath Differential Revision: https://reviews.llvm.org/D37273 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312596 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_coverage_fuchsia.cc | 11 +++++++---- lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc index 491d5a215..4d20bb2ed 100644 --- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -96,10 +96,13 @@ class TracePcGuardController { __sanitizer_publish_data(kSancovSinkName, vmo_); vmo_ = MX_HANDLE_INVALID; - // This will route to __sanitizer_log_write, which will ensure - // that information about shared libraries is written out. - Printf("SanitizerCoverage: published '%s' with up to %u PCs\n", vmo_name_, - next_index_ - 1); + // This will route to __sanitizer_log_write, which will ensure that + // information about shared libraries is written out. This message + // uses the `dumpfile` symbolizer markup element to highlight the + // dump. See the explanation for this in: + // https://fuchsia.googlesource.com/magenta/+/master/docs/symbolizer_markup.md + Printf("SanitizerCoverage: {{{dumpfile:%s:%s}}} with up to %u PCs\n", + kSancovSinkName, vmo_name_, next_index_ - 1); } } diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc index 8e383dd8f..942029254 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc @@ -25,8 +25,8 @@ namespace __sanitizer { // symbol names, embedded in Fuchsia's symbolization markup format. // Fuchsia's logging infrastructure emits enough information about // process memory layout that a post-processing filter can do the -// symbolization and pretty-print the markup. -// TODO(mcgrathr): URL to markup format document +// symbolization and pretty-print the markup. See the spec at: +// https://fuchsia.googlesource.com/magenta/+/master/docs/symbolizer_markup.md // This is used by UBSan for type names, and by ASan for global variable names. constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; -- cgit v1.2.1 From b0d00907ee528fe76cb4bac2f026cbfb4ac83022 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 6 Sep 2017 00:28:52 +0000 Subject: [msan] Remove a stale fixme (NFC). It was fixed in 312576. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312597 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 916e25557..4bf7fcbee 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -995,8 +995,6 @@ static void read_sigaction(const __sanitizer_sigaction *act) { INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { ENSURE_MSAN_INITED(); - // FIXME: check that *act is unpoisoned. - // That requires intercepting all of sigemptyset, sigfillset, etc. if (act) read_sigaction(act); int res; if (flags()->wrap_signals) { -- cgit v1.2.1 From 3bf34db38678fbb8dbb508e171c3ce1aa9d96c04 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Wed, 6 Sep 2017 10:17:29 +0000 Subject: [compiler-rt][xray][mips] Mark some tests as unsupported. Thesee tests require the integrated assembler which is still in development / testing for MIPS64. GAS doesn't understand the section directives produced by XRay, so marking the relevant tests as unsupported. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312628 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/argv0-log-file-name.cc | 2 ++ test/xray/TestCases/Linux/coverage-sample.cc | 2 ++ test/xray/TestCases/Linux/fixedsize-logging.cc | 2 ++ test/xray/TestCases/Linux/func-id-utils.cc | 2 ++ test/xray/TestCases/Linux/optional-inmemory-log.cc | 2 ++ test/xray/TestCases/Linux/patching-unpatching.cc | 2 ++ test/xray/TestCases/Linux/pic_test.cc | 2 ++ 7 files changed, 14 insertions(+) diff --git a/test/xray/TestCases/Linux/argv0-log-file-name.cc b/test/xray/TestCases/Linux/argv0-log-file-name.cc index 2960c5718..2f9a234f8 100644 --- a/test/xray/TestCases/Linux/argv0-log-file-name.cc +++ b/test/xray/TestCases/Linux/argv0-log-file-name.cc @@ -6,6 +6,8 @@ // RUN: ls | FileCheck xray.log.file.name // RUN: rm xray-log.* xray.log.file.name +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include #include diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Linux/coverage-sample.cc index 623b4e345..9ec22dcd6 100644 --- a/test/xray/TestCases/Linux/coverage-sample.cc +++ b/test/xray/TestCases/Linux/coverage-sample.cc @@ -3,6 +3,8 @@ // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include "xray/xray_interface.h" #include diff --git a/test/xray/TestCases/Linux/fixedsize-logging.cc b/test/xray/TestCases/Linux/fixedsize-logging.cc index eb32afe93..a2a41ce60 100644 --- a/test/xray/TestCases/Linux/fixedsize-logging.cc +++ b/test/xray/TestCases/Linux/fixedsize-logging.cc @@ -7,6 +7,8 @@ // // RUN: rm fixedsize-logging-* +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include [[clang::xray_always_instrument]] void foo() { diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc index 17185c34c..412753666 100644 --- a/test/xray/TestCases/Linux/func-id-utils.cc +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -4,6 +4,8 @@ // RUN: %clangxx_xray -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include "xray/xray_interface.h" #include #include diff --git a/test/xray/TestCases/Linux/optional-inmemory-log.cc b/test/xray/TestCases/Linux/optional-inmemory-log.cc index f459d5ab8..feaaa4124 100644 --- a/test/xray/TestCases/Linux/optional-inmemory-log.cc +++ b/test/xray/TestCases/Linux/optional-inmemory-log.cc @@ -8,6 +8,8 @@ // // RUN: rm -f optional-inmemory-log.xray-* +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include [[clang::xray_always_instrument]] void foo() { diff --git a/test/xray/TestCases/Linux/patching-unpatching.cc b/test/xray/TestCases/Linux/patching-unpatching.cc index 05478a488..a7ea58f6d 100644 --- a/test/xray/TestCases/Linux/patching-unpatching.cc +++ b/test/xray/TestCases/Linux/patching-unpatching.cc @@ -4,6 +4,8 @@ // RUN: %clangxx_xray -fxray-instrument -std=c++11 %s -o %t // RUN: XRAY_OPTIONS="patch_premain=false" %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include "xray/xray_interface.h" #include diff --git a/test/xray/TestCases/Linux/pic_test.cc b/test/xray/TestCases/Linux/pic_test.cc index 2999c6411..0e72f5dd6 100644 --- a/test/xray/TestCases/Linux/pic_test.cc +++ b/test/xray/TestCases/Linux/pic_test.cc @@ -7,6 +7,8 @@ // // RUN: rm pic-test-logging-* +// UNSUPPORTED: target-is-mips64,target-is-mips64el + #include [[clang::xray_always_instrument]] -- cgit v1.2.1 From 35e74d5f69b8936980b9d9f07f4bc15be21a0bcc Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 6 Sep 2017 17:51:32 +0000 Subject: [scudo] getauxval alternative for Android Summary: `getauxval` was introduced with API level 18. In order to get things to work at lower API levels (for the toolchain itself which is built at 14 for 32-bit), we introduce an alternative implementation reading directly from `/proc/self/auxv`. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D37488 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312653 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_utils.cpp | 56 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index f7903ff34..71d1b2e1b 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -13,15 +13,47 @@ #include "scudo_utils.h" -#include -#include +#include "sanitizer_common/sanitizer_posix.h" + #include -#include #if defined(__x86_64__) || defined(__i386__) # include #endif #if defined(__arm__) || defined(__aarch64__) -# include +# if SANITIZER_ANDROID && __ANDROID_API__ < 18 +// getauxval() was introduced with API level 18 on Android. Emulate it using +// /proc/self/auxv for lower API levels. +# include + +# define AT_HWCAP 16 + +namespace __sanitizer { + +uptr getauxval(uptr Type) { + uptr F = internal_open("/proc/self/auxv", O_RDONLY); + if (internal_iserror(F)) + return 0; + struct { uptr Tag; uptr Value; } Entry; + uptr Result = 0; + for (;;) { + uptr N = internal_read(F, &Entry, sizeof(Entry)); + if (internal_iserror(N)) + break; + if (N == 0 || N != sizeof(Entry) || (Entry.Tag == 0 && Entry.Value == 0)) + break; + if (Entry.Tag == Type) { + Result = Entry.Value; + break; + } + } + internal_close(F); + return Result; +} + +} // namespace __sanitizer +# else +# include +# endif #endif // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less @@ -82,9 +114,9 @@ CPUIDRegs getCPUFeatures() { return FeaturesRegs; } -#ifndef bit_SSE4_2 -# define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. -#endif +# ifndef bit_SSE4_2 +# define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. +# endif bool testCPUFeature(CPUFeature Feature) { @@ -99,12 +131,12 @@ bool testCPUFeature(CPUFeature Feature) return false; } #elif defined(__arm__) || defined(__aarch64__) -// For ARM and AArch64, hardware CRC32 support is indicated in the -// AT_HWVAL auxiliary vector. +// For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL +// auxiliary vector. -#ifndef HWCAP_CRC32 -# define HWCAP_CRC32 (1<<7) // HWCAP_CRC32 is missing on older platforms. -#endif +# ifndef HWCAP_CRC32 +# define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms. +# endif bool testCPUFeature(CPUFeature Feature) { uptr HWCap = getauxval(AT_HWCAP); -- cgit v1.2.1 From 89c9356294e3056da335ee04f48e219cb79aa09e Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 7 Sep 2017 01:35:59 +0000 Subject: [asan] Add a note to shadow memory setup error. Point to https://github.com/google/sanitizers/issues/856 as a possible cause of the failed mapping. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312687 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_shadow_setup.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index 33b4102b6..d65b27ee2 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -81,6 +81,15 @@ static void ProtectGap(uptr addr, uptr size) { Die(); } +static void MaybeReportLinuxPIEBug() { +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) + Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); + Report( + "See https://github.com/google/sanitizers/issues/837 for possible " + "workarounds.\n"); +#endif +} + void InitializeShadowMemory() { // Set the shadow memory address to uninitialized. __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; @@ -141,6 +150,7 @@ void InitializeShadowMemory() { "ASan cannot proceed correctly. ABORTING.\n"); Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", shadow_start, kHighShadowEnd); + MaybeReportLinuxPIEBug(); DumpProcessMap(); Die(); } -- cgit v1.2.1 From 9c41849040f2c7d0c6d61bd7d1b438d53db617f0 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 7 Sep 2017 01:36:47 +0000 Subject: [cmake] Work around more -Wunused-driver-argument warnings add_compiler_rt_object_libraries should strip out the -msse3 option on non-macOS Apple platforms. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312688 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/AddCompilerRT.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index 622292ede..700c31f16 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -56,8 +56,15 @@ function(add_compiler_rt_object_libraries name) foreach(libname ${libnames}) add_library(${libname} OBJECT ${LIB_SOURCES}) + + # Strip out -msse3 if this isn't macOS. + set(target_flags ${LIB_CFLAGS}) + if(APPLE AND NOT "${libname}" MATCHES ".*\.osx.*") + list(REMOVE_ITEM target_flags "-msse3") + endif() + set_target_compile_flags(${libname} - ${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${LIB_CFLAGS}) + ${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${target_flags}) set_property(TARGET ${libname} APPEND PROPERTY COMPILE_DEFINITIONS ${LIB_DEFS}) set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries") -- cgit v1.2.1 From e914d8b109b9a66c010514bb5d56f04683f5a464 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 7 Sep 2017 02:04:06 +0000 Subject: [libFuzzer] simplify and re-enable CustomCrossOverTest git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312689 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/CustomCrossOverTest.cpp | 43 ++++++++++++--------------------- test/fuzzer/fuzzer-customcrossover.test | 18 ++++++++------ 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/test/fuzzer/CustomCrossOverTest.cpp b/test/fuzzer/CustomCrossOverTest.cpp index 58059c9c1..b47a63e1d 100644 --- a/test/fuzzer/CustomCrossOverTest.cpp +++ b/test/fuzzer/CustomCrossOverTest.cpp @@ -1,7 +1,7 @@ // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -// Simple test for a cutom mutator. +// Simple test for a cutom crossover. #include #include #include @@ -10,23 +10,18 @@ #include #include #include +#include -#include "FuzzerInterface.h" - -static const char *Separator = "-_^_-"; -static const char *Target = "012-_^_-abc"; - -static volatile int sink; +static const char *Separator = "-########-"; +static const char *Target = "A-########-B"; extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { assert(Data); std::string Str(reinterpret_cast(Data), Size); + static const size_t TargetHash = std::hash{}(std::string(Target)); + size_t StrHash = std::hash{}(Str); - // Ensure that two different elements exist in the corpus. - if (Size && Data[0] == '0') sink++; - if (Size && Data[0] == 'a') sink--; - - if (Str.find(Target) != std::string::npos) { + if (TargetHash == StrHash) { std::cout << "BINGO; Found the target, exiting\n" << std::flush; exit(1); } @@ -37,28 +32,20 @@ extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize, unsigned int Seed) { - static bool Printed; + static size_t Printed; static size_t SeparatorLen = strlen(Separator); - if (!Printed) { - std::cerr << "In LLVMFuzzerCustomCrossover\n"; - Printed = true; - } - - std::mt19937 R(Seed); + if (Printed++ < 32) + std::cerr << "In LLVMFuzzerCustomCrossover " << Size1 << " " << Size2 << "\n"; - size_t Offset1 = 0; - size_t Len1 = R() % (Size1 - Offset1); - size_t Offset2 = 0; - size_t Len2 = R() % (Size2 - Offset2); - size_t Size = Len1 + Len2 + SeparatorLen; + size_t Size = Size1 + Size2 + SeparatorLen; if (Size > MaxOutSize) return 0; - memcpy(Out, Data1 + Offset1, Len1); - memcpy(Out + Len1, Separator, SeparatorLen); - memcpy(Out + Len1 + SeparatorLen, Data2 + Offset2, Len2); + memcpy(Out, Data1, Size1); + memcpy(Out + Size1, Separator, SeparatorLen); + memcpy(Out + Size1 + SeparatorLen, Data2, Size2); - return Len1 + Len2 + SeparatorLen; + return Size; } diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index 942e166ea..18c6631b8 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -2,14 +2,16 @@ RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest RUN: rm -rf %t/CustomCrossover RUN: mkdir -p %t/CustomCrossover -RUN: echo "0123456789" > %t/CustomCrossover/digits -RUN: echo "abcdefghij" > %t/CustomCrossover/chars -TODO: make this test more stable (currently, the target can be found by usual strcmp magic) -DISABLED: not %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover -RUN: echo In LLVMFuzzerCustomCrossover -RUN: echo BINGO +RUN: echo "A" > %t/CustomCrossover/digits +RUN: echo "B" > %t/CustomCrossover/chars +RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=CHECK_CO +Disable cross_over, verify that we can't find the target w/o it. +RUN: %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO RUN: rm -rf %t/CustomCrossover -LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover -LLVMFuzzerCustomCrossover: BINGO +CHECK_CO: In LLVMFuzzerCustomCrossover +CHECK_CO: BINGO + +CHECK_NO_CO-NO: LLVMFuzzerCustomCrossover +CHECK_NO_CO: DONE -- cgit v1.2.1 From 43832ee476535fef8b5fc14de39f7992c6357cfa Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 7 Sep 2017 05:23:23 +0000 Subject: [libFuzzer] simplify CustomCrossOverTest a bit more git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312695 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/fuzzer-customcrossover.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index 18c6631b8..d0537a054 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -2,8 +2,8 @@ RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest RUN: rm -rf %t/CustomCrossover RUN: mkdir -p %t/CustomCrossover -RUN: echo "A" > %t/CustomCrossover/digits -RUN: echo "B" > %t/CustomCrossover/chars +RUN: echo -n A > %t/CustomCrossover/digits +RUN: echo -n B > %t/CustomCrossover/chars RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=CHECK_CO Disable cross_over, verify that we can't find the target w/o it. RUN: %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO -- cgit v1.2.1 From 3057bb94ded15a39001c6b7d4755f70a3f7ab1a8 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 7 Sep 2017 05:33:05 +0000 Subject: [libFuzzer] simplify CustomCrossOverTest even more git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312697 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/CustomCrossOverTest.cpp | 8 ++++++++ test/fuzzer/fuzzer-customcrossover.test | 9 ++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/test/fuzzer/CustomCrossOverTest.cpp b/test/fuzzer/CustomCrossOverTest.cpp index b47a63e1d..bd9afe774 100644 --- a/test/fuzzer/CustomCrossOverTest.cpp +++ b/test/fuzzer/CustomCrossOverTest.cpp @@ -15,12 +15,20 @@ static const char *Separator = "-########-"; static const char *Target = "A-########-B"; +static volatile int sink; + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { assert(Data); std::string Str(reinterpret_cast(Data), Size); static const size_t TargetHash = std::hash{}(std::string(Target)); size_t StrHash = std::hash{}(Str); + // Ensure we have 'A' and 'B' in the corpus. + if (Size == 1 && *Data == 'A') + sink++; + if (Size == 1 && *Data == 'B') + sink--; + if (TargetHash == StrHash) { std::cout << "BINGO; Found the target, exiting\n" << std::flush; exit(1); diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index d0537a054..c32079f45 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -1,13 +1,8 @@ RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest -RUN: rm -rf %t/CustomCrossover -RUN: mkdir -p %t/CustomCrossover -RUN: echo -n A > %t/CustomCrossover/digits -RUN: echo -n B > %t/CustomCrossover/chars -RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=CHECK_CO +RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=CHECK_CO Disable cross_over, verify that we can't find the target w/o it. -RUN: %t-CustomCrossOverTest -seed=1 -runs=1000000 %t/CustomCrossover -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO -RUN: rm -rf %t/CustomCrossover +RUN: %t-CustomCrossOverTest -seed=1 -runs=1000000 -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO CHECK_CO: In LLVMFuzzerCustomCrossover CHECK_CO: BINGO -- cgit v1.2.1 From 94345c67bd1cf0378cc8d6ae1764cc5b4578ca07 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 8 Sep 2017 19:43:53 +0000 Subject: Prevent DCE on __lsan_is_turned_off and re-enable test case Summary: -dead_strip in ld64 strips weak interface symbols, which I believe is most likely the cause of this test failure. Re-enable after marking the interface function as used. Reviewers: alekseyshl, kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37635 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312824 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/lsan_interface.h | 2 ++ test/lsan/TestCases/link_turned_off.cc | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sanitizer/lsan_interface.h b/include/sanitizer/lsan_interface.h index 8fb8e756d..1f2e58909 100644 --- a/include/sanitizer/lsan_interface.h +++ b/include/sanitizer/lsan_interface.h @@ -64,6 +64,8 @@ extern "C" { // for the program it is linked into (if the return value is non-zero). This // function must be defined as returning a constant value; any behavior beyond // that is unsupported. + // To avoid dead stripping, you may need to define this function with + // __attribute__((used)) int __lsan_is_turned_off(); // This function may be optionally provided by the user and should return diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index fd11272ce..245fd017b 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -3,15 +3,13 @@ // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s -// -// UNSUPPORTED: darwin #include int argc_copy; extern "C" { -int __lsan_is_turned_off() { +int __attribute__((used)) __lsan_is_turned_off() { return (argc_copy == 1); } } -- cgit v1.2.1 From c6ca7345fbe67ac3b1ea5a23b75daea5a019814f Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 8 Sep 2017 21:09:43 +0000 Subject: Revert "Prevent DCE on __lsan_is_turned_off and re-enable test case" This doesn't fix the failing test. Leave in the comment and the attribute, since the used attribute is still required. This partially reverts commit r312824 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312827 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/link_turned_off.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc index 245fd017b..7e1b33e7a 100644 --- a/test/lsan/TestCases/link_turned_off.cc +++ b/test/lsan/TestCases/link_turned_off.cc @@ -3,6 +3,8 @@ // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts=$LSAN_BASE %run %t // RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// +// UNSUPPORTED: darwin #include -- cgit v1.2.1 From f7a6956f03bc399dfefc24a520302fbf6abaa97e Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 9 Sep 2017 00:56:34 +0000 Subject: [libFuzzer] remove a couple of reduntant includes git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312848 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerUtilPosix.cpp | 1 - lib/fuzzer/FuzzerUtilWindows.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp index bc85264ac..24c5ccc35 100644 --- a/lib/fuzzer/FuzzerUtilPosix.cpp +++ b/lib/fuzzer/FuzzerUtilPosix.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp index 25ac976fc..e8bdd2e81 100644 --- a/lib/fuzzer/FuzzerUtilWindows.cpp +++ b/lib/fuzzer/FuzzerUtilWindows.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.1 From 49cac23f37b00f4bdcc44d50e3a7696254c03139 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 9 Sep 2017 05:58:52 +0000 Subject: [asan] Use more generic string in error message Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37609 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312858 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 4 +++- test/asan/TestCases/Posix/allow_user_segv.cc | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index added746a..c34553838 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -38,7 +38,9 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. - internal_write(2, "ASAN:DEADLYSIGNAL\n", 18); + internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); SignalContext sig = SignalContext::Create(siginfo, context); // Access at a reasonable offset above SP, or slightly below it (to account diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc index 4bec6ad89..e9918910a 100644 --- a/test/asan/TestCases/Posix/allow_user_segv.cc +++ b/test/asan/TestCases/Posix/allow_user_segv.cc @@ -71,17 +71,17 @@ int main() { return DoSEGV(); } -// CHECK0-NOT: ASAN:DEADLYSIGNAL +// CHECK0-NOT: AddressSanitizer: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-NEXT: AddressSanitizer:DEADLYSIGNAL // CHECK1: AddressSanitizer: SEGV on unknown address // CHECK2-NOT: User sigaction called // CHECK2: User sigaction installed -// CHECK2-NEXT: ASAN:DEADLYSIGNAL +// CHECK2-NEXT: AddressSanitizer:DEADLYSIGNAL // CHECK2: AddressSanitizer: SEGV on unknown address -- cgit v1.2.1 From c5cad77b92f072222f3680cd2ccf82543448e43b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 9 Sep 2017 06:04:23 +0000 Subject: [compiler-rt] Move allow_user_segv.cc into sanitizer_common Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D37537 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312859 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/allow_user_segv.cc | 87 -------------------- .../TestCases/Linux/allow_user_segv.cc | 92 ++++++++++++++++++++++ 2 files changed, 92 insertions(+), 87 deletions(-) delete mode 100644 test/asan/TestCases/Posix/allow_user_segv.cc create mode 100644 test/sanitizer_common/TestCases/Linux/allow_user_segv.cc diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc deleted file mode 100644 index e9918910a..000000000 --- a/test/asan/TestCases/Posix/allow_user_segv.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Regression test for -// https://code.google.com/p/address-sanitizer/issues/detail?id=180 - -// clang-format off -// RUN: %clangxx_asan -O0 %s -o %t - -// RUN: %env_asan_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 - -// RUN: %env_asan_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_asan_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %env_asan_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 - -// RUN: %env_asan_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_asan_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %env_asan_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// clang-format on - -#include -#include -#include - -struct sigaction original_sigaction_sigbus; -struct sigaction original_sigaction_sigsegv; - -void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) { - fprintf(stderr, "User sigaction called\n"); - struct sigaction original_sigaction; - if (signum == SIGBUS) - original_sigaction = original_sigaction_sigbus; - else if (signum == SIGSEGV) - original_sigaction = original_sigaction_sigsegv; - else { - printf("Invalid signum"); - exit(1); - } - 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() { - volatile int *x = 0; - return *x; -} - -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 false; - } - 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) && - InstallHandler(SIGBUS, &original_sigaction_sigbus)) { - fprintf(stderr, "User sigaction installed\n"); - } - return DoSEGV(); -} - -// CHECK0-NOT: AddressSanitizer: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: AddressSanitizer:DEADLYSIGNAL -// CHECK1: AddressSanitizer: SEGV on unknown address - -// CHECK2-NOT: User sigaction called -// CHECK2: User sigaction installed -// CHECK2-NEXT: AddressSanitizer:DEADLYSIGNAL -// CHECK2: AddressSanitizer: SEGV on unknown address diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc new file mode 100644 index 000000000..628c8e3f0 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -0,0 +1,92 @@ +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=180 + +// clang-format off +// RUN: %clangxx -O0 %s -o %t + +// RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 + +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 + +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// clang-format on + +// Remove when fixed: https://github.com/google/sanitizers/issues/637 +// UNSUPPORTED: lsan +// UNSUPPORTED: msan +// UNSUPPORTED: tsan + +#include +#include +#include + +struct sigaction original_sigaction_sigbus; +struct sigaction original_sigaction_sigsegv; + +void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) { + fprintf(stderr, "User sigaction called\n"); + struct sigaction original_sigaction; + if (signum == SIGBUS) + original_sigaction = original_sigaction_sigbus; + else if (signum == SIGSEGV) + original_sigaction = original_sigaction_sigsegv; + else { + printf("Invalid signum"); + exit(1); + } + 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() { + volatile int *x = 0; + return *x; +} + +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 false; + } + 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) && + InstallHandler(SIGBUS, &original_sigaction_sigbus)) { + fprintf(stderr, "User sigaction installed\n"); + } + return DoSEGV(); +} + +// CHECK0-NOT: AddressSanitizer: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: AddressSanitizer:DEADLYSIGNAL +// CHECK1: AddressSanitizer: SEGV on unknown address + +// CHECK2-NOT: User sigaction called +// CHECK2: User sigaction installed +// CHECK2-NEXT: AddressSanitizer:DEADLYSIGNAL +// CHECK2: AddressSanitizer: SEGV on unknown address -- cgit v1.2.1 From 689b841c13f02c4f16a0f9d2bb5274e65ee7991a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 9 Sep 2017 06:10:58 +0000 Subject: [ubsan] Enable UBsan in sanitizer_common tests Summary: Failing tests just marked as UNSUPPORTED or XFAIL. Some of them can be easily supported, but I'll do this in separate patches. Reviewers: eugenis, alekseyshl Subscribers: srhines, kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D37630 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312860 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/CMakeLists.txt | 1 + test/sanitizer_common/TestCases/Linux/allow_user_segv.cc | 1 + test/sanitizer_common/TestCases/Linux/assert.cc | 1 + test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc | 3 ++- test/sanitizer_common/TestCases/Linux/deepbind.cc | 2 +- test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc | 1 + test/sanitizer_common/TestCases/Linux/ill.cc | 1 + test/sanitizer_common/TestCases/Linux/mlock_test.cc | 2 +- test/sanitizer_common/TestCases/Linux/mprobe.cc | 2 +- test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc | 2 +- test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc | 1 + .../TestCases/Linux/unexpected_format_specifier_test.cc | 1 + test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc | 1 + test/sanitizer_common/TestCases/Posix/fpe.cc | 1 + .../TestCases/Posix/sanitizer_set_death_callback_test.cc | 1 + .../TestCases/Posix/sanitizer_set_report_fd_test.cc | 1 + test/sanitizer_common/TestCases/Posix/weak_hook_test.cc | 1 + test/sanitizer_common/TestCases/corelimit.cc | 2 +- test/sanitizer_common/TestCases/malloc_hook.cc | 1 + test/sanitizer_common/TestCases/options-include.cc | 1 + test/sanitizer_common/TestCases/print-stack-trace.cc | 1 + test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- .../TestCases/sanitizer_coverage_trace_pc_guard-dso.cc | 5 +++-- .../sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc | 6 +++--- test/sanitizer_common/lit.common.cfg | 3 +++ 25 files changed, 32 insertions(+), 12 deletions(-) diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index b716f89df..2a3d7a038 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -11,6 +11,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID) list(APPEND SUPPORTED_TOOLS tsan) list(APPEND SUPPORTED_TOOLS msan) list(APPEND SUPPORTED_TOOLS lsan) + list(APPEND SUPPORTED_TOOLS ubsan) endif() # Create a separate config for each tool we support. diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index 628c8e3f0..4fe3c32f0 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -21,6 +21,7 @@ // UNSUPPORTED: lsan // UNSUPPORTED: msan // UNSUPPORTED: tsan +// UNSUPPORTED: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Linux/assert.cc b/test/sanitizer_common/TestCases/Linux/assert.cc index 5d58ea4f7..7422d400a 100644 --- a/test/sanitizer_common/TestCases/Linux/assert.cc +++ b/test/sanitizer_common/TestCases/Linux/assert.cc @@ -7,6 +7,7 @@ // XFAIL: msan // XFAIL: lsan // XFAIL: tsan +// XFAIL: ubsan #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc index 36d4df567..88275755f 100644 --- a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc +++ b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc @@ -57,5 +57,6 @@ int main(void) { // CHECK-tsan: rw-p {{.*}} [trace 1] // CHECK-tsan: rw-p {{.*}} [trace header 1] -// Nothing interesting with standalone LSan. +// Nothing interesting with standalone LSan and UBSan. // CHECK-lsan: decorate_proc_maps +// CHECK-ubsan: decorate_proc_maps diff --git a/test/sanitizer_common/TestCases/Linux/deepbind.cc b/test/sanitizer_common/TestCases/Linux/deepbind.cc index fc810ad03..81150fae9 100644 --- a/test/sanitizer_common/TestCases/Linux/deepbind.cc +++ b/test/sanitizer_common/TestCases/Linux/deepbind.cc @@ -1,5 +1,5 @@ // RUN: %clangxx %s -o %t && %run not %t 1 2>&1 | FileCheck %s -// UNSUPPORTED: lsan, android +// UNSUPPORTED: lsan,ubsan,android #include #include diff --git a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc index d4a60a0d3..5c8e19a4f 100644 --- a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc @@ -14,6 +14,7 @@ // XFAIL: lsan // XFAIL: tsan // XFAIL: msan +// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Linux/ill.cc b/test/sanitizer_common/TestCases/Linux/ill.cc index 2c69618ad..2707fc9af 100644 --- a/test/sanitizer_common/TestCases/Linux/ill.cc +++ b/test/sanitizer_common/TestCases/Linux/ill.cc @@ -7,6 +7,7 @@ // XFAIL: msan // XFAIL: lsan // XFAIL: tsan +// XFAIL: ubsan // // FIXME: seems to fail on ARM // REQUIRES: x86_64-target-arch diff --git a/test/sanitizer_common/TestCases/Linux/mlock_test.cc b/test/sanitizer_common/TestCases/Linux/mlock_test.cc index 69ea7cb91..a952922aa 100644 --- a/test/sanitizer_common/TestCases/Linux/mlock_test.cc +++ b/test/sanitizer_common/TestCases/Linux/mlock_test.cc @@ -1,5 +1,5 @@ // RUN: %clang %s -o %t && %run %t -// XFAIL: lsan +// XFAIL: ubsan,lsan #include #include diff --git a/test/sanitizer_common/TestCases/Linux/mprobe.cc b/test/sanitizer_common/TestCases/Linux/mprobe.cc index 57e5ba5a6..82c0faf0e 100644 --- a/test/sanitizer_common/TestCases/Linux/mprobe.cc +++ b/test/sanitizer_common/TestCases/Linux/mprobe.cc @@ -1,5 +1,5 @@ // RUN: %clangxx %s -o %t && %run %t 2>&1 | FileCheck %s -// UNSUPPORTED: android +// UNSUPPORTED: android, ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc index b7e8721a1..523ac9811 100644 --- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc +++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -1,7 +1,7 @@ // RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t // This test depends on the glibc layout of struct sem_t and checks that we // don't leave sem_t::private uninitialized. -// UNSUPPORTED: android, lsan-x86 +// UNSUPPORTED: android, lsan-x86, ubsan #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc index 83570a9f1..2ee809547 100644 --- a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc @@ -14,6 +14,7 @@ // XFAIL: lsan // XFAIL: tsan // XFAIL: msan +// XFAIL: ubsan #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc b/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc index f48cce8ea..641495508 100644 --- a/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc +++ b/test/sanitizer_common/TestCases/Linux/unexpected_format_specifier_test.cc @@ -1,6 +1,7 @@ // RUN: %clang -w -O0 %s -o %t && %run %t 2>&1 | FileCheck %s // UNSUPPORTED: lsan // UNSUPPORTED: msan +// UNSUPPORTED: ubsan #include int main() { int a; diff --git a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc index 261295790..ad94d13d2 100644 --- a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -11,6 +11,7 @@ // XFAIL: msan // XFAIL: lsan // XFAIL: tsan +// XFAIL: ubsan volatile int *null = 0; diff --git a/test/sanitizer_common/TestCases/Posix/fpe.cc b/test/sanitizer_common/TestCases/Posix/fpe.cc index 9a6f808a5..44d53274b 100644 --- a/test/sanitizer_common/TestCases/Posix/fpe.cc +++ b/test/sanitizer_common/TestCases/Posix/fpe.cc @@ -7,6 +7,7 @@ // XFAIL: msan // XFAIL: lsan // XFAIL: tsan +// XFAIL: ubsan // // FIXME: seems to fail on ARM // REQUIRES: x86_64-target-arch diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc index 12a56c73e..8d2db3641 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_death_callback_test.cc @@ -8,6 +8,7 @@ // the last line of main function. The problem doesn't reproduce with ASan because // quarantine prohibits memory block reuse for different allocations. // XFAIL: lsan-x86 +// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index af7eea1d7..5c5d3fb4b 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -9,6 +9,7 @@ // XFAIL: msan // XFAIL: lsan // XFAIL: tsan +// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc b/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc index d5667649b..9176a524d 100644 --- a/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc +++ b/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc @@ -4,6 +4,7 @@ // Hooks are not implemented for lsan. // XFAIL: lsan +// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/corelimit.cc b/test/sanitizer_common/TestCases/corelimit.cc index 0a86e5b7b..eb02afc01 100644 --- a/test/sanitizer_common/TestCases/corelimit.cc +++ b/test/sanitizer_common/TestCases/corelimit.cc @@ -1,5 +1,5 @@ // RUN: %clangxx -O0 %s -o %t && %run %t -// UNSUPPORTED: lsan +// UNSUPPORTED: lsan,ubsan #include #include diff --git a/test/sanitizer_common/TestCases/malloc_hook.cc b/test/sanitizer_common/TestCases/malloc_hook.cc index 59cd620b3..853bb66ac 100644 --- a/test/sanitizer_common/TestCases/malloc_hook.cc +++ b/test/sanitizer_common/TestCases/malloc_hook.cc @@ -2,6 +2,7 @@ // Malloc/free hooks are not supported on Windows. // XFAIL: win32 +// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/options-include.cc b/test/sanitizer_common/TestCases/options-include.cc index 5b0b6d525..8b131a785 100644 --- a/test/sanitizer_common/TestCases/options-include.cc +++ b/test/sanitizer_common/TestCases/options-include.cc @@ -1,4 +1,5 @@ // RUN: %clangxx -O0 %s -o %t +// UNSUPPORTED: ubsan // Recursive include: options1 includes options2 // RUN: echo "symbolize=1" > %t.options1.txt diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc index a6eca0b75..df7cc050a 100644 --- a/test/sanitizer_common/TestCases/print-stack-trace.cc +++ b/test/sanitizer_common/TestCases/print-stack-trace.cc @@ -4,6 +4,7 @@ // RUN: %env_tool_opts=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE // UNSUPPORTED: darwin +// XFAIL: ubsan #include diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 875193034..5e3825d06 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -2,7 +2,7 @@ // // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin -// XFAIL: tsan +// XFAIL: ubsan,tsan // // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc index 6185177a1..e2934964d 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -1,6 +1,7 @@ // Tests trace pc guard coverage collection. // // REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: ubsan // XFAIL: tsan,darwin,powerpc64,s390x,mips // // RUN: DIR=%t_workdir @@ -68,5 +69,5 @@ int baz() { // // CHECK-SANCOV: Ignoring {{.*}}_1.so and its coverage because __sanitizer_cov* functions were not found. // CHECK-SANCOV: Ignoring {{.*}}_2.so and its coverage because __sanitizer_cov* functions were not found. -// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:29 foo -// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:34 main +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:[[@LINE-42]] foo +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:[[@LINE-38]] main diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc index 2d6d00b6a..5740f2694 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -1,7 +1,7 @@ // Tests trace pc guard coverage collection. // // REQUIRES: has_sancovcc,stable-runtime -// UNSUPPORTED: i386-darwin +// UNSUPPORTED: ubsan,i386-darwin // XFAIL: tsan,powerpc64,s390x,mips // // RUN: DIR=%t_workdir @@ -36,7 +36,7 @@ int main() { // CHECK-NEXT: foo // CHECK-NEXT: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard.{{.*}}.sancov: 2 PCs written // -// CHECK-SANCOV: sanitizer_coverage_trace_pc_guard.cc:23 foo -// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard.cc:28 main +// CHECK-SANCOV: sanitizer_coverage_trace_pc_guard.cc:[[@LINE-16]] foo +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard.cc:[[@LINE-12]] main // // CHECK-NOCOV-NOT: SanitizerCoverage diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index 307a33ae7..7e3e66011 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -18,6 +18,9 @@ elif config.tool_name == "msan": elif config.tool_name == "lsan": tool_cflags = ["-fsanitize=leak"] tool_options = "LSAN_OPTIONS" +elif config.tool_name == "ubsan": + tool_cflags = ["-fsanitize=undefined"] + tool_options = "UBSAN_OPTIONS" else: lit_config.fatal("Unknown tool for sanitizer_common tests: %r" % config.tool_name) -- cgit v1.2.1 From 8726d836614ded9f90da6e51875d18405d2ebbca Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 9 Sep 2017 20:07:45 +0000 Subject: [asan] Fix tests broken by r312858 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312872 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/preinstalled_signal.cc | 6 +++--- test/asan/TestCases/global-address.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc index 4d466c21f..10feb71a5 100644 --- a/test/asan/TestCases/Linux/preinstalled_signal.cc +++ b/test/asan/TestCases/Linux/preinstalled_signal.cc @@ -98,10 +98,10 @@ int main(int argc, char *argv[]) { } // CHECK-NOT: TestSig -// CHECK: ASAN:DEADLYSIGNAL +// CHECK: AddressSanitizer:DEADLYSIGNAL -// CHECK-HANDLER-NOT: ASAN:DEADLYSIGNAL +// CHECK-HANDLER-NOT: AddressSanitizer:DEADLYSIGNAL // CHECK-HANDLER: TestSigHandler -// CHECK-ACTION-NOT: ASAN:DEADLYSIGNAL +// CHECK-ACTION-NOT: AddressSanitizer:DEADLYSIGNAL // CHECK-ACTION: TestSigAction diff --git a/test/asan/TestCases/global-address.cpp b/test/asan/TestCases/global-address.cpp index 0e56ca10c..81f0230b7 100644 --- a/test/asan/TestCases/global-address.cpp +++ b/test/asan/TestCases/global-address.cpp @@ -5,8 +5,8 @@ int g_i = 42; int main() { // CHECK: AddressSanitizer: attempting to call __sanitizer_get_allocated_size() for pointer which is not owned - // CHECK-NOT: ASAN:DEADLYSIGNAL + // CHECK-NOT: AddressSanitizer:DEADLYSIGNAL // CHECK: SUMMARY: AddressSanitizer: bad-__sanitizer_get_allocated_size - // CHECK-NOT: ASAN:DEADLYSIGNAL + // CHECK-NOT: AddressSanitizer:DEADLYSIGNAL return (int)__sanitizer_get_allocated_size(&g_i); } -- cgit v1.2.1 From 4224e9eadb693ac6e3ef44aade21741cb7aef66d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 18:32:51 +0000 Subject: [ubsan] Save binary name before parsing options Summary: To parser "include" we may need to do binary name substitution. Reviewers: eugenis, alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37658 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312933 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_init.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index 307bca376..d7433a5c9 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -40,8 +40,8 @@ static void CommonInit() { static void CommonStandaloneInit() { SanitizerToolName = GetSanititizerToolName(); - InitializeFlags(); CacheBinaryName(); + InitializeFlags(); __sanitizer_set_report_path(common_flags()->log_path); AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); -- cgit v1.2.1 From 2f11426d307445380d4e92caa6e54500aef63292 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 19:41:17 +0000 Subject: [asan] Include asan-dynamic into check-all Summary: It's adds just 1k to about 45k tests. Reviewers: eugenis, alekseyshl Subscribers: kubamracek, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D37666 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312937 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 19d9c88cf..bd6834d74 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -164,21 +164,12 @@ add_lit_testsuite(check-asan "Running the AddressSanitizer tests" set_target_properties(check-asan PROPERTIES FOLDER "Compiler-RT Misc") if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) - # Add check-dynamic-asan target. It is a part of check-all only on Windows, - # where we want to always test both dynamic and static runtime. - - if(NOT OS_NAME MATCHES "Windows") - set(EXCLUDE_FROM_ALL TRUE) - endif() add_lit_testsuite(check-asan-dynamic "Running the AddressSanitizer tests with dynamic runtime" ${ASAN_DYNAMIC_TESTSUITES} DEPENDS ${ASAN_DYNAMIC_TEST_DEPS}) set_target_properties(check-asan-dynamic PROPERTIES FOLDER "Compiler-RT Misc") - if(NOT OS_NAME MATCHES "Windows") - set(EXCLUDE_FROM_ALL FALSE) - endif() endif() # Reset EXCLUDE_FROM_ALL to its initial value. -- cgit v1.2.1 From 234cf084c21166521803aff655a89cf10806b656 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 11 Sep 2017 19:59:40 +0000 Subject: [scudo] Fix improper TSD init after TLS destructors are called Summary: Some of glibc's own thread local data is destroyed after a user's thread local destructors are called, via __libc_thread_freeres. This might involve calling free, as is the case for strerror_thread_freeres. If there is no prior heap operation in the thread, this free would end up initializing some thread specific data that would never be destroyed properly (as user's pthread destructors have already been called), while still being deallocated when the TLS goes away. As a result, a program could SEGV, usually in __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly linked list links would refer to a now unmapped memory area. To prevent this from happening, we will not do a full initialization from the deallocation path. This means that the fallback cache & quarantine will be used if no other heap operation has been called, and we effectively prevent the TSD being initialized and never destroyed. The TSD will be fully initialized for all other paths. In the event of a thread doing only frees and nothing else, a TSD would never be initialized for that thread, but this situation is unlikely and we can live with that. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37697 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312939 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 8 +++++++- lib/scudo/scudo_tls.h | 2 +- lib/scudo/scudo_tls_android.cpp | 2 +- lib/scudo/scudo_tls_android.inc | 4 ++-- lib/scudo/scudo_tls_linux.cpp | 4 +++- lib/scudo/scudo_tls_linux.inc | 6 +++--- test/scudo/tsd_destruction.cpp | 42 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 test/scudo/tsd_destruction.cpp diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 4f87d3523..92155797c 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -495,7 +495,13 @@ struct ScudoAllocator { // Deallocates a Chunk, which means adding it to the delayed free list (or // Quarantine). void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) { - initThreadMaybe(); + // For a deallocation, we only ensure minimal initialization, meaning thread + // local data will be left uninitialized for now (when using ELF TLS). The + // fallback cache will be used instead. This is a workaround for a situation + // where the only heap operation performed in a thread would be a free past + // the TLS destructors, ending up in initialized thread specific data never + // being destroyed properly. Any other heap operation will do a full init. + initThreadMaybe(/*MinimalInit=*/true); // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr); if (UNLIKELY(!UserPtr)) return; diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index 20c49204c..4784f6a30 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -36,7 +36,7 @@ struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { void commitBack(); }; -void initThread(); +void initThread(bool MinimalInit); // Platform specific dastpath functions definitions. #include "scudo_tls_android.inc" diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp index ec74e37c8..c0ea417ab 100644 --- a/lib/scudo/scudo_tls_android.cpp +++ b/lib/scudo/scudo_tls_android.cpp @@ -49,7 +49,7 @@ static void initOnce() { ThreadContexts[i].init(); } -void initThread() { +void initThread(bool MinimalInit) { pthread_once(&GlobalInitialized, initOnce); // Initial context assignment is done in a plain round-robin fashion. u32 Index = atomic_fetch_add(&ThreadContextCurrentIndex, 1, diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc index 8ecad7a30..6b82e49f5 100644 --- a/lib/scudo/scudo_tls_android.inc +++ b/lib/scudo/scudo_tls_android.inc @@ -20,10 +20,10 @@ #if SANITIZER_LINUX && SANITIZER_ANDROID -ALWAYS_INLINE void initThreadMaybe() { +ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { if (LIKELY(*get_android_tls_ptr())) return; - initThread(); + initThread(MinimalInit); } ScudoThreadContext *getThreadContextAndLockSlow(); diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index 1e38233f3..f2592266d 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -53,8 +53,10 @@ static void initOnce() { initScudo(); } -void initThread() { +void initThread(bool MinimalInit) { CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0); + if (UNLIKELY(MinimalInit)) + return; CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( GetPthreadDestructorIterations())), 0); ThreadLocalContext.init(); diff --git a/lib/scudo/scudo_tls_linux.inc b/lib/scudo/scudo_tls_linux.inc index 242ee3329..53b804485 100644 --- a/lib/scudo/scudo_tls_linux.inc +++ b/lib/scudo/scudo_tls_linux.inc @@ -31,14 +31,14 @@ extern THREADLOCAL ThreadState ScudoThreadState; __attribute__((tls_model("initial-exec"))) extern THREADLOCAL ScudoThreadContext ThreadLocalContext; -ALWAYS_INLINE void initThreadMaybe() { +ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { if (LIKELY(ScudoThreadState != ThreadNotInitialized)) return; - initThread(); + initThread(MinimalInit); } ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { - if (UNLIKELY(ScudoThreadState == ThreadTornDown)) + if (UNLIKELY(ScudoThreadState != ThreadInitialized)) return nullptr; return &ThreadLocalContext; } diff --git a/test/scudo/tsd_destruction.cpp b/test/scudo/tsd_destruction.cpp new file mode 100644 index 000000000..1b0d0eff9 --- /dev/null +++ b/test/scudo/tsd_destruction.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 + +#include +#include +#include +#include +#include + +// Some of glibc's own thread local data is destroyed after a user's thread +// local destructors are called, via __libc_thread_freeres. This might involve +// calling free, as is the case for strerror_thread_freeres. +// If there is no prior heap operation in the thread, this free would end up +// initializing some thread specific data that would never be destroyed +// properly, while still being deallocated when the TLS goes away. As a result, +// a program could SEGV, usually in +// __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly +// linked list links would refer to a now unmapped memory area. + +// This test reproduces those circumstances. Success means executing without +// a segmentation fault. + +const int kNumThreads = 16; +pthread_t tid[kNumThreads]; + +void *thread_func(void *arg) { + uintptr_t i = (uintptr_t)arg; + if ((i & 1) == 0) free(malloc(16)); + // Calling strerror_l allows for strerror_thread_freeres to be called. + strerror_l(0, LC_GLOBAL_LOCALE); + return 0; +} + +int main(int argc, char** argv) { + for (uintptr_t j = 0; j < 8; j++) { + for (uintptr_t i = 0; i < kNumThreads; i++) + pthread_create(&tid[i], 0, thread_func, (void *)i); + for (uintptr_t i = 0; i < kNumThreads; i++) + pthread_join(tid[i], 0); + } + return 0; +} -- cgit v1.2.1 From 2b6ced66bed1cc077d06664ef6bf9242e7d0fd6d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 20:55:49 +0000 Subject: [compiler-rt] Cleanup decorators Summary: Removed redundant End*() methods which defined same way. Removed redundant Warning() methods. Reviewers: eugenis Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D37549 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312950 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_descriptions.cc | 18 +++++++------- lib/asan/asan_descriptions.h | 5 ---- lib/asan/asan_errors.cc | 28 +++++++++++----------- lib/asan/asan_report.cc | 5 ++-- lib/lsan/lsan_common.cc | 5 ++-- lib/msan/msan_report.cc | 23 +++++++++--------- lib/sanitizer_common/sanitizer_report_decorator.h | 4 ++-- lib/tsan/rtl/tsan_report.cc | 29 +++++++++-------------- lib/ubsan/ubsan_diag.cc | 8 +++---- 9 files changed, 54 insertions(+), 71 deletions(-) diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc index 822a6a62d..5662e6b34 100644 --- a/lib/asan/asan_descriptions.cc +++ b/lib/asan/asan_descriptions.cc @@ -150,7 +150,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, (void *)descr.chunk_begin, (void *)(descr.chunk_begin + descr.chunk_size)); - str.append("%s", d.EndLocation()); + str.append("%s", d.Default()); Printf("%s", str.data()); } @@ -260,7 +260,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, // FIXME: we may want to also print the size of the access here, // but in case of accesses generated by memset it may be confusing. str.append("%s <== Memory access at offset %zd %s this variable%s\n", - d.Location(), addr, pos_descr, d.EndLocation()); + d.Location(), addr, pos_descr, d.Default()); } else { str.append("\n"); } @@ -295,7 +295,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, MaybeDemangleGlobalName(g.name)); PrintGlobalLocation(&str, g); str.append("' (0x%zx) of size %zu\n", g.beg, g.size); - str.append("%s", d.EndLocation()); + str.append("%s", d.Default()); PrintGlobalNameIfASCII(&str, g); Printf("%s", str.data()); } @@ -343,10 +343,10 @@ void StackAddressDescription::Print() const { ThreadNameWithParenthesis(tid, tname, sizeof(tname))); if (!frame_descr) { - Printf("%s\n", d.EndLocation()); + Printf("%s\n", d.Default()); return; } - Printf(" at offset %zu in frame%s\n", offset, d.EndLocation()); + Printf(" at offset %zu in frame%s\n", offset, d.Default()); // Now we print the frame where the alloca has happened. // We print this frame as a stack trace with one element. @@ -355,7 +355,7 @@ void StackAddressDescription::Print() const { // previously. That's unfortunate, but I have no better solution, // especially given that the alloca may be from entirely different place // (e.g. use-after-scope, or different thread's stack). - Printf("%s", d.EndLocation()); + Printf("%s", d.Default()); StackTrace alloca_stack(&frame_pc, 1); alloca_stack.Print(); @@ -405,18 +405,18 @@ void HeapAddressDescription::Print() const { Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), free_thread->tid, ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), - d.EndAllocation()); + d.Default()); StackTrace free_stack = GetStackTraceFromId(free_stack_id); free_stack.Print(); Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); + d.Default()); } else { Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); + d.Default()); } alloc_stack.Print(); DescribeThread(GetCurrentThread()); diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h index 0ee677eb7..5161715df 100644 --- a/lib/asan/asan_descriptions.h +++ b/lib/asan/asan_descriptions.h @@ -34,11 +34,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() {} const char *Access() { return Blue(); } - const char *EndAccess() { return Default(); } const char *Location() { return Green(); } - const char *EndLocation() { return Default(); } const char *Allocation() { return Magenta(); } - const char *EndAllocation() { return Default(); } const char *ShadowByte(u8 byte) { switch (byte) { @@ -72,9 +69,7 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { return Default(); } } - const char *EndShadowByte() { return Default(); } const char *MemoryByte() { return Magenta(); } - const char *EndMemoryByte() { return Default(); } }; enum ShadowKind : u8 { diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 4bc47600c..0f2a9e26f 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -29,7 +29,7 @@ void ErrorStackOverflow::Print() { "ERROR: AddressSanitizer: %s on address %p" " (pc %p bp %p sp %p T%d)\n", scariness.GetDescription(), (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); scariness.Print(); BufferedStackTrace stack; GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, @@ -77,7 +77,7 @@ void ErrorDeadlySignal::Print() { "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " "T%d)\n", description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n"); if (is_memory_access) { const char *access_type = @@ -109,7 +109,7 @@ void ErrorDoubleFree::Print() { "thread T%d%s:\n", scariness.GetDescription(), addr_description.addr, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); scariness.Print(); GET_STACK_TRACE_FATAL(second_free_stack->trace[0], second_free_stack->top_frame_bp); @@ -127,7 +127,7 @@ void ErrorNewDeleteSizeMismatch::Print() { "T%d%s:\n", scariness.GetDescription(), addr_description.addr, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); - Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); + Printf("%s object passed to delete has wrong type:\n", d.Default()); Printf( " size of the allocated type: %zd bytes;\n" " size of the deallocated type: %zd bytes.\n", @@ -152,7 +152,7 @@ void ErrorFreeNotMalloced::Print() { "which was not malloc()-ed: %p in thread T%d%s\n", addr_description.Address(), tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); CHECK_GT(free_stack->size, 0); scariness.Print(); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); @@ -173,7 +173,7 @@ void ErrorAllocTypeMismatch::Print() { scariness.GetDescription(), alloc_names[alloc_type], dealloc_names[dealloc_type], addr_description.addr); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); CHECK_GT(dealloc_stack->size, 0); scariness.Print(); GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp); @@ -192,7 +192,7 @@ void ErrorMallocUsableSizeNotOwned::Print() { "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for " "pointer which is not owned: %p\n", addr_description.Address()); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); stack->Print(); addr_description.Print(); ReportErrorSummary(scariness.GetDescription(), stack); @@ -205,7 +205,7 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { "ERROR: AddressSanitizer: attempting to call " "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n", addr_description.Address()); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); stack->Print(); addr_description.Print(); ReportErrorSummary(scariness.GetDescription(), stack); @@ -222,7 +222,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() { bug_type, addr1_description.Address(), addr1_description.Address() + length1, addr2_description.Address(), addr2_description.Address() + length2); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); scariness.Print(); stack->Print(); addr1_description.Print(); @@ -235,7 +235,7 @@ void ErrorStringFunctionSizeOverflow::Print() { Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", scariness.GetDescription(), size); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); scariness.Print(); stack->Print(); addr_description.Print(); @@ -263,7 +263,7 @@ void ErrorODRViolation::Print() { Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(), global1.beg); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); InternalScopedString g1_loc(256), g2_loc(256); PrintGlobalLocation(&g1_loc, global1); PrintGlobalLocation(&g2_loc, global2); @@ -292,7 +292,7 @@ void ErrorInvalidPointerPair::Print() { Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(), addr1_description.Address(), addr2_description.Address()); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); addr1_description.Print(); @@ -491,13 +491,13 @@ void ErrorGeneric::Print() { uptr addr = addr_description.Address(); Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n", bug_descr, (void *)addr, pc, bp, sp); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); char tname[128]; Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(), access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size, (void *)addr, tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess()); + ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default()); scariness.Print(); GET_STACK_TRACE_FATAL(pc, bp); diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 8e3d9454f..312dcaeae 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -60,9 +60,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, bool in_shadow, const char *after) { Decorator d; str->append("%s%s%x%x%s%s", before, - in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), - byte >> 4, byte & 15, - in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after); + in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4, + byte & 15, d.Default(), after); } static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index c121e6a8f..a7927684c 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -122,7 +122,6 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { Decorator() : SanitizerCommonDecorator() { } const char *Error() { return Red(); } const char *Leak() { return Blue(); } - const char *End() { return Default(); } }; static inline bool CanBeAHeapPointer(uptr p) { @@ -564,7 +563,7 @@ static bool CheckForLeaks() { "\n"); Printf("%s", d.Error()); Report("ERROR: LeakSanitizer: detected memory leaks\n"); - Printf("%s", d.End()); + Printf("%s", d.Default()); param.leak_report.ReportTopLeaks(flags()->max_leaks); } if (common_flags()->print_suppressions) @@ -698,7 +697,7 @@ void LeakReport::PrintReportForLeak(uptr index) { Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n", leaks_[index].is_directly_leaked ? "Direct" : "Indirect", leaks_[index].total_size, leaks_[index].hit_count); - Printf("%s", d.End()); + Printf("%s", d.Default()); PrintStackTraceById(leaks_[index].stack_trace_id); diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc index 9a35c9c13..cddad014b 100644 --- a/lib/msan/msan_report.cc +++ b/lib/msan/msan_report.cc @@ -30,10 +30,8 @@ namespace __msan { class Decorator: public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() { } - const char *Warning() { return Red(); } const char *Origin() { return Magenta(); } const char *Name() { return Green(); } - const char *End() { return Default(); } }; static void DescribeStackOrigin(const char *so, uptr pc) { @@ -47,7 +45,7 @@ static void DescribeStackOrigin(const char *so, uptr pc) { " %sUninitialized value was created by an allocation of '%s%s%s'" " in the stack frame of function '%s%s%s'%s\n", d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(), - d.End()); + d.Default()); InternalFree(s); if (pc) { @@ -66,7 +64,7 @@ static void DescribeOrigin(u32 id) { StackTrace stack; o = o.getNextChainedOrigin(&stack); Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(), - d.End()); + d.Default()); stack.Print(); } if (o.isStackOrigin()) { @@ -78,18 +76,19 @@ static void DescribeOrigin(u32 id) { switch (stack.tag) { case StackTrace::TAG_ALLOC: Printf(" %sUninitialized value was created by a heap allocation%s\n", - d.Origin(), d.End()); + d.Origin(), d.Default()); break; case StackTrace::TAG_DEALLOC: Printf(" %sUninitialized value was created by a heap deallocation%s\n", - d.Origin(), d.End()); + d.Origin(), d.Default()); break; case STACK_TRACE_TAG_POISON: Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(), - d.End()); + d.Default()); break; default: - Printf(" %sUninitialized value was created%s\n", d.Origin(), d.End()); + Printf(" %sUninitialized value was created%s\n", d.Origin(), + d.Default()); break; } stack.Print(); @@ -104,7 +103,7 @@ void ReportUMR(StackTrace *stack, u32 origin) { Decorator d; Printf("%s", d.Warning()); Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n"); - Printf("%s", d.End()); + Printf("%s", d.Default()); stack->Print(); if (origin) { DescribeOrigin(origin); @@ -144,7 +143,7 @@ void ReportAtExitStatistics() { Decorator d; Printf("%s", d.Warning()); Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count); - Printf("%s", d.End()); + Printf("%s", d.Default()); } } @@ -203,7 +202,7 @@ void DescribeMemoryRange(const void *x, uptr size) { Decorator d; Printf("%s", d.Warning()); Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start); - Printf("%s", d.End()); + Printf("%s", d.Default()); while (s < e) { // Line start. if (pos % 16 == 0) { @@ -265,7 +264,7 @@ void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, Printf("%s", d.Warning()); Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n", d.Warning(), d.Name(), what, d.Warning(), offset, start, size, - d.End()); + d.Default()); if (__sanitizer::Verbosity()) DescribeMemoryRange(start, size); } diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h index 86536aa19..daa7f00a0 100644 --- a/lib/sanitizer_common/sanitizer_report_decorator.h +++ b/lib/sanitizer_common/sanitizer_report_decorator.h @@ -27,8 +27,8 @@ class SanitizerCommonDecorator { SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} const char *Bold() const { return ansi_ ? "\033[1m" : ""; } const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } - const char *Warning() { return Red(); } - const char *EndWarning() { return Default(); } + const char *Warning() const { return Red(); } + protected: const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; } diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index b2c30ec9a..be5d6b7ea 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -39,18 +39,11 @@ ReportLocation *ReportLocation::New(ReportLocationType type) { class Decorator: public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() { } - const char *Warning() { return Red(); } - const char *EndWarning() { return Default(); } const char *Access() { return Blue(); } - const char *EndAccess() { return Default(); } const char *ThreadDescription() { return Cyan(); } - const char *EndThreadDescription() { return Default(); } const char *Location() { return Green(); } - const char *EndLocation() { return Default(); } const char *Sleep() { return Yellow(); } - const char *EndSleep() { return Default(); } const char *Mutex() { return Magenta(); } - const char *EndMutex() { return Default(); } }; ReportDesc::ReportDesc() @@ -181,7 +174,7 @@ static void PrintMop(const ReportMop *mop, bool first) { } PrintMutexSet(mop->mset); Printf(":\n"); - Printf("%s", d.EndAccess()); + Printf("%s", d.Default()); PrintStack(mop->stack); } @@ -222,20 +215,20 @@ static void PrintLocation(const ReportLocation *loc) { loc->fd, thread_name(thrbuf, loc->tid)); print_stack = true; } - Printf("%s", d.EndLocation()); + Printf("%s", d.Default()); if (print_stack) PrintStack(loc->stack); } static void PrintMutexShort(const ReportMutex *rm, const char *after) { Decorator d; - Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after); + Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.Default(), after); } static void PrintMutexShortWithAddress(const ReportMutex *rm, const char *after) { Decorator d; - Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after); + Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.Default(), after); } static void PrintMutex(const ReportMutex *rm) { @@ -243,11 +236,11 @@ static void PrintMutex(const ReportMutex *rm) { if (rm->destroyed) { Printf("%s", d.Mutex()); Printf(" Mutex M%llu is already destroyed.\n\n", rm->id); - Printf("%s", d.EndMutex()); + Printf("%s", d.Default()); } else { Printf("%s", d.Mutex()); Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr); - Printf("%s", d.EndMutex()); + Printf("%s", d.Default()); PrintStack(rm->stack); } } @@ -265,7 +258,7 @@ static void PrintThread(const ReportThread *rt) { if (rt->workerthread) { Printf(" (tid=%zu, %s) is a GCD worker thread\n", rt->os_id, thread_status); Printf("\n"); - Printf("%s", d.EndThreadDescription()); + Printf("%s", d.Default()); return; } Printf(" (tid=%zu, %s) created by %s", rt->os_id, thread_status, @@ -273,7 +266,7 @@ static void PrintThread(const ReportThread *rt) { if (rt->stack) Printf(" at:"); Printf("\n"); - Printf("%s", d.EndThreadDescription()); + Printf("%s", d.Default()); PrintStack(rt->stack); } @@ -281,7 +274,7 @@ static void PrintSleep(const ReportStack *s) { Decorator d; Printf("%s", d.Sleep()); Printf(" As if synchronized via sleep:\n"); - Printf("%s", d.EndSleep()); + Printf("%s", d.Default()); PrintStack(s); } @@ -325,7 +318,7 @@ void PrintReport(const ReportDesc *rep) { Printf("%s", d.Warning()); Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, (int)internal_getpid()); - Printf("%s", d.EndWarning()); + Printf("%s", d.Default()); if (rep->typ == ReportTypeDeadlock) { char thrbuf[kThreadBufSize]; @@ -343,7 +336,7 @@ void PrintReport(const ReportDesc *rep) { PrintMutexShort(rep->mutexes[i], " in "); Printf("%s", d.ThreadDescription()); Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i])); - Printf("%s", d.EndThreadDescription()); + Printf("%s", d.Default()); if (flags()->second_deadlock_stack) { PrintStack(rep->stacks[2*i]); Printf(" Mutex "); diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index 742802b8f..f039a317f 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -97,9 +97,7 @@ class Decorator : public SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() {} const char *Highlight() const { return Green(); } - const char *EndHighlight() const { return Default(); } const char *Note() const { return Black(); } - const char *EndNote() const { return Default(); } }; } @@ -295,7 +293,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc, Buffer.append("%c", P == Loc ? '^' : Byte); Buffer.append("%c", Byte); } - Buffer.append("%s\n", Decor.EndHighlight()); + Buffer.append("%s\n", Decor.Default()); // Go over the line again, and print names for the ranges. InRange = 0; @@ -345,12 +343,12 @@ Diag::~Diag() { switch (Level) { case DL_Error: - Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.EndWarning(), + Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.Default(), Decor.Bold()); break; case DL_Note: - Buffer.append("%s note: %s", Decor.Note(), Decor.EndNote()); + Buffer.append("%s note: %s", Decor.Note(), Decor.Default()); break; } -- cgit v1.2.1 From bc89e23c346455da26c0f9d4b14cfd9ea84f1624 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 21:00:24 +0000 Subject: [compiler-rt] Move IsStackOverflow from asan into sanitizer_common Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D37536 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312951 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 45 +------------------------------ lib/sanitizer_common/sanitizer_common.h | 1 + lib/sanitizer_common/sanitizer_posix.cc | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index c34553838..ee701fc02 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -35,56 +35,13 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); - int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); SignalContext sig = SignalContext::Create(siginfo, context); - - // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is - // probably a stack overflow. -#ifdef __s390__ - // On s390, the fault address in siginfo points to start of the page, not - // to the precise word that was accessed. Mask off the low bits of sp to - // take it into account. - bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && - sig.addr < sig.sp + 0xFFFF; -#else - bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; -#endif - -#if __powerpc__ - // Large stack frames can be allocated with e.g. - // lis r0,-10000 - // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 - // If the store faults then sp will not have been updated, so test above - // will not work, because the fault address will be more than just "slightly" - // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { - u32 inst = *(unsigned *)sig.pc; - u32 ra = (inst >> 16) & 0x1F; - u32 opcd = inst >> 26; - u32 xo = (inst >> 1) & 0x3FF; - // Check for store-with-update to sp. The instructions we accept are: - // stbu rs,d(ra) stbux rs,ra,rb - // sthu rs,d(ra) sthux rs,ra,rb - // stwu rs,d(ra) stwux rs,ra,rb - // stdu rs,ds(ra) stdux rs,ra,rb - // where ra is r1 (the stack pointer). - if (ra == 1 && - (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || - (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) - IsStackAccess = true; - } -#endif // __powerpc__ - - // We also check si_code to filter out SEGV caused by something else other - // then hitting the guard page or unmapped memory, like, for example, - // unaligned memory access. - if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) + if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) ReportStackOverflow(sig); else ReportDeadlySignal(signo, sig); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 048101295..cce1f61dd 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -306,6 +306,7 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); +bool IsStackOverflow(int code, const struct SignalContext &sig); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Alternative signal stack (POSIX-only). diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index b8f4575f7..1409d99ea 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -321,6 +321,53 @@ const char *DescribeSignalOrException(int signo) { return "UNKNOWN SIGNAL"; } +#if !SANITIZER_GO +bool IsStackOverflow(int code, const SignalContext &sig) { + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = + sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; +#else + bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { + u32 inst = *(unsigned *)sig.pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); +} +#endif //! SANITIZER_GO + } // namespace __sanitizer #endif // SANITIZER_POSIX -- cgit v1.2.1 From 0be5c228f6429f60d4e09267c4a42ed3f1abf442 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 21:12:43 +0000 Subject: Revert "[ubsan] Save binary name before parsing options" Patch was corrupted by rebase. This reverts commit r312933 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312952 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_init.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index d7433a5c9..307bca376 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -40,8 +40,8 @@ static void CommonInit() { static void CommonStandaloneInit() { SanitizerToolName = GetSanititizerToolName(); - CacheBinaryName(); InitializeFlags(); + CacheBinaryName(); __sanitizer_set_report_path(common_flags()->log_path); AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); -- cgit v1.2.1 From 7aef370457fa3854ec64cf0da19b8cda5279b2cf Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 21:13:06 +0000 Subject: [ubsan] Save binary name before parsing options Summary: To parser "include" we may need to do binary name substitution. Reviewers: eugenis, alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37658 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312953 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_init.cc | 2 +- test/sanitizer_common/TestCases/options-include.cc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index 307bca376..d7433a5c9 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -40,8 +40,8 @@ static void CommonInit() { static void CommonStandaloneInit() { SanitizerToolName = GetSanititizerToolName(); - InitializeFlags(); CacheBinaryName(); + InitializeFlags(); __sanitizer_set_report_path(common_flags()->log_path); AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); diff --git a/test/sanitizer_common/TestCases/options-include.cc b/test/sanitizer_common/TestCases/options-include.cc index 8b131a785..5b0b6d525 100644 --- a/test/sanitizer_common/TestCases/options-include.cc +++ b/test/sanitizer_common/TestCases/options-include.cc @@ -1,5 +1,4 @@ // RUN: %clangxx -O0 %s -o %t -// UNSUPPORTED: ubsan // Recursive include: options1 includes options2 // RUN: echo "symbolize=1" > %t.options1.txt -- cgit v1.2.1 From 81aed931b6ebd1c6f70920b492676c514ea99d8b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 11 Sep 2017 21:25:22 +0000 Subject: [ubsan] Make ubsan version of __sanitizer_print_stack_trace consistent with other sanitizers Summary: Other sanitizers include __sanitizer_print_stack_trace into stack trace. Reviewers: eugenis, alekseyshl Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37657 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312954 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_diag_standalone.cc | 5 +++-- test/sanitizer_common/TestCases/print-stack-trace.cc | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ubsan/ubsan_diag_standalone.cc b/lib/ubsan/ubsan_diag_standalone.cc index df8ed5fcd..1f4a5bd40 100644 --- a/lib/ubsan/ubsan_diag_standalone.cc +++ b/lib/ubsan/ubsan_diag_standalone.cc @@ -26,9 +26,10 @@ void __sanitizer_print_stack_trace() { if (request_fast_unwind) __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); - GET_REPORT_OPTIONS(false); + GET_CURRENT_PC_BP_SP; + (void)sp; BufferedStackTrace stack; - stack.Unwind(kStackTraceMax, Opts.pc, Opts.bp, nullptr, top, bottom, + stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, request_fast_unwind); stack.Print(); } diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc index df7cc050a..a6eca0b75 100644 --- a/test/sanitizer_common/TestCases/print-stack-trace.cc +++ b/test/sanitizer_common/TestCases/print-stack-trace.cc @@ -4,7 +4,6 @@ // RUN: %env_tool_opts=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE // UNSUPPORTED: darwin -// XFAIL: ubsan #include -- cgit v1.2.1 From d65db8479fb9ff1f4e313d7d90bb92f6f59bafe1 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 11 Sep 2017 21:37:53 +0000 Subject: [ubsan-minimal] Enable on Darwin Testing: check-ubsan-minimal Differential Revision: https://reviews.llvm.org/D37646 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312959 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- lib/ubsan_minimal/CMakeLists.txt | 5 ++++- test/ubsan_minimal/lit.common.cfg | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index d688abccb..5820946df 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -546,7 +546,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android") + OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android|Darwin") set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE) else() set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) diff --git a/lib/ubsan_minimal/CMakeLists.txt b/lib/ubsan_minimal/CMakeLists.txt index adc5d184d..e26fc34ce 100644 --- a/lib/ubsan_minimal/CMakeLists.txt +++ b/lib/ubsan_minimal/CMakeLists.txt @@ -16,6 +16,7 @@ add_compiler_rt_component(ubsan-minimal) # Common parts of UBSan runtime. add_compiler_rt_object_libraries(RTUbsan_minimal + OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} SOURCES ${UBSAN_MINIMAL_SOURCES} CFLAGS ${UBSAN_CFLAGS}) @@ -26,6 +27,7 @@ if(COMPILER_RT_HAS_UBSAN_MINIMAL) # Standalone UBSan runtimes. add_compiler_rt_runtime(clang_rt.ubsan_minimal STATIC + OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_SUPPORTED_ARCH} OBJECT_LIBS RTUbsan_minimal CFLAGS ${UBSAN_CFLAGS} @@ -33,13 +35,14 @@ if(COMPILER_RT_HAS_UBSAN_MINIMAL) add_compiler_rt_runtime(clang_rt.ubsan_minimal SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_SUPPORTED_ARCH} OBJECT_LIBS RTUbsan_minimal CFLAGS ${UBSAN_CFLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan-minimal) - if (UNIX) + if (UNIX AND NOT APPLE) set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) add_sanitizer_rt_symbols(clang_rt.ubsan_minimal diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index 45db6a6f6..6f239ede6 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -30,7 +30,7 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags config.suffixes = ['.c', '.cc', '.cpp'] # Check that the host supports UndefinedBehaviorSanitizerMinimal tests -if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD']: # TODO: Darwin, Windows +if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windows config.unsupported = True config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 2b4678996a6e46b574289f951fa0a7e958847533 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 11 Sep 2017 23:27:58 +0000 Subject: Runtime detection of android_set_abort_message. Summary: Use runtime detection (with a weak-undef symbol) of android_set_abort_message availability. Android NDK provides a single version of the ASan runtime library to be used for any target API level, which makes compile-time feature detection impossible (the library itself is built at API level 9). Reviewers: vitalybuka Subscribers: srhines, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37716 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312973 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 8 +++++--- lib/ubsan_minimal/ubsan_minimal_handlers.cc | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 858e4e32c..11d8b3ac0 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -553,9 +553,11 @@ void LogMessageOnPrintf(const char *str) { WriteToSyslog(str); } -#if SANITIZER_ANDROID && __ANDROID_API__ >= 21 -extern "C" void android_set_abort_message(const char *msg); -void SetAbortMessage(const char *str) { android_set_abort_message(str); } +#if SANITIZER_ANDROID +extern "C" __attribute__((weak)) void android_set_abort_message(const char *); +void SetAbortMessage(const char *str) { + if (&android_set_abort_message) android_set_abort_message(str); +} #else void SetAbortMessage(const char *str) {} #endif diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc index 3ab2811c6..97f7ae7b2 100644 --- a/lib/ubsan_minimal/ubsan_minimal_handlers.cc +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -44,11 +44,9 @@ static bool report_this_error(void *caller) { } #if defined(__ANDROID__) -extern "C" void android_set_abort_message(const char *msg); +extern "C" __attribute__((weak)) void android_set_abort_message(const char *); static void abort_with_message(const char *msg) { -#if __ANDROID_API__ >= 21 - android_set_abort_message(msg); -#endif + if (&android_set_abort_message) android_set_abort_message(msg); abort(); } #else -- cgit v1.2.1 From 21edaff6f39b7d929f4b99274c0dff5faa681eab Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 12 Sep 2017 00:01:13 +0000 Subject: [ubsan-minimal] Disable x86_64h tests when not on x86_64h git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312982 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/lit.common.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index 6f239ede6..ab0eb9720 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -33,4 +33,8 @@ config.suffixes = ['.c', '.cc', '.cpp'] if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windows config.unsupported = True +# Don't target x86_64h if the test machine can't execute x86_64h binaries. +if config.target_arch == 'x86_64h' and 'x86_64h' not in config.available_features: + config.unsupported = True + config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 6e990c4bc0d1f463fd260d4cbbe65173a6918c42 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 12 Sep 2017 00:14:33 +0000 Subject: Revert "[compiler-rt] Move IsStackOverflow from asan into sanitizer_common" Windows is broken. This reverts commit r312951 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312984 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 45 ++++++++++++++++++++++++++++++- lib/sanitizer_common/sanitizer_common.h | 1 - lib/sanitizer_common/sanitizer_posix.cc | 47 --------------------------------- 3 files changed, 44 insertions(+), 49 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index ee701fc02..c34553838 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -35,13 +35,56 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); + int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); SignalContext sig = SignalContext::Create(siginfo, context); - if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) + + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && + sig.addr < sig.sp + 0xFFFF; +#else + bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { + u32 inst = *(unsigned *)sig.pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(sig); else ReportDeadlySignal(signo, sig); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index cce1f61dd..048101295 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -306,7 +306,6 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); -bool IsStackOverflow(int code, const struct SignalContext &sig); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Alternative signal stack (POSIX-only). diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 1409d99ea..b8f4575f7 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -321,53 +321,6 @@ const char *DescribeSignalOrException(int signo) { return "UNKNOWN SIGNAL"; } -#if !SANITIZER_GO -bool IsStackOverflow(int code, const SignalContext &sig) { - // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is - // probably a stack overflow. -#ifdef __s390__ - // On s390, the fault address in siginfo points to start of the page, not - // to the precise word that was accessed. Mask off the low bits of sp to - // take it into account. - bool IsStackAccess = - sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; -#else - bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; -#endif - -#if __powerpc__ - // Large stack frames can be allocated with e.g. - // lis r0,-10000 - // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 - // If the store faults then sp will not have been updated, so test above - // will not work, because the fault address will be more than just "slightly" - // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { - u32 inst = *(unsigned *)sig.pc; - u32 ra = (inst >> 16) & 0x1F; - u32 opcd = inst >> 26; - u32 xo = (inst >> 1) & 0x3FF; - // Check for store-with-update to sp. The instructions we accept are: - // stbu rs,d(ra) stbux rs,ra,rb - // sthu rs,d(ra) sthux rs,ra,rb - // stwu rs,d(ra) stwux rs,ra,rb - // stdu rs,ds(ra) stdux rs,ra,rb - // where ra is r1 (the stack pointer). - if (ra == 1 && - (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || - (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) - IsStackAccess = true; - } -#endif // __powerpc__ - - // We also check si_code to filter out SEGV caused by something else other - // then hitting the guard page or unmapped memory, like, for example, - // unaligned memory access. - return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); -} -#endif //! SANITIZER_GO - } // namespace __sanitizer #endif // SANITIZER_POSIX -- cgit v1.2.1 From 5b686ccf0939d3df103a16b429d5719889c2fdd5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 12 Sep 2017 00:44:23 +0000 Subject: [compiler-rt] Move IsStackOverflow from asan into sanitizer_common Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D37536 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312987 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 45 +------------------------------ lib/sanitizer_common/sanitizer_common.h | 5 +++- lib/sanitizer_common/sanitizer_posix.cc | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index c34553838..ee701fc02 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -35,56 +35,13 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); - int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); SignalContext sig = SignalContext::Create(siginfo, context); - - // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is - // probably a stack overflow. -#ifdef __s390__ - // On s390, the fault address in siginfo points to start of the page, not - // to the precise word that was accessed. Mask off the low bits of sp to - // take it into account. - bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && - sig.addr < sig.sp + 0xFFFF; -#else - bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; -#endif - -#if __powerpc__ - // Large stack frames can be allocated with e.g. - // lis r0,-10000 - // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 - // If the store faults then sp will not have been updated, so test above - // will not work, because the fault address will be more than just "slightly" - // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { - u32 inst = *(unsigned *)sig.pc; - u32 ra = (inst >> 16) & 0x1F; - u32 opcd = inst >> 26; - u32 xo = (inst >> 1) & 0x3FF; - // Check for store-with-update to sp. The instructions we accept are: - // stbu rs,d(ra) stbux rs,ra,rb - // sthu rs,d(ra) sthux rs,ra,rb - // stwu rs,d(ra) stwux rs,ra,rb - // stdu rs,ds(ra) stdux rs,ra,rb - // where ra is r1 (the stack pointer). - if (ra == 1 && - (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || - (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) - IsStackAccess = true; - } -#endif // __powerpc__ - - // We also check si_code to filter out SEGV caused by something else other - // then hitting the guard page or unmapped memory, like, for example, - // unaligned memory access. - if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) + if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) ReportStackOverflow(sig); else ReportDeadlySignal(signo, sig); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 048101295..e5b53090e 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -29,8 +29,10 @@ extern "C" void _ReadWriteBarrier(); #endif namespace __sanitizer { -struct StackTrace; + struct AddressInfo; +struct SignalContext; +struct StackTrace; // Constants. const uptr kWordSize = SANITIZER_WORDSIZE / 8; @@ -306,6 +308,7 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); +bool IsStackOverflow(int code, const SignalContext &sig); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Alternative signal stack (POSIX-only). diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index b8f4575f7..1409d99ea 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -321,6 +321,53 @@ const char *DescribeSignalOrException(int signo) { return "UNKNOWN SIGNAL"; } +#if !SANITIZER_GO +bool IsStackOverflow(int code, const SignalContext &sig) { + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = + sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; +#else + bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { + u32 inst = *(unsigned *)sig.pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); +} +#endif //! SANITIZER_GO + } // namespace __sanitizer #endif // SANITIZER_POSIX -- cgit v1.2.1 From a16d671c83feef2f63925d62a581a2fc32a97d5e Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 12 Sep 2017 01:37:59 +0000 Subject: [XRay][compiler-rt] Use a single global volatile recursion guard for FDR handlers Summary: Before this change, the recursion guard for the flight data recorder (FDR) mode handlers were independent. This change makes it so that when a handler is already in the process of running and somehow the same or another handler starts running -- say in a signal handler, while the XRay handler is executing -- then we can use the same thread-local recursion guard to stop the second handler from running. Reviewers: kpw, eizan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37612 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312992 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 7 ++++--- lib/xray/xray_fdr_logging_impl.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index dee0e23ee..6123c3e47 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -42,7 +42,7 @@ namespace __xray { // NOTE: This is a pointer to avoid having to do atomic operations at // initialization time. This is OK to leak as there will only be one bufferqueue // for the runtime, initialized once through the fdrInit(...) sequence. -std::shared_ptr* BQ = nullptr; +std::shared_ptr *BQ = nullptr; __sanitizer::atomic_sint32_t LogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; @@ -207,7 +207,6 @@ void fdrLoggingHandleCustomEvent(void *Event, auto TSC_CPU = getTimestamp(); auto &TSC = std::get<0>(TSC_CPU); auto &CPU = std::get<1>(TSC_CPU); - thread_local bool Running = false; RecursionGuard Guard{Running}; if (!Guard) { assert(Running && "RecursionGuard is buggy!"); @@ -298,7 +297,9 @@ static auto UNUSED Unused = [] { using namespace __xray; if (flags()->xray_fdr_log) { XRayLogImpl Impl{ - fdrLoggingInit, fdrLoggingFinalize, fdrLoggingHandleArg0, + fdrLoggingInit, + fdrLoggingFinalize, + fdrLoggingHandleArg0, fdrLoggingFlush, }; __xray_set_log_impl(Impl); diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index ce81e4364..b2f7f3f23 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -571,6 +571,8 @@ inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { } } +thread_local volatile bool Running = false; + inline void processFunctionHook( int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, int (*wall_clock_reader)(clockid_t, struct timespec *), @@ -581,7 +583,6 @@ inline void processFunctionHook( // don't want to be clobbering potentially partial writes already happening in // the thread. We use a simple thread_local latch to only allow one on-going // handleArg0 to happen at any given time. - thread_local volatile bool Running = false; RecursionGuard Guard{Running}; if (!Guard) { assert(Running == true && "RecursionGuard is buggy!"); -- cgit v1.2.1 From 79d3d0a1edcec3f199f8de2e6b937017a7bb044b Mon Sep 17 00:00:00 2001 From: Max Moroz Date: Tue, 12 Sep 2017 02:01:54 +0000 Subject: [libfuzzer] Compare TotalNumberOfRuns with MaxNumberOfRuns when testing a memory leak. Summary: Fuzzer::TryDetectingAMemoryLeak may call ExecuteCallback which would increment TotalNumberOfRuns, but it doesn't respect Options.MaxNumberOfRuns value specified by a user. Context: https://github.com/google/oss-fuzz/issues/822#issuecomment-328153970 Reviewers: kcc Reviewed By: kcc Differential Revision: https://reviews.llvm.org/D37632 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@312993 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 2 ++ test/fuzzer/max-number-of-runs.test | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 test/fuzzer/max-number-of-runs.test diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 0354fc86e..d6185fdee 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -525,6 +525,8 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, bool DuringInitialCorpusExecution) { if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. if (!Options.DetectLeaks) return; + if (!DuringInitialCorpusExecution && + TotalNumberOfRuns >= Options.MaxNumberOfRuns) return; if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || !(EF->__lsan_do_recoverable_leak_check)) return; // No lsan. diff --git a/test/fuzzer/max-number-of-runs.test b/test/fuzzer/max-number-of-runs.test new file mode 100644 index 000000000..efe7a9c0f --- /dev/null +++ b/test/fuzzer/max-number-of-runs.test @@ -0,0 +1,10 @@ +RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest + +RUN: %t-AccumulateAllocationsTest -seed=1 -runs=2 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: Done 2 runs + +RUN: %t-AccumulateAllocationsTest -seed=1 -runs=3 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: Done 3 runs + +RUN: %t-AccumulateAllocationsTest -seed=1 -runs=4 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: Done 4 runs -- cgit v1.2.1 From 3fc19e2919f63fc084ae82d842080ea1611b31b3 Mon Sep 17 00:00:00 2001 From: Max Moroz Date: Tue, 12 Sep 2017 15:02:10 +0000 Subject: [libFuzzer] Fix lit files to make running tests more straightforward on Mac OS. Summary: Current implementation does not work if CMAKE_OSX_SYSROOT is not specified. It silently generates invalid command with the following flags: `-std=c++11 -lc++ -gline-tables-only -isysroot -fsanitize=address,fuzzer` and then fails with the following error: ``` warning: no such sysroot directory: '-fsanitize=address,fuzzer' [-Wmissing-sysroot]" <...>/RepeatedBytesTest.cpp:5:10: fatal error: 'assert.h' file not found #include ^~~~~~~~~~ 1 error generated. ``` However, if you have Command Line Tools installed, you have '/usr/include' dir. In that case, it is not necessary to specify isysroot path. Also, with the patch, in case of '/usr/include' does not exist, the '-sysroot' path would be resolved automatically in compiler-rt/cmake/base-config-ix.cmake. For more context, see the comment at `compiler-rt/cmake/base-config-ix.cmake#L76` Reviewers: kcc, george.karpenkov Reviewed By: kcc, george.karpenkov Differential Revision: https://reviews.llvm.org/D37721 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313033 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/lit.cfg | 3 +-- test/fuzzer/lit.site.cfg.in | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/fuzzer/lit.cfg b/test/fuzzer/lit.cfg index a82ca23b9..0350a1ad7 100644 --- a/test/fuzzer/lit.cfg +++ b/test/fuzzer/lit.cfg @@ -57,8 +57,7 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True): if fuzzer_enabled: sanitizers.append('fuzzer') sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers)) - isysroot_cmd = ('-isysroot %s' % config.osx_sysroot - ) if 'darwin' in config.target_triple else '' + isysroot_cmd = config.osx_sysroot_flag if config.osx_sysroot_flag else '' include_cmd = '-I%s' % libfuzzer_src_root return '%s %s %s -gline-tables-only %s %s %s' % ( compiler_cmd, std_cmd, link_cmd, isysroot_cmd, sanitizers_cmd, include_cmd) diff --git a/test/fuzzer/lit.site.cfg.in b/test/fuzzer/lit.site.cfg.in index 3f1957511..7f70c8f67 100644 --- a/test/fuzzer/lit.site.cfg.in +++ b/test/fuzzer/lit.site.cfg.in @@ -6,7 +6,7 @@ config.cpp_compiler = "@LIBFUZZER_TEST_COMPILER@" config.target_flags = "@LIBFUZZER_TEST_FLAGS@" config.c_compiler = "@LIBFUZZER_TEST_COMPILER@" -config.osx_sysroot = "@CMAKE_OSX_SYSROOT@" +config.osx_sysroot_flag = "@OSX_SYSROOT_FLAG@" config.cmake_binary_dir = "@CMAKE_BINARY_DIR@" config.target_triple = "@TARGET_TRIPLE@" -- cgit v1.2.1 From 9765720e33a1165d932d2a08690ad8ac8df0af3e Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 12 Sep 2017 17:32:25 +0000 Subject: [ubsan-minimal] Fix the x86_64h config check Checking if config.target_arch is x86_64h doesn't work (the 'h' suffix is dropped here, and I didn't account for that). Instead, check to see if '-arch x86_64h' is in the cflags. Tested on a pre-Haswell bot. rdar://problem/34378605 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313053 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index ab0eb9720..e8b42bb82 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -34,7 +34,7 @@ if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windo config.unsupported = True # Don't target x86_64h if the test machine can't execute x86_64h binaries. -if config.target_arch == 'x86_64h' and 'x86_64h' not in config.available_features: +if '-arch x86_64h' in target_cflags and 'x86_64h' not in config.available_features: config.unsupported = True config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 45735bcdc31ea2cb1e56eea5dd84189139c78eef Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 12 Sep 2017 20:03:39 +0000 Subject: [tsan] Disable user_malloc test which fails glibc 2.24 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313069 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Linux/user_malloc.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/tsan/Linux/user_malloc.cc b/test/tsan/Linux/user_malloc.cc index 6d51a9dd7..b470e6c54 100644 --- a/test/tsan/Linux/user_malloc.cc +++ b/test/tsan/Linux/user_malloc.cc @@ -1,5 +1,12 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + // UNSUPPORTED: powerpc64le + +// FIXME: Remove the test or find how to fix this. +// On some distributions, probably with newer glibc, tsan initialization calls +// dlsym which then calls malloc and crashes because of tsan is not initialized. +// UNSUPPORTED: linux + #include // Defined by tsan. -- cgit v1.2.1 From fd50a2ebe13b5ae0f7f77d9f5955eebf5f9f6811 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 12 Sep 2017 21:58:07 +0000 Subject: [libFuzzer] factor out some code into GetSizedFilesFromDir; NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313081 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerIO.cpp | 9 +++++++++ lib/fuzzer/FuzzerIO.h | 8 ++++++++ lib/fuzzer/FuzzerLoop.cpp | 33 ++++++++++++++------------------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index b3adfacf3..dac5ec658 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -86,6 +86,15 @@ void ReadDirToVectorOfUnits(const char *Path, Vector *V, } } + +void GetSizedFilesFromDir(const std::string &Dir, Vector *V) { + Vector Files; + ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true); + for (auto &File : Files) + if (size_t Size = FileSize(File)) + V->push_back({File, Size}); +} + std::string DirPlusFile(const std::string &DirPath, const std::string &FileName) { return DirPath + GetSeparator() + FileName; diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 5059c11ac..ea9f0d5a6 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -58,6 +58,14 @@ size_t FileSize(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector *V, bool TopDir); +struct SizedFile { + std::string File; + size_t Size; + bool operator<(const SizedFile &B) const { return Size < B.Size; } +}; + +void GetSizedFilesFromDir(const std::string &Dir, Vector *V); + char GetSeparator(); FILE* OpenFile(int Fd, const char *Mode); diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d6185fdee..ec126024e 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -597,26 +597,21 @@ void Fuzzer::MutateAndTestOne() { void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { const size_t kMaxSaneLen = 1 << 20; const size_t kMinDefaultLen = 4096; - struct SizedFile { - std::string File; - size_t Size; - }; Vector SizedFiles; size_t MaxSize = 0; size_t MinSize = -1; size_t TotalSize = 0; + size_t LastNumFiles = 0; for (auto &Dir : CorpusDirs) { - Vector Files; - ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true); - Printf("INFO: % 8zd files found in %s\n", Files.size(), Dir.c_str()); - for (auto &File : Files) { - if (size_t Size = FileSize(File)) { - MaxSize = Max(Size, MaxSize); - MinSize = Min(Size, MinSize); - TotalSize += Size; - SizedFiles.push_back({File, Size}); - } - } + GetSizedFilesFromDir(Dir, &SizedFiles); + Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles, + Dir.c_str()); + LastNumFiles = SizedFiles.size(); + } + for (auto &File : SizedFiles) { + MaxSize = Max(File.Size, MaxSize); + MinSize = Min(File.Size, MinSize); + TotalSize += File.Size; } if (Options.MaxLen == 0) SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); @@ -633,10 +628,10 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { if (Options.ShuffleAtStartUp) std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand()); - if (Options.PreferSmall) - std::stable_sort( - SizedFiles.begin(), SizedFiles.end(), - [](const SizedFile &A, const SizedFile &B) { return A.Size < B.Size; }); + if (Options.PreferSmall) { + std::stable_sort(SizedFiles.begin(), SizedFiles.end()); + assert(SizedFiles.front().Size <= SizedFiles.back().Size); + } // Load and execute inputs one by one. for (auto &SF : SizedFiles) { -- cgit v1.2.1 From f98401fb5848559569eb1e94b8a785b16248efa6 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Tue, 12 Sep 2017 23:32:34 +0000 Subject: Determine up front which projects are enabled. Some projects need to add conditional dependencies on other projects. compiler-rt is already doing this, and I attempted to add this to debuginfo-tests when I ran into the ordering problem, that you can't conditionally add a dependency unless that dependency's CMakeLists.txt has already been run (which would allow you to say if (TARGET foo). The solution to this seems to be to determine very early on the entire set of projects which is enabled. This is complicated by the fact that there are multiple ways to enable projects, and different tree layouts (e.g. mono-repo, out of -tree, external, etc). This patch attempts to centralize all of this into one place, and then updates compiler-rt to demonstrate as a proof of concept how this can simplify code. Differential Revision: https://reviews.llvm.org/D37637 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313091 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62118855b..cda9fb92e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,7 +225,7 @@ append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS) # always respect the optimization flags set by CMAKE_BUILD_TYPE instead. if (NOT MSVC) - # Build with optimization, unless we're in debug mode. + # Build with optimization, unless we're in debug mode. if(COMPILER_RT_DEBUG) list(APPEND SANITIZER_COMMON_CFLAGS -O0) else() @@ -315,28 +315,16 @@ endif() add_subdirectory(include) -set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx) -if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) - set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) -else() - set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/../libcxx) - if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) - set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) - else() - set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE) - endif() +set(COMPILER_RT_HAS_LIBCXX_SOURCES ${LLVM_PROJECT_LIBCXX_ENABLED}) +if (LLVM_PROJECT_LIBCXX_ENABLED) + set(COMPILER_RT_LIBCXX_PATH ${LLVM_PROJECT_LIBCXX_SOURCE_DIR}) + message("compiler-rt libcxx enabled at ${COMPILER_RT_LIBCXX_PATH}") endif() -set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) -if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) - set(COMPILER_RT_HAS_LLD TRUE) -else() - set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld) - if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) - set(COMPILER_RT_HAS_LLD TRUE) - else() - set(COMPILER_RT_HAS_LLD FALSE) - endif() +set(COMPILER_RT_HAS_LLD ${LLVM_PROJECT_LLD_ENABLED}) +if (LLVM_PROJECT_LLD_ENABLED) + set(COMPILER_RT_LLD_PATH ${LLVM_PROJECT_LLD_SOURCE_DIR}) + message("compiler-rt lld enabled at ${COMPILER_RT_LLD_PATH}") endif() pythonize_bool(COMPILER_RT_HAS_LLD) -- cgit v1.2.1 From 284242005b49b997d8528f25b9c0eb823a9d7747 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 13 Sep 2017 00:04:35 +0000 Subject: [ubsan] Enable -fsanitize=function test on Darwin Differential Revision: https://reviews.llvm.org/D37598 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313097 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/Function/function.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp index 6e7e314bf..1d631ad4e 100644 --- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp +++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp @@ -3,9 +3,6 @@ // Verify that we can disable symbolization if needed: // RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM -// -fsanitize=function is unsupported on Darwin yet. -// XFAIL: darwin - #include void f() {} @@ -18,9 +15,9 @@ void make_valid_call() { } void make_invalid_call() { - // CHECK: function.cpp:25:3: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)' - // CHECK-NEXT: function.cpp:11: note: f() defined here - // NOSYM: function.cpp:25:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' + // CHECK: function.cpp:[[@LINE+4]]:3: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)' + // CHECK-NEXT: function.cpp:[[@LINE-11]]: note: f() defined here + // NOSYM: function.cpp:[[@LINE+2]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)' // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here reinterpret_cast(reinterpret_cast(f))(42); } -- cgit v1.2.1 From cad7a086bf3ecc2d9cb1e79cfb299fe923a53c8e Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 00:24:44 +0000 Subject: [compiler-rt] Move IsStackOverflow into sanitizer_posix_libcdep.cc to the rest of instrumentation code. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313100 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix.cc | 47 ------------------------- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 45 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 1409d99ea..b8f4575f7 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -321,53 +321,6 @@ const char *DescribeSignalOrException(int signo) { return "UNKNOWN SIGNAL"; } -#if !SANITIZER_GO -bool IsStackOverflow(int code, const SignalContext &sig) { - // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is - // probably a stack overflow. -#ifdef __s390__ - // On s390, the fault address in siginfo points to start of the page, not - // to the precise word that was accessed. Mask off the low bits of sp to - // take it into account. - bool IsStackAccess = - sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; -#else - bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; -#endif - -#if __powerpc__ - // Large stack frames can be allocated with e.g. - // lis r0,-10000 - // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 - // If the store faults then sp will not have been updated, so test above - // will not work, because the fault address will be more than just "slightly" - // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { - u32 inst = *(unsigned *)sig.pc; - u32 ra = (inst >> 16) & 0x1F; - u32 opcd = inst >> 26; - u32 xo = (inst >> 1) & 0x3FF; - // Check for store-with-update to sp. The instructions we accept are: - // stbu rs,d(ra) stbux rs,ra,rb - // sthu rs,d(ra) sthux rs,ra,rb - // stwu rs,d(ra) stwux rs,ra,rb - // stdu rs,ds(ra) stdux rs,ra,rb - // where ra is r1 (the stack pointer). - if (ra == 1 && - (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || - (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) - IsStackAccess = true; - } -#endif // __powerpc__ - - // We also check si_code to filter out SEGV caused by something else other - // then hitting the guard page or unmapped memory, like, for example, - // unaligned memory access. - return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); -} -#endif //! SANITIZER_GO - } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 13062f000..5ff71b4e2 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -215,6 +215,51 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { MaybeInstallSigaction(SIGFPE, handler); MaybeInstallSigaction(SIGILL, handler); } +bool IsStackOverflow(int code, const SignalContext &sig) { + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = + sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; +#else + bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { + u32 inst = *(unsigned *)sig.pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); +} + #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { -- cgit v1.2.1 From 995eff5631725e6e6fceba4883d01a7151ee5962 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 13 Sep 2017 01:18:15 +0000 Subject: [Fuchsia] Magenta -> Zircon Fuchsia's lowest API layer has been renamed from Magenta to Zircon. Patch by Roland McGrath Differential Revision: https://reviews.llvm.org/D37770 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313106 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 +- lib/asan/asan_fuchsia.cc | 14 +- lib/interception/interception.h | 2 +- lib/sanitizer_common/sanitizer_coverage_fuchsia.cc | 38 ++-- lib/sanitizer_common/sanitizer_fuchsia.cc | 202 ++++++++++----------- lib/sanitizer_common/sanitizer_fuchsia.h | 2 +- .../sanitizer_symbolizer_fuchsia.cc | 10 +- 7 files changed, 134 insertions(+), 136 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cda9fb92e..2a5ac10d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -296,7 +296,7 @@ append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia") list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs,-z,now,-z,relro) - list(APPEND SANITIZER_COMMON_LINK_LIBS magenta) + list(APPEND SANITIZER_COMMON_LINK_LIBS zircon) endif() # Warnings to turn off for all libraries, not just sanitizers. diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc index f41fabdba..02fb8be4a 100644 --- a/lib/asan/asan_fuchsia.cc +++ b/lib/asan/asan_fuchsia.cc @@ -21,9 +21,9 @@ #include "asan_thread.h" #include -#include -#include -#include +#include +#include +#include namespace __asan { @@ -126,13 +126,13 @@ void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { // Called by __asan::AsanInitInternal (asan_rtl.c). AsanThread *CreateMainThread() { thrd_t self = thrd_current(); - char name[MX_MAX_NAME_LEN]; + char name[ZX_MAX_NAME_LEN]; CHECK_NE(__sanitizer::MainThreadStackBase, 0); CHECK_GT(__sanitizer::MainThreadStackSize, 0); AsanThread *t = CreateAsanThread( nullptr, 0, reinterpret_cast(self), true, - _mx_object_get_property(thrd_get_mx_handle(self), MX_PROP_NAME, name, - sizeof(name)) == MX_OK + _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name, + sizeof(name)) == ZX_OK ? name : nullptr, __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); @@ -192,7 +192,7 @@ static void ThreadExitHook(void *hook, uptr os_id) { } // namespace __asan -// These are declared (in extern "C") by . +// These are declared (in extern "C") by . // The system runtime will call our definitions directly. void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, diff --git a/lib/interception/interception.h b/lib/interception/interception.h index 9e65ffa8e..953498484 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -152,7 +152,7 @@ const interpose_substitution substitution_##func_name[] \ // There is no general interception at all on Fuchsia. // Sanitizer runtimes just define functions directly to preempt them, // and have bespoke ways to access the underlying libc functions. -# include +# include # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define REAL(x) __unsanitized_##x # define DECLARE_REAL(ret_type, func, ...) diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc index 4d20bb2ed..c5be48bce 100644 --- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -21,7 +21,7 @@ // Unlike the traditional implementation that uses an atexit hook to write // out data files at the end, the results on Fuchsia do not go into a file // per se. The 'coverage_dir' option is ignored. Instead, they are stored -// directly into a shared memory object (a Magenta VMO). At exit, that VMO +// directly into a shared memory object (a Zircon VMO). At exit, that VMO // is handed over to a system service that's responsible for getting the // data out to somewhere that it can be fed into the sancov tool (where and // how is not our problem). @@ -32,9 +32,9 @@ #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" -#include -#include -#include +#include +#include +#include using namespace __sanitizer; // NOLINT @@ -88,19 +88,19 @@ class TracePcGuardController { void Dump() { BlockingMutexLock locked(&setup_lock_); if (array_) { - CHECK_NE(vmo_, MX_HANDLE_INVALID); + CHECK_NE(vmo_, ZX_HANDLE_INVALID); // Publish the VMO to the system, where it can be collected and // analyzed after this process exits. This always consumes the VMO // handle. Any failure is just logged and not indicated to us. __sanitizer_publish_data(kSancovSinkName, vmo_); - vmo_ = MX_HANDLE_INVALID; + vmo_ = ZX_HANDLE_INVALID; // This will route to __sanitizer_log_write, which will ensure that // information about shared libraries is written out. This message // uses the `dumpfile` symbolizer markup element to highlight the // dump. See the explanation for this in: - // https://fuchsia.googlesource.com/magenta/+/master/docs/symbolizer_markup.md + // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md Printf("SanitizerCoverage: {{{dumpfile:%s:%s}}} with up to %u PCs\n", kSancovSinkName, vmo_name_, next_index_ - 1); } @@ -116,8 +116,8 @@ class TracePcGuardController { BlockingMutex setup_lock_; uptr *array_; u32 next_index_; - mx_handle_t vmo_; - char vmo_name_[MX_MAX_NAME_LEN]; + zx_handle_t vmo_; + char vmo_name_[ZX_MAX_NAME_LEN]; size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } @@ -126,19 +126,19 @@ class TracePcGuardController { DCHECK(common_flags()->coverage); if (next_index_ == 0) { - CHECK_EQ(vmo_, MX_HANDLE_INVALID); + CHECK_EQ(vmo_, ZX_HANDLE_INVALID); CHECK_EQ(array_, nullptr); // The first sample goes at [1] to reserve [0] for the magic number. next_index_ = 1 + num_guards; - mx_status_t status = _mx_vmo_create(DataSize(), 0, &vmo_); - CHECK_EQ(status, MX_OK); + zx_status_t status = _zx_vmo_create(DataSize(), 0, &vmo_); + CHECK_EQ(status, ZX_OK); // Give the VMO a name including our process KOID so it's easy to spot. internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName, internal_getpid()); - _mx_object_set_property(vmo_, MX_PROP_NAME, vmo_name_, + _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, internal_strlen(vmo_name_)); // Map the largest possible view we might need into the VMO. Later @@ -147,9 +147,9 @@ class TracePcGuardController { // any multi-thread synchronization issues with that. uintptr_t mapping; status = - _mx_vmar_map(_mx_vmar_root_self(), 0, vmo_, 0, MappingSize, - MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &mapping); - CHECK_EQ(status, MX_OK); + _zx_vmar_map(_zx_vmar_root_self(), 0, vmo_, 0, MappingSize, + ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &mapping); + CHECK_EQ(status, ZX_OK); // Hereafter other threads are free to start storing into // elements [1, next_index_) of the big array. @@ -164,14 +164,14 @@ class TracePcGuardController { // The VMO is already mapped in, but it's not big enough to use the // new indices. So increase the size to cover the new maximum index. - CHECK_NE(vmo_, MX_HANDLE_INVALID); + CHECK_NE(vmo_, ZX_HANDLE_INVALID); CHECK_NE(array_, nullptr); uint32_t first_index = next_index_; next_index_ += num_guards; - mx_status_t status = _mx_vmo_set_size(vmo_, DataSize()); - CHECK_EQ(status, MX_OK); + zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); + CHECK_EQ(status, ZX_OK); return first_index; } diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index a6abe4391..7ea522a0d 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -22,42 +22,42 @@ #include "sanitizer_stacktrace.h" #include -#include -#include -#include #include #include #include #include +#include +#include +#include namespace __sanitizer { -void NORETURN internal__exit(int exitcode) { _mx_process_exit(exitcode); } +void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); } uptr internal_sched_yield() { - mx_status_t status = _mx_nanosleep(0); - CHECK_EQ(status, MX_OK); + zx_status_t status = _zx_nanosleep(0); + CHECK_EQ(status, ZX_OK); return 0; // Why doesn't this return void? } -static void internal_nanosleep(mx_time_t ns) { - mx_status_t status = _mx_nanosleep(_mx_deadline_after(ns)); - CHECK_EQ(status, MX_OK); +static void internal_nanosleep(zx_time_t ns) { + zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns)); + CHECK_EQ(status, ZX_OK); } unsigned int internal_sleep(unsigned int seconds) { - internal_nanosleep(MX_SEC(seconds)); + internal_nanosleep(ZX_SEC(seconds)); return 0; } -u64 NanoTime() { return _mx_time_get(MX_CLOCK_UTC); } +u64 NanoTime() { return _zx_time_get(ZX_CLOCK_UTC); } uptr internal_getpid() { - mx_info_handle_basic_t info; - mx_status_t status = - _mx_object_get_info(_mx_process_self(), MX_INFO_HANDLE_BASIC, &info, + zx_info_handle_basic_t info; + zx_status_t status = + _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL); - CHECK_EQ(status, MX_OK); + CHECK_EQ(status, ZX_OK); uptr pid = static_cast(info.koid); CHECK_EQ(pid, info.koid); return pid; @@ -73,7 +73,7 @@ int Atexit(void (*function)(void)) { return atexit(function); } void SleepForSeconds(int seconds) { internal_sleep(seconds); } -void SleepForMillis(int millis) { internal_nanosleep(MX_MSEC(millis)); } +void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); } void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { pthread_attr_t attr; @@ -154,10 +154,10 @@ void BlockingMutex::Lock() { if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) return; while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { - mx_status_t status = _mx_futex_wait(reinterpret_cast(m), - MtxSleeping, MX_TIME_INFINITE); - if (status != MX_ERR_BAD_STATE) // Normal race. - CHECK_EQ(status, MX_OK); + zx_status_t status = _zx_futex_wait(reinterpret_cast(m), + MtxSleeping, ZX_TIME_INFINITE); + if (status != ZX_ERR_BAD_STATE) // Normal race. + CHECK_EQ(status, ZX_OK); } } @@ -166,8 +166,8 @@ void BlockingMutex::Unlock() { u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); CHECK_NE(v, MtxUnlocked); if (v == MtxSleeping) { - mx_status_t status = _mx_futex_wake(reinterpret_cast(m), 1); - CHECK_EQ(status, MX_OK); + zx_status_t status = _zx_futex_wake(reinterpret_cast(m), 1); + CHECK_EQ(status, ZX_OK); } } @@ -191,26 +191,26 @@ static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, bool raw_report, bool die_for_nomem) { size = RoundUpTo(size, PAGE_SIZE); - mx_handle_t vmo; - mx_status_t status = _mx_vmo_create(size, 0, &vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, mem_type, "mx_vmo_create", status, + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, raw_report); return nullptr; } - _mx_object_set_property(vmo, MX_PROP_NAME, mem_type, + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, internal_strlen(mem_type)); // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? uintptr_t addr; - status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, size, - MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &addr); - _mx_handle_close(vmo); + status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, size, + ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr); + _zx_handle_close(vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, mem_type, "mx_vmar_map", status, + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, raw_report); return nullptr; } @@ -237,22 +237,22 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie // uses that VMAR instead of the root. -mx_handle_t allocator_vmar = MX_HANDLE_INVALID; +zx_handle_t allocator_vmar = ZX_HANDLE_INVALID; uintptr_t allocator_vmar_base; size_t allocator_vmar_size; void *MmapNoAccess(uptr size) { size = RoundUpTo(size, PAGE_SIZE); - CHECK_EQ(allocator_vmar, MX_HANDLE_INVALID); + CHECK_EQ(allocator_vmar, ZX_HANDLE_INVALID); uintptr_t base; - mx_status_t status = - _mx_vmar_allocate(_mx_vmar_root_self(), 0, size, - MX_VM_FLAG_CAN_MAP_READ | MX_VM_FLAG_CAN_MAP_WRITE | - MX_VM_FLAG_CAN_MAP_SPECIFIC, + zx_status_t status = + _zx_vmar_allocate(_zx_vmar_root_self(), 0, size, + ZX_VM_FLAG_CAN_MAP_READ | ZX_VM_FLAG_CAN_MAP_WRITE | + ZX_VM_FLAG_CAN_MAP_SPECIFIC, &allocator_vmar, &base); - if (status != MX_OK) + if (status != ZX_OK) ReportMmapFailureAndDie(size, "sanitizer allocator address space", - "mx_vmar_allocate", status); + "zx_vmar_allocate", status); allocator_vmar_base = base; allocator_vmar_size = size; @@ -264,14 +264,14 @@ constexpr const char kAllocatorVmoName[] = "sanitizer_allocator"; static void *DoMmapFixedOrDie(uptr fixed_addr, uptr size, bool die_for_nomem) { size = RoundUpTo(size, PAGE_SIZE); - mx_handle_t vmo; - mx_status_t status = _mx_vmo_create(size, 0, &vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, kAllocatorVmoName, "mx_vmo_create", status); + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, kAllocatorVmoName, "zx_vmo_create", status); return nullptr; } - _mx_object_set_property(vmo, MX_PROP_NAME, kAllocatorVmoName, + _zx_object_set_property(vmo, ZX_PROP_NAME, kAllocatorVmoName, sizeof(kAllocatorVmoName) - 1); DCHECK_GE(fixed_addr, allocator_vmar_base); @@ -280,14 +280,14 @@ static void *DoMmapFixedOrDie(uptr fixed_addr, uptr size, bool die_for_nomem) { DCHECK_GE(allocator_vmar_size - offset, size); uintptr_t addr; - status = _mx_vmar_map( + status = _zx_vmar_map( allocator_vmar, offset, vmo, 0, size, - MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE | MX_VM_FLAG_SPECIFIC, + ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_SPECIFIC, &addr); - _mx_handle_close(vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, kAllocatorVmoName, "mx_vmar_map", status); + _zx_handle_close(vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, kAllocatorVmoName, "zx_vmar_map", status); return nullptr; } @@ -315,14 +315,14 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); - mx_handle_t vmo; - mx_status_t status = _mx_vmo_create(size, 0, &vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "mx_vmo_create", status, false); + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false); return nullptr; } - _mx_object_set_property(vmo, MX_PROP_NAME, mem_type, + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, internal_strlen(mem_type)); // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? @@ -333,37 +333,37 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, // beginning of the VMO, and unmap the excess before and after. size_t map_size = size + alignment; uintptr_t addr; - status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, map_size, - MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &addr); - if (status == MX_OK) { + status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size, + ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr); + if (status == ZX_OK) { uintptr_t map_addr = addr; uintptr_t map_end = map_addr + map_size; addr = RoundUpTo(map_addr, alignment); uintptr_t end = addr + size; if (addr != map_addr) { - mx_info_vmar_t info; - status = _mx_object_get_info(_mx_vmar_root_self(), MX_INFO_VMAR, &info, + zx_info_vmar_t info; + status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info, sizeof(info), NULL, NULL); - if (status == MX_OK) { + if (status == ZX_OK) { uintptr_t new_addr; status = - _mx_vmar_map(_mx_vmar_root_self(), addr - info.base, vmo, 0, size, - MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE | - MX_VM_FLAG_SPECIFIC_OVERWRITE, + _zx_vmar_map(_zx_vmar_root_self(), addr - info.base, vmo, 0, size, + ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | + ZX_VM_FLAG_SPECIFIC_OVERWRITE, &new_addr); - if (status == MX_OK) CHECK_EQ(new_addr, addr); + if (status == ZX_OK) CHECK_EQ(new_addr, addr); } } - if (status == MX_OK && addr != map_addr) - status = _mx_vmar_unmap(_mx_vmar_root_self(), map_addr, addr - map_addr); - if (status == MX_OK && end != map_end) - status = _mx_vmar_unmap(_mx_vmar_root_self(), end, map_end - end); + if (status == ZX_OK && addr != map_addr) + status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr); + if (status == ZX_OK && end != map_end) + status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end); } - _mx_handle_close(vmo); + _zx_handle_close(vmo); - if (status != MX_OK) { - if (status != MX_ERR_NO_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "mx_vmar_map", status, false); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false); return nullptr; } @@ -376,9 +376,9 @@ void UnmapOrDie(void *addr, uptr size) { if (!addr || !size) return; size = RoundUpTo(size, PAGE_SIZE); - mx_status_t status = _mx_vmar_unmap(_mx_vmar_root_self(), + zx_status_t status = _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast(addr), size); - if (status != MX_OK) { + if (status != ZX_OK) { Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", SanitizerToolName, size, size, addr); CHECK("unable to unmap" && 0); @@ -388,7 +388,7 @@ void UnmapOrDie(void *addr, uptr size) { } // This is used on the shadow mapping, which cannot be changed. -// Magenta doesn't have anything like MADV_DONTNEED. +// Zircon doesn't have anything like MADV_DONTNEED. void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} void DumpProcessMap() { @@ -397,22 +397,22 @@ void DumpProcessMap() { bool IsAccessibleMemoryRange(uptr beg, uptr size) { // TODO(mcgrathr): Figure out a better way. - mx_handle_t vmo; - mx_status_t status = _mx_vmo_create(size, 0, &vmo); - if (status == MX_OK) { + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status == ZX_OK) { while (size > 0) { size_t wrote; - status = _mx_vmo_write(vmo, reinterpret_cast(beg), 0, size, + status = _zx_vmo_write(vmo, reinterpret_cast(beg), 0, size, &wrote); - if (status != MX_OK) break; + if (status != ZX_OK) break; CHECK_GT(wrote, 0); CHECK_LE(wrote, size); beg += wrote; size -= wrote; } - _mx_handle_close(vmo); + _zx_handle_close(vmo); } - return status == MX_OK; + return status == ZX_OK; } // FIXME implement on this platform. @@ -420,27 +420,27 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {} bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr *read_len, uptr max_len, error_t *errno_p) { - mx_handle_t vmo; - mx_status_t status = __sanitizer_get_configuration(file_name, &vmo); - if (status == MX_OK) { + zx_handle_t vmo; + zx_status_t status = __sanitizer_get_configuration(file_name, &vmo); + if (status == ZX_OK) { uint64_t vmo_size; - status = _mx_vmo_get_size(vmo, &vmo_size); - if (status == MX_OK) { + status = _zx_vmo_get_size(vmo, &vmo_size); + if (status == ZX_OK) { if (vmo_size < max_len) max_len = vmo_size; size_t map_size = RoundUpTo(max_len, PAGE_SIZE); uintptr_t addr; - status = _mx_vmar_map(_mx_vmar_root_self(), 0, vmo, 0, map_size, - MX_VM_FLAG_PERM_READ, &addr); - if (status == MX_OK) { + status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size, + ZX_VM_FLAG_PERM_READ, &addr); + if (status == ZX_OK) { *buff = reinterpret_cast(addr); *buff_size = map_size; *read_len = max_len; } } - _mx_handle_close(vmo); + _zx_handle_close(vmo); } - if (status != MX_OK && errno_p) *errno_p = status; - return status == MX_OK; + if (status != ZX_OK && errno_p) *errno_p = status; + return status == ZX_OK; } void RawWrite(const char *buffer) { @@ -481,9 +481,9 @@ uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { uptr MainThreadStackBase, MainThreadStackSize; bool GetRandom(void *buffer, uptr length, bool blocking) { - CHECK_LE(length, MX_CPRNG_DRAW_MAX_LEN); + CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); size_t size; - CHECK_EQ(_mx_cprng_draw(buffer, length, &size), MX_OK); + CHECK_EQ(_zx_cprng_draw(buffer, length, &size), ZX_OK); CHECK_EQ(size, length); return true; } diff --git a/lib/sanitizer_common/sanitizer_fuchsia.h b/lib/sanitizer_common/sanitizer_fuchsia.h index 455eadf6f..18821b4fd 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.h +++ b/lib/sanitizer_common/sanitizer_fuchsia.h @@ -18,7 +18,7 @@ #include "sanitizer_common.h" -#include +#include namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc index 942029254..3d1117d9d 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc @@ -26,7 +26,7 @@ namespace __sanitizer { // Fuchsia's logging infrastructure emits enough information about // process memory layout that a post-processing filter can do the // symbolization and pretty-print the markup. See the spec at: -// https://fuchsia.googlesource.com/magenta/+/master/docs/symbolizer_markup.md +// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md // This is used by UBSan for type names, and by ASan for global variable names. constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; @@ -34,7 +34,7 @@ constexpr uptr kFormatDemangleMax = 1024; // Arbitrary. // Function name or equivalent from PC location. constexpr const char *kFormatFunction = "{{{pc:%p}}}"; -constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. +constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. // Global variable name or equivalent from data memory address. constexpr const char *kFormatData = "{{{data:%p}}}"; @@ -97,12 +97,10 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, } Symbolizer *Symbolizer::PlatformInit() { - return new(symbolizer_allocator_) Symbolizer({}); + return new (symbolizer_allocator_) Symbolizer({}); } -void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); -} +void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } } // namespace __sanitizer -- cgit v1.2.1 From 79b583e7f43a4d411a5b32f5da5eb3c50d1c735b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 04:46:37 +0000 Subject: [compiler-rt] Move *Sanitizer:DEADLYSIGNAL printing into common part Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D37764 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313115 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 6 +----- lib/sanitizer_common/sanitizer_common.h | 4 +++- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 8 ++++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index ee701fc02..8f788bd13 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -35,11 +35,7 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); - // Write the first message using fd=2, just in case. - // It may actually fail to write in case stderr is closed. - internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); - static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; - internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); + StartReportDeadlySignal(); SignalContext sig = SignalContext::Create(siginfo, context); if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) ReportStackOverflow(sig); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index e5b53090e..483af36d7 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -308,9 +308,11 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); -bool IsStackOverflow(int code, const SignalContext &sig); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); +// Signal reporting. +void StartReportDeadlySignal(); +bool IsStackOverflow(int code, const SignalContext &sig); // Alternative signal stack (POSIX-only). void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 5ff71b4e2..2250a0e42 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -260,6 +260,14 @@ bool IsStackOverflow(int code, const SignalContext &sig) { return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); } +void StartReportDeadlySignal() { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { -- cgit v1.2.1 From a2354569bf5883206577a8299c38449391cce3e6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 06:24:59 +0000 Subject: [compiler-rt] Move dump_instruction_bytes and dump_registers into sanitizer_common Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D37766 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313117 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_descriptions.h | 1 - lib/asan/asan_errors.cc | 31 ---------------- lib/asan/asan_flags.inc | 5 --- lib/sanitizer_common/sanitizer_common.h | 4 +++ lib/sanitizer_common/sanitizer_common_libcdep.cc | 41 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_flags.inc | 5 +++ lib/sanitizer_common/sanitizer_report_decorator.h | 1 + .../asan/TestCases/Posix/dump_instruction_bytes.cc | 20 ----------- .../TestCases/Posix/dump_instruction_bytes.cc | 21 +++++++++++ 9 files changed, 72 insertions(+), 57 deletions(-) delete mode 100644 test/asan/TestCases/Posix/dump_instruction_bytes.cc create mode 100644 test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h index 5161715df..006a240ac 100644 --- a/lib/asan/asan_descriptions.h +++ b/lib/asan/asan_descriptions.h @@ -69,7 +69,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { return Default(); } } - const char *MemoryByte() { return Magenta(); } }; enum ShadowKind : u8 { diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 0f2a9e26f..c9cf8f70b 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -38,37 +38,6 @@ void ErrorStackOverflow::Print() { ReportErrorSummary(scariness.GetDescription(), &stack); } -static void MaybeDumpInstructionBytes(uptr pc) { - if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return; - InternalScopedString str(1024); - str.append("First 16 instruction bytes at pc: "); - if (IsAccessibleMemoryRange(pc, 16)) { - for (int i = 0; i < 16; ++i) { - PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " "); - } - str.append("\n"); - } else { - str.append("unaccessible\n"); - } - Report("%s", str.data()); -} - -static void MaybeDumpRegisters(void *context) { - if (!flags()->dump_registers) return; - SignalContext::DumpAllRegisters(context); -} - -static void MaybeReportNonExecRegion(uptr pc) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD - MemoryMappingLayout proc_maps(/*cache_enabled*/ true); - MemoryMappedSegment segment; - while (proc_maps.Next(&segment)) { - if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) - Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); - } -#endif -} - void ErrorDeadlySignal::Print() { Decorator d; Printf("%s", d.Warning()); diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 19ebc696e..00071d39f 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -147,11 +147,6 @@ ASAN_FLAG(int, detect_odr_violation, 2, "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " "have different sizes") -ASAN_FLAG(bool, dump_instruction_bytes, false, - "If true, dump 16 bytes starting at the instruction that caused SEGV") -ASAN_FLAG(bool, dump_registers, true, - "If true, dump values of CPU registers when SEGV happens. Only " - "available on OS X for now.") ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") ASAN_FLAG(bool, halt_on_error, true, "Crash the program after printing the first error report " diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 483af36d7..d2021a0c9 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -313,6 +313,10 @@ const char *DescribeSignalOrException(int signo); // Signal reporting. void StartReportDeadlySignal(); bool IsStackOverflow(int code, const SignalContext &sig); +// FIXME: Hide after moving more signal handling code into common. +void MaybeReportNonExecRegion(uptr pc); +void MaybeDumpInstructionBytes(uptr pc); +void MaybeDumpRegisters(void *context); // Alternative signal stack (POSIX-only). void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index b54503a6d..cccb3be3e 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -16,6 +16,8 @@ #include "sanitizer_allocator_interface.h" #include "sanitizer_file.h" #include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" @@ -145,6 +147,45 @@ void BackgroundThread(void *arg) { } #endif +void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) + Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); + } +#endif +} + +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte) { + SanitizerCommonDecorator d; + str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, + d.Default()); +} + +void MaybeDumpInstructionBytes(uptr pc) { + if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) + return; + InternalScopedString str(1024); + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i]); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + +void MaybeDumpRegisters(void *context) { + if (!common_flags()->dump_registers) return; + SignalContext::DumpAllRegisters(context); +} + void WriteToSyslog(const char *msg) { InternalScopedString msg_copy(kErrorMessageBufferSize); msg_copy.append("%s", msg); diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 9f71861ef..eab33ab45 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -229,3 +229,8 @@ COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash " "(asan only).") COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.") COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.") +COMMON_FLAG(bool, dump_instruction_bytes, false, + "If true, dump 16 bytes starting at the instruction that caused SEGV") +COMMON_FLAG(bool, dump_registers, true, + "If true, dump values of CPU registers when SEGV happens. Only " + "available on OS X for now.") diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h index daa7f00a0..060b58d3f 100644 --- a/lib/sanitizer_common/sanitizer_report_decorator.h +++ b/lib/sanitizer_common/sanitizer_report_decorator.h @@ -28,6 +28,7 @@ class SanitizerCommonDecorator { const char *Bold() const { return ansi_ ? "\033[1m" : ""; } const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } const char *Warning() const { return Red(); } + const char *MemoryByte() { return Magenta(); } protected: const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } diff --git a/test/asan/TestCases/Posix/dump_instruction_bytes.cc b/test/asan/TestCases/Posix/dump_instruction_bytes.cc deleted file mode 100644 index b5b38ff08..000000000 --- a/test/asan/TestCases/Posix/dump_instruction_bytes.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Check that ASan prints the faulting instruction bytes on -// dump_instruction_bytes=1 -// RUN: %clangxx_asan %s -o %t -// RUN: %env_asan_opts=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP -// -// REQUIRES: x86-target-arch - -int main() { -#if defined(__x86_64__) - asm("movq $0, %rax"); - asm("movl $0xcafebabe, 0x0(%rax)"); -#elif defined(i386) - asm("movl $0, %eax"); - asm("movl $0xcafebabe, 0x0(%eax)"); -#endif - // CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca - // CHECK-NODUMP-NOT: First 16 instruction bytes - return 0; -} diff --git a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc new file mode 100644 index 000000000..408da6bb6 --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc @@ -0,0 +1,21 @@ +// Check that sanitizer prints the faulting instruction bytes on +// dump_instruction_bytes=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP +// +// REQUIRES: x86-target-arch +// XFAIL: lsan, msan, tsan, ubsan + +int main() { +#if defined(__x86_64__) + asm("movq $0, %rax"); + asm("movl $0xcafebabe, 0x0(%rax)"); +#elif defined(i386) + asm("movl $0, %eax"); + asm("movl $0xcafebabe, 0x0(%eax)"); +#endif + // CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca + // CHECK-NODUMP-NOT: First 16 instruction bytes + return 0; +} -- cgit v1.2.1 From d113a775f8301126be613eab8e70297444454eb9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 06:25:09 +0000 Subject: Fix line breaks. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313118 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 2250a0e42..d7d0e7d44 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -20,7 +20,6 @@ #include "sanitizer_flags.h" #include "sanitizer_platform_limits_netbsd.h" #include "sanitizer_platform_limits_posix.h" - #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" @@ -215,6 +214,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { MaybeInstallSigaction(SIGFPE, handler); MaybeInstallSigaction(SIGILL, handler); } + bool IsStackOverflow(int code, const SignalContext &sig) { // Access at a reasonable offset above SP, or slightly below it (to account // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is -- cgit v1.2.1 From 0a55927170a1f648a53c17325e55d89f36888852 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 06:33:43 +0000 Subject: [compiler-rt] Add test for not fully implemented dump_registers Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris, llvm-commits Differential Revision: https://reviews.llvm.org/D37765 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313120 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Posix/dump_registers.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/sanitizer_common/TestCases/Posix/dump_registers.cc diff --git a/test/sanitizer_common/TestCases/Posix/dump_registers.cc b/test/sanitizer_common/TestCases/Posix/dump_registers.cc new file mode 100644 index 000000000..07e87bedc --- /dev/null +++ b/test/sanitizer_common/TestCases/Posix/dump_registers.cc @@ -0,0 +1,20 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP +// +// FIXME: Implement. +// UNSUPPORTED: asan +// UNSUPPORTED: lsan +// UNSUPPORTED: msan +// UNSUPPORTED: tsan +// UNSUPPORTED: ubsan + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-NODUMP-NOT: Register values + return 0; +} -- cgit v1.2.1 From 5c8c2c47d086e5881ccda48a66b5b09eb938237c Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 08:10:16 +0000 Subject: [compiler-rt] Compile signal specific functions only for !SANITIZER_GO git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313130 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_libcdep.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index cccb3be3e..21a591e64 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -147,6 +147,7 @@ void BackgroundThread(void *arg) { } #endif +#if !SANITIZER_GO void MaybeReportNonExecRegion(uptr pc) { #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD MemoryMappingLayout proc_maps(/*cache_enabled*/ true); @@ -185,6 +186,7 @@ void MaybeDumpRegisters(void *context) { if (!common_flags()->dump_registers) return; SignalContext::DumpAllRegisters(context); } +#endif void WriteToSyslog(const char *msg) { InternalScopedString msg_copy(kErrorMessageBufferSize); -- cgit v1.2.1 From 2eaff6eec07f4e8ac7698bde99cd91ef01b7a0b1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 18:30:06 +0000 Subject: [compiler-rt] Add siginfo into SignalContext Summary: Information stored there is often been passed along with SignalContext. Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D37792 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313167 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.h | 4 ++-- lib/asan/asan_posix.cc | 4 ++-- lib/asan/asan_report.cc | 4 ++-- lib/asan/asan_report.h | 2 +- lib/sanitizer_common/sanitizer_common.h | 18 ++++++++++++++---- lib/sanitizer_common/sanitizer_posix.cc | 9 +++++++-- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 6 ++++-- lib/sanitizer_common/sanitizer_win.cc | 8 ++++++-- 8 files changed, 38 insertions(+), 17 deletions(-) diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index 9a1249244..55b8360a3 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -57,14 +57,14 @@ struct ErrorDeadlySignal : ErrorBase { // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor ErrorDeadlySignal() = default; - ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_) + ErrorDeadlySignal(u32 tid, const SignalContext &sig) : ErrorBase(tid), addr(sig.addr), pc(sig.pc), bp(sig.bp), sp(sig.sp), context(sig.context), - signo(signo_), + signo(sig.GetType()), write_flag(sig.write_flag), is_memory_access(sig.is_memory_access) { scariness.Clear(); diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 8f788bd13..497af02d7 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -37,10 +37,10 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal(); SignalContext sig = SignalContext::Create(siginfo, context); - if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) + if (IsStackOverflow(sig)) ReportStackOverflow(sig); else - ReportDeadlySignal(signo, sig); + ReportDeadlySignal(sig); } // ---------------------- TSD ---------------- {{{1 diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 312dcaeae..6055304e8 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -266,9 +266,9 @@ void ReportStackOverflow(const SignalContext &sig) { in_report.ReportError(error); } -void ReportDeadlySignal(int signo, const SignalContext &sig) { +void ReportDeadlySignal(const SignalContext &sig) { ScopedInErrorReport in_report(/*fatal*/ true); - ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo); + ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig); in_report.ReportError(error); } diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index 5a3533a31..259177bc7 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -47,7 +47,7 @@ bool ParseFrameDescription(const char *frame_descr, void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); void ReportStackOverflow(const SignalContext &sig); -void ReportDeadlySignal(int signo, const SignalContext &sig); +void ReportDeadlySignal(const SignalContext &sig); void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index d2021a0c9..32fd381cc 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -312,7 +312,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Signal reporting. void StartReportDeadlySignal(); -bool IsStackOverflow(int code, const SignalContext &sig); +bool IsStackOverflow(const SignalContext &sig); // FIXME: Hide after moving more signal handling code into common. void MaybeReportNonExecRegion(uptr pc); void MaybeDumpInstructionBytes(uptr pc); @@ -795,6 +795,7 @@ static inline void SanitizerBreakOptimization(void *arg) { } struct SignalContext { + void *siginfo; void *context; uptr addr; uptr pc; @@ -804,9 +805,12 @@ struct SignalContext { enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; - SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp, - bool is_memory_access, WriteFlag write_flag) - : context(context), + // SignalContext is going to keep pointers to siginfo and context without + // owning them. + SignalContext(void *siginfo, void *context, uptr addr, uptr pc, uptr sp, + uptr bp, bool is_memory_access, WriteFlag write_flag) + : siginfo(siginfo), + context(context), addr(addr), pc(pc), sp(sp), @@ -821,6 +825,12 @@ struct SignalContext { // Returns true if the "context" indicates a memory write. static WriteFlag GetWriteFlag(void *context); + + // Type of signal e.g. SIGSEGV or EXCEPTION_ACCESS_VIOLATION. + int GetType() const; + + // String description of the signal. + const char *Describe() const { return DescribeSignalOrException(GetType()); } }; void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index b8f4575f7..b74b1f995 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -296,13 +296,18 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { } SignalContext SignalContext::Create(void *siginfo, void *context) { - auto si = (siginfo_t *)siginfo; + auto si = static_cast(siginfo); uptr addr = (uptr)si->si_addr; uptr pc, sp, bp; GetPcSpBp(context, &pc, &sp, &bp); WriteFlag write_flag = GetWriteFlag(context); bool is_memory_access = si->si_signo == SIGSEGV; - return SignalContext(context, addr, pc, sp, bp, is_memory_access, write_flag); + return SignalContext(siginfo, context, addr, pc, sp, bp, is_memory_access, + write_flag); +} + +int SignalContext::GetType() const { + return static_cast(siginfo)->si_signo; } const char *DescribeSignalOrException(int signo) { diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index d7d0e7d44..e49101a7b 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -215,7 +215,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { MaybeInstallSigaction(SIGILL, handler); } -bool IsStackOverflow(int code, const SignalContext &sig) { +bool IsStackOverflow(const SignalContext &sig) { // Access at a reasonable offset above SP, or slightly below it (to account // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is // probably a stack overflow. @@ -257,7 +257,9 @@ bool IsStackOverflow(int code, const SignalContext &sig) { // We also check si_code to filter out SEGV caused by something else other // then hitting the guard page or unmapped memory, like, for example, // unaligned memory access. - return IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR); + auto si = static_cast(sig.siginfo); + return IsStackAccess && + (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); } void StartReportDeadlySignal() { diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a13a4c5a5..65898a709 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -966,14 +966,18 @@ SignalContext SignalContext::Create(void *siginfo, void *context) { case 8: write_flag = SignalContext::UNKNOWN; break; } bool is_memory_access = write_flag != SignalContext::UNKNOWN; - return SignalContext(context, access_addr, pc, sp, bp, is_memory_access, - write_flag); + return SignalContext(siginfo, context, access_addr, pc, sp, bp, + is_memory_access, write_flag); } void SignalContext::DumpAllRegisters(void *context) { // FIXME: Implement this. } +int SignalContext::GetType() const { + return static_cast(siginfo)->ExceptionCode; +} + uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { // FIXME: Actually implement this function. CHECK_GT(buf_len, 0); -- cgit v1.2.1 From a8682fdf74d3cb93769b7394f2cdffc5cefb8bd8 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 18:30:16 +0000 Subject: [compiler-rt] Use SignalContext in ErrorStackOverflow and ErrorDeadlySignal Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl, filcab Subscribers: kubamracek, llvm-commits, dberris Differential Revision: https://reviews.llvm.org/D37793 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313168 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 33 ++++++++------- lib/asan/asan_errors.h | 38 ++++------------- lib/sanitizer_common/sanitizer_common.h | 6 ++- lib/sanitizer_common/sanitizer_fuchsia.cc | 2 +- lib/sanitizer_common/sanitizer_posix.cc | 4 +- lib/sanitizer_common/sanitizer_win.cc | 69 +++++++++++++++++++------------ 6 files changed, 78 insertions(+), 74 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index c9cf8f70b..7625dc9b8 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -27,12 +27,14 @@ void ErrorStackOverflow::Print() { Printf("%s", d.Warning()); Report( "ERROR: AddressSanitizer: %s on address %p" - " (pc %p bp %p sp %p T%d)\n", scariness.GetDescription(), - (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + " (pc %p bp %p sp %p T%d)\n", + scariness.GetDescription(), (void *)signal.addr, (void *)signal.pc, + (void *)signal.bp, (void *)signal.sp, tid); Printf("%s", d.Default()); scariness.Print(); BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, signal.bp, + signal.context, common_flags()->fast_unwind_on_fatal); stack.Print(); ReportErrorSummary(scariness.GetDescription(), &stack); @@ -41,30 +43,33 @@ void ErrorStackOverflow::Print() { void ErrorDeadlySignal::Print() { Decorator d; Printf("%s", d.Warning()); - const char *description = __sanitizer::DescribeSignalOrException(signo); + const char *description = signal.Describe(); Report( "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " "T%d)\n", - description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + description, (void *)signal.addr, (void *)signal.pc, (void *)signal.bp, + (void *)signal.sp, tid); Printf("%s", d.Default()); - if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n"); - if (is_memory_access) { + if (signal.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (signal.is_memory_access) { const char *access_type = - write_flag == SignalContext::WRITE + signal.write_flag == SignalContext::WRITE ? "WRITE" - : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + : (signal.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); Report("The signal is caused by a %s memory access.\n", access_type); - if (addr < GetPageSizeCached()) + if (signal.addr < GetPageSizeCached()) Report("Hint: address points to the zero page.\n"); } - MaybeReportNonExecRegion(pc); + MaybeReportNonExecRegion(signal.pc); scariness.Print(); BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, signal.bp, + signal.context, common_flags()->fast_unwind_on_fatal); stack.Print(); - MaybeDumpInstructionBytes(pc); - MaybeDumpRegisters(context); + MaybeDumpInstructionBytes(signal.pc); + MaybeDumpRegisters(signal.context); Printf("AddressSanitizer can not provide additional info.\n"); ReportErrorSummary(description, &stack); } diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index 55b8360a3..b9944739b 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -28,19 +28,12 @@ struct ErrorBase { }; struct ErrorStackOverflow : ErrorBase { - uptr addr, pc, bp, sp; - // ErrorStackOverflow never owns the context. - void *context; + SignalContext signal; // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor ErrorStackOverflow() = default; ErrorStackOverflow(u32 tid, const SignalContext &sig) - : ErrorBase(tid), - addr(sig.addr), - pc(sig.pc), - bp(sig.bp), - sp(sig.sp), - context(sig.context) { + : ErrorBase(tid), signal(sig) { scariness.Clear(); scariness.Scare(10, "stack-overflow"); } @@ -48,34 +41,21 @@ struct ErrorStackOverflow : ErrorBase { }; struct ErrorDeadlySignal : ErrorBase { - uptr addr, pc, bp, sp; - // ErrorDeadlySignal never owns the context. - void *context; - int signo; - SignalContext::WriteFlag write_flag; - bool is_memory_access; + SignalContext signal; // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor ErrorDeadlySignal() = default; ErrorDeadlySignal(u32 tid, const SignalContext &sig) - : ErrorBase(tid), - addr(sig.addr), - pc(sig.pc), - bp(sig.bp), - sp(sig.sp), - context(sig.context), - signo(sig.GetType()), - write_flag(sig.write_flag), - is_memory_access(sig.is_memory_access) { + : ErrorBase(tid), signal(sig) { scariness.Clear(); - if (is_memory_access) { - if (addr < GetPageSizeCached()) { + if (signal.is_memory_access) { + if (signal.addr < GetPageSizeCached()) { scariness.Scare(10, "null-deref"); - } else if (addr == pc) { + } else if (signal.addr == signal.pc) { scariness.Scare(60, "wild-jump"); - } else if (write_flag == SignalContext::WRITE) { + } else if (signal.write_flag == SignalContext::WRITE) { scariness.Scare(30, "wild-addr-write"); - } else if (write_flag == SignalContext::READ) { + } else if (signal.write_flag == SignalContext::READ) { scariness.Scare(20, "wild-addr-read"); } else { scariness.Scare(25, "wild-addr"); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 32fd381cc..6cd21d79a 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -309,7 +309,6 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); -const char *DescribeSignalOrException(int signo); // Signal reporting. void StartReportDeadlySignal(); bool IsStackOverflow(const SignalContext &sig); @@ -805,6 +804,9 @@ struct SignalContext { enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + SignalContext() = default; // SignalContext is going to keep pointers to siginfo and context without // owning them. SignalContext(void *siginfo, void *context, uptr addr, uptr pc, uptr sp, @@ -830,7 +832,7 @@ struct SignalContext { int GetType() const; // String description of the signal. - const char *Describe() const { return DescribeSignalOrException(GetType()); } + const char *Describe() const; }; void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 7ea522a0d..07190f150 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -98,7 +98,7 @@ void InitTlsSize() {} void PrintModuleMap() {} void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } -const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } +const char *SignalContext::Describe() const { UNIMPLEMENTED(); } struct UnwindTraceArg { BufferedStackTrace *stack; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index b74b1f995..35fc35ce9 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -310,8 +310,8 @@ int SignalContext::GetType() const { return static_cast(siginfo)->si_signo; } -const char *DescribeSignalOrException(int signo) { - switch (signo) { +const char *SignalContext::Describe() const { + switch (GetType()) { case SIGFPE: return "FPE"; case SIGILL: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 65898a709..65e7aa8d7 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -890,32 +890,6 @@ bool IsHandledDeadlyException(DWORD exceptionCode) { return false; } -const char *DescribeSignalOrException(int signo) { - unsigned code = signo; - // Get the string description of the exception if this is a known deadly - // exception. - switch (code) { - case EXCEPTION_ACCESS_VIOLATION: return "access-violation"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "array-bounds-exceeded"; - case EXCEPTION_STACK_OVERFLOW: return "stack-overflow"; - case EXCEPTION_DATATYPE_MISALIGNMENT: return "datatype-misalignment"; - case EXCEPTION_IN_PAGE_ERROR: return "in-page-error"; - case EXCEPTION_ILLEGAL_INSTRUCTION: return "illegal-instruction"; - case EXCEPTION_PRIV_INSTRUCTION: return "priv-instruction"; - case EXCEPTION_BREAKPOINT: return "breakpoint"; - case EXCEPTION_FLT_DENORMAL_OPERAND: return "flt-denormal-operand"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "flt-divide-by-zero"; - case EXCEPTION_FLT_INEXACT_RESULT: return "flt-inexact-result"; - case EXCEPTION_FLT_INVALID_OPERATION: return "flt-invalid-operation"; - case EXCEPTION_FLT_OVERFLOW: return "flt-overflow"; - case EXCEPTION_FLT_STACK_CHECK: return "flt-stack-check"; - case EXCEPTION_FLT_UNDERFLOW: return "flt-underflow"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: return "int-divide-by-zero"; - case EXCEPTION_INT_OVERFLOW: return "int-overflow"; - } - return "unknown exception"; -} - bool IsAccessibleMemoryRange(uptr beg, uptr size) { SYSTEM_INFO si; GetNativeSystemInfo(&si); @@ -978,6 +952,49 @@ int SignalContext::GetType() const { return static_cast(siginfo)->ExceptionCode; } +const char *SignalContext::Describe() const { + unsigned code = GetType(); + // Get the string description of the exception if this is a known deadly + // exception. + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return "access-violation"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "array-bounds-exceeded"; + case EXCEPTION_STACK_OVERFLOW: + return "stack-overflow"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "datatype-misalignment"; + case EXCEPTION_IN_PAGE_ERROR: + return "in-page-error"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "illegal-instruction"; + case EXCEPTION_PRIV_INSTRUCTION: + return "priv-instruction"; + case EXCEPTION_BREAKPOINT: + return "breakpoint"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "flt-denormal-operand"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "flt-divide-by-zero"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "flt-inexact-result"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "flt-invalid-operation"; + case EXCEPTION_FLT_OVERFLOW: + return "flt-overflow"; + case EXCEPTION_FLT_STACK_CHECK: + return "flt-stack-check"; + case EXCEPTION_FLT_UNDERFLOW: + return "flt-underflow"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "int-divide-by-zero"; + case EXCEPTION_INT_OVERFLOW: + return "int-overflow"; + } + return "unknown exception"; +} + uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { // FIXME: Actually implement this function. CHECK_GT(buf_len, 0); -- cgit v1.2.1 From 1fb9a540cdaf80c43265d4211ca2bab863bbb9c0 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 13 Sep 2017 19:39:06 +0000 Subject: [asan] Fix Windows build git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313177 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_win.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 8a839d913..ff9a70843 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -58,7 +58,7 @@ long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. SignalContext sig = SignalContext::Create(exception_record, context); - ReportDeadlySignal(exception_record->ExceptionCode, sig); + ReportDeadlySignal(sig); UNREACHABLE("returned from reporting deadly signal"); } -- cgit v1.2.1 From 9b8d2f223ddb502146a82f2711f97f616fddf331 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 13 Sep 2017 20:46:26 +0000 Subject: [ubsan-minimal] Temporarily disable x86_64h testing on Darwin We're seeing strange issues on the public GreenDragon Darwin bots which we don't understand. x86_64h tests are still being run on pre-Haswell bots despite the added checks in test/ubsan_minimal/lit.common.cfg, which were verified on our internal bots. I'm unable to ssh into the affected public bot, so for now am trying a more aggressive check which disables all x86_64h testing for ubsan-minimal on Darwin. rdar://problem/34409349 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313189 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/lit.common.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index e8b42bb82..5fa44c770 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -37,4 +37,9 @@ if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windo if '-arch x86_64h' in target_cflags and 'x86_64h' not in config.available_features: config.unsupported = True +# Temporarily disable all x86_64h testing on Darwin to unblock the public bots, +# while we investigate rdar://problem/34409349 +if config.host_os == 'Darwin' and 'x86_64h' in target_cflags: + config.unsupported = True + config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From 90837bb59a2e12708c48f47e4c1dc425564c45b7 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Wed, 13 Sep 2017 20:49:25 +0000 Subject: Revert "Determine up front which projects are enabled." This was intended to be a generic CMake solution to a problem shared across several projects. It turns out it doesn't interact very well certain CMake configurations, and furthermore the "problem" is actually not a problem, as the problematic code is never executed to begin with. So this really isn't solving anything. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313191 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a5ac10d4..518428092 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,7 +225,7 @@ append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS) # always respect the optimization flags set by CMAKE_BUILD_TYPE instead. if (NOT MSVC) - # Build with optimization, unless we're in debug mode. + # Build with optimization, unless we're in debug mode. if(COMPILER_RT_DEBUG) list(APPEND SANITIZER_COMMON_CFLAGS -O0) else() @@ -315,16 +315,28 @@ endif() add_subdirectory(include) -set(COMPILER_RT_HAS_LIBCXX_SOURCES ${LLVM_PROJECT_LIBCXX_ENABLED}) -if (LLVM_PROJECT_LIBCXX_ENABLED) - set(COMPILER_RT_LIBCXX_PATH ${LLVM_PROJECT_LIBCXX_SOURCE_DIR}) - message("compiler-rt libcxx enabled at ${COMPILER_RT_LIBCXX_PATH}") +set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx) +if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) + set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) +else() + set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/../libcxx) + if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/) + set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE) + else() + set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE) + endif() endif() -set(COMPILER_RT_HAS_LLD ${LLVM_PROJECT_LLD_ENABLED}) -if (LLVM_PROJECT_LLD_ENABLED) - set(COMPILER_RT_LLD_PATH ${LLVM_PROJECT_LLD_SOURCE_DIR}) - message("compiler-rt lld enabled at ${COMPILER_RT_LLD_PATH}") +set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld) +if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) + set(COMPILER_RT_HAS_LLD TRUE) +else() + set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld) + if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD) + set(COMPILER_RT_HAS_LLD TRUE) + else() + set(COMPILER_RT_HAS_LLD FALSE) + endif() endif() pythonize_bool(COMPILER_RT_HAS_LLD) -- cgit v1.2.1 From 2984766b09a658f5fddc5dc4d24554b12f176fa0 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 13 Sep 2017 21:57:47 +0000 Subject: [ubsan-minimal] Filter targets to test by host arch on Darwin This reverts r313189, and adds a use of darwin_filter_host_archs() for ubsan-minimal. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313206 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/CMakeLists.txt | 3 +++ test/ubsan_minimal/lit.common.cfg | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/ubsan_minimal/CMakeLists.txt b/test/ubsan_minimal/CMakeLists.txt index 8e87b76bc..712654e94 100644 --- a/test/ubsan_minimal/CMakeLists.txt +++ b/test/ubsan_minimal/CMakeLists.txt @@ -1,6 +1,9 @@ set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(UBSAN_TEST_ARCH ${UBSAN_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(UBSAN_SUPPORTED_ARCH UBSAN_TEST_ARCH) +endif() set(UBSAN_TESTSUITES) set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index 5fa44c770..e8b42bb82 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -37,9 +37,4 @@ if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin']: # TODO: Windo if '-arch x86_64h' in target_cflags and 'x86_64h' not in config.available_features: config.unsupported = True -# Temporarily disable all x86_64h testing on Darwin to unblock the public bots, -# while we investigate rdar://problem/34409349 -if config.host_os == 'Darwin' and 'x86_64h' in target_cflags: - config.unsupported = True - config.available_features.add('arch=' + config.target_arch) -- cgit v1.2.1 From a2a96a61a024d0d7f71c3b4b86ce9bd8c50b78cd Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 02:48:41 +0000 Subject: [compiler-rt] Cleanup SignalContext initialization Reviewers: eugenis, alekseyshl Subscribers: kubamracek, dberris Differential Revision: https://reviews.llvm.org/D37827 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313223 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 2 +- lib/asan/asan_win.cc | 2 +- lib/sanitizer_common/sanitizer_common.h | 32 ++++++++-------- lib/sanitizer_common/sanitizer_linux.cc | 6 ++- lib/sanitizer_common/sanitizer_mac.cc | 6 ++- lib/sanitizer_common/sanitizer_posix.cc | 15 ++++---- .../sanitizer_stoptheworld_linux_libcdep.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 43 +++++++++++++++------- 8 files changed, 62 insertions(+), 46 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 497af02d7..8acadd751 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -36,7 +36,7 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal(); - SignalContext sig = SignalContext::Create(siginfo, context); + SignalContext sig(siginfo, context); if (IsStackOverflow(sig)) ReportStackOverflow(sig); else diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index ff9a70843..68eedd186 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -57,7 +57,7 @@ long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. - SignalContext sig = SignalContext::Create(exception_record, context); + SignalContext sig(exception_record, context); ReportDeadlySignal(sig); UNREACHABLE("returned from reporting deadly signal"); } diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 6cd21d79a..51c1f3575 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -801,41 +801,39 @@ struct SignalContext { uptr sp; uptr bp; bool is_memory_access; - enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor SignalContext() = default; + + // Creates signal context in a platform-specific manner. // SignalContext is going to keep pointers to siginfo and context without // owning them. - SignalContext(void *siginfo, void *context, uptr addr, uptr pc, uptr sp, - uptr bp, bool is_memory_access, WriteFlag write_flag) + SignalContext(void *siginfo, void *context) : siginfo(siginfo), context(context), - addr(addr), - pc(pc), - sp(sp), - bp(bp), - is_memory_access(is_memory_access), - write_flag(write_flag) {} + addr(GetAddress()), + is_memory_access(IsMemoryAccess()), + write_flag(GetWriteFlag()) { + InitPcSpBp(); + } static void DumpAllRegisters(void *context); - // Creates signal context in a platform-specific manner. - static SignalContext Create(void *siginfo, void *context); - - // Returns true if the "context" indicates a memory write. - static WriteFlag GetWriteFlag(void *context); - // Type of signal e.g. SIGSEGV or EXCEPTION_ACCESS_VIOLATION. int GetType() const; // String description of the signal. const char *Describe() const; -}; -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); + private: + // Platform specific initialization. + void InitPcSpBp(); + uptr GetAddress() const; + WriteFlag GetWriteFlag() const; + bool IsMemoryAccess() const; +}; void MaybeReexec(); diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 7923078a6..72d53e826 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1628,7 +1628,7 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { } #endif -SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) { +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { ucontext_t *ucontext = (ucontext_t *)context; #if defined(__x86_64__) || defined(__i386__) static const uptr PF_WRITE = 1U << 1; @@ -1659,7 +1659,7 @@ void SignalContext::DumpAllRegisters(void *context) { // FIXME: Implement this. } -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #if defined(__arm__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.arm_pc; @@ -1750,6 +1750,8 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #endif } +void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } + void MaybeReexec() { // No need to re-exec on Linux. } diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 6cb75266b..1570ae277 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -574,7 +574,7 @@ void LogFullErrorReport(const char *buffer) { #endif } -SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) { +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { #if defined(__x86_64__) || defined(__i386__) ucontext_t *ucontext = static_cast(context); return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; @@ -583,7 +583,7 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) { #endif } -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if defined(__aarch64__) *pc = ucontext->uc_mcontext->__ss.__pc; @@ -610,6 +610,8 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif } +void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } + #if !SANITIZER_GO static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; LowLevelAllocator allocator_for_env; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 35fc35ce9..1fad71f35 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -295,15 +295,14 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { return false; } -SignalContext SignalContext::Create(void *siginfo, void *context) { +uptr SignalContext::GetAddress() const { auto si = static_cast(siginfo); - uptr addr = (uptr)si->si_addr; - uptr pc, sp, bp; - GetPcSpBp(context, &pc, &sp, &bp); - WriteFlag write_flag = GetWriteFlag(context); - bool is_memory_access = si->si_signo == SIGSEGV; - return SignalContext(siginfo, context, addr, pc, sp, bp, is_memory_access, - write_flag); + return (uptr)si->si_addr; +} + +bool SignalContext::IsMemoryAccess() const { + auto si = static_cast(siginfo); + return si->si_signo == SIGSEGV; } int SignalContext::GetType() const { diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index d7fa5f645..7e89d0cc8 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -246,7 +246,7 @@ static void TracerThreadDieCallback() { // Signal handler to wake up suspended threads when the tracer thread dies. static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) { - SignalContext ctx = SignalContext::Create(siginfo, uctx); + SignalContext ctx(siginfo, uctx); Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, ctx.addr, ctx.pc, ctx.sp); ThreadSuspender *inst = thread_suspender_instance; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 65e7aa8d7..ed7b68dd9 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -915,33 +915,48 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { return true; } -SignalContext SignalContext::Create(void *siginfo, void *context) { +void SignalContext::InitPcSpBp() { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; CONTEXT *context_record = (CONTEXT *)context; - uptr pc = (uptr)exception_record->ExceptionAddress; + pc = (uptr)exception_record->ExceptionAddress; #ifdef _WIN64 - uptr bp = (uptr)context_record->Rbp; - uptr sp = (uptr)context_record->Rsp; + bp = (uptr)context_record->Rbp; + sp = (uptr)context_record->Rsp; #else - uptr bp = (uptr)context_record->Ebp; - uptr sp = (uptr)context_record->Esp; + bp = (uptr)context_record->Ebp; + sp = (uptr)context_record->Esp; #endif - uptr access_addr = exception_record->ExceptionInformation[1]; +} + +uptr SignalContext::GetAddress() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + return exception_record->ExceptionInformation[1]; +} + +bool SignalContext::IsMemoryAccess() const { + return GetWriteFlag() != SignalContext::UNKNOWN; +} +int SignalContext::GetType() const { + return static_cast(siginfo)->si_signo; +} + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; // The contents of this array are documented at // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx // The first element indicates read as 0, write as 1, or execute as 8. The // second element is the faulting address. - WriteFlag write_flag = SignalContext::UNKNOWN; switch (exception_record->ExceptionInformation[0]) { - case 0: write_flag = SignalContext::READ; break; - case 1: write_flag = SignalContext::WRITE; break; - case 8: write_flag = SignalContext::UNKNOWN; break; + case 0: + return SignalContext::READ; + case 1: + return SignalContext::WRITE; + case 8: + return SignalContext::UNKNOWN; } - bool is_memory_access = write_flag != SignalContext::UNKNOWN; - return SignalContext(siginfo, context, access_addr, pc, sp, bp, - is_memory_access, write_flag); + return SignalContext::UNKNOWN; } void SignalContext::DumpAllRegisters(void *context) { -- cgit v1.2.1 From 8b1cb01a8833130dbd685d7973d2c712ee49d978 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 02:58:18 +0000 Subject: [compiler-rt] Fix Windows build git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313224 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_win.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index ed7b68dd9..ff3d4b94b 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -938,10 +938,6 @@ bool SignalContext::IsMemoryAccess() const { return GetWriteFlag() != SignalContext::UNKNOWN; } -int SignalContext::GetType() const { - return static_cast(siginfo)->si_signo; -} - SignalContext::WriteFlag SignalContext::GetWriteFlag() const { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; // The contents of this array are documented at -- cgit v1.2.1 From 2586e28f76a27e269e46a291c6c8cfddf3956285 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 03:06:20 +0000 Subject: [asan] Add const into ScarinessScoreBase::Print git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313225 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_scariness_score.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_scariness_score.h b/lib/asan/asan_scariness_score.h index 7f1571416..7f095dd29 100644 --- a/lib/asan/asan_scariness_score.h +++ b/lib/asan/asan_scariness_score.h @@ -47,7 +47,7 @@ struct ScarinessScoreBase { }; int GetScore() const { return score; } const char *GetDescription() const { return descr; } - void Print() { + void Print() const { if (score && flags()->print_scariness) Printf("SCARINESS: %d (%s)\n", score, descr); } -- cgit v1.2.1 From 3083211518cea47e28b2c7173ccc559bf47927c0 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 03:06:35 +0000 Subject: [sanitizer] Add BufferedStackTrace::Reset() git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313226 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stacktrace.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h index 90142dffd..f15196e4b 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/lib/sanitizer_common/sanitizer_stacktrace.h @@ -97,6 +97,11 @@ struct BufferedStackTrace : public StackTrace { void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, uptr stack_bottom, bool request_fast_unwind); + void Reset() { + *static_cast(this) = StackTrace(trace_buffer, 0); + top_frame_bp = 0; + } + private: void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, u32 max_depth); @@ -106,8 +111,8 @@ struct BufferedStackTrace : public StackTrace { void PopStackFrames(uptr count); uptr LocatePcInTrace(uptr pc); - BufferedStackTrace(const BufferedStackTrace &); - void operator=(const BufferedStackTrace &); + BufferedStackTrace(const BufferedStackTrace &) = delete; + void operator=(const BufferedStackTrace &) = delete; }; // Check if given pointer points into allocated stack area. -- cgit v1.2.1 From f0843635190593b30bff060361463fbf12f1ed91 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 03:23:02 +0000 Subject: [sanitizer] Move IsStackOverflow into SignalContext git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313227 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_posix.cc | 2 +- lib/sanitizer_common/sanitizer_common.h | 4 +++- lib/sanitizer_common/sanitizer_fuchsia.cc | 1 + lib/sanitizer_common/sanitizer_posix_libcdep.cc | 13 ++++++------- lib/sanitizer_common/sanitizer_win.cc | 4 ++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 8acadd751..05892475d 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -37,7 +37,7 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal(); SignalContext sig(siginfo, context); - if (IsStackOverflow(sig)) + if (sig.IsStackOverflow()) ReportStackOverflow(sig); else ReportDeadlySignal(sig); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 51c1f3575..988acb794 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -311,7 +311,6 @@ HandleSignalMode GetHandleSignalMode(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); // Signal reporting. void StartReportDeadlySignal(); -bool IsStackOverflow(const SignalContext &sig); // FIXME: Hide after moving more signal handling code into common. void MaybeReportNonExecRegion(uptr pc); void MaybeDumpInstructionBytes(uptr pc); @@ -827,6 +826,9 @@ struct SignalContext { // String description of the signal. const char *Describe() const; + // Returns true if signal is stack overflow. + bool IsStackOverflow() const; + private: // Platform specific initialization. void InitPcSpBp(); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 07190f150..4619f6f7c 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -97,6 +97,7 @@ void InitTlsSize() {} void PrintModuleMap() {} +bool SignalContext::IsStackOverflow() const { return false; } void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } const char *SignalContext::Describe() const { UNIMPLEMENTED(); } diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index e49101a7b..b4d0ce5bf 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -215,7 +215,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { MaybeInstallSigaction(SIGILL, handler); } -bool IsStackOverflow(const SignalContext &sig) { +bool SignalContext::IsStackOverflow() const { // Access at a reasonable offset above SP, or slightly below it (to account // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is // probably a stack overflow. @@ -223,10 +223,9 @@ bool IsStackOverflow(const SignalContext &sig) { // On s390, the fault address in siginfo points to start of the page, not // to the precise word that was accessed. Mask off the low bits of sp to // take it into account. - bool IsStackAccess = - sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; + bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sp + 0xFFFF; #else - bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; + bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF; #endif #if __powerpc__ @@ -236,8 +235,8 @@ bool IsStackOverflow(const SignalContext &sig) { // If the store faults then sp will not have been updated, so test above // will not work, because the fault address will be more than just "slightly" // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { - u32 inst = *(unsigned *)sig.pc; + if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) { + u32 inst = *(unsigned *)pc; u32 ra = (inst >> 16) & 0x1F; u32 opcd = inst >> 26; u32 xo = (inst >> 1) & 0x3FF; @@ -257,7 +256,7 @@ bool IsStackOverflow(const SignalContext &sig) { // We also check si_code to filter out SEGV caused by something else other // then hitting the guard page or unmapped memory, like, for example, // unaligned memory access. - auto si = static_cast(sig.siginfo); + auto si = static_cast(siginfo); return IsStackAccess && (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index ff3d4b94b..4d68f5610 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -915,6 +915,10 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { return true; } +bool SignalContext::IsStackOverflow() const { + return GetType() == EXCEPTION_STACK_OVERFLOW; +} + void SignalContext::InitPcSpBp() { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; CONTEXT *context_record = (CONTEXT *)context; -- cgit v1.2.1 From 51d0db2cff01711c5243975135781bebfdea59e9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 08:14:38 +0000 Subject: [lsan] Extract GetStackTraceWithPcBpAndContext similar to asan version git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313239 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan.h | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h index 7446e9507..08794e9ea 100644 --- a/lib/lsan/lsan.h +++ b/lib/lsan/lsan.h @@ -12,24 +12,15 @@ // //===----------------------------------------------------------------------===// +#include "lsan_thread.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" -#define GET_STACK_TRACE(max_size, fast) \ - BufferedStackTrace stack; \ - { \ - uptr stack_top = 0, stack_bottom = 0; \ - ThreadContext *t; \ - if (fast && (t = CurrentThreadContext())) { \ - stack_top = t->stack_end(); \ - stack_bottom = t->stack_begin(); \ - } \ - if (!SANITIZER_MIPS || \ - IsValidFrame(GET_CURRENT_FRAME(), stack_top, stack_bottom)) { \ - stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ - /* context */ 0, stack_top, stack_bottom, fast); \ - } \ - } +#define GET_STACK_TRACE(max_size, fast) \ + __sanitizer::BufferedStackTrace stack; \ + GetStackTraceWithPcBpAndContext(&stack, max_size, \ + StackTrace::GetCurrentPc(), \ + GET_CURRENT_FRAME(), nullptr, fast); #define GET_STACK_TRACE_FATAL \ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) @@ -51,6 +42,25 @@ void ReplaceSystemMalloc(); __lsan_init(); \ } while (0) +// Get the stack trace with the given pc and bp. +// The pc will be in the position 0 of the resulting stack trace. +// The bp may refer to the current frame or to the caller's frame. +ALWAYS_INLINE +void GetStackTraceWithPcBpAndContext(__sanitizer::BufferedStackTrace *stack, + __sanitizer::uptr max_depth, + __sanitizer::uptr pc, __sanitizer::uptr bp, + void *context, bool fast) { + uptr stack_top = 0, stack_bottom = 0; + ThreadContext *t; + if (fast && (t = CurrentThreadContext())) { + stack_top = t->stack_end(); + stack_bottom = t->stack_begin(); + } + if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) { + stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast); + } +} + } // namespace __lsan extern bool lsan_inited; -- cgit v1.2.1 From 86427f15accde96cf407685c6bcfea5faccc704f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 08:14:56 +0000 Subject: [sanitizer] Add empty Fuchsia and Win versions of StartReportDeadlySignal git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313240 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_fuchsia.cc | 1 + lib/sanitizer_common/sanitizer_win.cc | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 4619f6f7c..e518708c0 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -91,6 +91,7 @@ void MaybeReexec() {} void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} void DisableCoreDumperIfNecessary() {} void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void StartReportDeadlySignal() {} void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 4d68f5610..5a78b64c6 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -858,6 +858,10 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // FIXME: Decide what to do on Windows. } +void StartReportDeadlySignal() { + // FIXME: Decide what to do on Windows. +} + HandleSignalMode GetHandleSignalMode(int signum) { // FIXME: Decide what to do on Windows. return kHandleSignalNo; -- cgit v1.2.1 From 6f6220991eadb35da366497f22d96e98422d11eb Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 08:15:13 +0000 Subject: [sanitizer] Mark allow_user_segv as XFAIL instead of UNSUPPORTED git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313241 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/allow_user_segv.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index 4fe3c32f0..fdc03b3fc 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -18,10 +18,10 @@ // clang-format on // Remove when fixed: https://github.com/google/sanitizers/issues/637 -// UNSUPPORTED: lsan -// UNSUPPORTED: msan -// UNSUPPORTED: tsan -// UNSUPPORTED: ubsan +// XFAIL: lsan +// XFAIL: msan +// XFAIL: tsan +// XFAIL: ubsan #include #include -- cgit v1.2.1 From a403018d684b206a4a9e20914d3f8ac0660483a6 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Thu, 14 Sep 2017 10:36:04 +0000 Subject: [mips] Fix sem_init_glibc test for MIPS. glibc changed the implementation of semaphores for glibc 2.21 requiring some target specific changes for this compiler-rt test. Modify the test to cope with MIPS64 and do some future/correctness work by tying the define for MIPS64 to exactly the define of __HAVE_64B_ATOMICS in glibc. Contributions from Nitesh Jain. Reviewers: eugenis Differential Revision: https://reviews.llvm.org/D37829 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313248 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc index 523ac9811..5fc9e4639 100644 --- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc +++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -13,9 +13,11 @@ typedef uint64_t semval_t; // This condition needs to correspond to __HAVE_64B_ATOMICS macro in glibc. -#elif (defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390x__) || defined(__sparc64__) || defined(__alpha__) || \ - defined(__ia64__) || defined(__m68k__)) && __GLIBC_PREREQ(2, 21) +#elif (defined(__x86_64__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390x__) || defined(__sparc64__) || \ + defined(__alpha__) || defined(__ia64__) || defined(__m68k__) || \ + (defined(__mips64) || _MIPS_SIM == _ABI64)) && \ + __GLIBC_PREREQ(2, 21) typedef uint64_t semval_t; #else typedef unsigned semval_t; -- cgit v1.2.1 From f796a78bcd21b0e6d0f729d2cda36133bd849f7e Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 14 Sep 2017 16:47:58 +0000 Subject: [lit] Force site configs to be run before source-tree configs This patch simplifies LLVM's lit infrastructure by enforcing an ordering that a site config is always run before a source-tree config. A significant amount of the complexity from lit config files arises from the fact that inside of a source-tree config file, we don't yet know if the site config has been run. However it is *always* required to run a site config first, because it passes various variables down through CMake that the main config depends on. As a result, every config file has to do a bunch of magic to try to reverse-engineer the location of the site config file if they detect (heuristically) that the site config file has not yet been run. This patch solves the problem by emitting a mapping from source tree config file to binary tree site config file in llvm-lit.py. Then, during discovery when we find a config file, we check to see if we have a target mapping for it, and if so we use that instead. This mechanism is generic enough that it does not affect external users of lit. They will just not have a config mapping defined, and everything will work as normal. On the other hand, for us it allows us to make many simplifications: * We are guaranteed that a site config will be executed first * Inside of a main config, we no longer have to assume that attributes might not be present and use getattr everywhere. * We no longer have to pass parameters such as --param llvm_site_config= on the command line. * It is future-proof, meaning you don't have to edit llvm-lit.in to add support for new projects. * All of the duplicated logic of trying various fallback mechanisms of finding a site config from the main config are now gone. One potentially noteworthy thing that was required to implement this change is that whereas the ninja check targets previously used the first method to spawn lit, they now use the second. In particular, you can no longer run lit.py against the source tree while specifying the various `foo_site_config=` parameters. Instead, you need to run llvm-lit.py. Differential Revision: https://reviews.llvm.org/D37756 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313270 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 11 +++++------ test/profile/lit.cfg | 11 ----------- unittests/lit.common.unit.cfg | 2 +- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 4f23ab285..6c07ca661 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -73,10 +73,9 @@ for name in possibly_dangerous_env_vars: del config.environment[name] # Tweak PATH to include llvm tools dir. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) -if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): - lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) -path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) +if (not config.llvm_tools_dir) or (not os.path.exists(config.llvm_tools_dir)): + lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % config.llvm_tools_dir) +path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH'])) config.environment['PATH'] = path # Help MSVS link.exe find the standard libraries. @@ -193,7 +192,7 @@ if config.host_os == 'Darwin': else: config.substitutions.append( ("%macos_min_target_10_11", "") ) -sancovcc_path = os.path.join(llvm_tools_dir, "sancov") +sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): config.available_features.add("has_sancovcc") config.substitutions.append( ("%sancovcc ", sancovcc_path) ) @@ -254,7 +253,7 @@ try: stdout = subprocess.PIPE, env=config.environment) except OSError: - print("Could not find llvm-config in " + llvm_tools_dir) + print("Could not find llvm-config in " + config.llvm_tools_dir) exit(42) if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 9ca394212..7f0d95a9a 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -22,17 +22,6 @@ if hasattr(config, 'profile_lit_binary_dir') and \ config.profile_lit_binary_dir is not None: config.test_exec_root = os.path.join(config.profile_lit_binary_dir, config.name) -# If the above check didn't work, we're probably in the source tree. Use some -# magic to re-execute from the build tree. -if config.test_exec_root is None: - # The magic relies on knowing compilerrt_site_basedir. - compilerrt_basedir = lit_config.params.get('compilerrt_site_basedir', None) - if compilerrt_basedir: - site_cfg = os.path.join(compilerrt_basedir, 'profile', 'lit.site.cfg') - if os.path.exists(site_cfg): - lit_config.load_config(config, site_cfg) - raise SystemExit - if config.host_os in ['Linux']: extra_link_flags = ["-ldl"] else: diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg index b08c1fe12..31206e913 100644 --- a/unittests/lit.common.unit.cfg +++ b/unittests/lit.common.unit.cfg @@ -16,7 +16,7 @@ config.test_format = lit.formats.GoogleTest(llvm_build_mode, "Test") config.suffixes = [] # Tweak PATH to include llvm tools dir. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) +llvm_tools_dir = config.llvm_tools_dir if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) -- cgit v1.2.1 From ee5ce553a0e466226246bde2390c6d18f06bcf86 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 18:19:28 +0000 Subject: [asan] Disable two dynamic tests on armhf This is not an regression. Tests are old and we just recently started to run them on bots with dynamic runtime. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313283 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/stack-use-after-return.cc | 3 +++ test/asan/TestCases/heavy_uar_test.cc | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc index 822d5be94..2da1a0590 100644 --- a/test/asan/TestCases/Posix/stack-use-after-return.cc +++ b/test/asan/TestCases/Posix/stack-use-after-return.cc @@ -17,6 +17,9 @@ // This test runs out of stack on AArch64. // UNSUPPORTED: aarch64 +// FIXME: Fix this test for dynamic runtime on armhf-linux. +// UNSUPPORTED: armhf-linux && asan-dynamic-runtime + #include #include #include diff --git a/test/asan/TestCases/heavy_uar_test.cc b/test/asan/TestCases/heavy_uar_test.cc index 8338f8085..ef61ead63 100644 --- a/test/asan/TestCases/heavy_uar_test.cc +++ b/test/asan/TestCases/heavy_uar_test.cc @@ -5,6 +5,9 @@ // FIXME: Fix this test under GCC. // REQUIRES: Clang +// FIXME: Fix this test for dynamic runtime on armhf-linux. +// UNSUPPORTED: armhf-linux && asan-dynamic-runtime + #include #include #include -- cgit v1.2.1 From aa753d2dffec736c1389b876a55f6390c70d8e71 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Thu, 14 Sep 2017 19:58:04 +0000 Subject: Revert "[mips] Fix sem_init_glibc test for MIPS." The commit did not fix the failing test and instead exposed an inconsistency between lsan and (t|m|a)san. I'm reverting the patch as it causes more failures and the original patch had a '||' instead of '&&', which meant that an N32 build of test would have be incorrect w.r.t. __HAVE_64B_ATOMICS for glibc. This reverts commit r313248. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313291 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc index 5fc9e4639..523ac9811 100644 --- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc +++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -13,11 +13,9 @@ typedef uint64_t semval_t; // This condition needs to correspond to __HAVE_64B_ATOMICS macro in glibc. -#elif (defined(__x86_64__) || defined(__aarch64__) || \ - defined(__powerpc64__) || defined(__s390x__) || defined(__sparc64__) || \ - defined(__alpha__) || defined(__ia64__) || defined(__m68k__) || \ - (defined(__mips64) || _MIPS_SIM == _ABI64)) && \ - __GLIBC_PREREQ(2, 21) +#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; #else typedef unsigned semval_t; -- cgit v1.2.1 From 9ff24034ff195b03df11b09ee2c55462f8489448 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 14 Sep 2017 20:34:32 +0000 Subject: [scudo] Fix bad request handling when allocator has not been initialized Summary: In a few functions (`scudoMemalign` and the like), we would call `ScudoAllocator::FailureHandler::OnBadRequest` if the parameters didn't check out. The issue is that if the allocator had not been initialized (eg: if this is the first heap related function called), we would use variables like `allocator_may_return_null` and `exitcode` that still had their default value (as opposed to the one set by the user or the initialization path). To solve this, we introduce `handleBadRequest` that will call `initThreadMaybe`, allowing the options to be correctly initialized. Unfortunately, the tests were passing because `exitcode` was still 0, so the results looked like success. Change those tests to do what they were supposed to. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37853 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313294 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 13 +++++++++---- test/scudo/memalign.cpp | 5 +++-- test/scudo/valloc.cpp | 5 +++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 92155797c..9d65b8683 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -620,6 +620,11 @@ struct ScudoAllocator { BackendAllocator.getStats(stats); return stats[StatType]; } + + void *handleBadRequest() { + initThreadMaybe(); + return FailureHandler::OnBadRequest(); + } }; static ScudoAllocator Instance(LINKER_INITIALIZED); @@ -677,7 +682,7 @@ void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) { errno = errno_ENOMEM; - return ScudoAllocator::FailureHandler::OnBadRequest(); + return Instance.handleBadRequest(); } // pvalloc(0) should allocate one page. Size = Size ? RoundUpTo(Size, PageSize) : PageSize; @@ -687,14 +692,14 @@ void *scudoPvalloc(uptr Size) { void *scudoMemalign(uptr Alignment, uptr Size) { if (UNLIKELY(!IsPowerOfTwo(Alignment))) { errno = errno_EINVAL; - return ScudoAllocator::FailureHandler::OnBadRequest(); + return Instance.handleBadRequest(); } return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign)); } int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) { - ScudoAllocator::FailureHandler::OnBadRequest(); + Instance.handleBadRequest(); return errno_EINVAL; } void *Ptr = Instance.allocate(Size, Alignment, FromMemalign); @@ -707,7 +712,7 @@ int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { void *scudoAlignedAlloc(uptr Alignment, uptr Size) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) { errno = errno_EINVAL; - return ScudoAllocator::FailureHandler::OnBadRequest(); + return Instance.handleBadRequest(); } return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc)); } diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 72aacffd2..8757c51c7 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -1,6 +1,7 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: %run %t invalid 2>&1 +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t invalid 2>&1 // Tests that the various aligned allocation functions work as intended. Also // tests for the condition where the alignment is not a power of 2. diff --git a/test/scudo/valloc.cpp b/test/scudo/valloc.cpp index 010dac2a5..eef556f46 100644 --- a/test/scudo/valloc.cpp +++ b/test/scudo/valloc.cpp @@ -1,6 +1,7 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: %run %t invalid 2>&1 +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t invalid 2>&1 // Tests that valloc and pvalloc work as intended. -- cgit v1.2.1 From 66d44ca6921eaafa08a9ddc886d761e321e78021 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Thu, 14 Sep 2017 22:19:10 +0000 Subject: [ASAN] Add macro denoting availability of new `__asan_handle_no_return()` function. Summary: Libc++abi attempts to use the newly added `__asan_handle_no_return()` when built under ASAN. Unfortunately older versions of compiler-rt do not provide this symbol, and so libc++abi needs a way to detect if `asan_interface.h` actually provides the function. This patch adds the macro `SANITIZER_ASAN_INTERFACE_HAS_HANDLE_NO_RETURN` which can be used to detect the availability of the new function. Reviewers: phosek, kcc, vitalybuka, alekseyshl Reviewed By: phosek Subscribers: mclow.lists, cfe-commits Differential Revision: https://reviews.llvm.org/D37871 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313303 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/asan_interface.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h index e689a730e..8828392b6 100644 --- a/include/sanitizer/asan_interface.h +++ b/include/sanitizer/asan_interface.h @@ -148,6 +148,10 @@ extern "C" { // before things like _exit and execl to avoid false positives on stack. void __asan_handle_no_return(void); + // Required to allow ASAN versions of libc++abi to build against older + // versions of compiler-rt that do not provide this interface. +# define SANITIZER_ASAN_INTERFACE_HAS_HANDLE_NO_RETURN + #ifdef __cplusplus } // extern "C" #endif -- cgit v1.2.1 From bb16fc935b350a775ec52b6e189966c98cf5c127 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Thu, 14 Sep 2017 22:31:34 +0000 Subject: [ASAN] Revert r313303 - Add macro denoting availability of new `__asan_handle_no_return()` function. It was pointed out that compiler-rt has always defined the symbol, but only recently added it to the public headers. Meaning that libc++abi can re-declare it instead of needing this macro. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313306 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/asan_interface.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h index 8828392b6..e689a730e 100644 --- a/include/sanitizer/asan_interface.h +++ b/include/sanitizer/asan_interface.h @@ -148,10 +148,6 @@ extern "C" { // before things like _exit and execl to avoid false positives on stack. void __asan_handle_no_return(void); - // Required to allow ASAN versions of libc++abi to build against older - // versions of compiler-rt that do not provide this interface. -# define SANITIZER_ASAN_INTERFACE_HAS_HANDLE_NO_RETURN - #ifdef __cplusplus } // extern "C" #endif -- cgit v1.2.1 From e3c17f18663a16b332846f3971ea1ab38cc7639c Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 22:43:53 +0000 Subject: [asan] Remove ErrorStackOverflow Summary: The only difference from ErrorDeadlySignal is reporting code and it lives in sanitizer common. Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl, filcab Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37868 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313309 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 96 ++++++++++++++++++++++++------------------------- lib/asan/asan_errors.h | 40 +++++++-------------- lib/asan/asan_posix.cc | 5 +-- lib/asan/asan_report.cc | 6 ---- lib/asan/asan_report.h | 1 - 5 files changed, 62 insertions(+), 86 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 7625dc9b8..cc09248af 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -22,56 +22,56 @@ namespace __asan { -void ErrorStackOverflow::Print() { - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: %s on address %p" - " (pc %p bp %p sp %p T%d)\n", - scariness.GetDescription(), (void *)signal.addr, (void *)signal.pc, - (void *)signal.bp, (void *)signal.sp, tid); - Printf("%s", d.Default()); - scariness.Print(); - BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, signal.bp, - signal.context, - common_flags()->fast_unwind_on_fatal); - stack.Print(); - ReportErrorSummary(scariness.GetDescription(), &stack); -} - void ErrorDeadlySignal::Print() { - Decorator d; - Printf("%s", d.Warning()); - const char *description = signal.Describe(); - Report( - "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " - "T%d)\n", - description, (void *)signal.addr, (void *)signal.pc, (void *)signal.bp, - (void *)signal.sp, tid); - Printf("%s", d.Default()); - if (signal.pc < GetPageSizeCached()) - Report("Hint: pc points to the zero page.\n"); - if (signal.is_memory_access) { - const char *access_type = - signal.write_flag == SignalContext::WRITE - ? "WRITE" - : (signal.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); - Report("The signal is caused by a %s memory access.\n", access_type); - if (signal.addr < GetPageSizeCached()) - Report("Hint: address points to the zero page.\n"); + if (signal.IsStackOverflow()) { + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: %s on address %p" + " (pc %p bp %p sp %p T%d)\n", + scariness.GetDescription(), (void *)signal.addr, (void *)signal.pc, + (void *)signal.bp, (void *)signal.sp, tid); + Printf("%s", d.Default()); + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, + signal.bp, signal.context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); + } else { + Decorator d; + Printf("%s", d.Warning()); + const char *description = signal.Describe(); + Report( + "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " + "T%d)\n", + description, (void *)signal.addr, (void *)signal.pc, (void *)signal.bp, + (void *)signal.sp, tid); + Printf("%s", d.Default()); + if (signal.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (signal.is_memory_access) { + const char *access_type = + signal.write_flag == SignalContext::WRITE + ? "WRITE" + : (signal.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (signal.addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + MaybeReportNonExecRegion(signal.pc); + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, + signal.bp, signal.context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + MaybeDumpInstructionBytes(signal.pc); + MaybeDumpRegisters(signal.context); + Printf("AddressSanitizer can not provide additional info.\n"); + ReportErrorSummary(description, &stack); } - MaybeReportNonExecRegion(signal.pc); - scariness.Print(); - BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, signal.bp, - signal.context, - common_flags()->fast_unwind_on_fatal); - stack.Print(); - MaybeDumpInstructionBytes(signal.pc); - MaybeDumpRegisters(signal.context); - Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary(description, &stack); } void ErrorDoubleFree::Print() { diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index b9944739b..b35cb259c 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -27,19 +27,6 @@ struct ErrorBase { u32 tid; }; -struct ErrorStackOverflow : ErrorBase { - SignalContext signal; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorStackOverflow() = default; - ErrorStackOverflow(u32 tid, const SignalContext &sig) - : ErrorBase(tid), signal(sig) { - scariness.Clear(); - scariness.Scare(10, "stack-overflow"); - } - void Print(); -}; - struct ErrorDeadlySignal : ErrorBase { SignalContext signal; // VS2013 doesn't implement unrestricted unions, so we need a trivial default @@ -48,20 +35,20 @@ struct ErrorDeadlySignal : ErrorBase { ErrorDeadlySignal(u32 tid, const SignalContext &sig) : ErrorBase(tid), signal(sig) { scariness.Clear(); - if (signal.is_memory_access) { - if (signal.addr < GetPageSizeCached()) { - scariness.Scare(10, "null-deref"); - } else if (signal.addr == signal.pc) { - scariness.Scare(60, "wild-jump"); - } else if (signal.write_flag == SignalContext::WRITE) { - scariness.Scare(30, "wild-addr-write"); - } else if (signal.write_flag == SignalContext::READ) { - scariness.Scare(20, "wild-addr-read"); - } else { - scariness.Scare(25, "wild-addr"); - } - } else { + if (signal.IsStackOverflow()) { + scariness.Scare(10, "stack-overflow"); + } else if (!signal.is_memory_access) { scariness.Scare(10, "signal"); + } else if (signal.addr < GetPageSizeCached()) { + scariness.Scare(10, "null-deref"); + } else if (signal.addr == signal.pc) { + scariness.Scare(60, "wild-jump"); + } else if (signal.write_flag == SignalContext::WRITE) { + scariness.Scare(30, "wild-addr-write"); + } else if (signal.write_flag == SignalContext::READ) { + scariness.Scare(20, "wild-addr-read"); + } else { + scariness.Scare(25, "wild-addr"); } } void Print(); @@ -304,7 +291,6 @@ struct ErrorGeneric : ErrorBase { // clang-format off #define ASAN_FOR_EACH_ERROR_KIND(macro) \ - macro(StackOverflow) \ macro(DeadlySignal) \ macro(DoubleFree) \ macro(NewDeleteSizeMismatch) \ diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 05892475d..034ff58bb 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -37,10 +37,7 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal(); SignalContext sig(siginfo, context); - if (sig.IsStackOverflow()) - ReportStackOverflow(sig); - else - ReportDeadlySignal(sig); + ReportDeadlySignal(sig); } // ---------------------- TSD ---------------- {{{1 diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 6055304e8..7e83466cc 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -260,12 +260,6 @@ StaticSpinMutex ScopedInErrorReport::lock_; u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid; ErrorDescription ScopedInErrorReport::current_error_; -void ReportStackOverflow(const SignalContext &sig) { - ScopedInErrorReport in_report(/*fatal*/ true); - ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig); - in_report.ReportError(error); -} - void ReportDeadlySignal(const SignalContext &sig) { ScopedInErrorReport in_report(/*fatal*/ true); ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig); diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index 259177bc7..324e454ea 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -46,7 +46,6 @@ bool ParseFrameDescription(const char *frame_descr, // Different kinds of error reports. void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); -void ReportStackOverflow(const SignalContext &sig); void ReportDeadlySignal(const SignalContext &sig); void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack); -- cgit v1.2.1 From 476bb23ca07911c2a52644e743fabdba40a0c1b4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 14 Sep 2017 22:44:03 +0000 Subject: [sanitizer] Move stack overflow and signal reporting from Asan into common. Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D37844 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313310 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 63 +++++----------------- lib/sanitizer_common/sanitizer_common.h | 12 +++-- lib/sanitizer_common/sanitizer_common_libcdep.cc | 68 ++++++++++++++++++++++-- lib/sanitizer_common/sanitizer_fuchsia.cc | 3 ++ 4 files changed, 89 insertions(+), 57 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index cc09248af..f2870d48e 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -22,56 +22,21 @@ namespace __asan { +static void OnStackUnwind(const SignalContext &sig, + const void *callback_context, + BufferedStackTrace *stack) { + // Tests and maybe some users expect that scariness is going to be printed + // just before the stack. As only asan has scariness score we have no + // corresponding code in the sanitizer_common and we use this callback to + // print it. + static_cast(callback_context)->Print(); + GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp, + sig.context, + common_flags()->fast_unwind_on_fatal); +} + void ErrorDeadlySignal::Print() { - if (signal.IsStackOverflow()) { - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: %s on address %p" - " (pc %p bp %p sp %p T%d)\n", - scariness.GetDescription(), (void *)signal.addr, (void *)signal.pc, - (void *)signal.bp, (void *)signal.sp, tid); - Printf("%s", d.Default()); - scariness.Print(); - BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, - signal.bp, signal.context, - common_flags()->fast_unwind_on_fatal); - stack.Print(); - ReportErrorSummary(scariness.GetDescription(), &stack); - } else { - Decorator d; - Printf("%s", d.Warning()); - const char *description = signal.Describe(); - Report( - "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " - "T%d)\n", - description, (void *)signal.addr, (void *)signal.pc, (void *)signal.bp, - (void *)signal.sp, tid); - Printf("%s", d.Default()); - if (signal.pc < GetPageSizeCached()) - Report("Hint: pc points to the zero page.\n"); - if (signal.is_memory_access) { - const char *access_type = - signal.write_flag == SignalContext::WRITE - ? "WRITE" - : (signal.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); - Report("The signal is caused by a %s memory access.\n", access_type); - if (signal.addr < GetPageSizeCached()) - Report("Hint: address points to the zero page.\n"); - } - MaybeReportNonExecRegion(signal.pc); - scariness.Print(); - BufferedStackTrace stack; - GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, signal.pc, - signal.bp, signal.context, - common_flags()->fast_unwind_on_fatal); - stack.Print(); - MaybeDumpInstructionBytes(signal.pc); - MaybeDumpRegisters(signal.context); - Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary(description, &stack); - } + ReportDeadlySignal(signal, tid, &OnStackUnwind, &scariness); } void ErrorDoubleFree::Print() { diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 988acb794..75508cbe4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -31,6 +31,7 @@ extern "C" void _ReadWriteBarrier(); namespace __sanitizer { struct AddressInfo; +struct BufferedStackTrace; struct SignalContext; struct StackTrace; @@ -311,10 +312,13 @@ HandleSignalMode GetHandleSignalMode(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); // Signal reporting. void StartReportDeadlySignal(); -// FIXME: Hide after moving more signal handling code into common. -void MaybeReportNonExecRegion(uptr pc); -void MaybeDumpInstructionBytes(uptr pc); -void MaybeDumpRegisters(void *context); +// Each sanitizer uses slightly different implementation of stack unwinding. +typedef void (*UnwindSignalStackCallbackType)(const SignalContext &sig, + const void *callback_context, + BufferedStackTrace *stack); +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context); // Alternative signal stack (POSIX-only). void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 21a591e64..4f26a2227 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -148,7 +148,7 @@ void BackgroundThread(void *arg) { #endif #if !SANITIZER_GO -void MaybeReportNonExecRegion(uptr pc) { +static void MaybeReportNonExecRegion(uptr pc) { #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; @@ -166,7 +166,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before, d.Default()); } -void MaybeDumpInstructionBytes(uptr pc) { +static void MaybeDumpInstructionBytes(uptr pc) { if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return; InternalScopedString str(1024); @@ -182,11 +182,71 @@ void MaybeDumpInstructionBytes(uptr pc) { Report("%s", str.data()); } -void MaybeDumpRegisters(void *context) { +static void MaybeDumpRegisters(void *context) { if (!common_flags()->dump_registers) return; SignalContext::DumpAllRegisters(context); } -#endif + +static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + static const char kDescription[] = "stack-overflow"; + Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + InternalScopedBuffer stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + ReportErrorSummary(kDescription, stack); +} + +static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + const char *description = sig.Describe(); + Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + if (sig.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (sig.is_memory_access) { + const char *access_type = + sig.write_flag == SignalContext::WRITE + ? "WRITE" + : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (sig.addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + MaybeReportNonExecRegion(sig.pc); + InternalScopedBuffer stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + MaybeDumpInstructionBytes(sig.pc); + MaybeDumpRegisters(sig.context); + Printf("%s can not provide additional info.\n", SanitizerToolName); + ReportErrorSummary(description, stack); +} + +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + if (sig.IsStackOverflow()) + ReportStackOverflowImpl(sig, tid, unwind, unwind_context); + else + ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); +} +#endif // !SANITIZER_GO void WriteToSyslog(const char *msg) { InternalScopedString msg_copy(kErrorMessageBufferSize); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index e518708c0..708f7f0c5 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -92,6 +92,9 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} void DisableCoreDumperIfNecessary() {} void InstallDeadlySignalHandlers(SignalHandlerType handler) {} void StartReportDeadlySignal() {} +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) {} void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} -- cgit v1.2.1 From 973030f71da9f1620364652baca380d2df6bfd8d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 15 Sep 2017 00:02:30 +0000 Subject: [lsan] Disable clang-format on few RUN: statements git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313321 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/assert.cc | 4 ++++ test/sanitizer_common/TestCases/Linux/ill.cc | 4 ++++ test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/Linux/assert.cc b/test/sanitizer_common/TestCases/Linux/assert.cc index 7422d400a..51a9163f4 100644 --- a/test/sanitizer_common/TestCases/Linux/assert.cc +++ b/test/sanitizer_common/TestCases/Linux/assert.cc @@ -1,8 +1,12 @@ // Test the handle_abort option. + +// clang-format off // RUN: %clang %s -o %t // RUN: not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_abort=0 not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_abort=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s +// clang-format on + // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan // XFAIL: lsan diff --git a/test/sanitizer_common/TestCases/Linux/ill.cc b/test/sanitizer_common/TestCases/Linux/ill.cc index 2707fc9af..030da3376 100644 --- a/test/sanitizer_common/TestCases/Linux/ill.cc +++ b/test/sanitizer_common/TestCases/Linux/ill.cc @@ -1,8 +1,12 @@ // Test the handle_sigill option. + +// clang-format off // RUN: %clang %s -o %t -O1 // RUN: not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_sigill=0 not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_sigill=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s +// clang-format on + // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan // XFAIL: lsan diff --git a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc index 408da6bb6..b5e45c307 100644 --- a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc +++ b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc @@ -1,9 +1,12 @@ // Check that sanitizer prints the faulting instruction bytes on // dump_instruction_bytes=1 + +// clang-format off // RUN: %clangxx %s -o %t // RUN: %env_tool_opts=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP -// +// clang-format on + // REQUIRES: x86-target-arch // XFAIL: lsan, msan, tsan, ubsan -- cgit v1.2.1 From e765db3a13ea619ba6a7521e81545c96d8b336a1 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 15 Sep 2017 02:56:40 +0000 Subject: Revert "[lit] Force site configs to run before source-tree configs" This patch is still breaking several multi-stage compiler-rt bots. I already know what the fix is, but I want to get the bots green for now and then try re-applying in the morning. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313335 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 11 ++++++----- test/profile/lit.cfg | 11 +++++++++++ unittests/lit.common.unit.cfg | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 6c07ca661..4f23ab285 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -73,9 +73,10 @@ for name in possibly_dangerous_env_vars: del config.environment[name] # Tweak PATH to include llvm tools dir. -if (not config.llvm_tools_dir) or (not os.path.exists(config.llvm_tools_dir)): - lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % config.llvm_tools_dir) -path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH'])) +llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) +if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): + lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) +path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) config.environment['PATH'] = path # Help MSVS link.exe find the standard libraries. @@ -192,7 +193,7 @@ if config.host_os == 'Darwin': else: config.substitutions.append( ("%macos_min_target_10_11", "") ) -sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") +sancovcc_path = os.path.join(llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): config.available_features.add("has_sancovcc") config.substitutions.append( ("%sancovcc ", sancovcc_path) ) @@ -253,7 +254,7 @@ try: stdout = subprocess.PIPE, env=config.environment) except OSError: - print("Could not find llvm-config in " + config.llvm_tools_dir) + print("Could not find llvm-config in " + llvm_tools_dir) exit(42) if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 7f0d95a9a..9ca394212 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -22,6 +22,17 @@ if hasattr(config, 'profile_lit_binary_dir') and \ config.profile_lit_binary_dir is not None: config.test_exec_root = os.path.join(config.profile_lit_binary_dir, config.name) +# If the above check didn't work, we're probably in the source tree. Use some +# magic to re-execute from the build tree. +if config.test_exec_root is None: + # The magic relies on knowing compilerrt_site_basedir. + compilerrt_basedir = lit_config.params.get('compilerrt_site_basedir', None) + if compilerrt_basedir: + site_cfg = os.path.join(compilerrt_basedir, 'profile', 'lit.site.cfg') + if os.path.exists(site_cfg): + lit_config.load_config(config, site_cfg) + raise SystemExit + if config.host_os in ['Linux']: extra_link_flags = ["-ldl"] else: diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg index 31206e913..b08c1fe12 100644 --- a/unittests/lit.common.unit.cfg +++ b/unittests/lit.common.unit.cfg @@ -16,7 +16,7 @@ config.test_format = lit.formats.GoogleTest(llvm_build_mode, "Test") config.suffixes = [] # Tweak PATH to include llvm tools dir. -llvm_tools_dir = config.llvm_tools_dir +llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) -- cgit v1.2.1 From a1a53ed7b2fc19d93149c2834313a301e29781bf Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 15 Sep 2017 04:05:15 +0000 Subject: [sanitizer] Use __sanitizer:: in CHECK_IMPL on both sides of assignment git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313338 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_internal_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 601f230ed..0889034e1 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -261,8 +261,8 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, #define CHECK_IMPL(c1, op, c2) \ do { \ - __sanitizer::u64 v1 = (u64)(c1); \ - __sanitizer::u64 v2 = (u64)(c2); \ + __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \ + __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \ if (UNLIKELY(!(v1 op v2))) \ __sanitizer::CheckFailed(__FILE__, __LINE__, \ "(" #c1 ") " #op " (" #c2 ")", v1, v2); \ -- cgit v1.2.1 From 58f0da74566438074cff6107b4173f9b26d5ebaa Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 15 Sep 2017 04:48:02 +0000 Subject: [sanitizer] Simplify checks in allow_user_segv.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313342 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/allow_user_segv.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index fdc03b3fc..e76f0b1af 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -77,17 +77,17 @@ int main() { return DoSEGV(); } -// CHECK0-NOT: AddressSanitizer:DEADLYSIGNAL -// CHECK0-NOT: AddressSanitizer: SEGV on unknown address +// CHECK0-NOT: Sanitizer:DEADLYSIGNAL +// CHECK0-NOT: Sanitizer: SEGV on unknown address // CHECK0: User sigaction installed // CHECK0-NEXT: User sigaction called // CHECK1: User sigaction installed // CHECK1-NEXT: User sigaction called -// CHECK1-NEXT: AddressSanitizer:DEADLYSIGNAL -// CHECK1: AddressSanitizer: SEGV on unknown address +// CHECK1-NEXT: Sanitizer:DEADLYSIGNAL +// CHECK1: Sanitizer: SEGV on unknown address // CHECK2-NOT: User sigaction called // CHECK2: User sigaction installed -// CHECK2-NEXT: AddressSanitizer:DEADLYSIGNAL -// CHECK2: AddressSanitizer: SEGV on unknown address +// CHECK2-NEXT: Sanitizer:DEADLYSIGNAL +// CHECK2: Sanitizer: SEGV on unknown address -- cgit v1.2.1 From 2187d5ac003476a5b5c6596a92c0686dec7802be Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 15 Sep 2017 06:51:37 +0000 Subject: tsan: respect LDFLAGS when build Go test Reported at: https://bugs.llvm.org/show_bug.cgi?id=27597 Some platforms need additional LDFLAGS when building the test (e.g. -no-pie). Respect LDFLAGS. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313347 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/go/buildgo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index 9d4d7d7fc..c27b72afe 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -127,7 +127,7 @@ if [ "$SILENT" != "1" ]; then fi $CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS -$CC $OSCFLAGS test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS +$CC $OSCFLAGS test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS $LDFLAGS export GORACE="exitcode=0 atexit_sleep_ms=0" if [ "$SILENT" != "1" ]; then -- cgit v1.2.1 From 3ed5043d1ed3d45009d3a2cbb3deca8f334f1318 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 15 Sep 2017 08:11:53 +0000 Subject: [ubsan] Extract GetStackTraceWithPcBpAndContext similar to asan version git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313350 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_diag.cc | 20 ++++++++++++-------- lib/ubsan/ubsan_diag.h | 4 ++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index f039a317f..e73fe9042 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -26,21 +26,25 @@ using namespace __ubsan; +void __ubsan::GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, + uptr max_depth, uptr pc, uptr bp, + void *context, bool fast) { + uptr top = 0; + uptr bottom = 0; + if (fast) + GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(max_depth, pc, bp, context, top, bottom, fast); +} + static void MaybePrintStackTrace(uptr pc, uptr bp) { // We assume that flags are already parsed, as UBSan runtime // will definitely be called when we print the first diagnostics message. if (!flags()->print_stacktrace) return; - uptr top = 0; - uptr bottom = 0; - bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; - if (request_fast_unwind) - __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); - BufferedStackTrace stack; - stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, - request_fast_unwind); + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, nullptr, + common_flags()->fast_unwind_on_fatal); stack.Print(); } diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 3edb67a03..2e1983947 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -231,6 +231,10 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET); GET_CALLER_PC_BP; \ ReportOptions Opts = {unrecoverable_handler, pc, bp} +void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, + uptr pc, uptr bp, void *context, + bool fast); + /// \brief Instantiate this class before printing diagnostics in the error /// report. This class ensures that reports from different threads and from /// different sanitizers won't be mixed. -- cgit v1.2.1 From dc6a7dbdb4efabcd7fcbc98ba73a1576ac4aca6c Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Fri, 15 Sep 2017 15:18:51 +0000 Subject: [sanitizer][mips64] fix MIPS64 kernel_stat_to_stat() This patch tackles with two issues: Output stat st_[a|m|c]time fields were holding wrong values. st_[a|m|c]time fields should have contained value of seconds and instead these are filled with st_[a|m|c]time_nsec fields which hold nanoseconds. Build fails for MIPS64 if SANITIZER_ANDROID. Recently from bionic introduced st_[a|m|c]time_nsec macros for compatibility with old NDKs and those clashed with the field names of the kernel_stat structure. To fix both issues and make sure sanitizer builds on all platforms, we must un-define all compatibility macros and access the fields directly when copying the 'time' fields. Patch by Miodrag Dinic Differential Revision: https://reviews.llvm.org/D35671 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313360 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.cc | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 72d53e826..48c53d46d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -255,6 +255,21 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) { #endif #if defined(__mips64) +// Undefine compatibility macros from +// so that they would not clash with the kernel_stat +// st_[a|m|c]time fields +#undef st_atime +#undef st_mtime +#undef st_ctime +#if defined(SANITIZER_ANDROID) +// Bionic sys/stat.h defines additional macros +// for compatibility with the old NDKs and +// they clash with the kernel_stat structure +// st_[a|m|c]time_nsec fields. +#undef st_atime_nsec +#undef st_mtime_nsec +#undef st_ctime_nsec +#endif static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; @@ -267,9 +282,23 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { out->st_size = in->st_size; out->st_blksize = in->st_blksize; out->st_blocks = in->st_blocks; - out->st_atime = in->st_atime_nsec; - out->st_mtime = in->st_mtime_nsec; - out->st_ctime = in->st_ctime_nsec; +#if defined(__USE_MISC) || \ + defined(__USE_XOPEN2K8) || \ + defined(SANITIZER_ANDROID) + out->st_atim.tv_sec = in->st_atime; + out->st_atim.tv_nsec = in->st_atime_nsec; + out->st_mtim.tv_sec = in->st_mtime; + out->st_mtim.tv_nsec = in->st_mtime_nsec; + out->st_ctim.tv_sec = in->st_ctime; + out->st_ctim.tv_nsec = in->st_ctime_nsec; +#else + out->st_atime = in->st_atime; + out->st_atimensec = in->st_atime_nsec; + out->st_mtime = in->st_mtime; + out->st_mtimensec = in->st_mtime_nsec; + out->st_ctime = in->st_ctime; + out->st_atimensec = in->st_ctime_nsec; +#endif } #endif -- cgit v1.2.1 From 1a95a19d077499da2b1e7c03e868d0aadc16024d Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 15 Sep 2017 18:54:37 +0000 Subject: ubsan: Stop building the DLL version of the runtime library on Windows. As far as I know we never use it. Differential Revision: https://reviews.llvm.org/D37884 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313378 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 457d9e505..a29c0eed9 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -153,30 +153,30 @@ else() CFLAGS ${UBSAN_CXXFLAGS} PARENT_TARGET ubsan) - add_compiler_rt_runtime(clang_rt.ubsan_standalone - SHARED - ARCHS ${UBSAN_SUPPORTED_ARCH} - OBJECT_LIBS RTSanitizerCommon - RTSanitizerCommonLibc - RTUbsan - CFLAGS ${UBSAN_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} - LINK_LIBS ${UBSAN_DYNAMIC_LIBS} - PARENT_TARGET ubsan) - - add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx - SHARED - ARCHS ${UBSAN_SUPPORTED_ARCH} - OBJECT_LIBS RTSanitizerCommon - RTSanitizerCommonLibc - RTUbsan - RTUbsan_cxx - CFLAGS ${UBSAN_CXXFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} - LINK_LIBS ${UBSAN_DYNAMIC_LIBS} - PARENT_TARGET ubsan) - if (UNIX) + add_compiler_rt_runtime(clang_rt.ubsan_standalone + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTSanitizerCommon + RTSanitizerCommonLibc + RTUbsan + CFLAGS ${UBSAN_CFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan) + + add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx + SHARED + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTSanitizerCommon + RTSanitizerCommonLibc + RTUbsan + RTUbsan_cxx + CFLAGS ${UBSAN_CXXFLAGS} + LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan) + set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386) add_sanitizer_rt_symbols(clang_rt.ubsan_standalone -- cgit v1.2.1 From 958f7a8d5ece142207e0bd64207257a7f98ff730 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 15 Sep 2017 18:55:35 +0000 Subject: cfi: Enable ThinLTO tests on Windows. We now avoid using absolute symbols on Windows (D37407 and D37408), so this should work. Fixes PR32770. Differential Revision: https://reviews.llvm.org/D37883 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313379 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 0bad50e2d..3313fb233 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -33,8 +33,8 @@ if (APPLE) # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 add_cfi_test_suites(False False) elseif(WIN32) - # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32770 add_cfi_test_suites(True False) + add_cfi_test_suites(True True) else() if (CFI_SUPPORTED_ARCH) add_cfi_test_suites(False False) -- cgit v1.2.1 From 76cdb74591bf05bef9919e4e1a79ff0a14a21d29 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 15 Sep 2017 20:24:12 +0000 Subject: ubsan: Unbreak ubsan_cxx runtime library on Windows. This was originally broken by r258744 which introduced a weak reference from ubsan to ubsan_cxx. This reference does not work directly on Windows because COFF has no direct concept of weak symbols. The fix is to use /alternatename to create a weak external reference to ubsan_cxx. Also fix the definition (and the name, so that we drop cached values) of the cmake flag that controls whether to build ubsan_cxx. Now the user-controllable flag is always on, and we turn it off internally depending on whether we support building it. Differential Revision: https://reviews.llvm.org/D37882 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313391 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 13 ++++++---- lib/ubsan/ubsan_handlers.cc | 29 +++++++++++++++++----- lib/ubsan/ubsan_handlers.h | 7 ++++++ lib/ubsan/ubsan_handlers_cxx.cc | 4 +-- test/cfi/target_uninstrumented.cpp | 1 + test/ubsan/TestCases/TypeCheck/PR33221.cpp | 1 + .../TypeCheck/vptr-non-unique-typeinfo.cpp | 1 + .../TypeCheck/vptr-virtual-base-construction.cpp | 1 + .../TestCases/TypeCheck/vptr-virtual-base.cpp | 1 + test/ubsan/TestCases/TypeCheck/vptr.cpp | 1 + 10 files changed, 46 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 518428092..90cdac73a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,14 +94,17 @@ include(config-ix) if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9") # Mac OS X prior to 10.9 had problems with exporting symbols from # libc++/libc++abi. - set(use_cxxabi_default OFF) -elseif(MSVC) - set(use_cxxabi_default OFF) + set(cxxabi_supported OFF) else() - set(use_cxxabi_default ON) + set(cxxabi_supported ON) endif() -option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default}) +option(SANITIZER_ALLOW_CXXABI "Allow use of C++ ABI details in ubsan" ON) + +set(SANITIZE_CAN_USE_CXXABI OFF) +if (cxxabi_supported AND SANITIZER_ALLOW_CXXABI) + set(SANITIZER_CAN_USE_CXXABI ON) +endif() pythonize_bool(SANITIZER_CAN_USE_CXXABI) set(SANITIZER_CXX_ABI "default" CACHE STRING diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 06438a5d3..93f6ee2ab 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -652,16 +652,33 @@ static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, } namespace __ubsan { + #ifdef UBSAN_CAN_USE_CXXABI + +#ifdef _WIN32 + +extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data, + ValueHandle Vtable, + bool ValidVtable, + ReportOptions Opts) { + Die(); +} + +WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default) +#else SANITIZER_WEAK_ATTRIBUTE -void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable, - bool ValidVtable, ReportOptions Opts); +#endif +void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, + bool ValidVtable, ReportOptions Opts); + #else -static void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable, - bool ValidVtable, ReportOptions Opts) { +static void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, + ValueHandle Vtable, + bool ValidVtable, ReportOptions Opts) { Die(); } #endif + } // namespace __ubsan void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, @@ -671,7 +688,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, if (Data->CheckKind == CFITCK_ICall) handleCFIBadIcall(Data, Value, Opts); else - HandleCFIBadType(Data, Value, ValidVtable, Opts); + __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); } void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data, @@ -681,7 +698,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data, if (Data->CheckKind == CFITCK_ICall) handleCFIBadIcall(Data, Value, Opts); else - HandleCFIBadType(Data, Value, ValidVtable, Opts); + __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); Die(); } diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 5a9e902ce..311776b9f 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -192,6 +192,13 @@ struct CFICheckFailData { /// \brief Handle control flow integrity failures. RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function, uptr VtableIsValid) + +struct ReportOptions; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_handle_cfi_bad_type( + CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, + ReportOptions Opts); + } #endif // UBSAN_HANDLERS_H diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index d97ec4813..e15abc64e 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -95,8 +95,8 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( } namespace __ubsan { -void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable, - bool ValidVtable, ReportOptions Opts) { +void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, + bool ValidVtable, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); ErrorType ET = ErrorType::CFIBadType; diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp index 2ec2b5bbc..bf20f58e2 100644 --- a/test/cfi/target_uninstrumented.cpp +++ b/test/cfi/target_uninstrumented.cpp @@ -3,6 +3,7 @@ // RUN: %t 2>&1 | FileCheck %s // REQUIRES: cxxabi +// UNSUPPORTED: win32 #include #include diff --git a/test/ubsan/TestCases/TypeCheck/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/PR33221.cpp index 71da06c09..65cbf5d00 100644 --- a/test/ubsan/TestCases/TypeCheck/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/PR33221.cpp @@ -2,6 +2,7 @@ // RUN: %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi +// UNSUPPORTED: win32 #include diff --git a/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp b/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp index 8ab7bfcaa..e8d510694 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp @@ -3,6 +3,7 @@ // RUN: %run %t // // REQUIRES: cxxabi +// UNSUPPORTED: win32 struct X { virtual ~X() {} diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base-construction.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base-construction.cpp index dc27d9f39..a86960d12 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base-construction.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base-construction.cpp @@ -2,6 +2,7 @@ // RUN: %run %t // REQUIRES: cxxabi +// UNSUPPORTED: win32 int volatile n; diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp index f1fb11131..aa0123c46 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp @@ -2,6 +2,7 @@ // RUN: not %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi +// UNSUPPORTED: win32 struct S { virtual int f() { return 0; } }; struct T : virtual S {}; diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index 183c7b743..21d762ee1 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -26,6 +26,7 @@ // RUN: %env_ubsan_opts=suppressions='"%t.loc-supp"' not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS // REQUIRES: stable-runtime, cxxabi +// UNSUPPORTED: win32 #include #include #include -- cgit v1.2.1 From f621dd83d4c4f4aaff040b2ce1788e205c012ff0 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 15 Sep 2017 22:02:26 +0000 Subject: [libFuzzer] reduce the size of the merge control file by not dumping redundant features into it git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313403 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerMerge.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index 6f111a5e4..78f2253a4 100644 --- a/lib/fuzzer/FuzzerMerge.cpp +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -221,6 +221,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { M.Files.size() - M.FirstNotProcessedFile); std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); + Set AllFeatures; for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { auto U = FileToVector(M.Files[i].Name); if (U.size() > MaxInputLen) { @@ -234,10 +235,15 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { // Run. TPC.ResetMaps(); ExecuteCallback(U.data(), U.size()); - // Collect coverage. - Set Features; + // Collect coverage. We are iterating over the files in this order: + // * First, files in the initial corpus ordered by size, smallest first. + // * Then, all other files, smallest first. + // So it makes no sense to record all features for all files, instead we + // only record features that were not seen before. + Set UniqFeatures; TPC.CollectFeatures([&](size_t Feature) -> bool { - Features.insert(Feature); + if (AllFeatures.insert(Feature).second) + UniqFeatures.insert(Feature); return true; }); // Show stats. @@ -245,7 +251,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { PrintStats("pulse "); // Write the post-run marker and the coverage. OF << "DONE " << i; - for (size_t F : Features) + for (size_t F : UniqFeatures) OF << " " << std::hex << F; OF << "\n"; } @@ -260,11 +266,13 @@ void Fuzzer::CrashResistantMerge(const Vector &Args, Printf("Merge requires two or more corpus dirs\n"); return; } - Vector AllFiles; - ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); + Vector AllFiles; + GetSizedFilesFromDir(Corpora[0], &AllFiles); size_t NumFilesInFirstCorpus = AllFiles.size(); + std::sort(AllFiles.begin(), AllFiles.end()); for (size_t i = 1; i < Corpora.size(); i++) - ListFilesInDirRecursive(Corpora[i], nullptr, &AllFiles, /*TopDir*/true); + GetSizedFilesFromDir(Corpora[i], &AllFiles); + std::sort(AllFiles.begin() + NumFilesInFirstCorpus, AllFiles.end()); Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n", AllFiles.size(), NumFilesInFirstCorpus); auto CFPath = DirPlusFile(TmpDir(), @@ -274,8 +282,8 @@ void Fuzzer::CrashResistantMerge(const Vector &Args, std::ofstream ControlFile(CFPath); ControlFile << AllFiles.size() << "\n"; ControlFile << NumFilesInFirstCorpus << "\n"; - for (auto &Path: AllFiles) - ControlFile << Path << "\n"; + for (auto &SF: AllFiles) + ControlFile << SF.File << "\n"; if (!ControlFile) { Printf("MERGE-OUTER: failed to write to the control file: %s\n", CFPath.c_str()); -- cgit v1.2.1 From 4c32603421b9d0fec32fc9b6d11661babdfc21bf Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 15 Sep 2017 22:10:36 +0000 Subject: [libFuzzer] minor refactoring, NFC git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313406 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerDriver.cpp | 6 ++---- lib/fuzzer/FuzzerMerge.cpp | 3 +-- lib/fuzzer/FuzzerTracePC.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 804f426e9..cc995348e 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -471,9 +471,8 @@ int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, // Get coverage for the testcase without modifications. F->ExecuteCallback(C.data(), C.size()); InitialFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { + TPC.CollectFeatures([&](size_t Feature) { InitialFeatures.push_back(Feature); - return true; }); for (size_t i = 0; i < Dict.size(); ++i) { @@ -498,9 +497,8 @@ int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, // Get coverage for testcase with masked occurrences of dictionary unit. F->ExecuteCallback(Data.data(), Data.size()); ModifiedFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { + TPC.CollectFeatures([&](size_t Feature) { ModifiedFeatures.push_back(Feature); - return true; }); if (InitialFeatures == ModifiedFeatures) diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index 78f2253a4..03cf00a56 100644 --- a/lib/fuzzer/FuzzerMerge.cpp +++ b/lib/fuzzer/FuzzerMerge.cpp @@ -241,10 +241,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { // So it makes no sense to record all features for all files, instead we // only record features that were not seen before. Set UniqFeatures; - TPC.CollectFeatures([&](size_t Feature) -> bool { + TPC.CollectFeatures([&](size_t Feature) { if (AllFeatures.insert(Feature).second) UniqFeatures.insert(Feature); - return true; }); // Show stats. if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1))) diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 54172608d..743db5483 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -208,7 +208,7 @@ unsigned CounterToFeature(T Counter) { return Bit; } -template // bool Callback(size_t Feature) +template // void Callback(size_t Feature) ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((noinline)) void TracePC::CollectFeatures(Callback HandleFeature) const { -- cgit v1.2.1 From bf4ab7a4ac3100bf9f640f5d0b4ac5fe572b2620 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 15 Sep 2017 22:10:46 +0000 Subject: Resubmit "[lit] Force site configs to run before source-tree configs" This is a resubmission of r313270. It broke standalone builds of compiler-rt because we were not correctly generating the llvm-lit script in the standalone build directory. The fixes incorporated here attempt to find llvm/utils/llvm-lit from the source tree returned by llvm-config. If present, it will generate llvm-lit into the output directory. Regardless, the user can specify -DLLVM_EXTERNAL_LIT to point to a specific lit.py on their file system. This supports the use case of someone installing lit via a package manager. If it cannot find a source tree, and -DLLVM_EXTERNAL_LIT is either unspecified or invalid, then we print a warning that tests will not be able to run. Differential Revision: https://reviews.llvm.org/D37756 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313407 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 14 +++++++++++++- test/lit.common.cfg | 11 +++++------ test/profile/lit.cfg | 11 ----------- unittests/lit.common.unit.cfg | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90cdac73a..e021bf84a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ if (COMPILER_RT_STANDALONE_BUILD) set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") endif() set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + set(LLVM_LIT_OUTPUT_DIR "${COMPILER_RT_EXEC_OUTPUT_DIR}") endif() construct_compiler_rt_default_triple() @@ -228,7 +229,7 @@ append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS) # always respect the optimization flags set by CMAKE_BUILD_TYPE instead. if (NOT MSVC) - # Build with optimization, unless we're in debug mode. + # Build with optimization, unless we're in debug mode. if(COMPILER_RT_DEBUG) list(APPEND SANITIZER_COMMON_CFLAGS -O0) else() @@ -348,4 +349,15 @@ add_subdirectory(lib) if(COMPILER_RT_INCLUDE_TESTS) add_subdirectory(unittests) add_subdirectory(test) + if (COMPILER_RT_STANDALONE_BUILD) + # If we have a valid source tree, generate llvm-lit into the bin directory. + # The user can still choose to have the check targets *use* a different lit + # by specifying -DLLVM_EXTERNAL_LIT, but we generate it regardless. + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit) + elseif(NOT EXISTS ${LLVM_EXTERNAL_LIT}) + message(WARNING "Could not find LLVM source directory and LLVM_EXTERNAL_LIT does not" + "point to a valid file. You will not be able to run tests.") + endif() + endif() endif() diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 4f23ab285..6c07ca661 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -73,10 +73,9 @@ for name in possibly_dangerous_env_vars: del config.environment[name] # Tweak PATH to include llvm tools dir. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) -if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): - lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) -path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) +if (not config.llvm_tools_dir) or (not os.path.exists(config.llvm_tools_dir)): + lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % config.llvm_tools_dir) +path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH'])) config.environment['PATH'] = path # Help MSVS link.exe find the standard libraries. @@ -193,7 +192,7 @@ if config.host_os == 'Darwin': else: config.substitutions.append( ("%macos_min_target_10_11", "") ) -sancovcc_path = os.path.join(llvm_tools_dir, "sancov") +sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): config.available_features.add("has_sancovcc") config.substitutions.append( ("%sancovcc ", sancovcc_path) ) @@ -254,7 +253,7 @@ try: stdout = subprocess.PIPE, env=config.environment) except OSError: - print("Could not find llvm-config in " + llvm_tools_dir) + print("Could not find llvm-config in " + config.llvm_tools_dir) exit(42) if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')): diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 9ca394212..7f0d95a9a 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -22,17 +22,6 @@ if hasattr(config, 'profile_lit_binary_dir') and \ config.profile_lit_binary_dir is not None: config.test_exec_root = os.path.join(config.profile_lit_binary_dir, config.name) -# If the above check didn't work, we're probably in the source tree. Use some -# magic to re-execute from the build tree. -if config.test_exec_root is None: - # The magic relies on knowing compilerrt_site_basedir. - compilerrt_basedir = lit_config.params.get('compilerrt_site_basedir', None) - if compilerrt_basedir: - site_cfg = os.path.join(compilerrt_basedir, 'profile', 'lit.site.cfg') - if os.path.exists(site_cfg): - lit_config.load_config(config, site_cfg) - raise SystemExit - if config.host_os in ['Linux']: extra_link_flags = ["-ldl"] else: diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg index b08c1fe12..31206e913 100644 --- a/unittests/lit.common.unit.cfg +++ b/unittests/lit.common.unit.cfg @@ -16,7 +16,7 @@ config.test_format = lit.formats.GoogleTest(llvm_build_mode, "Test") config.suffixes = [] # Tweak PATH to include llvm tools dir. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) +llvm_tools_dir = config.llvm_tools_dir if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) -- cgit v1.2.1 From e0a2ec37f5639468977161a3d93e041b5a2f867b Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 15 Sep 2017 22:29:20 +0000 Subject: [libFuzzer] test fix git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313411 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/fuzzer-flags.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzer/fuzzer-flags.test b/test/fuzzer/fuzzer-flags.test index 2f9a31063..59c8d1536 100644 --- a/test/fuzzer/fuzzer-flags.test +++ b/test/fuzzer/fuzzer-flags.test @@ -14,6 +14,6 @@ RUN: not %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 PASSTHRU: BINGO --foo-bar --baz -help=1 test RUN: mkdir -p %t/T0 %t/T1 -RUN: touch %t/T1/empty +RUN: echo z > %t/T1/z RUN: not %t-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test -- cgit v1.2.1 From 2fd9c24c1592e3a09f10e5dcb5be89e1dc73b6dd Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 15 Sep 2017 23:07:18 +0000 Subject: [libFuzzer] add linux-specific test for gc-sections git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313421 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/GcSectionsTest.cpp | 14 ++++++++++++++ test/fuzzer/gc-sections.test | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/fuzzer/GcSectionsTest.cpp create mode 100644 test/fuzzer/gc-sections.test diff --git a/test/fuzzer/GcSectionsTest.cpp b/test/fuzzer/GcSectionsTest.cpp new file mode 100644 index 000000000..fd9da7735 --- /dev/null +++ b/test/fuzzer/GcSectionsTest.cpp @@ -0,0 +1,14 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. +// The unused function should not be present in the binary. +#include +#include + +extern "C" void UnusedFunctionShouldBeRemovedByLinker() { } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return 0; +} + diff --git a/test/fuzzer/gc-sections.test b/test/fuzzer/gc-sections.test new file mode 100644 index 000000000..8785bb00e --- /dev/null +++ b/test/fuzzer/gc-sections.test @@ -0,0 +1,13 @@ +REQUIRES: linux + +No gc-sections: +RUN: %cpp_compiler %S/GcSectionsTest.cpp -o %t +RUN: nm %t | grep UnusedFunctionShouldBeRemovedByLinker | count 1 + +With gc-sections. Currently, we can't remove unused code. +DISABLED: %cpp_compiler %S/GcSectionsTest.cpp -o %t -ffunction-sections -Wl,-gc-sections +DISABLED: nm %t | grep UnusedFunctionShouldBeRemovedByLinker | count 1 + +With gc sections, with trace-pc. Unused code is removed. +RUN: %cpp_compiler %S/GcSectionsTest.cpp -o %t -fsanitize-coverage=0 -fsanitize-coverage=trace-pc -ffunction-sections -Wl,-gc-sections +RUN: nm %t | not grep UnusedFunctionShouldBeRemovedByLinker -- cgit v1.2.1 From 1d17d2ba0fe5916fcb182fa431fc356e8a410458 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 15 Sep 2017 23:37:22 +0000 Subject: Try to fix check-asan. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313423 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_interface.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 4c8f92e4f..d2e5a67fa 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -11,6 +11,7 @@ INTERFACE_FUNCTION(__ubsan_handle_add_overflow) INTERFACE_FUNCTION(__ubsan_handle_add_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_builtin_unreachable) +INTERFACE_FUNCTION(__ubsan_handle_cfi_bad_type) INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail) INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow) -- cgit v1.2.1 From 763214631ca3644bca56db75e36988068ff72ee2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 01:21:04 +0000 Subject: [ubsan] Update ubsan_interface.inc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313432 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_interface.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index d2e5a67fa..9beb3e2ff 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -16,6 +16,8 @@ INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail) INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow_abort) +INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss) +INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch) -- cgit v1.2.1 From 9ad3f746861b60ba767d92d23a8a9920dbcd1af4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 03:26:03 +0000 Subject: [asan] Enable asan_and_llvm_coverage_test.cc on Android Test just needs profile. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313438 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CMakeLists.txt | 8 +++++--- test/asan/CMakeLists.txt | 4 +--- test/asan/TestCases/asan_and_llvm_coverage_test.cc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2e344056f..6bc7cdbec 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,6 +9,11 @@ configure_lit_site_cfg( # add_subdirectory(BlocksRuntime) set(SANITIZER_COMMON_LIT_TEST_DEPS) + +if (COMPILER_RT_HAS_PROFILE) + list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile) +endif() + if(COMPILER_RT_STANDALONE_BUILD) add_executable(FileCheck IMPORTED GLOBAL) set_property(TARGET FileCheck PROPERTY IMPORTED_LOCATION ${LLVM_TOOLS_BINARY_DIR}/FileCheck) @@ -23,9 +28,6 @@ if(NOT ANDROID) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS clang clang-headers FileCheck count not llvm-config llvm-nm llvm-objdump llvm-readobj llvm-symbolizer compiler-rt-headers sancov) - if (COMPILER_RT_HAS_PROFILE) - list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile) - endif() if (WIN32) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS KillTheDoctor) endif() diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index bd6834d74..739ae56e7 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -31,9 +31,7 @@ set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND ASAN_TEST_DEPS asan) if(NOT APPLE AND COMPILER_RT_HAS_LLD) - list(APPEND ASAN_TEST_DEPS - lld - ) + list(APPEND ASAN_TEST_DEPS lld) endif() endif() set(ASAN_DYNAMIC_TEST_DEPS ${ASAN_TEST_DEPS}) diff --git a/test/asan/TestCases/asan_and_llvm_coverage_test.cc b/test/asan/TestCases/asan_and_llvm_coverage_test.cc index d53deb447..1574a3443 100644 --- a/test/asan/TestCases/asan_and_llvm_coverage_test.cc +++ b/test/asan/TestCases/asan_and_llvm_coverage_test.cc @@ -1,6 +1,6 @@ // RUN: %clangxx_asan -coverage -O0 %s -o %t // RUN: %env_asan_opts=check_initialization_order=1 %run %t 2>&1 | FileCheck %s -// XFAIL: android + // We don't really support running tests using profile runtime on Windows. // UNSUPPORTED: win32 #include -- cgit v1.2.1 From b1a3dbe82d08705931de8a3cf4e123955922ecbd Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 03:26:12 +0000 Subject: Revert "[ubsan] Update ubsan_interface.inc" This brakes interface_symbols_linux.c test. This reverts commit r313432. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313439 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_interface.inc | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 9beb3e2ff..d2e5a67fa 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -16,8 +16,6 @@ INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail) INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow_abort) -INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss) -INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch) -- cgit v1.2.1 From 04f544bb4f537fc2a82973d70a911bf9c1cfd640 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 03:41:16 +0000 Subject: [asan] Remove not-android Replaced with !android git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313440 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/asan_preload_test-1.cc | 2 +- test/asan/TestCases/Linux/asan_preload_test-2.cc | 2 +- test/asan/TestCases/Linux/calloc-preload.c | 2 +- test/asan/TestCases/Linux/preinstalled_signal.cc | 2 +- test/asan/TestCases/pass-struct-byval-uar.cc | 2 +- test/asan/lit.cfg | 2 -- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/asan/TestCases/Linux/asan_preload_test-1.cc b/test/asan/TestCases/Linux/asan_preload_test-1.cc index 4e365b563..e11bd623d 100644 --- a/test/asan/TestCases/Linux/asan_preload_test-1.cc +++ b/test/asan/TestCases/Linux/asan_preload_test-1.cc @@ -10,7 +10,7 @@ // REQUIRES: asan-dynamic-runtime // This way of setting LD_PRELOAD does not work with Android test runner. -// REQUIRES: not-android +// REQUIRES: !android #if BUILD_SO char dummy; diff --git a/test/asan/TestCases/Linux/asan_preload_test-2.cc b/test/asan/TestCases/Linux/asan_preload_test-2.cc index 488fd52e6..817c560d4 100644 --- a/test/asan/TestCases/Linux/asan_preload_test-2.cc +++ b/test/asan/TestCases/Linux/asan_preload_test-2.cc @@ -6,7 +6,7 @@ // REQUIRES: asan-dynamic-runtime // This way of setting LD_PRELOAD does not work with Android test runner. -// REQUIRES: not-android +// REQUIRES: !android #include diff --git a/test/asan/TestCases/Linux/calloc-preload.c b/test/asan/TestCases/Linux/calloc-preload.c index eb1c6738b..e1f33192b 100644 --- a/test/asan/TestCases/Linux/calloc-preload.c +++ b/test/asan/TestCases/Linux/calloc-preload.c @@ -7,7 +7,7 @@ // REQUIRES: asan-dynamic-runtime // // This way of setting LD_PRELOAD does not work with Android test runner. -// REQUIRES: not-android +// REQUIRES: !android #include #include diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc index 10feb71a5..2beba4e66 100644 --- a/test/asan/TestCases/Linux/preinstalled_signal.cc +++ b/test/asan/TestCases/Linux/preinstalled_signal.cc @@ -16,7 +16,7 @@ // REQUIRES: asan-dynamic-runtime // This way of setting LD_PRELOAD does not work with Android test runner. -// REQUIRES: not-android +// REQUIRES: !android // clang-format on #include diff --git a/test/asan/TestCases/pass-struct-byval-uar.cc b/test/asan/TestCases/pass-struct-byval-uar.cc index 3f2fd09c6..aa6fa579e 100644 --- a/test/asan/TestCases/pass-struct-byval-uar.cc +++ b/test/asan/TestCases/pass-struct-byval-uar.cc @@ -9,7 +9,7 @@ // instead creates a copy in main() and gives foo() a pointer to the copy. In // that case, ASAN has nothing to poison on return from foo() and will not // detect the UAR. -// REQUIRES: x86_64-target-arch, linux, not-android +// REQUIRES: x86_64-target-arch, linux, !android #include diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index c7c5036b6..1edefe9d7 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -115,8 +115,6 @@ if config.android == "1": config.available_features.add('android') compile_wrapper = os.path.join(asan_lit_source_dir, "android_commands", "android_compile.py") + " " config.compile_wrapper = compile_wrapper -else: - config.available_features.add('not-android') def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " -- cgit v1.2.1 From 3c6b804641aa83d6a5307ca3ea6a73e75fc4ecce Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 03:47:19 +0000 Subject: [builtins] Remove one more missed not-android git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313441 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/builtins/Unit/lit.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/test/builtins/Unit/lit.cfg b/test/builtins/Unit/lit.cfg index 9e3a0d6f7..0e17e479e 100644 --- a/test/builtins/Unit/lit.cfg +++ b/test/builtins/Unit/lit.cfg @@ -55,7 +55,6 @@ clang_builtins_cxxflags = clang_builtins_static_cxxflags if not is_msvc: config.available_features.add('c99-complex') -config.available_features.add('not-android') clang_wrapper = "" def build_invocation(compile_flags): -- cgit v1.2.1 From 2e99c092c389eed3bdf31282f8f06f4265d8eab0 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 05:13:56 +0000 Subject: [sanitizer] Move android_commoands from asan into sanitizer_common git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313443 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 1 + test/asan/android_commands/android_common.py | 41 ---------------------- test/asan/android_commands/android_compile.py | 36 ------------------- test/asan/android_commands/android_run.py | 40 --------------------- test/asan/lit.cfg | 13 +------ test/asan/lit.site.cfg.in | 2 -- test/lit.common.cfg | 12 ++++++- test/lit.common.configured.in | 1 + .../android_commands/android_common.py | 41 ++++++++++++++++++++++ .../android_commands/android_compile.py | 36 +++++++++++++++++++ .../android_commands/android_run.py | 40 +++++++++++++++++++++ 11 files changed, 131 insertions(+), 132 deletions(-) delete mode 100644 test/asan/android_commands/android_common.py delete mode 100755 test/asan/android_commands/android_compile.py delete mode 100755 test/asan/android_commands/android_run.py create mode 100644 test/sanitizer_common/android_commands/android_common.py create mode 100755 test/sanitizer_common/android_commands/android_compile.py create mode 100755 test/sanitizer_common/android_commands/android_run.py diff --git a/CMakeLists.txt b/CMakeLists.txt index e021bf84a..dd408d7e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ construct_compiler_rt_default_triple() if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi") set(ANDROID 1) endif() +pythonize_bool(ANDROID) set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/test/asan/android_commands/android_common.py b/test/asan/android_commands/android_common.py deleted file mode 100644 index 41994bb87..000000000 --- a/test/asan/android_commands/android_common.py +++ /dev/null @@ -1,41 +0,0 @@ -import os, subprocess, tempfile -import time - -ANDROID_TMPDIR = '/data/local/tmp/Output' -ADB = os.environ.get('ADB', 'adb') - -verbose = False -if os.environ.get('ANDROID_RUN_VERBOSE') == '1': - verbose = True - -def adb(args, attempts = 1): - if verbose: - print args - tmpname = tempfile.mktemp() - out = open(tmpname, 'w') - ret = 255 - while attempts > 0 and ret != 0: - attempts -= 1 - ret = subprocess.call([ADB] + args, stdout=out, stderr=subprocess.STDOUT) - if attempts != 0: - ret = 5 - if ret != 0: - print "adb command failed", args - print tmpname - out.close() - out = open(tmpname, 'r') - print out.read() - out.close() - os.unlink(tmpname) - return ret - -def pull_from_device(path): - tmp = tempfile.mktemp() - adb(['pull', path, tmp], 5) - text = open(tmp, 'r').read() - os.unlink(tmp) - return text - -def push_to_device(path): - dst_path = os.path.join(ANDROID_TMPDIR, os.path.basename(path)) - adb(['push', path, dst_path], 5) diff --git a/test/asan/android_commands/android_compile.py b/test/asan/android_commands/android_compile.py deleted file mode 100755 index 4b880886b..000000000 --- a/test/asan/android_commands/android_compile.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python - -import os, sys, subprocess -from android_common import * - - -here = os.path.abspath(os.path.dirname(sys.argv[0])) -android_run = os.path.join(here, 'android_run.py') - -output = None -output_type = 'executable' - -args = sys.argv[1:] -while args: - arg = args.pop(0) - if arg == '-shared': - output_type = 'shared' - elif arg == '-c': - output_type = 'object' - elif arg == '-o': - output = args.pop(0) - -if output == None: - print "No output file name!" - sys.exit(1) - -ret = subprocess.call(sys.argv[1:]) -if ret != 0: - sys.exit(ret) - -if output_type in ['executable', 'shared']: - push_to_device(output) - -if output_type == 'executable': - os.rename(output, output + '.real') - os.symlink(android_run, output) diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py deleted file mode 100755 index 7e599453d..000000000 --- a/test/asan/android_commands/android_run.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python - -import os, signal, sys, subprocess, tempfile -from android_common import * - -ANDROID_TMPDIR = '/data/local/tmp/Output' - -here = os.path.abspath(os.path.dirname(sys.argv[0])) -device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) - -def build_env(): - args = [] - # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. - args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) - for (key, value) in os.environ.items(): - if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: - args.append('%s="%s"' % (key, value)) - return ' '.join(args) - -is_64bit = (subprocess.check_output(['file', sys.argv[0] + '.real']).find('64-bit') != -1) - -device_env = build_env() -device_args = ' '.join(sys.argv[1:]) # FIXME: escape? -device_stdout = device_binary + '.stdout' -device_stderr = device_binary + '.stderr' -device_exitcode = device_binary + '.exitcode' -ret = adb(['shell', 'cd %s && %s %s %s >%s 2>%s ; echo $? >%s' % - (ANDROID_TMPDIR, device_env, device_binary, device_args, - device_stdout, device_stderr, device_exitcode)]) -if ret != 0: - sys.exit(ret) - -sys.stdout.write(pull_from_device(device_stdout)) -sys.stderr.write(pull_from_device(device_stderr)) -retcode = int(pull_from_device(device_exitcode)) -# If the device process died with a signal, do abort(). -# Not exactly the same, but good enough to fool "not --crash". -if retcode > 128: - os.kill(os.getpid(), signal.SIGABRT) -sys.exit(retcode) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 1edefe9d7..213693e6f 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -71,11 +71,6 @@ if config.compiler_id == 'GNU': else: extra_link_flags = [] -# BFD linker in 64-bit android toolchains fails to find libm.so, which is a -# transitive shared library dependency (via asan runtime). -if config.android: - extra_link_flags += ["-lm"] - # Setup default compiler flags used with -fsanitize=address option. # FIXME: Review the set of required flags and check if it can be reduced. target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags @@ -110,12 +105,6 @@ if platform.system() == 'Windows': win_runtime_feature = "win32-static-asan" config.available_features.add(win_runtime_feature) -asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir") -if config.android == "1": - config.available_features.add('android') - compile_wrapper = os.path.join(asan_lit_source_dir, "android_commands", "android_compile.py") + " " - config.compile_wrapper = compile_wrapper - def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " @@ -178,7 +167,7 @@ python_exec = get_required_attr(config, "python_executable") config.substitutions.append( ("%sancov ", python_exec + " " + sancov + " ") ) # Determine kernel bitness -if config.host_arch.find('64') != -1 and config.android != "1": +if config.host_arch.find('64') != -1 and not config.android: kernel_bits = '64' else: kernel_bits = '32' diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in index 100592db2..6c8f882bc 100644 --- a/test/asan/lit.site.cfg.in +++ b/test/asan/lit.site.cfg.in @@ -2,11 +2,9 @@ # Tool-specific config options. config.name_suffix = "@ASAN_TEST_CONFIG_SUFFIX@" -config.asan_lit_source_dir = "@ASAN_LIT_SOURCE_DIR@" config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@" config.clang = "@ASAN_TEST_TARGET_CC@" config.bits = "@ASAN_TEST_BITS@" -config.android = "@ANDROID@" config.ios = @ASAN_TEST_IOS_PYBOOL@ config.iossim = @ASAN_TEST_IOSSIM_PYBOOL@ config.asan_dynamic = @ASAN_TEST_DYNAMIC@ diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 6c07ca661..5667e12a2 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -52,6 +52,11 @@ else: # Add compiler ID to the list of available features. config.available_features.add(compiler_id) +# BFD linker in 64-bit android toolchains fails to find libm.so, which is a +# transitive shared library dependency (via asan runtime). +if config.android: + config.target_cflags += " -lm" + # Clear some environment variables that might affect Clang. possibly_dangerous_env_vars = ['ASAN_OPTIONS', 'DFSAN_OPTIONS', 'LSAN_OPTIONS', 'MSAN_OPTIONS', 'UBSAN_OPTIONS', @@ -99,7 +104,6 @@ if config.emulator: config.compile_wrapper = "" elif config.ios: config.available_features.add('ios') - device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER" if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env] ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands") @@ -109,6 +113,12 @@ elif config.ios: config.substitutions.append(('%env ', env_wrapper + " ")) compile_wrapper = os.path.join(ios_commands_dir, "iossim_compile.py" if config.iossim else "ios_compile.py") config.compile_wrapper = compile_wrapper +elif config.android: + config.available_features.add('android') + compile_wrapper = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "android_commands", "android_compile.py") + " " + config.compile_wrapper = compile_wrapper + config.substitutions.append( ('%run', "") ) + config.substitutions.append( ('%env ', "env ") ) else: config.substitutions.append( ('%run', "") ) config.substitutions.append( ('%env ', "env ") ) diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index dc3081d6a..b49e8eb9a 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -32,6 +32,7 @@ set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) set_default("use_lld", False) set_default("use_thinlto", False) +set_default("android", @ANDROID_PYBOOL@) config.available_features.add('target-is-%s' % config.target_arch) # LLVM tools dir can be passed in lit parameters, so try to diff --git a/test/sanitizer_common/android_commands/android_common.py b/test/sanitizer_common/android_commands/android_common.py new file mode 100644 index 000000000..41994bb87 --- /dev/null +++ b/test/sanitizer_common/android_commands/android_common.py @@ -0,0 +1,41 @@ +import os, subprocess, tempfile +import time + +ANDROID_TMPDIR = '/data/local/tmp/Output' +ADB = os.environ.get('ADB', 'adb') + +verbose = False +if os.environ.get('ANDROID_RUN_VERBOSE') == '1': + verbose = True + +def adb(args, attempts = 1): + if verbose: + print args + tmpname = tempfile.mktemp() + out = open(tmpname, 'w') + ret = 255 + while attempts > 0 and ret != 0: + attempts -= 1 + ret = subprocess.call([ADB] + args, stdout=out, stderr=subprocess.STDOUT) + if attempts != 0: + ret = 5 + if ret != 0: + print "adb command failed", args + print tmpname + out.close() + out = open(tmpname, 'r') + print out.read() + out.close() + os.unlink(tmpname) + return ret + +def pull_from_device(path): + tmp = tempfile.mktemp() + adb(['pull', path, tmp], 5) + text = open(tmp, 'r').read() + os.unlink(tmp) + return text + +def push_to_device(path): + dst_path = os.path.join(ANDROID_TMPDIR, os.path.basename(path)) + adb(['push', path, dst_path], 5) diff --git a/test/sanitizer_common/android_commands/android_compile.py b/test/sanitizer_common/android_commands/android_compile.py new file mode 100755 index 000000000..4b880886b --- /dev/null +++ b/test/sanitizer_common/android_commands/android_compile.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +import os, sys, subprocess +from android_common import * + + +here = os.path.abspath(os.path.dirname(sys.argv[0])) +android_run = os.path.join(here, 'android_run.py') + +output = None +output_type = 'executable' + +args = sys.argv[1:] +while args: + arg = args.pop(0) + if arg == '-shared': + output_type = 'shared' + elif arg == '-c': + output_type = 'object' + elif arg == '-o': + output = args.pop(0) + +if output == None: + print "No output file name!" + sys.exit(1) + +ret = subprocess.call(sys.argv[1:]) +if ret != 0: + sys.exit(ret) + +if output_type in ['executable', 'shared']: + push_to_device(output) + +if output_type == 'executable': + os.rename(output, output + '.real') + os.symlink(android_run, output) diff --git a/test/sanitizer_common/android_commands/android_run.py b/test/sanitizer_common/android_commands/android_run.py new file mode 100755 index 000000000..7e599453d --- /dev/null +++ b/test/sanitizer_common/android_commands/android_run.py @@ -0,0 +1,40 @@ +#!/usr/bin/python + +import os, signal, sys, subprocess, tempfile +from android_common import * + +ANDROID_TMPDIR = '/data/local/tmp/Output' + +here = os.path.abspath(os.path.dirname(sys.argv[0])) +device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) + +def build_env(): + args = [] + # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. + args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) + for (key, value) in os.environ.items(): + if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: + args.append('%s="%s"' % (key, value)) + return ' '.join(args) + +is_64bit = (subprocess.check_output(['file', sys.argv[0] + '.real']).find('64-bit') != -1) + +device_env = build_env() +device_args = ' '.join(sys.argv[1:]) # FIXME: escape? +device_stdout = device_binary + '.stdout' +device_stderr = device_binary + '.stderr' +device_exitcode = device_binary + '.exitcode' +ret = adb(['shell', 'cd %s && %s %s %s >%s 2>%s ; echo $? >%s' % + (ANDROID_TMPDIR, device_env, device_binary, device_args, + device_stdout, device_stderr, device_exitcode)]) +if ret != 0: + sys.exit(ret) + +sys.stdout.write(pull_from_device(device_stdout)) +sys.stderr.write(pull_from_device(device_stderr)) +retcode = int(pull_from_device(device_exitcode)) +# If the device process died with a signal, do abort(). +# Not exactly the same, but good enough to fool "not --crash". +if retcode > 128: + os.kill(os.getpid(), signal.SIGABRT) +sys.exit(retcode) -- cgit v1.2.1 From d27254a74648ddf9204624021cd3d4542d46f0df Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 05:14:05 +0000 Subject: [sanitizer] Support check-asan on Android This patch enabled asan tests from sanitizer_common. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313444 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/abort_on_error.cc | 1 + test/sanitizer_common/CMakeLists.txt | 9 ++++++--- test/sanitizer_common/TestCases/Linux/abort_on_error.cc | 3 +++ test/sanitizer_common/TestCases/Linux/iconv_test.c | 3 +++ test/sanitizer_common/TestCases/Linux/ptrace.cc | 2 ++ .../TestCases/Linux/sysconf_interceptor_bypass_test.cc | 2 ++ test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc | 4 +++- test/sanitizer_common/TestCases/options-include.cc | 2 ++ test/sanitizer_common/TestCases/print-stack-trace.cc | 6 +++--- test/sanitizer_common/lit.common.cfg | 8 +++++++- 10 files changed, 32 insertions(+), 8 deletions(-) diff --git a/test/asan/TestCases/Linux/abort_on_error.cc b/test/asan/TestCases/Linux/abort_on_error.cc index 3f70613e4..3fe98995f 100644 --- a/test/asan/TestCases/Linux/abort_on_error.cc +++ b/test/asan/TestCases/Linux/abort_on_error.cc @@ -9,6 +9,7 @@ // lit doesn't set ASAN_OPTIONS anyway. // RUN: not %run %t 2>&1 | FileCheck %s +// Android runs with abort_on_error=0 // UNSUPPORTED: android #include diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index 2a3d7a038..8b210a08a 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -4,7 +4,7 @@ set(SANITIZER_COMMON_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) set(SANITIZER_COMMON_TESTSUITES) set(SUPPORTED_TOOLS) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD" AND NOT ANDROID) +if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD") list(APPEND SUPPORTED_TOOLS asan) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID) @@ -43,8 +43,11 @@ if(COMPILER_RT_INCLUDE_TESTS) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) - list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) - list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests) + # FIXME: support unit test in the android test runner + if (NOT ANDROID) + list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) + list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests) + endif() endif() if(SANITIZER_COMMON_TESTSUITES) diff --git a/test/sanitizer_common/TestCases/Linux/abort_on_error.cc b/test/sanitizer_common/TestCases/Linux/abort_on_error.cc index a5ef66536..e4b246e35 100644 --- a/test/sanitizer_common/TestCases/Linux/abort_on_error.cc +++ b/test/sanitizer_common/TestCases/Linux/abort_on_error.cc @@ -10,6 +10,9 @@ // lit doesn't set options anyway. // RUN: not %run %t 2>&1 +// Android needs abort_on_error=0 +// UNSUPPORTED: android + namespace __sanitizer { void Die(); } diff --git a/test/sanitizer_common/TestCases/Linux/iconv_test.c b/test/sanitizer_common/TestCases/Linux/iconv_test.c index 08da34d89..eb995d21c 100644 --- a/test/sanitizer_common/TestCases/Linux/iconv_test.c +++ b/test/sanitizer_common/TestCases/Linux/iconv_test.c @@ -1,6 +1,9 @@ // RUN: %clang %s -o %t && %run %t // Verify that even if iconv returned -1 // we still treat the initialized part of outbuf as properly initialized. + +// UNSUPPORTED: android + #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/ptrace.cc b/test/sanitizer_common/TestCases/Linux/ptrace.cc index b10aecd35..82532c35f 100644 --- a/test/sanitizer_common/TestCases/Linux/ptrace.cc +++ b/test/sanitizer_common/TestCases/Linux/ptrace.cc @@ -1,5 +1,7 @@ // RUN: %clangxx -O0 %s -o %t && %run %t +// UNSUPPORTED: android + #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc index eb4deace0..c3a656022 100644 --- a/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc +++ b/test/sanitizer_common/TestCases/Linux/sysconf_interceptor_bypass_test.cc @@ -1,5 +1,7 @@ // RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// XFAIL: android + #include // getauxval() used instead of sysconf() in GetPageSize() is defined starting diff --git a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc index f5a18e672..69ccb7234 100644 --- a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc +++ b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc @@ -1,8 +1,10 @@ // RUN: %clangxx -DSHARED %s -shared -o %T/get_module_and_offset_for_pc.so -fPIC // RUN: %clangxx -DSO_DIR=\"%T\" -O0 %s -ldl -o %t // RUN: %run %t 2>&1 | FileCheck %s + // UNSUPPORTED: i386-darwin -// +// XFAIL: android + // Tests __sanitizer_get_module_and_offset_for_pc. #include diff --git a/test/sanitizer_common/TestCases/options-include.cc b/test/sanitizer_common/TestCases/options-include.cc index 5b0b6d525..3d9127b7f 100644 --- a/test/sanitizer_common/TestCases/options-include.cc +++ b/test/sanitizer_common/TestCases/options-include.cc @@ -34,6 +34,8 @@ // RUN: %env_tool_opts=include_if_exists='"%t.options-not-found.%b"' %run %t 2>&1 | tee %t.out // RUN: FileCheck %s --check-prefix=CHECK-WITHOUT-HELP --check-prefix=CHECK-FOUND < %t.out +// Android tests run on remote device so includes will not work. +// UNSUPPORTED: android #include diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc index a6eca0b75..fce850366 100644 --- a/test/sanitizer_common/TestCases/print-stack-trace.cc +++ b/test/sanitizer_common/TestCases/print-stack-trace.cc @@ -1,6 +1,6 @@ // RUN: %clangxx -O0 %s -o %t && %env_tool_opts=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s // RUN: %clangxx -O3 %s -o %t && %env_tool_opts=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s -// RUN: %env_tool_opts=stack_trace_format='"frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM +// RUN: %env_tool_opts=stack_trace_format=frame%n_lineno%l %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM // RUN: %env_tool_opts=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE // UNSUPPORTED: darwin @@ -19,8 +19,8 @@ int main() { // CHECK: {{ #1 0x.* in FooBarBaz(\(\))? .*}}print-stack-trace.cc:[[@LINE-8]] // CHECK: {{ #2 0x.* in main.*}}print-stack-trace.cc:[[@LINE-5]] -// CUSTOM: frame:1 lineno:[[@LINE-11]] -// CUSTOM: frame:2 lineno:[[@LINE-8]] +// CUSTOM: frame1_lineno[[@LINE-11]] +// CUSTOM: frame2_lineno[[@LINE-8]] // NOINLINE: #0 0x{{.*}} in __sanitizer_print_stack_trace // NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:[[@LINE-15]] diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index 7e3e66011..be9a5c4a1 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -36,6 +36,12 @@ if config.host_os == 'Darwin': # On Darwin, we default to `abort_on_error=1`, which would make tests run # much slower. Let's override this and run lit tests with 'abort_on_error=0'. default_tool_options += ['abort_on_error=0'] +elif config.android: + # The same as on Darwin, we default to "abort_on_error=1" which slows down + # testing. Also, all existing tests are using "not" instead of "not --crash" + # which does not work for abort()-terminated programs. + default_tool_options += ['abort_on_error=0'] + default_tool_options_str = ':'.join(default_tool_options) if default_tool_options_str: config.environment[tool_options] = default_tool_options_str @@ -45,7 +51,7 @@ clang_cflags = config.debug_info_flags + tool_cflags + [config.target_cflags] clang_cxxflags = config.cxx_mode_flags + clang_cflags def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) -- cgit v1.2.1 From 384eeea2d58c5c0140506b1f79c7cd5cbc71dcd1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 07:08:23 +0000 Subject: [sanitizer] Disable sanitizer test which already fails on Android i386 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313447 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc | 3 +++ test/sanitizer_common/TestCases/Posix/getpass.cc | 3 +++ .../TestCases/Posix/sanitizer_set_report_fd_test.cc | 1 + test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 5 +++-- .../TestCases/sanitizer_coverage_trace_pc_guard-dso.cc | 5 +++-- .../TestCases/sanitizer_coverage_trace_pc_guard.cc | 9 ++++----- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc index 88275755f..27b62f7d0 100644 --- a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc +++ b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc @@ -1,6 +1,9 @@ // RUN: %clangxx -g %s -o %t // RUN: %env_tool_opts=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%tool_name + // REQUIRES: stable-runtime +// XFAIL: android && i386 && asan + #include #include #include diff --git a/test/sanitizer_common/TestCases/Posix/getpass.cc b/test/sanitizer_common/TestCases/Posix/getpass.cc index 251f9119d..fc2d05d74 100644 --- a/test/sanitizer_common/TestCases/Posix/getpass.cc +++ b/test/sanitizer_common/TestCases/Posix/getpass.cc @@ -1,5 +1,8 @@ // RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t | FileCheck %s + // REQUIRES: stable-runtime +// XFAIL: android && i386 && asan + #include #include #include diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index 5c5d3fb4b..0fbbb5f22 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -5,6 +5,7 @@ // RUN: not %run %t %t-out && FileCheck < %t-out %s // REQUIRES: stable-runtime +// XFAIL: android && i386 && asan // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan // XFAIL: lsan diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 5e3825d06..623813bac 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -1,9 +1,10 @@ // Tests -fsanitize-coverage=no-prune -// + // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin // XFAIL: ubsan,tsan -// +// XFAIL: android && i386 && asan + // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 4 diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc index e2934964d..a7f71efc2 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -1,9 +1,10 @@ // Tests trace pc guard coverage collection. -// + // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan // XFAIL: tsan,darwin,powerpc64,s390x,mips -// +// XFAIL: android && i386 && asan + // RUN: DIR=%t_workdir // RUN: CLANG_ARGS="-O0 -fsanitize-coverage=trace-pc-guard" // RUN: rm -rf $DIR diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc index 5740f2694..1c9389112 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -1,9 +1,10 @@ // Tests trace pc guard coverage collection. -// + // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan,i386-darwin // XFAIL: tsan,powerpc64,s390x,mips -// +// XFAIL: android && i386 && asan + // RUN: DIR=%t_workdir // RUN: rm -rf $DIR // RUN: mkdir -p $DIR @@ -15,9 +16,7 @@ // RUN: %env_tool_opts=coverage=0 %t 2>&1 | FileCheck --check-prefix=CHECK-NOCOV %s // RUN: rm -rf $DIR // Make some room to stabilize line numbers -// -// -// + #include int foo() { -- cgit v1.2.1 From 6ec8636dcb2924d52dbf6d804e7b4dd8628be9f4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 07:16:29 +0000 Subject: [sanitizer] Move signal interceptors from asan to sanitizer_common Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D37889 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313449 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_interceptors.cc | 48 ++-------------- lib/asan/asan_interceptors.h | 6 -- .../sanitizer_platform_interceptors.h | 2 + .../sanitizer_signal_interceptors.inc | 67 ++++++++++++++++++++++ 4 files changed, 73 insertions(+), 50 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_signal_interceptors.inc diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index b43f12948..cb7dcb3b1 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -161,6 +161,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) } while (false) #include "sanitizer_common/sanitizer_common_interceptors.inc" +#include "sanitizer_common/sanitizer_signal_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions // for them. @@ -242,42 +243,6 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) { DEFINE_REAL_PTHREAD_FUNCTIONS #endif // ASAN_INTERCEPT_PTHREAD_CREATE -#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION - -#if SANITIZER_ANDROID -INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { - if (GetHandleSignalMode(signum) != kHandleSignalExclusive) - return REAL(bsd_signal)(signum, handler); - return 0; -} -#endif - -INTERCEPTOR(void*, signal, int signum, void *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 (GetHandleSignalMode(signum) != kHandleSignalExclusive) - return REAL(sigaction)(signum, act, oldact); - return 0; -} - -namespace __sanitizer { -int real_sigaction(int signum, const void *act, void *oldact) { - return REAL(sigaction)(signum, (const struct sigaction *)act, - (struct sigaction *)oldact); -} -} // namespace __sanitizer - -#elif SANITIZER_POSIX -// We need to have defined REAL(sigaction) on posix systems. -DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act, - struct sigaction *oldact) -#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION - #if ASAN_INTERCEPT_SWAPCONTEXT static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { // Align to page size. @@ -590,6 +555,7 @@ void InitializeAsanInterceptors() { CHECK(!was_called_once); was_called_once = true; InitializeCommonInterceptors(); + InitializeSignalInterceptors(); // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT @@ -612,15 +578,9 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strtoll); #endif - // Intecept signal- and jump-related functions. + // Intecept jump-related functions. ASAN_INTERCEPT_FUNC(longjmp); -#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION - ASAN_INTERCEPT_FUNC(sigaction); -#if SANITIZER_ANDROID - ASAN_INTERCEPT_FUNC(bsd_signal); -#endif - ASAN_INTERCEPT_FUNC(signal); -#endif + #if ASAN_INTERCEPT_SWAPCONTEXT ASAN_INTERCEPT_FUNC(swapcontext); #endif diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 1422b159d..7728b356a 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -67,12 +67,6 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_SWAPCONTEXT 0 #endif -#if !SANITIZER_WINDOWS -# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1 -#else -# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0 -#endif - #if !SANITIZER_WINDOWS # define ASAN_INTERCEPT_SIGLONGJMP 1 #else diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 5d6ea6a66..854ab691e 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -389,5 +389,7 @@ #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX +#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SANITIZER_WINDOWS) +#define SANITIZER_INTERCEPT_BSD_SIGNAL SANITIZER_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/lib/sanitizer_common/sanitizer_signal_interceptors.inc new file mode 100644 index 000000000..f38e1b96e --- /dev/null +++ b/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -0,0 +1,67 @@ +//===-- sanitizer_signal_interceptors.inc -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Signal interceptors for sanitizers. +// +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_interceptors.h" + +using namespace __sanitizer; + +#if SANITIZER_INTERCEPT_BSD_SIGNAL +INTERCEPTOR(void *, bsd_signal, int signum, void *handler) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + return REAL(bsd_signal)(signum, handler); +} +#define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) +#else // SANITIZER_INTERCEPT_BSD_SIGNAL +#define INIT_BSD_SIGNAL +#endif // SANITIZER_INTERCEPT_BSD_SIGNAL + +#if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION +INTERCEPTOR(void *, signal, int signum, void *handler) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return nullptr; + return REAL(signal)(signum, handler); +} +#define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) + +INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, + struct sigaction *oldact) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + return REAL(sigaction)(signum, act, oldact); +} +#define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction) + +namespace __sanitizer { +int real_sigaction(int signum, const void *act, void *oldact) { + return REAL(sigaction)(signum, (const struct sigaction *)act, + (struct sigaction *)oldact); +} +} // namespace __sanitizer +#else // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION +#define INIT_SIGNAL +#define INIT_SIGACTION +// We need to have defined REAL(sigaction) on other systems. +DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act, + struct sigaction *oldact) +#endif // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION + +static void InitializeSignalInterceptors() { + static bool was_called_once; + CHECK(!was_called_once); + was_called_once = true; + + INIT_BSD_SIGNAL; + INIT_SIGNAL; + INIT_SIGACTION; +} -- cgit v1.2.1 From e7f4e4a3486317ee6287dc272427e0ae009f5362 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 16 Sep 2017 07:56:06 +0000 Subject: [sanitizer] Fix check for i386 Android in lit tests git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313452 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc | 2 +- test/sanitizer_common/TestCases/Posix/getpass.cc | 2 +- test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc | 2 +- test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- .../sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc | 2 +- test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc index 27b62f7d0..a690193bd 100644 --- a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc +++ b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc @@ -2,7 +2,7 @@ // RUN: %env_tool_opts=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%tool_name // REQUIRES: stable-runtime -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/getpass.cc b/test/sanitizer_common/TestCases/Posix/getpass.cc index fc2d05d74..59919a1ae 100644 --- a/test/sanitizer_common/TestCases/Posix/getpass.cc +++ b/test/sanitizer_common/TestCases/Posix/getpass.cc @@ -1,7 +1,7 @@ // RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t | FileCheck %s // REQUIRES: stable-runtime -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index 0fbbb5f22..f619b2205 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -5,7 +5,7 @@ // RUN: not %run %t %t-out && FileCheck < %t-out %s // REQUIRES: stable-runtime -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan // XFAIL: lsan diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index 623813bac..b90c93fb3 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin // XFAIL: ubsan,tsan -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc index a7f71efc2..db1d94e82 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan // XFAIL: tsan,darwin,powerpc64,s390x,mips -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan // RUN: DIR=%t_workdir // RUN: CLANG_ARGS="-O0 -fsanitize-coverage=trace-pc-guard" diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc index 1c9389112..cfcb242ca 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan,i386-darwin // XFAIL: tsan,powerpc64,s390x,mips -// XFAIL: android && i386 && asan +// XFAIL: android && i386-target-arch && asan // RUN: DIR=%t_workdir // RUN: rm -rf $DIR -- cgit v1.2.1 From 4c69a6571bb1d476ef27b949b46e9700011fb3fb Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sun, 17 Sep 2017 09:38:55 +0000 Subject: [compiler-rt] Fix build break after r313277 on s390x Commit r313277 moved IsStackOverflow to inside the SignalContext class, but didn't update a code block in #ifdef s390x accordingly. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313480 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index b4d0ce5bf..309fe1df6 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -223,7 +223,7 @@ bool SignalContext::IsStackOverflow() const { // On s390, the fault address in siginfo points to start of the page, not // to the precise word that was accessed. Mask off the low bits of sp to // take it into account. - bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sp + 0xFFFF; + bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF; #else bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF; #endif -- cgit v1.2.1 From 502737ef91f185a9b789a064369543a34b380b65 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Sun, 17 Sep 2017 20:00:43 +0000 Subject: Mark various failing tests with "UNSUPPORTED: ios". git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313498 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Darwin/abort_on_error.cc | 2 ++ test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc | 2 ++ test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc | 2 ++ test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc | 2 ++ test/asan/TestCases/Posix/deep_call_stack.cc | 3 +++ test/asan/TestCases/Posix/handle_abort_on_error.cc | 2 ++ test/asan/TestCases/Posix/new_array_cookie_test.cc | 3 +++ test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc | 3 +++ test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc | 3 +++ test/asan/TestCases/Posix/stack-overflow.cc | 2 ++ test/asan/TestCases/heavy_uar_test.cc | 2 ++ 11 files changed, 26 insertions(+) diff --git a/test/asan/TestCases/Darwin/abort_on_error.cc b/test/asan/TestCases/Darwin/abort_on_error.cc index 295afb844..0aa123414 100644 --- a/test/asan/TestCases/Darwin/abort_on_error.cc +++ b/test/asan/TestCases/Darwin/abort_on_error.cc @@ -8,6 +8,8 @@ // When we use lit's default ASAN_OPTIONS, we shouldn't crash. // RUN: not %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: ios + #include int main() { char *x = (char*)malloc(10 * sizeof(char)); diff --git a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc index cd277a05b..bee23f25c 100644 --- a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc +++ b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc @@ -10,6 +10,8 @@ // RUN: %env DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ // RUN: %run %t 2>&1 | FileCheck %s || exit 1 +// UNSUPPORTED: ios + #if !defined(SHARED_LIB) #include #include diff --git a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc index 966b46958..38fb3aa55 100644 --- a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc +++ b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc @@ -13,6 +13,8 @@ // RUN: %env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \ // RUN: %run %t %t-echo-env 2>&1 | FileCheck %s || exit 1 +// UNSUPPORTED: ios + #if !defined(SHARED_LIB) #include int main(int argc, char *argv[]) { diff --git a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc index 2c4c133b7..11d5928a8 100644 --- a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc +++ b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc @@ -9,6 +9,8 @@ // RUN: %env_asan_opts=symbolize=0 not %run %t 2>&1 | %asan_symbolize | FileCheck %s // REQUIRES: stable-runtime +// UNSUPPORTED: ios + #if !defined(SHARED_LIB) #include #include diff --git a/test/asan/TestCases/Posix/deep_call_stack.cc b/test/asan/TestCases/Posix/deep_call_stack.cc index 2d2b056d6..e6e82a475 100644 --- a/test/asan/TestCases/Posix/deep_call_stack.cc +++ b/test/asan/TestCases/Posix/deep_call_stack.cc @@ -5,6 +5,9 @@ // Also check that use_sigaltstack+verbosity doesn't crash. // RUN: %env_asan_opts=verbosity=1:use_sigaltstack=1:detect_stack_use_after_return=1 %run %t | FileCheck %s + +// UNSUPPORTED: ios + #include __attribute__((noinline)) diff --git a/test/asan/TestCases/Posix/handle_abort_on_error.cc b/test/asan/TestCases/Posix/handle_abort_on_error.cc index fa8cdd4ce..1be060e06 100644 --- a/test/asan/TestCases/Posix/handle_abort_on_error.cc +++ b/test/asan/TestCases/Posix/handle_abort_on_error.cc @@ -1,6 +1,8 @@ // Regression test: this used to abort() in SIGABRT handler in an infinite loop. // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_abort=1,abort_on_error=1 not --crash %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: ios + #include int main() { diff --git a/test/asan/TestCases/Posix/new_array_cookie_test.cc b/test/asan/TestCases/Posix/new_array_cookie_test.cc index dd50bf7fe..40a9b7874 100644 --- a/test/asan/TestCases/Posix/new_array_cookie_test.cc +++ b/test/asan/TestCases/Posix/new_array_cookie_test.cc @@ -3,6 +3,9 @@ // RUN: not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=poison_array_cookie=1 not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=poison_array_cookie=0 not %run %t 2>&1 | FileCheck %s --check-prefix=NO_COOKIE + +// UNSUPPORTED: ios + #include #include struct C { diff --git a/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc index f36da2b54..335a56757 100644 --- a/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc +++ b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc @@ -2,6 +2,9 @@ // RUN: %clangxx_asan -O3 %s -o %t // RUN: %env_asan_opts=poison_array_cookie=1 not %run %t 2>&1 | FileCheck %s --check-prefix=COOKIE // RUN: %env_asan_opts=poison_array_cookie=0 not %run %t 2>&1 | FileCheck %s --check-prefix=NO_COOKIE + +// UNSUPPORTED: ios + #include #include #include diff --git a/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc index 0683e391c..e7f774674 100644 --- a/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc +++ b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc @@ -3,6 +3,9 @@ // RUN: %clangxx_asan %s -o %t && %run %t // // XFAIL: arm + +// UNSUPPORTED: ios + #include #include #include diff --git a/test/asan/TestCases/Posix/stack-overflow.cc b/test/asan/TestCases/Posix/stack-overflow.cc index 8ef161862..d6b062ed3 100644 --- a/test/asan/TestCases/Posix/stack-overflow.cc +++ b/test/asan/TestCases/Posix/stack-overflow.cc @@ -16,6 +16,8 @@ // RUN: not %run %t 2>&1 | FileCheck %s // REQUIRES: stable-runtime +// UNSUPPORTED: ios + #include #include #include diff --git a/test/asan/TestCases/heavy_uar_test.cc b/test/asan/TestCases/heavy_uar_test.cc index ef61ead63..9ad29f079 100644 --- a/test/asan/TestCases/heavy_uar_test.cc +++ b/test/asan/TestCases/heavy_uar_test.cc @@ -8,6 +8,8 @@ // FIXME: Fix this test for dynamic runtime on armhf-linux. // UNSUPPORTED: armhf-linux && asan-dynamic-runtime +// UNSUPPORTED: ios + #include #include #include -- cgit v1.2.1 From 655b76e994a8605ad251fb75d27344c92adc711c Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 00:12:12 +0000 Subject: [sanitizer] Use SI_ instead of SANITIZER_ in sanitizer_platform_interceptors git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313505 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform_interceptors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 854ab691e..897aeddca 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -389,7 +389,7 @@ #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX -#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SANITIZER_WINDOWS) -#define SANITIZER_INTERCEPT_BSD_SIGNAL SANITIZER_ANDROID +#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS) +#define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H -- cgit v1.2.1 From 7c29ef848de951da429abe7438a85c678ea3e6f6 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Mon, 18 Sep 2017 06:18:03 +0000 Subject: [XRay][compiler-rt] Handle tail-call exits in the XRay runtime Summary: This change starts differentiating tail exits from normal exits. We also increase the version number of the "naive" log to version 2, which will be the starting version where these records start appearing. In FDR mode we treat the tail exits as normal exits, and are thus subject to the same treatment with regard to record unwriting. Updating the version number is important to signal older builds of the llvm-xray tool that do not deal with the tail exit records must fail early (and that users should only use the llvm-xray tool built after the support for tail exits to get accurate handling of these records). Depends on D37964. Reviewers: kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37965 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313515 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_records.h | 5 ++++- lib/xray/xray_fdr_logging_impl.h | 1 - lib/xray/xray_inmemory_log.cc | 11 ++++++++++- lib/xray/xray_trampoline_x86_64.S | 6 +----- test/xray/TestCases/Linux/fdr-mode.cc | 14 +++++++------- test/xray/TestCases/Linux/fdr-thread-order.cc | 4 ++-- 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/xray/xray_records.h b/include/xray/xray_records.h index 506755dbd..98e54cb69 100644 --- a/include/xray/xray_records.h +++ b/include/xray/xray_records.h @@ -78,7 +78,10 @@ struct alignas(32) XRayRecord { // The CPU where the thread is running. We assume number of CPUs <= 256. uint8_t CPU = 0; - // The type of the event. Usually either ENTER = 0 or EXIT = 1. + // The type of the event. One of the following: + // ENTER = 0 + // EXIT = 1 + // TAIL_EXIT = 2 uint8_t Type = 0; // The function ID for the record. diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index b2f7f3f23..0e67c7c0e 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -690,7 +690,6 @@ inline void processFunctionHook( TLD.LastFunctionEntryTSC = TSC; break; case XRayEntryType::TAIL: - break; case XRayEntryType::EXIT: // Break out and write the exit record if we can't erase any functions. if (TLD.NumConsecutiveFnEnters == 0 || diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc index 2f407e2a3..3d8ecda6f 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_inmemory_log.cc @@ -89,7 +89,7 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { // header will only be written once, at the start, and let the threads // logging do writes which just append. XRayFileHeader Header; - Header.Version = 1; + Header.Version = 2; // Version 2 includes tail exit records. Header.Type = FileTypes::NAIVE_LOG; Header.CycleFrequency = CycleFrequency; @@ -117,6 +117,13 @@ void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, Fd, reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer), Offset); thread_local pid_t TId = syscall(SYS_gettid); + // Use a simple recursion guard, to handle cases where we're already logging + // and for one reason or another, this function gets called again in the same + // thread. + thread_local volatile bool RecusionGuard = false; + if (RecusionGuard) return; + RecusionGuard = true; + // First we get the useful data, and stuff it into the already aligned buffer // through a pointer offset. auto &R = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer)[Offset]; @@ -133,6 +140,8 @@ void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, reinterpret_cast(RecordBuffer + Offset)); Offset = 0; } + + RecusionGuard = false; } void __xray_InMemoryRawLogRealTSC(int32_t FuncId, diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index 5c38c40e2..9a3bc1c1f 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -135,10 +135,6 @@ __xray_FunctionExit: .type __xray_FunctionTailExit,@function __xray_FunctionTailExit: .cfi_startproc - // Save the important registers as in the entry trampoline, but indicate that - // this is an exit. In the future, we will introduce a new entry type that - // differentiates between a normal exit and a tail exit, but we'd have to do - // this and increment the version number for the header. SAVE_REGISTERS movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax @@ -146,7 +142,7 @@ __xray_FunctionTailExit: je .Ltmp4 movl %r10d, %edi - movl $1, %esi + movl $2, %esi callq *%rax .Ltmp4: diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index f1e087673..d08a7d492 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -69,24 +69,24 @@ int main(int argc, char *argv[]) { // Check that we're able to see two threads, each entering and exiting fA(). // TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // TRACE-DAG: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // // Do the same as above for fC() // TRACE-DAG: - { type: 0, func-id: [[FIDC:[0-9]+]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // TRACE-DAG: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // Do the same as above for fB() // TRACE-DAG: - { type: 0, func-id: [[FIDB:[0-9]+]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } // Assert that when unwriting is enabled with a high threshold time, all the function records are erased. A CPU switch could erroneously fail this test, but // is unlikely given the test program. // UNWRITE: header // UNWRITE-NOT: function-enter -// UNWRITE-NOT: function-exit +// UNWRITE-NOT: function-{{exit|tail-exit}} diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index e5e5cd020..6ac2114a5 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -37,5 +37,5 @@ int main(int argc, char *argv[]) { // We want to make sure that the order of the function log doesn't matter. // TRACE-DAG: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } // TRACE-DAG: - { type: 0, func-id: [[FID2:[0-9]+]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: function-exit, tsc: {{[0-9]+}} } -// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } -- cgit v1.2.1 From fabb9da5777dcbf106a0aa2b6895bbe31521ed5b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 06:56:57 +0000 Subject: [asan] Remove ScopedDeadlySignal This is used only to make fast = true in GetStackTraceWithPcBpAndContext on SANITIZER_FREEBSD and SANITIZER_NETBSD and can be done explicitly. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313517 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 10 ++++++++-- lib/asan/asan_posix.cc | 1 - lib/asan/asan_stack.h | 6 ------ lib/asan/asan_thread.h | 19 ------------------- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index f2870d48e..d42a86850 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -25,14 +25,20 @@ namespace __asan { static void OnStackUnwind(const SignalContext &sig, const void *callback_context, BufferedStackTrace *stack) { + bool fast = common_flags()->fast_unwind_on_fatal; +#if SANITIZER_FREEBSD || SANITIZER_NETBSD + // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() + // yields the call stack of the signal's handler and not of the code + // that raised the signal (as it does on Linux). + fast = true; +#endif // Tests and maybe some users expect that scariness is going to be printed // just before the stack. As only asan has scariness score we have no // corresponding code in the sanitizer_common and we use this callback to // print it. static_cast(callback_context)->Print(); GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp, - sig.context, - common_flags()->fast_unwind_on_fatal); + sig.context, fast); } void ErrorDeadlySignal::Print() { diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 034ff58bb..38299e51c 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -34,7 +34,6 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { - ScopedDeadlySignal signal_scope(GetCurrentThread()); StartReportDeadlySignal(); SignalContext sig(siginfo, context); ReportDeadlySignal(sig); diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h index 9f7b102c6..9ee7f5c0c 100644 --- a/lib/asan/asan_stack.h +++ b/lib/asan/asan_stack.h @@ -41,12 +41,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, stack->size = 0; if (LIKELY(asan_inited)) { if ((t = GetCurrentThread()) && !t->isUnwinding()) { - // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() - // yields the call stack of the signal's handler and not of the code - // that raised the signal (as it does on Linux). -#if SANITIZER_FREEBSD || SANITIZER_NETBSD - if (t->isInDeadlySignal()) fast = true; -#endif uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index d34942492..1cd283a59 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -125,10 +125,6 @@ class AsanThread { bool isUnwinding() const { return unwinding_; } void setUnwinding(bool b) { unwinding_ = b; } - // True if we are in a deadly signal handler. - bool isInDeadlySignal() const { return in_deadly_signal_; } - void setInDeadlySignal(bool b) { in_deadly_signal_ = b; } - AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } @@ -167,7 +163,6 @@ class AsanThread { AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; bool unwinding_; - bool in_deadly_signal_; }; // ScopedUnwinding is a scope for stacktracing member of a context @@ -182,20 +177,6 @@ class ScopedUnwinding { AsanThread *thread; }; -// ScopedDeadlySignal is a scope for handling deadly signals. -class ScopedDeadlySignal { - public: - explicit ScopedDeadlySignal(AsanThread *t) : thread(t) { - if (thread) thread->setInDeadlySignal(true); - } - ~ScopedDeadlySignal() { - if (thread) thread->setInDeadlySignal(false); - } - - private: - AsanThread *thread; -}; - // Returns a single instance of registry. ThreadRegistry &asanThreadRegistry(); -- cgit v1.2.1 From 0af7953049526b89f4c202951afcc5796257645b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 07:36:32 +0000 Subject: [sanitizer] Move StartReportDeadlySignal into sanitizer_common_libcdep git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313518 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_libcdep.cc | 8 ++++++++ lib/sanitizer_common/sanitizer_posix_libcdep.cc | 8 -------- lib/sanitizer_common/sanitizer_win.cc | 4 ---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 4f26a2227..d96890ff5 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -148,6 +148,14 @@ void BackgroundThread(void *arg) { #endif #if !SANITIZER_GO +void StartReportDeadlySignal() { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + static void MaybeReportNonExecRegion(uptr pc) { #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD MemoryMappingLayout proc_maps(/*cache_enabled*/ true); diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 309fe1df6..4214d91c5 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -261,14 +261,6 @@ bool SignalContext::IsStackOverflow() const { (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); } -void StartReportDeadlySignal() { - // Write the first message using fd=2, just in case. - // It may actually fail to write in case stderr is closed. - internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); - static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; - internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); -} - #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 5a78b64c6..4d68f5610 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -858,10 +858,6 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // FIXME: Decide what to do on Windows. } -void StartReportDeadlySignal() { - // FIXME: Decide what to do on Windows. -} - HandleSignalMode GetHandleSignalMode(int signum) { // FIXME: Decide what to do on Windows. return kHandleSignalNo; -- cgit v1.2.1 From 7d99e86de41f90564aae1ef0fd588d8f8e290c2f Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 08:04:03 +0000 Subject: [ubsan] Add RTUbsan_standalone into UBSAN standalone shared Same as for Apple. This also fixes flags related tests on Android as without this flags are not initialized. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313519 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index a29c0eed9..e67f5dfe5 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -160,6 +160,7 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan + RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} -- cgit v1.2.1 From 5de033a80d0b6343cd648ff41cddd26b673c19c4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 08:15:00 +0000 Subject: Revert "[ubsan] Add RTUbsan_standalone into UBSAN standalone shared" Error: .preinit_array section is not allowed in DSO This reverts commit r313519. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313520 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index e67f5dfe5..a29c0eed9 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -160,7 +160,6 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan - RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} -- cgit v1.2.1 From f951abe9908d2034b99e579e8b88afab5b7a7d24 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 18 Sep 2017 15:40:53 +0000 Subject: [scudo] Android build support Summary: Mark Android as supported in the cmake configuration for Scudo. Scudo is not added yet in the Android build bots, but code builds and tests pass locally. It is for a later CL. I also checked that Scudo builds as part of the Android toolchain. A few modifications had to be made: - Android defaults to `abort_on_error=1`, which doesn't work well with the current tests. So change the default way to pass `SCUDO_OPTIONS` to the tests to account for this, setting it to 0 by default; - Disable the `valloc.cpp` & `random_shuffle.cpp` tests on Android; - There is a bit of gymnatic to be done with the `SCUDO_TEST_TARGET_ARCH` string, due to android using the `-android` suffix, and `i686` instead of `i386`; - Android doesn't need `-lrt`. Reviewers: alekseyshl, eugenis Reviewed By: alekseyshl Subscribers: srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D37907 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313538 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/scudo/CMakeLists.txt | 10 +++++++++- test/scudo/lit.cfg | 21 ++++++++++++++++++--- test/scudo/lit.site.cfg.in | 1 + test/scudo/memalign.cpp | 6 +++--- test/scudo/mismatch.cpp | 16 ++++++++-------- test/scudo/options.cpp | 6 +++--- test/scudo/overflow.cpp | 4 ++-- test/scudo/quarantine.cpp | 12 ++++++------ test/scudo/random_shuffle.cpp | 1 + test/scudo/sized-delete.cpp | 12 ++++++------ test/scudo/sizes.cpp | 18 +++++++++--------- test/scudo/threads.cpp | 4 ++-- test/scudo/valloc.cpp | 7 ++++--- 14 files changed, 73 insertions(+), 47 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 5820946df..2c395c0fe 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -574,7 +574,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux") + OS_NAME MATCHES "Linux|Android") set(COMPILER_RT_HAS_SCUDO TRUE) else() set(COMPILER_RT_HAS_SCUDO FALSE) diff --git a/test/scudo/CMakeLists.txt b/test/scudo/CMakeLists.txt index a89909997..513168b18 100644 --- a/test/scudo/CMakeLists.txt +++ b/test/scudo/CMakeLists.txt @@ -15,7 +15,15 @@ configure_lit_site_cfg( set(SCUDO_TEST_ARCH ${SCUDO_SUPPORTED_ARCH}) foreach(arch ${SCUDO_TEST_ARCH}) - set(SCUDO_TEST_TARGET_ARCH ${arch}) + if(ANDROID) + if (${arch} STREQUAL "i386") + set(SCUDO_TEST_TARGET_ARCH i686-android) + else() + set(SCUDO_TEST_TARGET_ARCH ${arch}-android) + endif() + else() + set(SCUDO_TEST_TARGET_ARCH ${arch}) + endif() string(TOLOWER "-${arch}" SCUDO_TEST_CONFIG_SUFFIX) get_test_cc_for_arch(${arch} SCUDO_TEST_TARGET_CC SCUDO_TEST_TARGET_CFLAGS) string(TOUPPER ${arch} ARCH_UPPER_CASE) diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index adf16f57b..d0a4cb167 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -25,15 +25,30 @@ c_flags = ([config.target_cflags] + "-O0", "-UNDEBUG", "-ldl", - "-lrt", "-Wl,--gc-sections"]) +# Android doesn't want -lrt. +if not config.android: + c_flags += ["-lrt"] + def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " # Add clang substitutions. -config.substitutions.append( ("%clang_scudo ", - build_invocation(c_flags) + whole_archive) ) +config.substitutions.append(("%clang_scudo ", + build_invocation(c_flags) + whole_archive)) + +# Platform-specific default SCUDO_OPTIONS for lit tests. +default_scudo_opts = '' +if config.android: + # Android defaults to abort_on_error=1, which doesn't work for us. + default_scudo_opts = 'abort_on_error=0' + +if default_scudo_opts: + config.environment['SCUDO_OPTIONS'] = default_scudo_opts + default_scudo_opts += ':' +config.substitutions.append(('%env_scudo_opts=', + 'env SCUDO_OPTIONS=' + default_scudo_opts)) # Hardened Allocator tests are currently supported on Linux only. if config.host_os not in ['Linux']: diff --git a/test/scudo/lit.site.cfg.in b/test/scudo/lit.site.cfg.in index 429951875..be0d88c10 100644 --- a/test/scudo/lit.site.cfg.in +++ b/test/scudo/lit.site.cfg.in @@ -3,6 +3,7 @@ config.name_suffix = "@SCUDO_TEST_CONFIG_SUFFIX@" config.target_arch = "@SCUDO_TEST_TARGET_ARCH@" config.target_cflags = "@SCUDO_TEST_TARGET_CFLAGS@" +config.android = "@ANDROID@" # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 8757c51c7..fece04dfc 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -1,7 +1,7 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t invalid 2>&1 +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 // Tests that the various aligned allocation functions work as intended. Also // tests for the condition where the alignment is not a power of 2. diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index 0e51da4a5..538c8e6de 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -1,12 +1,12 @@ // RUN: %clang_scudo %s -o %t -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t newfree 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t memalignrealloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t memalignrealloc 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t newfree 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memalignrealloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t memalignrealloc 2>&1 // Tests that type mismatches between allocation and deallocation functions are // caught when the related option is set. diff --git a/test/scudo/options.cpp b/test/scudo/options.cpp index bb0ed2963..6464bc65b 100644 --- a/test/scudo/options.cpp +++ b/test/scudo/options.cpp @@ -1,7 +1,7 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t 2>&1 -// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s +// RUN: %run %t 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t 2>&1 +// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s // Tests that the options can be passed using getScudoDefaultOptions, and that // the environment ones take precedence over them. diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp index 82ea10fd1..c5a58f87f 100644 --- a/test/scudo/overflow.cpp +++ b/test/scudo/overflow.cpp @@ -1,6 +1,6 @@ // RUN: %clang_scudo %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s +// RUN: not %run %t malloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s // Tests that header corruption of an allocated or quarantined chunk is caught. diff --git a/test/scudo/quarantine.cpp b/test/scudo/quarantine.cpp index 89560dffd..8872fe688 100644 --- a/test/scudo/quarantine.cpp +++ b/test/scudo/quarantine.cpp @@ -1,10 +1,10 @@ // RUN: %clang_scudo %s -o %t -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 -// RUN: SCUDO_OPTIONS="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 -// RUN: SCUDO_OPTIONS=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 -// RUN: SCUDO_OPTIONS=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 +// RUN: %env_scudo_opts=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 +// RUN: %env_scudo_opts=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 // Tests that the quarantine prevents a chunk from being reused right away. // Also tests that a chunk will eventually become available again for diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index c98d431e4..da004484a 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -8,6 +8,7 @@ // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir // UNSUPPORTED: i386-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux +// UNSUPPORTED: android // Tests that the allocator shuffles the chunks before returning to the user. diff --git a/test/scudo/sized-delete.cpp b/test/scudo/sized-delete.cpp index e467f5565..9c3a2c596 100644 --- a/test/scudo/sized-delete.cpp +++ b/test/scudo/sized-delete.cpp @@ -1,10 +1,10 @@ // RUN: %clang_scudo -fsized-deallocation %s -o %t -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 %run %t gooddel 2>&1 -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=0 %run %t baddel 2>&1 -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 %run %t gooddelarr 2>&1 -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=1 not %run %t baddelarr 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=DeleteSizeMismatch=0 %run %t baddelarr 2>&1 +// RUN: %env_scudo_opts=DeleteSizeMismatch=1 %run %t gooddel 2>&1 +// RUN: %env_scudo_opts=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=DeleteSizeMismatch=0 %run %t baddel 2>&1 +// RUN: %env_scudo_opts=DeleteSizeMismatch=1 %run %t gooddelarr 2>&1 +// RUN: %env_scudo_opts=DeleteSizeMismatch=1 not %run %t baddelarr 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=DeleteSizeMismatch=0 %run %t baddelarr 2>&1 // Ensures that the sized delete operator errors out when the appropriate // option is passed and the sizes do not match between allocation and diff --git a/test/scudo/sizes.cpp b/test/scudo/sizes.cpp index a0994c251..8f147b708 100644 --- a/test/scudo/sizes.cpp +++ b/test/scudo/sizes.cpp @@ -1,13 +1,13 @@ // RUN: %clang_scudo %s -lstdc++ -o %t -// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 -// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 -// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t new-nothrow 2>&1 -// RUN: %run %t usable 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t malloc 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t calloc 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 +// RUN: %run %t usable 2>&1 // Tests for various edge cases related to sizes, notably the maximum size the // allocator can allocate. Tests that an integer overflow in the parameters of diff --git a/test/scudo/threads.cpp b/test/scudo/threads.cpp index d9f4a86c1..643eda77d 100644 --- a/test/scudo/threads.cpp +++ b/test/scudo/threads.cpp @@ -1,6 +1,6 @@ // RUN: %clang_scudo %s -o %t -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 -// RUN: SCUDO_OPTIONS="QuarantineSizeMb=1:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=1024:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 // Tests parallel allocations and deallocations of memory chunks from a number // of concurrent threads, with and without quarantine. diff --git a/test/scudo/valloc.cpp b/test/scudo/valloc.cpp index eef556f46..8764502a1 100644 --- a/test/scudo/valloc.cpp +++ b/test/scudo/valloc.cpp @@ -1,7 +1,8 @@ // RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 -// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 %run %t invalid 2>&1 +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 +// UNSUPPORTED: android // Tests that valloc and pvalloc work as intended. -- cgit v1.2.1 From 6a0bc1fdc9f713f4cc9a89866dab7d66135519a9 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 18 Sep 2017 18:13:47 +0000 Subject: [cmake] Make it possible to build and test profile without sanitizers This should fix an issue which arises when running check-compiler-rt on the coverage bot: http://green.lab.llvm.org/green/job/clang-stage2-coverage-R_build/1590/ The bot doesn't build the sanitizers, but the check-compiler-rt target always expects the profile runtime to exist. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313549 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CMakeLists.txt | 2 ++ test/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 025320f47..a92d0a3f0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -39,7 +39,9 @@ if(COMPILER_RT_BUILD_SANITIZERS) foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD}) compiler_rt_build_runtime(${sanitizer}) endforeach() +endif() +if (COMPILER_RT_HAS_PROFILE) compiler_rt_build_runtime(profile) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6bc7cdbec..e691eab7d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,7 +71,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) compiler_rt_test_runtime(${sanitizer}) endif() endforeach() - + endif() + if (COMPILER_RT_HAS_PROFILE) compiler_rt_test_runtime(profile) endif() if(COMPILER_RT_BUILD_XRAY) -- cgit v1.2.1 From 3a6c8910afe0594078e93a62d1d2aa1504d8e925 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 18:46:19 +0000 Subject: [ubsan] Fix interface_symbols_windows test Summary: 1. Update ubsan_interface.inc to make the test happy. 2. Switch interface_symbols_linux and interface_symbols_darwin to C++ to import __ubsan_handle_dynamic_type_cache_miss 3. Switch interface_symbols_windows to C++ for consistency. Reviewers: rnk, zturner Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D37986 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313551 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_interface.inc | 2 + .../TestCases/Darwin/interface_symbols_darwin.c | 37 --------------- .../TestCases/Darwin/interface_symbols_darwin.cc | 36 +++++++++++++++ .../asan/TestCases/Linux/interface_symbols_linux.c | 33 -------------- .../TestCases/Linux/interface_symbols_linux.cc | 32 +++++++++++++ .../TestCases/Windows/interface_symbols_windows.c | 52 --------------------- .../TestCases/Windows/interface_symbols_windows.cc | 53 ++++++++++++++++++++++ 7 files changed, 123 insertions(+), 122 deletions(-) delete mode 100644 test/asan/TestCases/Darwin/interface_symbols_darwin.c create mode 100644 test/asan/TestCases/Darwin/interface_symbols_darwin.cc delete mode 100644 test/asan/TestCases/Linux/interface_symbols_linux.c create mode 100644 test/asan/TestCases/Linux/interface_symbols_linux.cc delete mode 100644 test/asan/TestCases/Windows/interface_symbols_windows.c create mode 100644 test/asan/TestCases/Windows/interface_symbols_windows.cc diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index d2e5a67fa..9beb3e2ff 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -16,6 +16,8 @@ INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail) INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow) INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow_abort) +INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss) +INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow) INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch) diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c deleted file mode 100644 index 431de435f..000000000 --- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c +++ /dev/null @@ -1,37 +0,0 @@ -// Check the presence of interface symbols in the ASan runtime dylib. -// If you're changing this file, please also change -// ../Linux/interface_symbols.c - -// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe -// -// note: we can not use -D on Darwin. -// RUN: nm -g `%clang_asan %s -fsanitize=address -### 2>&1 | grep "libclang_rt.asan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ -// RUN: | grep " [TU] " \ -// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ -// RUN: | grep -v "__sanitizer_syscall" \ -// RUN: | grep -v "__sanitizer_weak_hook" \ -// RUN: | grep -v "__sanitizer_mz" \ -// RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss" \ -// RUN: | grep -v "__sancov_lowest_stack" \ -// RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ -// RUN: > %t.exports -// -// RUN: grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ -// RUN: %p/../../../../lib/asan/asan_interface.inc \ -// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface_posix.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ -// RUN: | grep -v "__sanitizer_weak_hook" \ -// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports -// -// RUN: cat %t.imports | sort | uniq > %t.imports-sorted -// RUN: cat %t.exports | sort | uniq > %t.exports-sorted -// -// RUN: echo -// RUN: echo "=== NOTE === If you see a mismatch below, please update sanitizer_interface.inc files." -// RUN: diff %t.imports-sorted %t.exports-sorted - -// UNSUPPORTED: ios - -int main() { return 0; } diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.cc b/test/asan/TestCases/Darwin/interface_symbols_darwin.cc new file mode 100644 index 000000000..a8e2bcb3e --- /dev/null +++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.cc @@ -0,0 +1,36 @@ +// Check the presence of interface symbols in the ASan runtime dylib. +// If you're changing this file, please also change +// ../Linux/interface_symbols.c + +// RUN: %clangxx_asan -dead_strip -O2 %s -o %t.exe +// +// note: we can not use -D on Darwin. +// RUN: nm -g `%clang_asan %s -fsanitize=address -### 2>&1 | grep "libclang_rt.asan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ +// RUN: | grep " [TU] " \ +// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ +// RUN: | grep -v "__sanitizer_syscall" \ +// RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | grep -v "__sanitizer_mz" \ +// RUN: | grep -v "__sancov_lowest_stack" \ +// RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ +// RUN: > %t.exports +// +// RUN: grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ +// RUN: %p/../../../../lib/asan/asan_interface.inc \ +// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface_posix.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ +// RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports +// +// RUN: cat %t.imports | sort | uniq > %t.imports-sorted +// RUN: cat %t.exports | sort | uniq > %t.exports-sorted +// +// RUN: echo +// RUN: echo "=== NOTE === If you see a mismatch below, please update sanitizer_interface.inc files." +// RUN: diff %t.imports-sorted %t.exports-sorted + +// UNSUPPORTED: ios + +int main() { return 0; } diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c deleted file mode 100644 index a8b9d37cc..000000000 --- a/test/asan/TestCases/Linux/interface_symbols_linux.c +++ /dev/null @@ -1,33 +0,0 @@ -// Check the presence of interface symbols in compiled file. - -// RUN: %clang_asan -O2 %s -o %t.exe -// RUN: nm -D %t.exe | grep " [TWw] " \ -// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ -// RUN: | grep -v "__sanitizer_syscall" \ -// RUN: | grep -v "__sanitizer_weak_hook" \ -// RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss" \ -// RUN: | grep -v "__sancov_lowest_stack" \ -// RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ -// RUN: > %t.exports -// -// RUN: grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ -// RUN: %p/../../../../lib/asan/asan_interface.inc \ -// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface_posix.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ -// RUN: | grep -v "__sanitizer_weak_hook" \ -// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports -// -// RUN: cat %t.imports | sort | uniq > %t.imports-sorted -// RUN: cat %t.exports | sort | uniq > %t.exports-sorted -// -// RUN: echo -// RUN: echo "=== NOTE === If you see a mismatch below, please update sanitizer_interface.inc files." -// RUN: diff %t.imports-sorted %t.exports-sorted -// -// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing -// in "initialized data section". -// REQUIRES: x86-target-arch,asan-static-runtime - -int main() { return 0; } diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.cc b/test/asan/TestCases/Linux/interface_symbols_linux.cc new file mode 100644 index 000000000..8c22976e7 --- /dev/null +++ b/test/asan/TestCases/Linux/interface_symbols_linux.cc @@ -0,0 +1,32 @@ +// Check the presence of interface symbols in compiled file. + +// RUN: %clangxx_asan -O2 %s -o %t.exe +// RUN: nm -D %t.exe | grep " [TWw] " \ +// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \ +// RUN: | grep -v "__sanitizer_syscall" \ +// RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | grep -v "__sancov_lowest_stack" \ +// RUN: | sed -e "s/__asan_version_mismatch_check_v[0-9]+/__asan_version_mismatch_check/" \ +// RUN: > %t.exports +// +// RUN: grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ +// RUN: %p/../../../../lib/asan/asan_interface.inc \ +// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface_posix.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ +// RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports +// +// RUN: cat %t.imports | sort | uniq > %t.imports-sorted +// RUN: cat %t.exports | sort | uniq > %t.exports-sorted +// +// RUN: echo +// RUN: echo "=== NOTE === If you see a mismatch below, please update sanitizer_interface.inc files." +// RUN: diff %t.imports-sorted %t.exports-sorted +// +// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing +// in "initialized data section". +// REQUIRES: x86-target-arch,asan-static-runtime + +int main() { return 0; } diff --git a/test/asan/TestCases/Windows/interface_symbols_windows.c b/test/asan/TestCases/Windows/interface_symbols_windows.c deleted file mode 100644 index bc2f3e883..000000000 --- a/test/asan/TestCases/Windows/interface_symbols_windows.c +++ /dev/null @@ -1,52 +0,0 @@ -// Check that the interface exported by asan static lib matches the list of -// functions mentioned in sanitizer_interface.inc. -// -// Just make sure we can compile this. -// RUN: %clang_cl_asan -O0 %s -Fe%t -// -// note: The mangling decoration (i.e. @4 )is removed because calling convention -// differ from 32-bit and 64-bit. -// -// RUN: dumpbin /EXPORTS %t | sed "s/=.*//" \ -// RUN: | grep -o "\(__asan_\|__ubsan_\|__sanitizer_\|__sancov_\)[^ ]*" \ -// RUN: | grep -v "__asan_wrap" \ -// RUN: | sed -e s/@.*// > %t.exports -// -// [BEWARE: be really careful with the sed commands, as this test can be run -// from different environemnts with different shells and seds] -// -// RUN: grep -e "INTERFACE_FUNCTION" \ -// RUN: %p/../../../../lib/asan/asan_interface.inc \ -// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ -// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports1 -// -// RUN: grep -e "INTERFACE_WEAK_FUNCTION" \ -// RUN: %p/../../../../lib/asan/asan_interface.inc \ -// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ -// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ -// RUN: | sed -e "s/.*(//" -e "s/).*/__dll/" > %t.imports2 -// -// Add functions not included in the interface lists: -// RUN: grep '[I]MPORT:' %s | sed -e 's/.*[I]MPORT: //' > %t.imports3 -// IMPORT: __asan_shadow_memory_dynamic_address -// IMPORT: __asan_get_shadow_memory_dynamic_address -// IMPORT: __asan_option_detect_stack_use_after_return -// IMPORT: __asan_should_detect_stack_use_after_return -// IMPORT: __asan_set_seh_filter -// IMPORT: __asan_unhandled_exception_filter -// IMPORT: __asan_test_only_reported_buggy_pointer -// IMPORT: __sancov_lowest_stack -// -// RUN: cat %t.imports1 %t.imports2 %t.imports3 | sort | uniq > %t.imports-sorted -// RUN: cat %t.exports | sort | uniq > %t.exports-sorted -// -// Now make sure the DLL thunk imports everything: -// RUN: echo -// RUN: echo "=== NOTE === If you see a mismatch below, please update interface.inc files." -// RUN: diff %t.imports-sorted %t.exports-sorted -// REQUIRES: asan-static-runtime - -int main() { return 0; } diff --git a/test/asan/TestCases/Windows/interface_symbols_windows.cc b/test/asan/TestCases/Windows/interface_symbols_windows.cc new file mode 100644 index 000000000..4a59dba25 --- /dev/null +++ b/test/asan/TestCases/Windows/interface_symbols_windows.cc @@ -0,0 +1,53 @@ +// Check that the interface exported by asan static lib matches the list of +// functions mentioned in sanitizer_interface.inc. +// +// Just make sure we can compile this. +// RUN: %clang_cl_asan -O0 %s -Fe%t +// +// note: The mangling decoration (i.e. @4 )is removed because calling convention +// differ from 32-bit and 64-bit. +// +// RUN: dumpbin /EXPORTS %t | sed "s/=.*//" \ +// RUN: | grep -o "\(__asan_\|__ubsan_\|__sanitizer_\|__sancov_\)[^ ]*" \ +// RUN: | grep -v "__asan_wrap" \ +// RUN: | sed -e s/@.*// > %t.exports +// +// [BEWARE: be really careful with the sed commands, as this test can be run +// from different environemnts with different shells and seds] +// +// RUN: grep -e "INTERFACE_FUNCTION" \ +// RUN: %p/../../../../lib/asan/asan_interface.inc \ +// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ +// RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports1 +// +// RUN: grep -e "INTERFACE_WEAK_FUNCTION" \ +// RUN: %p/../../../../lib/asan/asan_interface.inc \ +// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \ +// RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ +// RUN: | sed -e "s/.*(//" -e "s/).*/__dll/" > %t.imports2 +// +// Add functions not included in the interface lists: +// RUN: grep '[I]MPORT:' %s | sed -e 's/.*[I]MPORT: //' > %t.imports3 +// IMPORT: __asan_shadow_memory_dynamic_address +// IMPORT: __asan_get_shadow_memory_dynamic_address +// IMPORT: __asan_option_detect_stack_use_after_return +// IMPORT: __asan_should_detect_stack_use_after_return +// IMPORT: __asan_set_seh_filter +// IMPORT: __asan_unhandled_exception_filter +// IMPORT: __asan_test_only_reported_buggy_pointer +// IMPORT: __sancov_lowest_stack +// IMPORT: __ubsan_vptr_type_cache +// +// RUN: cat %t.imports1 %t.imports2 %t.imports3 | sort | uniq > %t.imports-sorted +// RUN: cat %t.exports | sort | uniq > %t.exports-sorted +// +// Now make sure the DLL thunk imports everything: +// RUN: echo +// RUN: echo "=== NOTE === If you see a mismatch below, please update interface.inc files." +// RUN: diff %t.imports-sorted %t.exports-sorted +// REQUIRES: asan-static-runtime + +int main() { return 0; } -- cgit v1.2.1 From eca49ebb092bd846aed33508b613f3c582ef8587 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 18 Sep 2017 20:31:57 +0000 Subject: [scudo] Additional modifications for Android tests support Summary: With the recent move of `android_commands` to `sanitizer_common`, some things have to be updated with regard to Scudo on Android. Notably: - `config.android` is dealt with in the common code - `config.compile_wrapper` can be prepended to allow for the use of the android commands - `SCUDO_OPTIONS` must be passed with the environment when running a test - `preinit.cpp` fails with some API levels, not sure why, I will have to dig into this later. Note that `check-scudo` is not enabled yet in the bots. It's all local testing for now until everything looks good. Reviewers: alekseyshl, vitalybuka Reviewed By: vitalybuka Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D37990 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313561 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/android_commands/android_run.py | 2 +- test/scudo/lit.cfg | 2 +- test/scudo/lit.site.cfg.in | 1 - test/scudo/preinit.cpp | 4 ++++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/sanitizer_common/android_commands/android_run.py b/test/sanitizer_common/android_commands/android_run.py index 7e599453d..a7f45b9f9 100755 --- a/test/sanitizer_common/android_commands/android_run.py +++ b/test/sanitizer_common/android_commands/android_run.py @@ -13,7 +13,7 @@ def build_env(): # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) for (key, value) in os.environ.items(): - if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: + if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS', 'SCUDO_OPTIONS']: args.append('%s="%s"' % (key, value)) return ' '.join(args) diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index d0a4cb167..bd9e6aa31 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -32,7 +32,7 @@ if not config.android: c_flags += ["-lrt"] def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " # Add clang substitutions. config.substitutions.append(("%clang_scudo ", diff --git a/test/scudo/lit.site.cfg.in b/test/scudo/lit.site.cfg.in index be0d88c10..429951875 100644 --- a/test/scudo/lit.site.cfg.in +++ b/test/scudo/lit.site.cfg.in @@ -3,7 +3,6 @@ config.name_suffix = "@SCUDO_TEST_CONFIG_SUFFIX@" config.target_arch = "@SCUDO_TEST_TARGET_ARCH@" config.target_cflags = "@SCUDO_TEST_TARGET_CFLAGS@" -config.android = "@ANDROID@" # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/test/scudo/preinit.cpp b/test/scudo/preinit.cpp index b8c01a401..f904c6c2d 100644 --- a/test/scudo/preinit.cpp +++ b/test/scudo/preinit.cpp @@ -4,6 +4,10 @@ // Verifies that calling malloc in a preinit_array function succeeds, and that // the resulting pointer can be freed at program termination. +// On some Android versions, calling mmap() from a preinit function segfaults. +// It looks like __mmap2.S ends up calling a NULL function pointer. +// UNSUPPORTED: android + #include #include #include -- cgit v1.2.1 From 474ec9e95dcb85850097b84c0017b44770dcecb7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 21:35:49 +0000 Subject: [ubsan] Fix conflict with previous declaration on Mac git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313572 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_handlers.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 93f6ee2ab..1112ce1cc 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -672,9 +672,8 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, ReportOptions Opts); #else -static void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, - ValueHandle Vtable, - bool ValidVtable, ReportOptions Opts) { +void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, + bool ValidVtable, ReportOptions Opts) { Die(); } #endif -- cgit v1.2.1 From 7055da967bd6e8d188d6821bc1ab63bebfb363de Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 22:38:18 +0000 Subject: [ubsan] Split ubsan_init_standalone On Linux we may need preinit_array in static lib and ubsan_standalone_initializer in shared lib. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313583 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 15 ++++++++++++--- lib/ubsan/ubsan_init_standalone.cc | 7 ------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index a29c0eed9..0375cffb9 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -10,7 +10,6 @@ set(UBSAN_SOURCES set(UBSAN_STANDALONE_SOURCES ubsan_diag_standalone.cc - ubsan_init_standalone.cc ) set(UBSAN_CXXABI_SOURCES @@ -64,6 +63,7 @@ if(APPLE) OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_SUPPORTED_ARCH} SOURCES ${UBSAN_STANDALONE_SOURCES} + ubsan_init_standalone.cc CFLAGS ${UBSAN_STANDALONE_CFLAGS}) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) @@ -133,7 +133,15 @@ else() # Initializer of standalone UBSan runtime. add_compiler_rt_object_libraries(RTUbsan_standalone ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS}) + SOURCES ${UBSAN_STANDALONE_SOURCES} + ubsan_init_standalone + CFLAGS ${UBSAN_STANDALONE_CFLAGS}) + # This can't not be linked into share lib + add_compiler_rt_object_libraries(RTUbsan_standalone_preinit + ARCHS ${UBSAN_SUPPORTED_ARCH} + SOURCES ${UBSAN_STANDALONE_SOURCES} + ubsan_init_standalone_preinit.cc + CFLAGS ${UBSAN_STANDALONE_CFLAGS}) # Standalone UBSan runtimes. add_compiler_rt_runtime(clang_rt.ubsan_standalone @@ -142,7 +150,7 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan - RTUbsan_standalone + RTUbsan_standalone_preinit CFLAGS ${UBSAN_CFLAGS} PARENT_TARGET ubsan) @@ -160,6 +168,7 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan + RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc index ff1a20efe..8e999e3ac 100644 --- a/lib/ubsan/ubsan_init_standalone.cc +++ b/lib/ubsan/ubsan_init_standalone.cc @@ -19,11 +19,6 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "ubsan_init.h" -#if SANITIZER_CAN_USE_PREINIT_ARRAY -__attribute__((section(".preinit_array"), used)) -void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone; -#else -// Use a dynamic initializer. class UbsanStandaloneInitializer { public: UbsanStandaloneInitializer() { @@ -31,5 +26,3 @@ class UbsanStandaloneInitializer { } }; static UbsanStandaloneInitializer ubsan_standalone_initializer; -#endif // SANITIZER_CAN_USE_PREINIT_ARRAY - -- cgit v1.2.1 From 084609f437ce6bc03d716b612f441d9bc7aff1bf Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 22:43:28 +0000 Subject: [ubsan] Add file missing from r313583 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313584 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/ubsan_init_standalone_preinit.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/ubsan/ubsan_init_standalone_preinit.cc diff --git a/lib/ubsan/ubsan_init_standalone_preinit.cc b/lib/ubsan/ubsan_init_standalone_preinit.cc new file mode 100644 index 000000000..229ecc5c8 --- /dev/null +++ b/lib/ubsan/ubsan_init_standalone_preinit.cc @@ -0,0 +1,26 @@ +//===-- ubsan_init_standalone_preinit.cc +//------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Initialization of standalone UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if !CAN_SANITIZE_UB +#error "UBSan is not supported on this platform!" +#endif + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "ubsan_init.h" + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)( + void) = __ubsan::InitAsStandalone; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY -- cgit v1.2.1 From 9be9a94b09e5513dbf83bffca7e99589f7c4fa8a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 18 Sep 2017 22:47:36 +0000 Subject: Revert "[ubsan] Split ubsan_init_standalone" Breaks build. This reverts commit r313583 and r313584. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313585 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 15 +++------------ lib/ubsan/ubsan_init_standalone.cc | 7 +++++++ lib/ubsan/ubsan_init_standalone_preinit.cc | 26 -------------------------- 3 files changed, 10 insertions(+), 38 deletions(-) delete mode 100644 lib/ubsan/ubsan_init_standalone_preinit.cc diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 0375cffb9..a29c0eed9 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -10,6 +10,7 @@ set(UBSAN_SOURCES set(UBSAN_STANDALONE_SOURCES ubsan_diag_standalone.cc + ubsan_init_standalone.cc ) set(UBSAN_CXXABI_SOURCES @@ -63,7 +64,6 @@ if(APPLE) OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_SUPPORTED_ARCH} SOURCES ${UBSAN_STANDALONE_SOURCES} - ubsan_init_standalone.cc CFLAGS ${UBSAN_STANDALONE_CFLAGS}) add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS) @@ -133,15 +133,7 @@ else() # Initializer of standalone UBSan runtime. add_compiler_rt_object_libraries(RTUbsan_standalone ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES ${UBSAN_STANDALONE_SOURCES} - ubsan_init_standalone - CFLAGS ${UBSAN_STANDALONE_CFLAGS}) - # This can't not be linked into share lib - add_compiler_rt_object_libraries(RTUbsan_standalone_preinit - ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES ${UBSAN_STANDALONE_SOURCES} - ubsan_init_standalone_preinit.cc - CFLAGS ${UBSAN_STANDALONE_CFLAGS}) + SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS}) # Standalone UBSan runtimes. add_compiler_rt_runtime(clang_rt.ubsan_standalone @@ -150,7 +142,7 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan - RTUbsan_standalone_preinit + RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} PARENT_TARGET ubsan) @@ -168,7 +160,6 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan - RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc index 8e999e3ac..ff1a20efe 100644 --- a/lib/ubsan/ubsan_init_standalone.cc +++ b/lib/ubsan/ubsan_init_standalone.cc @@ -19,6 +19,11 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "ubsan_init.h" +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), used)) +void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone; +#else +// Use a dynamic initializer. class UbsanStandaloneInitializer { public: UbsanStandaloneInitializer() { @@ -26,3 +31,5 @@ class UbsanStandaloneInitializer { } }; static UbsanStandaloneInitializer ubsan_standalone_initializer; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY + diff --git a/lib/ubsan/ubsan_init_standalone_preinit.cc b/lib/ubsan/ubsan_init_standalone_preinit.cc deleted file mode 100644 index 229ecc5c8..000000000 --- a/lib/ubsan/ubsan_init_standalone_preinit.cc +++ /dev/null @@ -1,26 +0,0 @@ -//===-- ubsan_init_standalone_preinit.cc -//------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Initialization of standalone UBSan runtime. -// -//===----------------------------------------------------------------------===// - -#include "ubsan_platform.h" -#if !CAN_SANITIZE_UB -#error "UBSan is not supported on this platform!" -#endif - -#include "sanitizer_common/sanitizer_internal_defs.h" -#include "ubsan_init.h" - -#if SANITIZER_CAN_USE_PREINIT_ARRAY -__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)( - void) = __ubsan::InitAsStandalone; -#endif // SANITIZER_CAN_USE_PREINIT_ARRAY -- cgit v1.2.1 From 3b5c45da8b49e39df007e092eba9abbb2f93c6bd Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 18 Sep 2017 23:37:32 +0000 Subject: [profile] Update InstrProfData.inc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313599 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/InstrProfData.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc index be0dd4ad0..66d63a462 100644 --- a/lib/profile/InstrProfData.inc +++ b/lib/profile/InstrProfData.inc @@ -630,7 +630,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, /* Indexed profile format version (start from 1). */ #define INSTR_PROF_INDEX_VERSION 4 /* Coverage mapping format vresion (start from 0). */ -#define INSTR_PROF_COVMAP_VERSION 1 +#define INSTR_PROF_COVMAP_VERSION 2 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 -- cgit v1.2.1 From 7bd22ca122d1a8289eda6962827e9ed1c1786577 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 19 Sep 2017 00:15:18 +0000 Subject: [profile] Update Linux-only tests after r313597 Addresses bot failure: http://lab.llvm.org:8011/builders/clang-ppc64le-linux/builds/9803 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313602 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/Inputs/extern_template.h | 2 +- test/profile/Linux/coverage_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/profile/Inputs/extern_template.h b/test/profile/Inputs/extern_template.h index d08592da0..aa59f6c1e 100644 --- a/test/profile/Inputs/extern_template.h +++ b/test/profile/Inputs/extern_template.h @@ -3,7 +3,7 @@ template struct Test { void doIt(int N) { // CHECK: [[@LINE]]| 2| void doIt if (N > 10) { // CHECK: [[@LINE]]| 2| if (N > 10) { M += 2; // CHECK: [[@LINE]]| 1| M += 2; - } else // CHECK: [[@LINE]]| 2| } else + } else // CHECK: [[@LINE]]| 1| } else M -= 2; // CHECK: [[@LINE]]| 1| M -= 2; } T M; diff --git a/test/profile/Linux/coverage_test.cpp b/test/profile/Linux/coverage_test.cpp index e636e5559..67adeb724 100644 --- a/test/profile/Linux/coverage_test.cpp +++ b/test/profile/Linux/coverage_test.cpp @@ -19,7 +19,7 @@ void foo(bool cond) { // CHECK: [[@LINE]]| 1|void foo( if (cond) { // CHECK: [[@LINE]]| 1| if (cond) { - } // CHECK: [[@LINE]]| 1| } + } // CHECK: [[@LINE]]| 0| } } // CHECK: [[@LINE]]| 1|} void bar() { // CHECK: [[@LINE]]| 1|void bar() { } // CHECK: [[@LINE]]| 1|} -- cgit v1.2.1 From c85c0b5fe40d3204e454b7452df80a524dda1823 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 19 Sep 2017 06:46:36 +0000 Subject: [ubsan-minimal] Make the interface more compatible with RTUBSan This eliminates a few inconsistencies between the symbol sets exported by RTUBSan and RTUBSan_minimal: * Handlers for nonnull_return were missing from the minimal RT, and are now added in. * The minimal runtime exported recoverable handlers for builtin_unreachable and missing_return. These are not supposed to exist, and are now removed. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313614 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan_minimal/ubsan_minimal_handlers.cc | 17 ++++++++++++----- test/ubsan_minimal/TestCases/recover-dedup.cpp | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc index 97f7ae7b2..dac127bc2 100644 --- a/lib/ubsan_minimal/ubsan_minimal_handlers.cc +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -57,17 +57,22 @@ static void abort_with_message(const char *) { abort(); } // FIXME: add caller pc to the error message (possibly as "ubsan: error-type // @1234ABCD"). -#define HANDLER(name, msg) \ +#define HANDLER_RECOVER(name, msg) \ INTERFACE void __ubsan_handle_##name##_minimal() { \ if (!report_this_error(__builtin_return_address(0))) return; \ message("ubsan: " msg "\n"); \ - } \ - \ + } + +#define HANDLER_NORECOVER(name, msg) \ INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ message("ubsan: " msg "\n"); \ abort_with_message("ubsan: " msg); \ } +#define HANDLER(name, msg) \ + HANDLER_RECOVER(name, msg) \ + HANDLER_NORECOVER(name, msg) + HANDLER(type_mismatch, "type-mismatch") HANDLER(add_overflow, "add-overflow") HANDLER(sub_overflow, "sub-overflow") @@ -76,14 +81,16 @@ HANDLER(negate_overflow, "negate-overflow") HANDLER(divrem_overflow, "divrem-overflow") HANDLER(shift_out_of_bounds, "shift-out-of-bounds") HANDLER(out_of_bounds, "out-of-bounds") -HANDLER(builtin_unreachable, "builtin-unreachable") -HANDLER(missing_return, "missing-return") +HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable") +HANDLER_RECOVER(missing_return, "missing-return") HANDLER(vla_bound_not_positive, "vla-bound-not-positive") 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(nonnull_arg, "nonnull-arg") +HANDLER(nonnull_return, "nonnull-return") HANDLER(nullability_arg, "nullability-arg") +HANDLER(nullability_return, "nullability-return") HANDLER(pointer_overflow, "pointer-overflow") HANDLER(cfi_check_fail, "cfi-check-fail") diff --git a/test/ubsan_minimal/TestCases/recover-dedup.cpp b/test/ubsan_minimal/TestCases/recover-dedup.cpp index 744471c66..4dfd6991e 100644 --- a/test/ubsan_minimal/TestCases/recover-dedup.cpp +++ b/test/ubsan_minimal/TestCases/recover-dedup.cpp @@ -1,6 +1,18 @@ -// RUN: %clangxx -fsanitize=signed-integer-overflow -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -w -fsanitize=signed-integer-overflow,nullability-return,returns-nonnull-attribute -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s #include +#include + +int *_Nonnull h() { + // CHECK: nullability-return + return NULL; +} + +__attribute__((returns_nonnull)) +int *i() { + // CHECK: nonnull-return + return NULL; +} __attribute__((noinline)) int f(int x, int y) { @@ -15,6 +27,8 @@ int g(int x, int y) { } int main() { + h(); + i(); int x = 2; for (int i = 0; i < 10; ++i) x = f(x, x); -- cgit v1.2.1 From f9dd70c4988603f97de3b3b9a3ee7cb578bff699 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 19 Sep 2017 06:46:36 +0000 Subject: [ubsan-minimal] Test exported symbol set against RTUBsan Check that the symbol sets exported by the minimal runtime and the full runtime match (making exceptions for special cases as needed). This test uses some possibly non-standard nm options, and needs to inspect the symbols in runtime dylibs. I haven't found a portable way to do this, so it's limited to x86-64/Darwin for now. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313615 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/TestCases/test-darwin-interface.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/ubsan_minimal/TestCases/test-darwin-interface.c diff --git a/test/ubsan_minimal/TestCases/test-darwin-interface.c b/test/ubsan_minimal/TestCases/test-darwin-interface.c new file mode 100644 index 000000000..1da049f9a --- /dev/null +++ b/test/ubsan_minimal/TestCases/test-darwin-interface.c @@ -0,0 +1,16 @@ +// Check that the ubsan and ubsan-minimal runtimes have the same symbols, +// making exceptions as necessary. +// +// REQUIRES: x86_64-darwin + +// RUN: nm -jgU `%clangxx -fsanitize-minimal-runtime -fsanitize=undefined %s -o %t '-###' 2>&1 | grep "libclang_rt.ubsan_minimal_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.ubsan_minimal_osx_dynamic.dylib\)".*/\1/'` | grep "^___ubsan_handle" \ +// RUN: | sed 's/_minimal//g' \ +// RUN: > %t.minimal.symlist +// +// RUN: nm -jgU `%clangxx -fno-sanitize-minimal-runtime -fsanitize=undefined %s -o %t '-###' 2>&1 | grep "libclang_rt.ubsan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.ubsan_osx_dynamic.dylib\)".*/\1/'` | grep "^___ubsan_handle" \ +// RUN: | grep -vE "^___ubsan_handle_dynamic_type_cache_miss" \ +// RUN: | grep -vE "^___ubsan_handle_cfi_bad_type" \ +// RUN: | sed 's/_v1//g' \ +// RUN: > %t.full.symlist +// +// RUN: diff %t.minimal.symlist %t.full.symlist -- cgit v1.2.1 From daa58c8bfbcdfda7dfcfe1f334341d5212393377 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Tue, 19 Sep 2017 17:00:22 +0000 Subject: [sanitizer] Don't define common ReportDeadlySignal on Fuchsia This causes a linker error because of duplicate symbol since ReportDeadlySignal is defined both in sanitizer_common_libcdep and sanitizer_fuchsia. Differential Revision: https://reviews.llvm.org/D37952 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313641 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_libcdep.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index d96890ff5..69dd93d87 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -147,7 +147,7 @@ void BackgroundThread(void *arg) { } #endif -#if !SANITIZER_GO +#if !SANITIZER_FUCHSIA && !SANITIZER_GO void StartReportDeadlySignal() { // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. @@ -254,7 +254,7 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, else ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); } -#endif // !SANITIZER_GO +#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO void WriteToSyslog(const char *msg) { InternalScopedString msg_copy(kErrorMessageBufferSize); -- cgit v1.2.1 From 4035097abb6703beaaa9fbbf9bdbd80a1ab522c1 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Tue, 19 Sep 2017 17:26:02 +0000 Subject: [mips][compiler-rt] UnXFAIL test. lsan and asan were reporting leaks caused by a glibc configuration issue. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313645 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc index 5bee1fb4b..c0d6cfea1 100644 --- a/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc +++ b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc @@ -1,8 +1,6 @@ // Regression test for a crash in getpwnam_r and similar interceptors. // RUN: %clangxx -O0 -g %s -o %t && %run %t -// XFAIL: mips - #include #include #include -- cgit v1.2.1 From af5d32eeb88de110fcb0aa1c5eaa77833d421ba9 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 19 Sep 2017 17:54:11 +0000 Subject: Ensure that armhf builtins library is created when using an hf abi Reviewers: beanz, compnerd Reviewed By: compnerd Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D38045 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313650 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd408d7e6..a3df7cc0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,11 @@ if (COMPILER_RT_STANDALONE_BUILD) endif() construct_compiler_rt_default_triple() +if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "hf$") + if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^arm") + set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf") + endif() +endif() if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi") set(ANDROID 1) endif() -- cgit v1.2.1 From 0feb616cb30a9d33d74edfa143525a6df126a61f Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 19 Sep 2017 17:56:27 +0000 Subject: Set ANDROID when any android abi is used, not just androideabi Reviewers: compnerd, beanz Subscribers: srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D38044 Change-Id: Idab521f187aba18977818d91503763e0e9d3aa0e git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313652 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3df7cc0e..c05403ebf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "hf$") set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf") endif() endif() -if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi") +if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "^android") set(ANDROID 1) endif() pythonize_bool(ANDROID) -- cgit v1.2.1 From 387a685d243baec9a0c09d3f41be73bd66aba38a Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 20 Sep 2017 07:01:19 +0000 Subject: [asan] Resolve FIXME by converting gtest into lit test git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313727 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_interface_test.cc | 17 ----------------- test/asan/TestCases/error_report_callback.cc | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 test/asan/TestCases/error_report_callback.cc diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc index 03351e02b..0540ab5e0 100644 --- a/lib/asan/tests/asan_interface_test.cc +++ b/lib/asan/tests/asan_interface_test.cc @@ -386,23 +386,6 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { free(array); } -#if !defined(_WIN32) // FIXME: This should really be a lit test. -static void ErrorReportCallbackOneToZ(const char *report) { - int report_len = strlen(report); - ASSERT_EQ(6, write(2, "ABCDEF", 6)); - ASSERT_EQ(report_len, write(2, report, report_len)); - ASSERT_EQ(6, write(2, "ABCDEF", 6)); - _exit(1); -} - -TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) { - __asan_set_error_report_callback(ErrorReportCallbackOneToZ); - EXPECT_DEATH(__asan_report_error((void *)GET_CALLER_PC(), 0, 0, 0, true, 1), - ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF"); - __asan_set_error_report_callback(NULL); -} -#endif - TEST(AddressSanitizerInterface, GetOwnershipStressTest) { std::vector pointers; std::vector sizes; diff --git a/test/asan/TestCases/error_report_callback.cc b/test/asan/TestCases/error_report_callback.cc new file mode 100644 index 000000000..354369a67 --- /dev/null +++ b/test/asan/TestCases/error_report_callback.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 0 2>&1 | FileCheck %s + +#include +#include + +static void ErrorReportCallbackOneToZ(const char *report) { + fprintf(stderr, "ABCDEF%sGHIJKL", report); +} + +int main(int argc, char **argv) { + __asan_set_error_report_callback(ErrorReportCallbackOneToZ); + __asan_report_error( + (void *)__builtin_extract_return_addr(__builtin_return_address(0)), 0, 0, + 0, true, 1); + // CHECK: ABCDEF + // CHECK: ERROR: AddressSanitizer + // CHECK: GHIJKL + return 0; +} -- cgit v1.2.1 From e07838d519dfde31a87fe518c6cc6b3be0387d5b Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 20 Sep 2017 07:16:08 +0000 Subject: [asan] Try to fix windows test by fflush(stderr) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313728 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/error_report_callback.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/asan/TestCases/error_report_callback.cc b/test/asan/TestCases/error_report_callback.cc index 354369a67..8c5bbe418 100644 --- a/test/asan/TestCases/error_report_callback.cc +++ b/test/asan/TestCases/error_report_callback.cc @@ -6,6 +6,7 @@ static void ErrorReportCallbackOneToZ(const char *report) { fprintf(stderr, "ABCDEF%sGHIJKL", report); + fflush(stderr); } int main(int argc, char **argv) { -- cgit v1.2.1 From eb117e449131a540ead3267402da40ce0aea98b9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 20 Sep 2017 23:27:38 +0000 Subject: [asan] Fix nested error detection Summary: Fixes https://github.com/google/sanitizers/issues/858 Reviewers: eugenis, dvyukov Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D38019 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313835 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 87 +++++++++--------------- test/asan/TestCases/Posix/concurrent_overflow.cc | 33 +++++++++ 2 files changed, 67 insertions(+), 53 deletions(-) create mode 100644 test/asan/TestCases/Posix/concurrent_overflow.cc diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 7e83466cc..8523a74a3 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -122,53 +122,37 @@ bool ParseFrameDescription(const char *frame_descr, // immediately after printing error report. class ScopedInErrorReport { public: + static const u32 kUnclaimedTid = 0xfffffe; + static_assert(kUnclaimedTid != kInvalidTid, "Must be different"); + explicit ScopedInErrorReport(bool fatal = false) { halt_on_error_ = fatal || flags()->halt_on_error; - - if (lock_.TryLock()) { - StartReporting(); - return; - } - - // ASan found two bugs in different threads simultaneously. - u32 current_tid = GetCurrentTidOrInvalid(); - if (reporting_thread_tid_ == current_tid || - reporting_thread_tid_ == kInvalidTid) { - // This is either asynch signal or nested error during error reporting. - // Fail simple to avoid deadlocks in Report(). - - // Can't use Report() here because of potential deadlocks - // in nested signal handlers. - static const char msg[] = - "AddressSanitizer: nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); - - internal__exit(common_flags()->exitcode); - } - - if (halt_on_error_) { - // Do not print more than one report, otherwise they will mix up. - // Error reporting functions shouldn't return at this situation, as - // they are effectively no-returns. - - Report("AddressSanitizer: while reporting a bug found another one. " - "Ignoring.\n"); - // Sleep long enough to make sure that the thread which started - // to print an error report will finish doing it. - SleepForSeconds(Max(100, flags()->sleep_before_dying + 1)); - - // If we're still not dead for some reason, use raw _exit() instead of - // Die() to bypass any additional checks. - internal__exit(common_flags()->exitcode); - } else { - // The other thread will eventually finish reporting - // so it's safe to wait - lock_.Lock(); + for (;;) { + u32 expected_tid = kUnclaimedTid; + if (atomic_compare_exchange_strong(&reporting_thread_tid_, &expected_tid, + current_tid, memory_order_relaxed)) { + // We've claimed reporting_thread_tid_ so proceed. + StartReporting(); + return; + } + + if (expected_tid == current_tid) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + static const char msg[] = + "AddressSanitizer: nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + SleepForMillis(100); } - - StartReporting(); } ~ScopedInErrorReport() { @@ -216,13 +200,13 @@ class ScopedInErrorReport { if (!halt_on_error_) internal_memset(¤t_error_, 0, sizeof(current_error_)); - CommonSanitizerReportMutex.Unlock(); - reporting_thread_tid_ = kInvalidTid; - lock_.Unlock(); if (halt_on_error_) { Report("ABORTING\n"); Die(); } + + atomic_store_relaxed(&reporting_thread_tid_, kUnclaimedTid); + CommonSanitizerReportMutex.Unlock(); } void ReportError(const ErrorDescription &description) { @@ -237,27 +221,24 @@ class ScopedInErrorReport { private: void StartReporting() { + CommonSanitizerReportMutex.Lock(); // Make sure the registry and sanitizer report mutexes are locked while // we're printing an error report. // We can lock them only here to avoid self-deadlock in case of // recursive reports. asanThreadRegistry().Lock(); - CommonSanitizerReportMutex.Lock(); - reporting_thread_tid_ = GetCurrentTidOrInvalid(); - Printf("====================================================" - "=============\n"); + Printf( + "=================================================================\n"); } - static StaticSpinMutex lock_; - static u32 reporting_thread_tid_; + static atomic_uint32_t reporting_thread_tid_; // Error currently being reported. This enables the destructor to interact // with the debugger and point it to an error description. static ErrorDescription current_error_; bool halt_on_error_; }; -StaticSpinMutex ScopedInErrorReport::lock_; -u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid; +atomic_uint32_t ScopedInErrorReport::reporting_thread_tid_ = {kUnclaimedTid}; ErrorDescription ScopedInErrorReport::current_error_; void ReportDeadlySignal(const SignalContext &sig) { diff --git a/test/asan/TestCases/Posix/concurrent_overflow.cc b/test/asan/TestCases/Posix/concurrent_overflow.cc new file mode 100644 index 000000000..e9b9899c3 --- /dev/null +++ b/test/asan/TestCases/Posix/concurrent_overflow.cc @@ -0,0 +1,33 @@ +// RUN: %clangxx_asan -O0 -w %s -o %t && not %run %t 2>&1 | FileCheck %s + +// Checks that concurrent reports will not trigger false "nested bug" reports. +// Regression test for https://github.com/google/sanitizers/issues/858 + +#include +#include +#include + +static void *start_routine(void *arg) { + volatile int *counter = (volatile int *)arg; + char buf[8]; + __atomic_sub_fetch(counter, 1, __ATOMIC_SEQ_CST); + while (*counter) + ; + buf[0] = buf[9]; + return 0; +} + +int main(void) { + const int n_threads = 8; + int i, counter = n_threads; + pthread_t thread; + + for (i = 0; i < n_threads; ++i) + pthread_create(&thread, NULL, &start_routine, (void *)&counter); + sleep(5); + return 0; +} + +// CHECK-NOT: nested bug +// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow on address +// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow -- cgit v1.2.1 From a70d41b8c9931d3b18ec90bbea8c10912ee587cf Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 21 Sep 2017 00:06:08 +0000 Subject: [asan] Remove "rm -f" in tests where it was needed only because of >> git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313843 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-signals.c | 5 ++--- test/asan/TestCases/Posix/halt_on_error-torture.cc | 19 ++++++++----------- .../Posix/halt_on_error_suppress_equal_pcs.cc | 5 ++--- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-signals.c b/test/asan/TestCases/Posix/halt_on_error-signals.c index 6bdf30bb4..931ab8635 100644 --- a/test/asan/TestCases/Posix/halt_on_error-signals.c +++ b/test/asan/TestCases/Posix/halt_on_error-signals.c @@ -2,10 +2,9 @@ // // RUN: %clang_asan -fsanitize-recover=address -pthread %s -o %t // -// RUN: rm -f %t.log -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 100 >>%t.log 2>&1 || true +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 100 >%t.log 2>&1 || true // Collision will almost always get triggered but we still need to check the unlikely case: -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < %t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s < %t.log +// RUN: FileCheck --check-prefix=CHECK-COLLISION %s <%t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log #define _SVID_SOURCE 1 // SA_NODEFER diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 829568e26..220bbff85 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -2,21 +2,18 @@ // // RUN: %clangxx_asan -fsanitize-recover=address -pthread %s -o %t // -// RUN: rm -f 1.txt -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >>1.txt 2>&1 -// RUN: FileCheck %s < 1.txt -// RUN: grep 'ERROR: AddressSanitizer: use-after-poison' 1.txt | count 10 -// RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >%t.log 2>&1 +// RUN: FileCheck %s <%t.log +// RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 10 +// RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log // // Collisions are unlikely but still possible so we need the ||. -// RUN: rm -f 10.txt -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 2>&1 | cat > 10.txt -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: FileCheck --check-prefix=CHECK-COLLISION %s <%t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log // // Collisions are unlikely but still possible so we need the ||. -// RUN: rm -f 20.txt -// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 2>&1 | cat > 20.txt -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt +// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: FileCheck --check-prefix=CHECK-COLLISION %s <%t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log #include #include diff --git a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc index b9d85ef94..6b926180c 100644 --- a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc +++ b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc @@ -6,8 +6,7 @@ // RUN: %env_asan_opts=halt_on_error=false %run %t 2>&1 | FileCheck %s // // Check that we die after reaching different reports number threshold. -// RUN: rm -f %t1.log -// RUN: %env_asan_opts=halt_on_error=false not %run %t 1 >> %t1.log 2>&1 +// RUN: %env_asan_opts=halt_on_error=false not %run %t 1 >%t1.log 2>&1 // RUN: grep 'ERROR: AddressSanitizer: stack-buffer-overflow' %t1.log | count 25 // // Check suppress_equal_pcs=true behavior is equal to default one. @@ -15,7 +14,7 @@ // // Check suppress_equal_pcs=false behavior isn't equal to default one. // RUN: rm -f %t2.log -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t >> %t2.log 2>&1 +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t >%t2.log 2>&1 // RUN: grep 'ERROR: AddressSanitizer: stack-buffer-overflow' %t2.log | count 30 #define ACCESS_ARRAY_FIVE_ELEMENTS(array, i) \ -- cgit v1.2.1 From 368e57c46a9d11275d6186653ab59dca2afffa20 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 21 Sep 2017 00:11:30 +0000 Subject: [asan] Remove "COLLISION" workaround for datarace in asan "nested bug in the same thread" is not expected in case like this and was caused by https://github.com/google/sanitizers/issues/858 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313844 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 220bbff85..10a6dfcd4 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -3,17 +3,16 @@ // RUN: %clangxx_asan -fsanitize-recover=address -pthread %s -o %t // // RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >%t.log 2>&1 -// RUN: FileCheck %s <%t.log // RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 10 -// RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log +// RUN: FileCheck %s <%t.log // -// Collisions are unlikely but still possible so we need the ||. -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s <%t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 200 +// RUN: FileCheck %s <%t.log // -// Collisions are unlikely but still possible so we need the ||. -// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s <%t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s <%t.log +// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 1 +// RUN: FileCheck %s <%t.log #include #include @@ -39,7 +38,6 @@ void *run(void *arg) { for (size_t i = 0; i < niter; ++i) { random_delay(&seed); - // Expect error collisions here // CHECK: ERROR: AddressSanitizer: use-after-poison volatile int idx = 0; tmp[idx] = 0; @@ -73,8 +71,7 @@ int main(int argc, char **argv) { } } - // CHECK-COLLISION: AddressSanitizer: nested bug in the same thread, aborting - // CHECK-NO-COLLISION: All threads terminated + // CHECK: All threads terminated printf("All threads terminated\n"); delete [] tids; -- cgit v1.2.1 From e9e2379f37d15b1c887b1d43ce00213bf9fd34e1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 21 Sep 2017 00:14:17 +0000 Subject: [asan] Remove trailing spaces git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313845 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Posix/halt_on_error-torture.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index 10a6dfcd4..d4b123512 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -6,11 +6,11 @@ // RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 10 // RUN: FileCheck %s <%t.log // -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 // RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 200 // RUN: FileCheck %s <%t.log // -// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 +// RUN: %env_asan_opts=halt_on_error=false:exitcode=0 %run %t 10 20 >%t.log 2>&1 // RUN: grep 'ERROR: AddressSanitizer: use-after-poison' %t.log | count 1 // RUN: FileCheck %s <%t.log -- cgit v1.2.1 From 28ad3fe834d87731a13a712bb92c8f56ecbc0aec Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 21 Sep 2017 00:35:22 +0000 Subject: [ubsan] Split ubsan_init_standalone Summary: On Linux we may need preinit_array in static lib and ubsan_standalone_initializer in shared lib. Reviewers: eugenis Subscribers: kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D38013 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313851 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 10 +++++---- lib/ubsan/ubsan_init.cc | 36 ++++++++---------------------- lib/ubsan/ubsan_init_standalone.cc | 7 ------ lib/ubsan/ubsan_init_standalone_preinit.cc | 26 +++++++++++++++++++++ 4 files changed, 41 insertions(+), 38 deletions(-) create mode 100644 lib/ubsan/ubsan_init_standalone_preinit.cc diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index a29c0eed9..4a2957c18 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -130,15 +130,16 @@ else() endif() if(COMPILER_RT_HAS_UBSAN) - # Initializer of standalone UBSan runtime. add_compiler_rt_object_libraries(RTUbsan_standalone ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS}) + SOURCES ${UBSAN_STANDALONE_SOURCES} + CFLAGS ${UBSAN_STANDALONE_CFLAGS}) # Standalone UBSan runtimes. add_compiler_rt_runtime(clang_rt.ubsan_standalone STATIC ARCHS ${UBSAN_SUPPORTED_ARCH} + SOURCES ubsan_init_standalone_preinit.cc OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan @@ -158,8 +159,9 @@ else() SHARED ARCHS ${UBSAN_SUPPORTED_ARCH} OBJECT_LIBS RTSanitizerCommon - RTSanitizerCommonLibc - RTUbsan + RTSanitizerCommonLibc + RTUbsan + RTUbsan_standalone CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index d7433a5c9..32fc434ad 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -27,11 +27,7 @@ const char *__ubsan::GetSanititizerToolName() { return "UndefinedBehaviorSanitizer"; } -static enum { - UBSAN_MODE_UNKNOWN = 0, - UBSAN_MODE_STANDALONE, - UBSAN_MODE_PLUGIN -} ubsan_mode; +static bool ubsan_initialized; static StaticSpinMutex ubsan_init_mu; static void CommonInit() { @@ -46,38 +42,24 @@ static void CommonStandaloneInit() { AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); CommonInit(); - ubsan_mode = UBSAN_MODE_STANDALONE; } void __ubsan::InitAsStandalone() { - if (SANITIZER_CAN_USE_PREINIT_ARRAY) { - CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode); - CommonStandaloneInit(); - return; - } SpinMutexLock l(&ubsan_init_mu); - CHECK_NE(UBSAN_MODE_PLUGIN, ubsan_mode); - if (ubsan_mode == UBSAN_MODE_UNKNOWN) + if (!ubsan_initialized) { CommonStandaloneInit(); -} - -void __ubsan::InitAsStandaloneIfNecessary() { - if (SANITIZER_CAN_USE_PREINIT_ARRAY) { - CHECK_NE(UBSAN_MODE_UNKNOWN, ubsan_mode); - return; + ubsan_initialized = true; } - SpinMutexLock l(&ubsan_init_mu); - if (ubsan_mode == UBSAN_MODE_UNKNOWN) - CommonStandaloneInit(); } +void __ubsan::InitAsStandaloneIfNecessary() { return InitAsStandalone(); } + void __ubsan::InitAsPlugin() { -#if !SANITIZER_CAN_USE_PREINIT_ARRAY SpinMutexLock l(&ubsan_init_mu); -#endif - CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode); - CommonInit(); - ubsan_mode = UBSAN_MODE_PLUGIN; + if (!ubsan_initialized) { + CommonInit(); + ubsan_initialized = true; + } } #endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc index ff1a20efe..8e999e3ac 100644 --- a/lib/ubsan/ubsan_init_standalone.cc +++ b/lib/ubsan/ubsan_init_standalone.cc @@ -19,11 +19,6 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "ubsan_init.h" -#if SANITIZER_CAN_USE_PREINIT_ARRAY -__attribute__((section(".preinit_array"), used)) -void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone; -#else -// Use a dynamic initializer. class UbsanStandaloneInitializer { public: UbsanStandaloneInitializer() { @@ -31,5 +26,3 @@ class UbsanStandaloneInitializer { } }; static UbsanStandaloneInitializer ubsan_standalone_initializer; -#endif // SANITIZER_CAN_USE_PREINIT_ARRAY - diff --git a/lib/ubsan/ubsan_init_standalone_preinit.cc b/lib/ubsan/ubsan_init_standalone_preinit.cc new file mode 100644 index 000000000..229ecc5c8 --- /dev/null +++ b/lib/ubsan/ubsan_init_standalone_preinit.cc @@ -0,0 +1,26 @@ +//===-- ubsan_init_standalone_preinit.cc +//------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Initialization of standalone UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if !CAN_SANITIZE_UB +#error "UBSan is not supported on this platform!" +#endif + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "ubsan_init.h" + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)( + void) = __ubsan::InitAsStandalone; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY -- cgit v1.2.1 From 1fc69acfb655e2088be9d08716148cd8dccc4448 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 21 Sep 2017 10:16:56 +0000 Subject: [XRay][compiler-rt] Remove non-trivial globals from xray_log_interface.cc Summary: Remove dependency on std::unique_ptr<...> for the global representing the installed XRay implementation. Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38121 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313871 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_log_interface.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc index ee14ae4b1..5cc6ade0f 100644 --- a/lib/xray/xray_log_interface.cc +++ b/lib/xray/xray_log_interface.cc @@ -17,30 +17,30 @@ #include "xray/xray_interface.h" #include "xray_defs.h" -#include - __sanitizer::SpinMutex XRayImplMutex; -std::unique_ptr GlobalXRayImpl; +XRayLogImpl *GlobalXRayImpl = nullptr; void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT { if (Impl.log_init == nullptr || Impl.log_finalize == nullptr || Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); - GlobalXRayImpl.reset(); + delete GlobalXRayImpl; + GlobalXRayImpl = nullptr; __xray_remove_handler(); __xray_remove_handler_arg1(); return; } __sanitizer::SpinMutexLock Guard(&XRayImplMutex); - GlobalXRayImpl.reset(new XRayLogImpl); + GlobalXRayImpl = new XRayLogImpl(); *GlobalXRayImpl = Impl; __xray_set_handler(Impl.handle_arg0); } void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); - GlobalXRayImpl.reset(); + delete GlobalXRayImpl; + GlobalXRayImpl = nullptr; __xray_remove_handler(); __xray_remove_handler_arg1(); } -- cgit v1.2.1 From 0b01c05ec7545697a453b594f3b288e38d4c36cb Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 21 Sep 2017 22:16:50 +0000 Subject: [tsan] Annotate function parameters with attribute 'noescape'. This commit annotates the block parameters of the following functions declared in compiler-rt with 'noescape': - dispatch_sync - dispatch_barrier_sync - dispatch_once - dispatch_apply This is needed to commit the patch that adds support for 'noescape' in clang (see https://reviews.llvm.org/D32210) since these functions are annotated with 'noescape' in the SDK header files. Differential Revision: https://reviews.llvm.org/D32210 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313929 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_libdispatch_mac.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc index 4a36f03ff..0bd010700 100644 --- a/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -177,7 +177,8 @@ static void invoke_and_release_block(void *param) { } #define DISPATCH_INTERCEPT_SYNC_B(name, barrier) \ - TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \ + TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \ + DISPATCH_NOESCAPE dispatch_block_t block) { \ SCOPED_TSAN_INTERCEPTOR(name, q, block); \ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ dispatch_block_t heap_block = Block_copy(block); \ @@ -267,7 +268,7 @@ TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, // need to undefine the macro. #undef dispatch_once TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate, - dispatch_block_t block) { + DISPATCH_NOESCAPE dispatch_block_t block) { SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block); atomic_uint32_t *a = reinterpret_cast(predicate); u32 v = atomic_load(a, memory_order_acquire); @@ -477,7 +478,8 @@ TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f, } TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations, - dispatch_queue_t queue, void (^block)(size_t)) { + dispatch_queue_t queue, + DISPATCH_NOESCAPE void (^block)(size_t)) { SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block); void *parent_to_child_sync = nullptr; -- cgit v1.2.1 From acea4097cecbb48fab482ada95e585f54a5e7436 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 22 Sep 2017 07:11:43 +0000 Subject: [asan/lsan] Make LSan compliant with recovery mode when running on top of ASan Don't overwrite exit code in LSan when running on top of ASan in recovery mode to avoid breakage of users code due to found leaks. Patch by Slava Barinov. Differential Revision: https://reviews.llvm.org/D38026 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313966 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_rtl.cc | 5 ++++- lib/lsan/lsan_common.cc | 3 +++ lib/lsan/lsan_common.h | 1 + test/asan/TestCases/recoverable-lsan.cc | 21 +++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/asan/TestCases/recoverable-lsan.cc diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 6e83671ab..8608e4a60 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -459,7 +459,10 @@ static void AsanInitInternal() { if (CAN_SANITIZE_LEAKS) { __lsan::InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { - Atexit(__lsan::DoLeakCheck); + if (flags()->halt_on_error) + Atexit(__lsan::DoLeakCheck); + else + Atexit(__lsan::DoRecoverableLeakCheckVoid); } } diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a7927684c..b9b6fe086 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -593,6 +593,8 @@ static int DoRecoverableLeakCheck() { return have_leaks ? 1 : 0; } +void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); } + static Suppression *GetSuppressionForAddr(uptr addr) { Suppression *s = nullptr; @@ -755,6 +757,7 @@ uptr LeakReport::UnsuppressedLeakCount() { namespace __lsan { void InitCommonLsan() { } void DoLeakCheck() { } +void DoRecoverableLeakCheckVoid() { } void DisableInThisThread() { } void EnableInThisThread() { } } diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 31bf3eb1d..1bb3e4198 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -145,6 +145,7 @@ enum IgnoreObjectResult { // Functions called from the parent tool. void InitCommonLsan(); void DoLeakCheck(); +void DoRecoverableLeakCheckVoid(); void DisableCounterUnderflow(); bool DisabledInThisThread(); diff --git a/test/asan/TestCases/recoverable-lsan.cc b/test/asan/TestCases/recoverable-lsan.cc new file mode 100644 index 000000000..997206012 --- /dev/null +++ b/test/asan/TestCases/recoverable-lsan.cc @@ -0,0 +1,21 @@ +// Ensure that output is the same but exit code depends on halt_on_error value +// RUN: %clangxx_asan %s -o %t +// RUN: %env_asan_opts="halt_on_error=0" %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts="halt_on_error=1" not %run %t 2>&1 | FileCheck %s +// RUN: not %run %t 2>&1 | FileCheck %s + +#include + +int f() { + volatile int *a = (int *)malloc(20); + a[0] = 1; + return a[0]; +} + +int main() { + f(); + f(); +} + +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: AddressSanitizer: 20 byte(s) leaked -- cgit v1.2.1 From 5ee8cc2310abd21a8b56ead57efa3c5cdc63d304 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 22 Sep 2017 08:23:16 +0000 Subject: [asan/lsan] Trying to fix buildbots after r313966 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313967 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/recoverable-lsan.cc | 22 ++++++++++++++++++++++ test/asan/TestCases/recoverable-lsan.cc | 21 --------------------- 2 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 test/asan/TestCases/Linux/recoverable-lsan.cc delete mode 100644 test/asan/TestCases/recoverable-lsan.cc diff --git a/test/asan/TestCases/Linux/recoverable-lsan.cc b/test/asan/TestCases/Linux/recoverable-lsan.cc new file mode 100644 index 000000000..e65e71df8 --- /dev/null +++ b/test/asan/TestCases/Linux/recoverable-lsan.cc @@ -0,0 +1,22 @@ +// Ensure that output is the same but exit code depends on halt_on_error value +// RUN: %clangxx_asan %s -o %t +// RUN: %env_asan_opts="halt_on_error=0" %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts="halt_on_error=1" not %run %t 2>&1 | FileCheck %s +// RUN: not %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: android + +#include + +int f() { + volatile int *a = (int *)malloc(20); + a[0] = 1; + return a[0]; +} + +int main() { + f(); + f(); +} + +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: AddressSanitizer: 20 byte(s) leaked diff --git a/test/asan/TestCases/recoverable-lsan.cc b/test/asan/TestCases/recoverable-lsan.cc deleted file mode 100644 index 997206012..000000000 --- a/test/asan/TestCases/recoverable-lsan.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Ensure that output is the same but exit code depends on halt_on_error value -// RUN: %clangxx_asan %s -o %t -// RUN: %env_asan_opts="halt_on_error=0" %run %t 2>&1 | FileCheck %s -// RUN: %env_asan_opts="halt_on_error=1" not %run %t 2>&1 | FileCheck %s -// RUN: not %run %t 2>&1 | FileCheck %s - -#include - -int f() { - volatile int *a = (int *)malloc(20); - a[0] = 1; - return a[0]; -} - -int main() { - f(); - f(); -} - -// CHECK: LeakSanitizer: detected memory leaks -// CHECK: SUMMARY: AddressSanitizer: 20 byte(s) leaked -- cgit v1.2.1 From 7e3a14329a9b9ff9434d442fa5ad7c90be14416e Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 22 Sep 2017 10:44:28 +0000 Subject: [asan/lsan] Trying to fix PPC64 and x380x buildbots after r313966 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313974 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/recoverable-lsan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asan/TestCases/Linux/recoverable-lsan.cc b/test/asan/TestCases/Linux/recoverable-lsan.cc index e65e71df8..935645327 100644 --- a/test/asan/TestCases/Linux/recoverable-lsan.cc +++ b/test/asan/TestCases/Linux/recoverable-lsan.cc @@ -3,6 +3,7 @@ // RUN: %env_asan_opts="halt_on_error=0" %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts="halt_on_error=1" not %run %t 2>&1 | FileCheck %s // RUN: not %run %t 2>&1 | FileCheck %s +// REQUIRES: leak-detection // UNSUPPORTED: android #include @@ -19,4 +20,3 @@ int main() { } // CHECK: LeakSanitizer: detected memory leaks -// CHECK: SUMMARY: AddressSanitizer: 20 byte(s) leaked -- cgit v1.2.1 From 10b087da020f9008012c82d8cb1c35463108c912 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 22 Sep 2017 15:35:37 +0000 Subject: [scudo] Scudo thread specific data refactor, part 1 Summary: We are going through an overhaul of Scudo's TSD, to allow for new platforms to be integrated more easily, and make the code more sound. This first part is mostly renaming, preferring some shorter names, correcting some comments. I removed `getPrng` and `getAllocatorCache` to directly access the members, there was not really any benefit to them (and it was suggested by Dmitry in D37590). The only functional change is in `scudo_tls_android.cpp`: we enforce bounds to the `NumberOfTSDs` and most of the logic in `getTSDAndLockSlow` is skipped if we only have 1 TSD. Reviewers: alekseyshl, dvyukov, kcc Reviewed By: dvyukov Subscribers: llvm-commits, srhines Differential Revision: https://reviews.llvm.org/D38139 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313987 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 60 ++++++++++-------------- lib/scudo/scudo_tls.h | 4 +- lib/scudo/scudo_tls_android.cpp | 81 +++++++++++++++++---------------- lib/scudo/scudo_tls_android.inc | 15 +++--- lib/scudo/scudo_tls_context_android.inc | 16 +++---- lib/scudo/scudo_tls_context_linux.inc | 2 +- lib/scudo/scudo_tls_linux.cpp | 6 +-- lib/scudo/scudo_tls_linux.inc | 6 +-- 8 files changed, 90 insertions(+), 100 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 9d65b8683..e490a469d 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -250,19 +250,11 @@ struct QuarantineCallback { typedef Quarantine ScudoQuarantine; typedef ScudoQuarantine::Cache ScudoQuarantineCache; COMPILER_CHECK(sizeof(ScudoQuarantineCache) <= - sizeof(ScudoThreadContext::QuarantineCachePlaceHolder)); + sizeof(ScudoTSD::QuarantineCachePlaceHolder)); -AllocatorCache *getAllocatorCache(ScudoThreadContext *ThreadContext) { - return &ThreadContext->Cache; -} - -ScudoQuarantineCache *getQuarantineCache(ScudoThreadContext *ThreadContext) { - return reinterpret_cast< - ScudoQuarantineCache *>(ThreadContext->QuarantineCachePlaceHolder); -} - -ScudoPrng *getPrng(ScudoThreadContext *ThreadContext) { - return &ThreadContext->Prng; +ScudoQuarantineCache *getQuarantineCache(ScudoTSD *TSD) { + return reinterpret_cast( + TSD->QuarantineCachePlaceHolder); } struct ScudoAllocator { @@ -381,12 +373,11 @@ struct ScudoAllocator { uptr AllocSize; if (FromPrimary) { AllocSize = AlignedSize; - ScudoThreadContext *ThreadContext = getThreadContextAndLock(); - if (LIKELY(ThreadContext)) { - Salt = getPrng(ThreadContext)->getU8(); - Ptr = BackendAllocator.allocatePrimary(getAllocatorCache(ThreadContext), - AllocSize); - ThreadContext->unlock(); + ScudoTSD *TSD = getTSDAndLock(); + if (LIKELY(TSD)) { + Salt = TSD->Prng.getU8(); + Ptr = BackendAllocator.allocatePrimary(&TSD->Cache, AllocSize); + TSD->unlock(); } else { SpinMutexLock l(&FallbackMutex); Salt = FallbackPrng.getU8(); @@ -454,11 +445,10 @@ struct ScudoAllocator { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); if (Header->FromPrimary) { - ScudoThreadContext *ThreadContext = getThreadContextAndLock(); - if (LIKELY(ThreadContext)) { - getBackendAllocator().deallocatePrimary( - getAllocatorCache(ThreadContext), Ptr); - ThreadContext->unlock(); + ScudoTSD *TSD = getTSDAndLock(); + if (LIKELY(TSD)) { + getBackendAllocator().deallocatePrimary(&TSD->Cache, Ptr); + TSD->unlock(); } else { SpinMutexLock Lock(&FallbackMutex); getBackendAllocator().deallocatePrimary(&FallbackAllocatorCache, Ptr); @@ -476,13 +466,12 @@ struct ScudoAllocator { UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); - ScudoThreadContext *ThreadContext = getThreadContextAndLock(); - if (LIKELY(ThreadContext)) { - AllocatorQuarantine.Put(getQuarantineCache(ThreadContext), - QuarantineCallback( - getAllocatorCache(ThreadContext)), + ScudoTSD *TSD = getTSDAndLock(); + if (LIKELY(TSD)) { + AllocatorQuarantine.Put(getQuarantineCache(TSD), + QuarantineCallback(&TSD->Cache), Chunk, EstimatedSize); - ThreadContext->unlock(); + TSD->unlock(); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, @@ -607,11 +596,10 @@ struct ScudoAllocator { return allocate(NMemB * Size, MinAlignment, FromMalloc, true); } - void commitBack(ScudoThreadContext *ThreadContext) { - AllocatorCache *Cache = getAllocatorCache(ThreadContext); - AllocatorQuarantine.Drain(getQuarantineCache(ThreadContext), - QuarantineCallback(Cache)); - BackendAllocator.destroyCache(Cache); + void commitBack(ScudoTSD *TSD) { + AllocatorQuarantine.Drain(getQuarantineCache(TSD), + QuarantineCallback(&TSD->Cache)); + BackendAllocator.destroyCache(&TSD->Cache); } uptr getStats(AllocatorStat StatType) { @@ -637,13 +625,13 @@ static void initScudoInternal(const AllocatorOptions &Options) { Instance.init(Options); } -void ScudoThreadContext::init() { +void ScudoTSD::init() { getBackendAllocator().initCache(&Cache); Prng.init(); memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder)); } -void ScudoThreadContext::commitBack() { +void ScudoTSD::commitBack() { Instance.commitBack(this); } diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index 4784f6a30..a3992e264 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -28,7 +28,7 @@ namespace __scudo { #include "scudo_tls_context_android.inc" #include "scudo_tls_context_linux.inc" -struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { +struct ALIGNED(64) ScudoTSD : public ScudoTSDPlatform { AllocatorCache Cache; ScudoPrng Prng; uptr QuarantineCachePlaceHolder[4]; @@ -38,7 +38,7 @@ struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { void initThread(bool MinimalInit); -// Platform specific dastpath functions definitions. +// Platform specific fastpath functions definitions. #include "scudo_tls_android.inc" #include "scudo_tls_linux.inc" diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp index c0ea417ab..3f215a72f 100644 --- a/lib/scudo/scudo_tls_android.cpp +++ b/lib/scudo/scudo_tls_android.cpp @@ -24,9 +24,9 @@ namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; static pthread_key_t PThreadKey; -static atomic_uint32_t ThreadContextCurrentIndex; -static ScudoThreadContext *ThreadContexts; -static uptr NumberOfContexts; +static atomic_uint32_t CurrentIndex; +static ScudoTSD *TSDs; +static u32 NumberOfTSDs; // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. static uptr getNumberOfCPUs() { @@ -42,52 +42,55 @@ static void initOnce() { // TODO(kostyak): remove and restrict to N and above. CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); initScudo(); - NumberOfContexts = getNumberOfCPUs(); - ThreadContexts = reinterpret_cast( - MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__)); - for (uptr i = 0; i < NumberOfContexts; i++) - ThreadContexts[i].init(); + NumberOfTSDs = getNumberOfCPUs(); + if (NumberOfTSDs == 0) + NumberOfTSDs = 1; + if (NumberOfTSDs > 32) + NumberOfTSDs = 32; + TSDs = reinterpret_cast( + MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); + for (u32 i = 0; i < NumberOfTSDs; i++) + TSDs[i].init(); } void initThread(bool MinimalInit) { pthread_once(&GlobalInitialized, initOnce); // Initial context assignment is done in a plain round-robin fashion. - u32 Index = atomic_fetch_add(&ThreadContextCurrentIndex, 1, - memory_order_relaxed); - ScudoThreadContext *ThreadContext = - &ThreadContexts[Index % NumberOfContexts]; - *get_android_tls_ptr() = reinterpret_cast(ThreadContext); + u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); + ScudoTSD *TSD = &TSDs[Index % NumberOfTSDs]; + *get_android_tls_ptr() = reinterpret_cast(TSD); } -ScudoThreadContext *getThreadContextAndLockSlow() { - ScudoThreadContext *ThreadContext; - // Go through all the contexts and find the first unlocked one. - for (u32 i = 0; i < NumberOfContexts; i++) { - ThreadContext = &ThreadContexts[i]; - if (ThreadContext->tryLock()) { - *get_android_tls_ptr() = reinterpret_cast(ThreadContext); - return ThreadContext; +ScudoTSD *getTSDAndLockSlow() { + ScudoTSD *TSD; + if (NumberOfTSDs > 1) { + // Go through all the contexts and find the first unlocked one. + for (u32 i = 0; i < NumberOfTSDs; i++) { + TSD = &TSDs[i]; + if (TSD->tryLock()) { + *get_android_tls_ptr() = reinterpret_cast(TSD); + return TSD; + } } - } - // No luck, find the one with the lowest precedence, and slow lock it. - u64 Precedence = UINT64_MAX; - for (u32 i = 0; i < NumberOfContexts; i++) { - u64 SlowLockPrecedence = ThreadContexts[i].getSlowLockPrecedence(); - if (SlowLockPrecedence && SlowLockPrecedence < Precedence) { - ThreadContext = &ThreadContexts[i]; - Precedence = SlowLockPrecedence; + // No luck, find the one with the lowest Precedence, and slow lock it. + u64 LowestPrecedence = UINT64_MAX; + for (u32 i = 0; i < NumberOfTSDs; i++) { + u64 Precedence = TSDs[i].getPrecedence(); + if (Precedence && Precedence < LowestPrecedence) { + TSD = &TSDs[i]; + LowestPrecedence = Precedence; + } + } + if (LIKELY(LowestPrecedence != UINT64_MAX)) { + TSD->lock(); + *get_android_tls_ptr() = reinterpret_cast(TSD); + return TSD; } } - if (LIKELY(Precedence != UINT64_MAX)) { - ThreadContext->lock(); - *get_android_tls_ptr() = reinterpret_cast(ThreadContext); - return ThreadContext; - } - // Last resort (can this happen?), stick with the current one. - ThreadContext = - reinterpret_cast(*get_android_tls_ptr()); - ThreadContext->lock(); - return ThreadContext; + // Last resort, stick with the current one. + TSD = reinterpret_cast(*get_android_tls_ptr()); + TSD->lock(); + return TSD; } } // namespace __scudo diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc index 6b82e49f5..9f3ef1a23 100644 --- a/lib/scudo/scudo_tls_android.inc +++ b/lib/scudo/scudo_tls_android.inc @@ -26,17 +26,16 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { initThread(MinimalInit); } -ScudoThreadContext *getThreadContextAndLockSlow(); +ScudoTSD *getTSDAndLockSlow(); -ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { - ScudoThreadContext *ThreadContext = - reinterpret_cast(*get_android_tls_ptr()); - CHECK(ThreadContext); +ALWAYS_INLINE ScudoTSD *getTSDAndLock() { + ScudoTSD *TSD = reinterpret_cast(*get_android_tls_ptr()); + CHECK(TSD); // Try to lock the currently associated context. - if (ThreadContext->tryLock()) - return ThreadContext; + if (TSD->tryLock()) + return TSD; // If it failed, go the slow path. - return getThreadContextAndLockSlow(); + return getTSDAndLockSlow(); } #endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_context_android.inc b/lib/scudo/scudo_tls_context_android.inc index f1951319d..4787ec7b6 100644 --- a/lib/scudo/scudo_tls_context_android.inc +++ b/lib/scudo/scudo_tls_context_android.inc @@ -20,33 +20,33 @@ #if SANITIZER_LINUX && SANITIZER_ANDROID -struct ScudoThreadContextPlatform { +struct ScudoTSDPlatform { INLINE bool tryLock() { if (Mutex.TryLock()) { - atomic_store_relaxed(&SlowLockPrecedence, 0); + atomic_store_relaxed(&Precedence, 0); return true; } - if (atomic_load_relaxed(&SlowLockPrecedence) == 0) - atomic_store_relaxed(&SlowLockPrecedence, NanoTime()); + if (atomic_load_relaxed(&Precedence) == 0) + atomic_store_relaxed(&Precedence, NanoTime()); return false; } INLINE void lock() { Mutex.Lock(); - atomic_store_relaxed(&SlowLockPrecedence, 0); + atomic_store_relaxed(&Precedence, 0); } INLINE void unlock() { Mutex.Unlock(); } - INLINE u64 getSlowLockPrecedence() { - return atomic_load_relaxed(&SlowLockPrecedence); + INLINE u64 getPrecedence() { + return atomic_load_relaxed(&Precedence); } private: StaticSpinMutex Mutex; - atomic_uint64_t SlowLockPrecedence; + atomic_uint64_t Precedence; }; #endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_context_linux.inc b/lib/scudo/scudo_tls_context_linux.inc index 8d292bdbc..9a24256f2 100644 --- a/lib/scudo/scudo_tls_context_linux.inc +++ b/lib/scudo/scudo_tls_context_linux.inc @@ -20,7 +20,7 @@ #if SANITIZER_LINUX && !SANITIZER_ANDROID -struct ScudoThreadContextPlatform { +struct ScudoTSDPlatform { ALWAYS_INLINE void unlock() {} }; diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index f2592266d..845539457 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -28,7 +28,7 @@ static pthread_key_t PThreadKey; __attribute__((tls_model("initial-exec"))) THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; __attribute__((tls_model("initial-exec"))) -THREADLOCAL ScudoThreadContext ThreadLocalContext; +THREADLOCAL ScudoTSD TSD; static void teardownThread(void *Ptr) { uptr I = reinterpret_cast(Ptr); @@ -43,7 +43,7 @@ static void teardownThread(void *Ptr) { reinterpret_cast(I - 1)) == 0)) return; } - ThreadLocalContext.commitBack(); + TSD.commitBack(); ScudoThreadState = ThreadTornDown; } @@ -59,7 +59,7 @@ void initThread(bool MinimalInit) { return; CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( GetPthreadDestructorIterations())), 0); - ThreadLocalContext.init(); + TSD.init(); ScudoThreadState = ThreadInitialized; } diff --git a/lib/scudo/scudo_tls_linux.inc b/lib/scudo/scudo_tls_linux.inc index 53b804485..492807c58 100644 --- a/lib/scudo/scudo_tls_linux.inc +++ b/lib/scudo/scudo_tls_linux.inc @@ -29,7 +29,7 @@ enum ThreadState : u8 { __attribute__((tls_model("initial-exec"))) extern THREADLOCAL ThreadState ScudoThreadState; __attribute__((tls_model("initial-exec"))) -extern THREADLOCAL ScudoThreadContext ThreadLocalContext; +extern THREADLOCAL ScudoTSD TSD; ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { if (LIKELY(ScudoThreadState != ThreadNotInitialized)) @@ -37,10 +37,10 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { initThread(MinimalInit); } -ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { +ALWAYS_INLINE ScudoTSD *getTSDAndLock() { if (UNLIKELY(ScudoThreadState != ThreadInitialized)) return nullptr; - return &ThreadLocalContext; + return &TSD; } #endif // SANITIZER_LINUX && !SANITIZER_ANDROID -- cgit v1.2.1 From 4401e9e8e146773064d65b2c2e266bc4d3223fd7 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 22 Sep 2017 17:48:24 +0000 Subject: Removed platform-specific ifdefs from sanitizer_procmaps.h Summary: Removed platform-specific ifdefs for linux, mac, freebsd and netbsd from sanitizer_procmaps.h Patch by Yicheng Wang Reviewers: kcc, kubamracek, alekseyshl, fjricci, vitalybuka Reviewed By: fjricci, vitalybuka Subscribers: vitalybuka, emaste, krytarowski, llvm-commits Differential Revision: https://reviews.llvm.org/D38098 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@313999 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux.h | 13 +++ lib/sanitizer_common/sanitizer_mac.h | 11 +++ lib/sanitizer_common/sanitizer_procmaps.h | 32 +------ lib/sanitizer_common/sanitizer_procmaps_common.cc | 37 ++++---- lib/sanitizer_common/sanitizer_procmaps_freebsd.cc | 10 +- lib/sanitizer_common/sanitizer_procmaps_linux.cc | 60 ++++++------ lib/sanitizer_common/sanitizer_procmaps_mac.cc | 101 +++++++++++---------- 7 files changed, 132 insertions(+), 132 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index cbe2f17f4..88cac33d8 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -28,6 +28,19 @@ namespace __sanitizer { // the one in , which is used by readdir(). struct linux_dirent; +struct ProcSelfMapsBuff { + char *data; + uptr mmaped_size; + uptr len; +}; + +struct MemoryMappingLayoutData { + ProcSelfMapsBuff proc_self_maps; + const char *current; +}; + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps); + // Syscall wrappers. uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); uptr internal_sigaltstack(const void* ss, void* oss); diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h index 3f1c68c86..60febefd5 100644 --- a/lib/sanitizer_common/sanitizer_mac.h +++ b/lib/sanitizer_common/sanitizer_mac.h @@ -20,6 +20,17 @@ namespace __sanitizer { +struct MemoryMappingLayoutData { + int current_image; + u32 current_magic; + u32 current_filetype; + ModuleArch current_arch; + u8 current_uuid[kModuleUUIDSize]; + int current_load_cmd_count; + char *current_load_cmd_addr; + bool current_instrumented; +}; + enum MacosVersion { MACOS_VERSION_UNINITIALIZED = 0, MACOS_VERSION_UNKNOWN, diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 20b93c1d2..0e2deb2a2 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -16,20 +16,12 @@ #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_linux.h" +#include "sanitizer_mac.h" #include "sanitizer_mutex.h" namespace __sanitizer { -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -struct ProcSelfMapsBuff { - char *data; - uptr mmaped_size; - uptr len; -}; - -// Reads process memory map in an OS-specific way. -void ReadProcMaps(ProcSelfMapsBuff *proc_maps); -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD // Memory protection masks. static const uptr kProtectionRead = 1; @@ -87,25 +79,7 @@ class MemoryMappingLayout { // FIXME: Hide implementation details for different platforms in // platform-specific files. -# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD - ProcSelfMapsBuff proc_self_maps_; - const char *current_; - - // Static mappings cache. - static ProcSelfMapsBuff cached_proc_self_maps_; - static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_. -# elif SANITIZER_MAC - template - bool NextSegmentLoad(MemoryMappedSegment *segment); - int current_image_; - u32 current_magic_; - u32 current_filetype_; - ModuleArch current_arch_; - u8 current_uuid_[kModuleUUIDSize]; - int current_load_cmd_count_; - char *current_load_cmd_addr_; - bool current_instrumented_; -# endif + MemoryMappingLayoutData data_; }; typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index c4daf0497..30663e8c6 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -20,9 +20,8 @@ namespace __sanitizer { -// Linker initialized. -ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_; -StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized. +static ProcSelfMapsBuff cached_proc_self_maps; +static StaticSpinMutex cache_lock; static int TranslateDigit(char c) { if (c >= '0' && c <= '9') @@ -71,14 +70,14 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { } MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { - ReadProcMaps(&proc_self_maps_); + ReadProcMaps(&data_.proc_self_maps); if (cache_enabled) { - if (proc_self_maps_.mmaped_size == 0) { + if (data_.proc_self_maps.mmaped_size == 0) { LoadFromCache(); - CHECK_GT(proc_self_maps_.len, 0); + CHECK_GT(data_.proc_self_maps.len, 0); } } else { - CHECK_GT(proc_self_maps_.mmaped_size, 0); + CHECK_GT(data_.proc_self_maps.mmaped_size, 0); } Reset(); // FIXME: in the future we may want to cache the mappings on demand only. @@ -89,24 +88,22 @@ MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { MemoryMappingLayout::~MemoryMappingLayout() { // Only unmap the buffer if it is different from the cached one. Otherwise // it will be unmapped when the cache is refreshed. - if (proc_self_maps_.data != cached_proc_self_maps_.data) { - UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size); + if (data_.proc_self_maps.data != cached_proc_self_maps.data) { + UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size); } } -void MemoryMappingLayout::Reset() { - current_ = proc_self_maps_.data; -} +void MemoryMappingLayout::Reset() { data_.current = data_.proc_self_maps.data; } // static void MemoryMappingLayout::CacheMemoryMappings() { - SpinMutexLock l(&cache_lock_); + SpinMutexLock l(&cache_lock); // Don't invalidate the cache if the mappings are unavailable. ProcSelfMapsBuff old_proc_self_maps; - old_proc_self_maps = cached_proc_self_maps_; - ReadProcMaps(&cached_proc_self_maps_); - if (cached_proc_self_maps_.mmaped_size == 0) { - cached_proc_self_maps_ = old_proc_self_maps; + old_proc_self_maps = cached_proc_self_maps; + ReadProcMaps(&cached_proc_self_maps); + if (cached_proc_self_maps.mmaped_size == 0) { + cached_proc_self_maps = old_proc_self_maps; } else { if (old_proc_self_maps.mmaped_size) { UnmapOrDie(old_proc_self_maps.data, @@ -116,9 +113,9 @@ void MemoryMappingLayout::CacheMemoryMappings() { } void MemoryMappingLayout::LoadFromCache() { - SpinMutexLock l(&cache_lock_); - if (cached_proc_self_maps_.data) { - proc_self_maps_ = cached_proc_self_maps_; + SpinMutexLock l(&cache_lock); + if (cached_proc_self_maps.data) { + data_.proc_self_maps = cached_proc_self_maps; } } diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc index 3c7b98d6b..c26a6d47e 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc @@ -67,9 +67,9 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { } bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - char *last = proc_self_maps_.data + proc_self_maps_.len; - if (current_ >= last) return false; - struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_; + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry *)data_.current; segment->start = (uptr)VmEntry->kve_start; segment->end = (uptr)VmEntry->kve_end; @@ -90,9 +90,9 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } #if SANITIZER_FREEBSD - current_ += VmEntry->kve_structsize; + data_.current += VmEntry->kve_structsize; #else - current_ += sizeof(*VmEntry); + data_.current += sizeof(*VmEntry); #endif return true; diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc index 1bcad2bf7..ac894eb3a 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -27,48 +27,48 @@ static bool IsOneOf(char c, char c1, char c2) { } bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - char *last = proc_self_maps_.data + proc_self_maps_.len; - if (current_ >= last) return false; - char *next_line = (char*)internal_memchr(current_, '\n', last - current_); + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + char *next_line = + (char *)internal_memchr(data_.current, '\n', last - data_.current); if (next_line == 0) next_line = last; // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar - segment->start = ParseHex(¤t_); - CHECK_EQ(*current_++, '-'); - segment->end = ParseHex(¤t_); - CHECK_EQ(*current_++, ' '); - CHECK(IsOneOf(*current_, '-', 'r')); + segment->start = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, '-'); + segment->end = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + CHECK(IsOneOf(*data_.current, '-', 'r')); segment->protection = 0; - if (*current_++ == 'r') segment->protection |= kProtectionRead; - CHECK(IsOneOf(*current_, '-', 'w')); - if (*current_++ == 'w') segment->protection |= kProtectionWrite; - CHECK(IsOneOf(*current_, '-', 'x')); - if (*current_++ == 'x') segment->protection |= kProtectionExecute; - CHECK(IsOneOf(*current_, 's', 'p')); - if (*current_++ == 's') segment->protection |= kProtectionShared; - CHECK_EQ(*current_++, ' '); - segment->offset = ParseHex(¤t_); - CHECK_EQ(*current_++, ' '); - ParseHex(¤t_); - CHECK_EQ(*current_++, ':'); - ParseHex(¤t_); - CHECK_EQ(*current_++, ' '); - while (IsDecimal(*current_)) - current_++; + if (*data_.current++ == 'r') segment->protection |= kProtectionRead; + CHECK(IsOneOf(*data_.current, '-', 'w')); + if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; + CHECK(IsOneOf(*data_.current, '-', 'x')); + if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; + CHECK(IsOneOf(*data_.current, 's', 'p')); + if (*data_.current++ == 's') segment->protection |= kProtectionShared; + CHECK_EQ(*data_.current++, ' '); + segment->offset = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ':'); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + while (IsDecimal(*data_.current)) data_.current++; // Qemu may lack the trailing space. // https://github.com/google/sanitizers/issues/160 - // CHECK_EQ(*current_++, ' '); + // CHECK_EQ(*data_.current++, ' '); // Skip spaces. - while (current_ < next_line && *current_ == ' ') - current_++; + while (data_.current < next_line && *data_.current == ' ') data_.current++; // Fill in the filename. if (segment->filename) { - uptr len = Min((uptr)(next_line - current_), segment->filename_size - 1); - internal_strncpy(segment->filename, current_, len); + uptr len = + Min((uptr)(next_line - data_.current), segment->filename_size - 1); + internal_strncpy(segment->filename, data_.current, len); segment->filename[len] = 0; } - current_ = next_line + 1; + data_.current = next_line + 1; return true; } diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 106294cac..786876f04 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -108,13 +108,13 @@ void MemoryMappingLayout::Reset() { // _dyld_image_count is thread-unsafe. We need to register callbacks for // adding and removing images which will invalidate the MemoryMappingLayout // state. - current_image_ = _dyld_image_count(); - current_load_cmd_count_ = -1; - current_load_cmd_addr_ = 0; - current_magic_ = 0; - current_filetype_ = 0; - current_arch_ = kModuleArchUnknown; - internal_memset(current_uuid_, 0, kModuleUUIDSize); + data_.current_image = _dyld_image_count(); + data_.current_load_cmd_count = -1; + data_.current_load_cmd_addr = 0; + data_.current_magic = 0; + data_.current_filetype = 0; + data_.current_arch = kModuleArchUnknown; + internal_memset(data_.current_uuid, 0, kModuleUUIDSize); } // The dyld load address should be unchanged throughout process execution, @@ -183,14 +183,14 @@ const mach_header *get_dyld_hdr() { // segment. // Note that the segment addresses are not necessarily sorted. template -bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { - const char *lc = current_load_cmd_addr_; - current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; +static bool NextSegmentLoad(MemoryMappedSegment *segment, +MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) { + const char *lc = layout_data.current_load_cmd_addr; + layout_data.current_load_cmd_addr += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - uptr base_virt_addr, addr_mask; - if (current_image_ == kDyldImageIdx) { + if (layout_data.current_image == kDyldImageIdx) { base_virt_addr = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. @@ -200,37 +200,40 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) { // and the mask will give just this offset. addr_mask = 0xfffff; } else { - base_virt_addr = (uptr)_dyld_get_image_vmaddr_slide(current_image_); + base_virt_addr = + (uptr)_dyld_get_image_vmaddr_slide(layout_data.current_image); addr_mask = ~0; } + segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; segment->end = segment->start + sc->vmsize; - // Most callers don't need section information, so only fill this struct // when required. - if (segment->data_) { - segment->data_->nsects = sc->nsects; - segment->data_->current_load_cmd_addr = + if (seg_data) { + seg_data->nsects = sc->nsects; + seg_data->current_load_cmd_addr = (char *)lc + sizeof(SegmentCommand); - segment->data_->lc_type = kLCSegment; - segment->data_->base_virt_addr = base_virt_addr; - segment->data_->addr_mask = addr_mask; - internal_strncpy(segment->data_->name, sc->segname, - ARRAY_SIZE(segment->data_->name)); + seg_data->lc_type = kLCSegment; + seg_data->base_virt_addr = base_virt_addr; + seg_data->addr_mask = addr_mask; + internal_strncpy(seg_data->name, sc->segname, + ARRAY_SIZE(seg_data->name)); } // Return the initial protection. segment->protection = sc->initprot; - segment->offset = - (current_filetype_ == /*MH_EXECUTE*/ 0x2) ? sc->vmaddr : sc->fileoff; + segment->offset = (layout_data.current_filetype == + /*MH_EXECUTE*/ 0x2) + ? sc->vmaddr + : sc->fileoff; if (segment->filename) { - const char *src = (current_image_ == kDyldImageIdx) + const char *src = (layout_data.current_image == kDyldImageIdx) ? kDyldPath - : _dyld_get_image_name(current_image_); + : _dyld_get_image_name(layout_data.current_image); internal_strncpy(segment->filename, src, segment->filename_size); } - segment->arch = current_arch_; - internal_memcpy(segment->uuid, current_uuid_, kModuleUUIDSize); + segment->arch = layout_data.current_arch; + internal_memcpy(segment->uuid, layout_data.current_uuid, kModuleUUIDSize); return true; } return false; @@ -292,50 +295,52 @@ static bool IsModuleInstrumented(const load_command *first_lc) { } bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - for (; current_image_ >= kDyldImageIdx; current_image_--) { - const mach_header *hdr = (current_image_ == kDyldImageIdx) + for (; data_.current_image >= kDyldImageIdx; data_.current_image--) { + const mach_header *hdr = (data_.current_image == kDyldImageIdx) ? get_dyld_hdr() - : _dyld_get_image_header(current_image_); + : _dyld_get_image_header(data_.current_image); if (!hdr) continue; - if (current_load_cmd_count_ < 0) { + if (data_.current_load_cmd_count < 0) { // Set up for this image; - current_load_cmd_count_ = hdr->ncmds; - current_magic_ = hdr->magic; - current_filetype_ = hdr->filetype; - current_arch_ = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); - switch (current_magic_) { + data_.current_load_cmd_count = hdr->ncmds; + data_.current_magic = hdr->magic; + data_.current_filetype = hdr->filetype; + data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); + switch (data_.current_magic) { #ifdef MH_MAGIC_64 case MH_MAGIC_64: { - current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64); + data_.current_load_cmd_addr = (char *)hdr + sizeof(mach_header_64); break; } #endif case MH_MAGIC: { - current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header); + data_.current_load_cmd_addr = (char *)hdr + sizeof(mach_header); break; } default: { continue; } } - FindUUID((const load_command *)current_load_cmd_addr_, ¤t_uuid_[0]); - current_instrumented_ = - IsModuleInstrumented((const load_command *)current_load_cmd_addr_); + FindUUID((const load_command *)data_.current_load_cmd_addr, + data_.current_uuid); + data_.current_instrumented = IsModuleInstrumented( + (const load_command *)data_.current_load_cmd_addr); } - for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) { - switch (current_magic_) { - // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64. + for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) { + switch (data_.current_magic) { + // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64. #ifdef MH_MAGIC_64 case MH_MAGIC_64: { if (NextSegmentLoad( - segment)) + segment, segment->data_, data_)) return true; break; } #endif case MH_MAGIC: { - if (NextSegmentLoad(segment)) + if (NextSegmentLoad( + segment, segment->data_, data_)) return true; break; } @@ -364,7 +369,7 @@ void MemoryMappingLayout::DumpListOfModules( modules->push_back(LoadedModule()); cur_module = &modules->back(); cur_module->set(segment.filename, segment.start, segment.arch, - segment.uuid, current_instrumented_); + segment.uuid, data_.current_instrumented); } segment.AddAddressRanges(cur_module); } -- cgit v1.2.1 From b5edc3e43f30a5dec99834dbd9b20cddc42039a3 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 22 Sep 2017 18:17:26 +0000 Subject: Fix windows buildbot broken by r313999 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314001 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 1 + lib/sanitizer_common/sanitizer_win.h | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 0e2deb2a2..a066cb721 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -19,6 +19,7 @@ #include "sanitizer_linux.h" #include "sanitizer_mac.h" #include "sanitizer_mutex.h" +#include "sanitizer_win.h" namespace __sanitizer { diff --git a/lib/sanitizer_common/sanitizer_win.h b/lib/sanitizer_common/sanitizer_win.h index 23e01ab75..515792054 100644 --- a/lib/sanitizer_common/sanitizer_win.h +++ b/lib/sanitizer_common/sanitizer_win.h @@ -20,6 +20,7 @@ namespace __sanitizer { // Check based on flags if we should handle the exception. bool IsHandledDeadlyException(DWORD exceptionCode); +struct MemoryMappingLayoutData {}; } // namespace __sanitizer #endif // SANITIZER_WINDOWS -- cgit v1.2.1 From fa06689f9e24187eebc71b182e9b55a81a39bc79 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 18:31:37 +0000 Subject: [sanitizer] Move CommonSanitizerReportMutex from _print.cc to _common.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314006 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.cc | 2 ++ lib/sanitizer_common/sanitizer_printf.cc | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 87e04240a..970b11c00 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -34,6 +34,8 @@ uptr stoptheworld_tracer_pid = 0; // writing to the same log file. uptr stoptheworld_tracer_ppid = 0; +StaticSpinMutex CommonSanitizerReportMutex; + void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, const char *mmap_type, error_t err, bool raw_report) { diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index a44cfae40..5c2360043 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -28,8 +28,6 @@ namespace __sanitizer { -StaticSpinMutex CommonSanitizerReportMutex; - static int AppendChar(char **buff, const char *buff_end, char c) { if (*buff < buff_end) { **buff = c; -- cgit v1.2.1 From 106ad97baa50902f586a3b513fab86760ad73705 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 18:31:51 +0000 Subject: [asan] Fix unlocking order for CommonSanitizerReportMutex and reporting_thread_tid_ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314007 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 8523a74a3..d832633db 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -205,8 +205,8 @@ class ScopedInErrorReport { Die(); } - atomic_store_relaxed(&reporting_thread_tid_, kUnclaimedTid); CommonSanitizerReportMutex.Unlock(); + atomic_store_relaxed(&reporting_thread_tid_, kUnclaimedTid); } void ReportError(const ErrorDescription &description) { -- cgit v1.2.1 From 13b2b2b8855fd5eadff25fc0a1a9e54152154557 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 18:32:05 +0000 Subject: [sanitizer] Move report locking code from asan into common git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314008 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 55 +++++++------------------------- lib/sanitizer_common/sanitizer_common.cc | 36 +++++++++++++++++++++ lib/sanitizer_common/sanitizer_common.h | 8 +++++ 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index d832633db..9536ead66 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -125,34 +125,16 @@ class ScopedInErrorReport { static const u32 kUnclaimedTid = 0xfffffe; static_assert(kUnclaimedTid != kInvalidTid, "Must be different"); - explicit ScopedInErrorReport(bool fatal = false) { - halt_on_error_ = fatal || flags()->halt_on_error; - u32 current_tid = GetCurrentTidOrInvalid(); - - for (;;) { - u32 expected_tid = kUnclaimedTid; - if (atomic_compare_exchange_strong(&reporting_thread_tid_, &expected_tid, - current_tid, memory_order_relaxed)) { - // We've claimed reporting_thread_tid_ so proceed. - StartReporting(); - return; - } - - if (expected_tid == current_tid) { - // This is either asynch signal or nested error during error reporting. - // Fail simple to avoid deadlocks in Report(). - - // Can't use Report() here because of potential deadlocks in nested - // signal handlers. - static const char msg[] = - "AddressSanitizer: nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); - - internal__exit(common_flags()->exitcode); - } - - SleepForMillis(100); - } + explicit ScopedInErrorReport(bool fatal = false) + : error_report_lock_(GetCurrentTidOrInvalid()), + halt_on_error_(fatal || flags()->halt_on_error) { + // Make sure the registry and sanitizer report mutexes are locked while + // we're printing an error report. + // We can lock them only here to avoid self-deadlock in case of + // recursive reports. + asanThreadRegistry().Lock(); + Printf( + "=================================================================\n"); } ~ScopedInErrorReport() { @@ -204,9 +186,6 @@ class ScopedInErrorReport { Report("ABORTING\n"); Die(); } - - CommonSanitizerReportMutex.Unlock(); - atomic_store_relaxed(&reporting_thread_tid_, kUnclaimedTid); } void ReportError(const ErrorDescription &description) { @@ -220,25 +199,13 @@ class ScopedInErrorReport { } private: - void StartReporting() { - CommonSanitizerReportMutex.Lock(); - // Make sure the registry and sanitizer report mutexes are locked while - // we're printing an error report. - // We can lock them only here to avoid self-deadlock in case of - // recursive reports. - asanThreadRegistry().Lock(); - Printf( - "=================================================================\n"); - } - - static atomic_uint32_t reporting_thread_tid_; + ScopedErrorReportLock error_report_lock_; // Error currently being reported. This enables the destructor to interact // with the debugger and point it to an error description. static ErrorDescription current_error_; bool halt_on_error_; }; -atomic_uint32_t ScopedInErrorReport::reporting_thread_tid_ = {kUnclaimedTid}; ErrorDescription ScopedInErrorReport::current_error_; void ReportDeadlySignal(const SignalContext &sig) { diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 970b11c00..c31f4e3a6 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -348,6 +348,42 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), return 0; } +static const u32 kUnclaimedTid = 0xfffffe; +static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid}; + +ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { + for (;;) { + u32 expected_tid = kUnclaimedTid; + if (current_tid == kUnclaimedTid || + atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid, + current_tid, memory_order_relaxed)) { + // We've claimed reporting_thread_tid_ so proceed. + CommonSanitizerReportMutex.Lock(); + return; + } + + if (expected_tid == current_tid) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + static const char msg[] = + "AddressSanitizer: nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + internal_sched_yield(); + } +} + +ScopedErrorReportLock::~ScopedErrorReportLock() { + CommonSanitizerReportMutex.Unlock(); + atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid); +} + } // namespace __sanitizer using namespace __sanitizer; // NOLINT diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 75508cbe4..e2e2224d4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -205,8 +205,16 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)); } while (0) // Can be used to prevent mixing error reports from different sanitizers. +// FIXME: Replace with ScopedErrorReportLock and hide. extern StaticSpinMutex CommonSanitizerReportMutex; +// Lock sanitizer error reporting and protects against nested errors. +class ScopedErrorReportLock { + public: + explicit ScopedErrorReportLock(u32 current_tid); + ~ScopedErrorReportLock(); +}; + extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; -- cgit v1.2.1 From b774cd86d3c200831da6e80aac59f6e20c786ccd Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 22 Sep 2017 18:49:56 +0000 Subject: Deflake the "xpc-race.mm" test. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314014 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/Darwin/xpc-race.mm | 53 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm index a1e214c12..872c9ee73 100644 --- a/test/tsan/Darwin/xpc-race.mm +++ b/test/tsan/Darwin/xpc-race.mm @@ -1,22 +1,26 @@ -// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %clangxx_tsan %s -o %t -framework Foundation // RUN: %deflake %run %t 2>&1 | FileCheck %s // UNSUPPORTED: ios #import #import +#import #import "../test.h" long global; -long received_msgs; +_Atomic(long) msg_counter; +_Atomic(long) processed_msgs; xpc_connection_t server_conn; xpc_connection_t client_conns[2]; int main(int argc, const char *argv[]) { @autoreleasepool { - NSLog(@"Hello world."); + fprintf(stderr, "Hello world.\n"); + // CHECK: Hello world. + barrier_init(&barrier, 2); dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT); @@ -24,21 +28,34 @@ int main(int argc, const char *argv[]) { server_conn = xpc_connection_create(NULL, server_q); xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) { - NSLog(@"server event handler, client = %@", client); + fprintf(stderr, "server event handler, client = %p\n", client); if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) { return; } xpc_connection_set_event_handler(client, ^(xpc_object_t object) { - NSLog(@"received message: %@", object); + fprintf(stderr, "received message: %p\n", object); - barrier_wait(&barrier); - global = 42; + long msg_number = atomic_fetch_add_explicit(&msg_counter, 1, memory_order_relaxed); - dispatch_sync(dispatch_get_main_queue(), ^{ - received_msgs++; + if (msg_number == 0) + barrier_wait(&barrier); + + global++; + // CHECK: WARNING: ThreadSanitizer: data race + // CHECK: Write of size 8 + // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-3]] + // CHECK: Previous write of size 8 + // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-5]] + // CHECK: Location is global 'global' + + if (msg_number == 1) + barrier_wait(&barrier); - if (received_msgs >= 2) { + atomic_fetch_add(&processed_msgs, 1); + + dispatch_sync(dispatch_get_main_queue(), ^{ + if (processed_msgs >= 2) { xpc_connection_cancel(client_conns[0]); xpc_connection_cancel(client_conns[1]); xpc_connection_cancel(server_conn); @@ -55,12 +72,12 @@ int main(int argc, const char *argv[]) { for (int i = 0; i < 2; i++) { client_conns[i] = xpc_connection_create_from_endpoint(endpoint); xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) { - NSLog(@"client event handler, event = %@", event); + fprintf(stderr, "client event handler, event = %p\n", event); }); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_string(msg, "hello", "world"); - NSLog(@"sending message: %@", msg); + fprintf(stderr, "sending message: %p\n", msg); xpc_connection_send_message(client_conns[i], msg); xpc_connection_resume(client_conns[i]); @@ -68,16 +85,8 @@ int main(int argc, const char *argv[]) { CFRunLoopRun(); - NSLog(@"Done."); + fprintf(stderr, "Done.\n"); + // CHECK: Done. } return 0; } - -// CHECK: Hello world. -// CHECK: WARNING: ThreadSanitizer: data race -// CHECK: Write of size 8 -// CHECK: #0 {{.*}}xpc-race.mm:36 -// CHECK: Previous write of size 8 -// CHECK: #0 {{.*}}xpc-race.mm:36 -// CHECK: Location is global 'global' -// CHECK: Done. -- cgit v1.2.1 From 988561edd4724ff5c78fd0a6c8a8bc3d86546f38 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 18:50:18 +0000 Subject: [sanitizer] Replace AddressSanitizer with correct tool name git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314015 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index c31f4e3a6..e5ae1a9f1 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -368,8 +368,9 @@ ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { // Can't use Report() here because of potential deadlocks in nested // signal handlers. - static const char msg[] = - "AddressSanitizer: nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(SanitizerToolName, + internal_strlen(SanitizerToolName)); + static const char msg[] = ": nested bug in the same thread, aborting.\n"; CatastrophicErrorWrite(msg, sizeof(msg) - 1); internal__exit(common_flags()->exitcode); -- cgit v1.2.1 From feeabcf3b98ef72cdbd24c5b98db1e41ec53e219 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 22 Sep 2017 19:22:08 +0000 Subject: Fix fuchsia builds broken by r313999 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314021 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_fuchsia.h | 4 ++++ lib/sanitizer_common/sanitizer_procmaps.h | 1 + 2 files changed, 5 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_fuchsia.h b/lib/sanitizer_common/sanitizer_fuchsia.h index 18821b4fd..48d7154f3 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.h +++ b/lib/sanitizer_common/sanitizer_fuchsia.h @@ -25,6 +25,10 @@ namespace __sanitizer { extern uptr MainThreadStackBase, MainThreadStackSize; extern sanitizer_shadow_bounds_t ShadowBounds; +// TODO(fjricci) Remove this struct by refactoring common functions +// out of sanitizer_procmaps.h +struct MemoryMappingLayoutData {}; + } // namespace __sanitizer #endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index a066cb721..395688c3e 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -16,6 +16,7 @@ #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_fuchsia.h" #include "sanitizer_linux.h" #include "sanitizer_mac.h" #include "sanitizer_mutex.h" -- cgit v1.2.1 From 9b376627e371c9d879a8ba4d38aaa0638c9f0d58 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 22:36:11 +0000 Subject: [sanitizer] Move ScopedErrorReportLock into libcdep version git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314039 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.cc | 37 ------------------------ lib/sanitizer_common/sanitizer_common_libcdep.cc | 37 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index e5ae1a9f1..970b11c00 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -348,43 +348,6 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), return 0; } -static const u32 kUnclaimedTid = 0xfffffe; -static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid}; - -ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { - for (;;) { - u32 expected_tid = kUnclaimedTid; - if (current_tid == kUnclaimedTid || - atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid, - current_tid, memory_order_relaxed)) { - // We've claimed reporting_thread_tid_ so proceed. - CommonSanitizerReportMutex.Lock(); - return; - } - - if (expected_tid == current_tid) { - // This is either asynch signal or nested error during error reporting. - // Fail simple to avoid deadlocks in Report(). - - // Can't use Report() here because of potential deadlocks in nested - // signal handlers. - CatastrophicErrorWrite(SanitizerToolName, - internal_strlen(SanitizerToolName)); - static const char msg[] = ": nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); - - internal__exit(common_flags()->exitcode); - } - - internal_sched_yield(); - } -} - -ScopedErrorReportLock::~ScopedErrorReportLock() { - CommonSanitizerReportMutex.Unlock(); - atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid); -} - } // namespace __sanitizer using namespace __sanitizer; // NOLINT diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 69dd93d87..ce6bff447 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -286,6 +286,43 @@ void MaybeStartBackgroudThread() { #endif } +static const u32 kUnclaimedTid = 0xfffffe; +static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid}; + +ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { + for (;;) { + u32 expected_tid = kUnclaimedTid; + if (current_tid == kUnclaimedTid || + atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid, + current_tid, memory_order_relaxed)) { + // We've claimed reporting_thread_tid_ so proceed. + CommonSanitizerReportMutex.Lock(); + return; + } + + if (expected_tid == current_tid) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + CatastrophicErrorWrite(SanitizerToolName, + internal_strlen(SanitizerToolName)); + static const char msg[] = ": nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + internal_sched_yield(); + } +} + +ScopedErrorReportLock::~ScopedErrorReportLock() { + CommonSanitizerReportMutex.Unlock(); + atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid); +} + } // namespace __sanitizer SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, -- cgit v1.2.1 From 4365a0449cc7cba181357669774caf835f2ef9dd Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 22:36:21 +0000 Subject: [sanitizer] Replace thread id with GetThreadSelf This allows to avoid constructor parameter git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314040 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_report.cc | 6 +----- lib/sanitizer_common/sanitizer_common.h | 2 +- lib/sanitizer_common/sanitizer_common_libcdep.cc | 19 +++++++++---------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index 9536ead66..cda93f3e6 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -122,12 +122,8 @@ bool ParseFrameDescription(const char *frame_descr, // immediately after printing error report. class ScopedInErrorReport { public: - static const u32 kUnclaimedTid = 0xfffffe; - static_assert(kUnclaimedTid != kInvalidTid, "Must be different"); - explicit ScopedInErrorReport(bool fatal = false) - : error_report_lock_(GetCurrentTidOrInvalid()), - halt_on_error_(fatal || flags()->halt_on_error) { + : halt_on_error_(fatal || flags()->halt_on_error) { // Make sure the registry and sanitizer report mutexes are locked while // we're printing an error report. // We can lock them only here to avoid self-deadlock in case of diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index e2e2224d4..4a6b58d39 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -211,7 +211,7 @@ extern StaticSpinMutex CommonSanitizerReportMutex; // Lock sanitizer error reporting and protects against nested errors. class ScopedErrorReportLock { public: - explicit ScopedErrorReportLock(u32 current_tid); + ScopedErrorReportLock(); ~ScopedErrorReportLock(); }; diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index ce6bff447..b10eaeb96 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -286,21 +286,20 @@ void MaybeStartBackgroudThread() { #endif } -static const u32 kUnclaimedTid = 0xfffffe; -static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid}; +static atomic_uintptr_t reporting_thread = {0}; -ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { +ScopedErrorReportLock::ScopedErrorReportLock() { + uptr current = GetThreadSelf(); for (;;) { - u32 expected_tid = kUnclaimedTid; - if (current_tid == kUnclaimedTid || - atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid, - current_tid, memory_order_relaxed)) { - // We've claimed reporting_thread_tid_ so proceed. + uptr expected = 0; + if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, + memory_order_relaxed)) { + // We've claimed reporting_thread so proceed. CommonSanitizerReportMutex.Lock(); return; } - if (expected_tid == current_tid) { + if (expected == current) { // This is either asynch signal or nested error during error reporting. // Fail simple to avoid deadlocks in Report(). @@ -320,7 +319,7 @@ ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) { ScopedErrorReportLock::~ScopedErrorReportLock() { CommonSanitizerReportMutex.Unlock(); - atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid); + atomic_store_relaxed(&reporting_thread, 0); } } // namespace __sanitizer -- cgit v1.2.1 From 67a6c824cb6d0ab2c7b961f8e482bc1aedad3c27 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 22:57:48 +0000 Subject: [lsan] Deadly signal handler for lsan Summary: Part of https://github.com/google/sanitizers/issues/637 Reviewers: eugenis, alekseyshl Subscribers: llvm-commits, dberris, kubamracek, krytarowski Differential Revision: https://reviews.llvm.org/D37608 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314041 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan.cc | 13 +++++++++++++ lib/lsan/lsan_interceptors.cc | 5 +++++ lib/sanitizer_common/sanitizer_common.h | 11 ++++++++++- lib/sanitizer_common/sanitizer_common_libcdep.cc | 12 ++++++++++++ test/sanitizer_common/TestCases/Linux/allow_user_segv.cc | 1 - test/sanitizer_common/TestCases/Linux/assert.cc | 4 ++-- test/sanitizer_common/TestCases/Linux/ill.cc | 3 +-- .../TestCases/Posix/dedup_token_length_test.cc | 1 - .../TestCases/Posix/dump_instruction_bytes.cc | 5 ++++- test/sanitizer_common/TestCases/Posix/fpe.cc | 1 - .../TestCases/Posix/sanitizer_set_report_fd_test.cc | 1 - 11 files changed, 47 insertions(+), 10 deletions(-) diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc index 6c4767d61..a51a63ba8 100644 --- a/lib/lsan/lsan.cc +++ b/lib/lsan/lsan.cc @@ -65,6 +65,18 @@ static void InitializeFlags() { if (common_flags()->help) parser.PrintFlagDescriptions(); } +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp, + sig.context, + common_flags()->fast_unwind_on_fatal); +} + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, + nullptr); +} + extern "C" void __lsan_init() { CHECK(!lsan_init_is_running); if (lsan_inited) @@ -80,6 +92,7 @@ extern "C" void __lsan_init() { InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); + InstallDeadlySignalHandlers(LsanOnDeadlySignal); u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); ThreadStart(tid, GetTid()); diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc index 259c138ec..a7c0f72f6 100644 --- a/lib/lsan/lsan_interceptors.cc +++ b/lib/lsan/lsan_interceptors.cc @@ -401,9 +401,14 @@ INTERCEPTOR(void, _exit, int status) { REAL(_exit)(status); } +#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) +#include "sanitizer_common/sanitizer_signal_interceptors.inc" + namespace __lsan { void InitializeInterceptors() { + InitializeSignalInterceptors(); + INTERCEPT_FUNCTION(malloc); INTERCEPT_FUNCTION(free); LSAN_MAYBE_INTERCEPT_CFREE; diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 4a6b58d39..0c5ea0999 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -318,15 +318,24 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); + // Signal reporting. -void StartReportDeadlySignal(); // Each sanitizer uses slightly different implementation of stack unwinding. typedef void (*UnwindSignalStackCallbackType)(const SignalContext &sig, const void *callback_context, BufferedStackTrace *stack); +// Print deadly signal report and die. +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context); + +// Part of HandleDeadlySignal, exposed for asan. +void StartReportDeadlySignal(); +// Part of HandleDeadlySignal, exposed for asan. void ReportDeadlySignal(const SignalContext &sig, u32 tid, UnwindSignalStackCallbackType unwind, const void *unwind_context); + // Alternative signal stack (POSIX-only). void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index b10eaeb96..cce544dd8 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -254,6 +254,18 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, else ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); } + +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + StartReportDeadlySignal(); + ScopedErrorReportLock rl; + SignalContext sig(siginfo, context); + ReportDeadlySignal(sig, tid, unwind, unwind_context); + Report("ABORTING\n"); + Die(); +} + #endif // !SANITIZER_FUCHSIA && !SANITIZER_GO void WriteToSyslog(const char *msg) { diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index e76f0b1af..7f0a19027 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -18,7 +18,6 @@ // clang-format on // Remove when fixed: https://github.com/google/sanitizers/issues/637 -// XFAIL: lsan // XFAIL: msan // XFAIL: tsan // XFAIL: ubsan diff --git a/test/sanitizer_common/TestCases/Linux/assert.cc b/test/sanitizer_common/TestCases/Linux/assert.cc index 51a9163f4..af0853e6b 100644 --- a/test/sanitizer_common/TestCases/Linux/assert.cc +++ b/test/sanitizer_common/TestCases/Linux/assert.cc @@ -7,11 +7,11 @@ // RUN: %env_tool_opts=handle_abort=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // clang-format on -// FIXME: implement in other sanitizers, not just asan. +// FIXME: implement in other sanitizers. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan + #include #include #include diff --git a/test/sanitizer_common/TestCases/Linux/ill.cc b/test/sanitizer_common/TestCases/Linux/ill.cc index 030da3376..7d39abefa 100644 --- a/test/sanitizer_common/TestCases/Linux/ill.cc +++ b/test/sanitizer_common/TestCases/Linux/ill.cc @@ -7,9 +7,8 @@ // RUN: %env_tool_opts=handle_sigill=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // clang-format on -// FIXME: implement in other sanitizers, not just asan. +// FIXME: implement in other sanitizers. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan // diff --git a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc index ad94d13d2..86ad40bcb 100644 --- a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -9,7 +9,6 @@ // REQUIRES: stable-runtime // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan diff --git a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc index b5e45c307..4cb075807 100644 --- a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc +++ b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc @@ -8,7 +8,10 @@ // clang-format on // REQUIRES: x86-target-arch -// XFAIL: lsan, msan, tsan, ubsan +// FIXME: implement in other sanitizers. +// XFAIL: msan +// XFAIL: tsan +// XFAIL: ubsan int main() { #if defined(__x86_64__) diff --git a/test/sanitizer_common/TestCases/Posix/fpe.cc b/test/sanitizer_common/TestCases/Posix/fpe.cc index 44d53274b..46fe4f439 100644 --- a/test/sanitizer_common/TestCases/Posix/fpe.cc +++ b/test/sanitizer_common/TestCases/Posix/fpe.cc @@ -5,7 +5,6 @@ // RUN: %env_tool_opts=handle_sigfpe=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan // diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index f619b2205..cdccf97bd 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -8,7 +8,6 @@ // XFAIL: android && i386-target-arch && asan // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan -- cgit v1.2.1 From 36e72f5e2464e26fe15deae0641fc44f5af7cca7 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Fri, 22 Sep 2017 23:49:49 +0000 Subject: [lsan] Add __lsan_default_options For consistency with asan, msan, tsan and ubsan. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314048 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/lsan_interface.h | 4 ++++ lib/asan/asan_flags.cc | 4 ++++ lib/lsan/lsan.cc | 3 +++ lib/lsan/lsan_common.cc | 9 +++++++++ lib/lsan/lsan_common.h | 4 ++++ lib/lsan/weak_symbols.txt | 1 + test/lsan/TestCases/default_options.cc | 11 +++++++++++ 7 files changed, 36 insertions(+) create mode 100644 test/lsan/TestCases/default_options.cc diff --git a/include/sanitizer/lsan_interface.h b/include/sanitizer/lsan_interface.h index 1f2e58909..e3e509ff7 100644 --- a/include/sanitizer/lsan_interface.h +++ b/include/sanitizer/lsan_interface.h @@ -68,6 +68,10 @@ extern "C" { // __attribute__((used)) int __lsan_is_turned_off(); + // This function may be optionally provided by user and should return + // a string containing LSan runtime options. See lsan_flags.inc for details. + const char *__lsan_default_options(); + // This function may be optionally provided by the user and should return // a string containing LSan suppressions. const char *__lsan_default_suppressions(); diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 6be0d6e94..d3efadc54 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -118,6 +118,10 @@ void InitializeFlags() { const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); ubsan_parser.ParseString(ubsan_default_options); #endif +#if CAN_SANITIZE_LEAKS + const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions(); + lsan_parser.ParseString(lsan_default_options); +#endif // Override from command line. asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc index a51a63ba8..603050aae 100644 --- a/lib/lsan/lsan.cc +++ b/lib/lsan/lsan.cc @@ -56,6 +56,9 @@ static void InitializeFlags() { RegisterLsanFlags(&parser, f); RegisterCommonFlags(&parser); + // Override from user-specified string. + const char *lsan_default_options = MaybeCallLsanDefaultOptions(); + parser.ParseString(lsan_default_options); parser.ParseString(GetEnv("LSAN_OPTIONS")); SetVerbosity(common_flags()->verbosity); diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index b9b6fe086..622aae734 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -107,6 +107,10 @@ void InitializeRootRegions() { root_regions = new(placeholder) InternalMmapVector(1); } +const char *MaybeCallLsanDefaultOptions() { + return (&__lsan_default_options) ? __lsan_default_options() : ""; +} + void InitCommonLsan() { InitializeRootRegions(); if (common_flags()->detect_leaks) { @@ -855,6 +859,11 @@ int __lsan_do_recoverable_leak_check() { } #if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char * __lsan_default_options() { + return ""; +} + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int __lsan_is_turned_off() { return 0; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 1bb3e4198..5adcaad56 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -143,6 +143,7 @@ enum IgnoreObjectResult { }; // Functions called from the parent tool. +const char *MaybeCallLsanDefaultOptions(); void InitCommonLsan(); void DoLeakCheck(); void DoRecoverableLeakCheckVoid(); @@ -250,6 +251,9 @@ class LsanMetadata { } // namespace __lsan extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char *__lsan_default_options(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int __lsan_is_turned_off(); diff --git a/lib/lsan/weak_symbols.txt b/lib/lsan/weak_symbols.txt index da4f994da..692255679 100644 --- a/lib/lsan/weak_symbols.txt +++ b/lib/lsan/weak_symbols.txt @@ -1,2 +1,3 @@ +___lsan_default_options ___lsan_default_suppressions ___lsan_is_turned_off diff --git a/test/lsan/TestCases/default_options.cc b/test/lsan/TestCases/default_options.cc new file mode 100644 index 000000000..b5361c0cf --- /dev/null +++ b/test/lsan/TestCases/default_options.cc @@ -0,0 +1,11 @@ +// RUN: %clangxx_lsan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s + +extern "C" +const char *__lsan_default_options() { + // CHECK: Available flags for {{Leak|Address}}Sanitizer: + return "verbosity=1 help=1"; +} + +int main() { + return 0; +} -- cgit v1.2.1 From 6ae24b6faca880e679232692d7723fb44bd4dcf5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 23 Sep 2017 02:47:11 +0000 Subject: [ubsan] Support signal specific options in ubsan Summary: Part of https://github.com/google/sanitizers/issues/637 Standalone ubsan needs signal and sigaction handlers and interceptors. Plugin mode should rely on parent tool. Reviewers: eugenis, alekseyshl Subscribers: kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D37895 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314052 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 4 ++ lib/ubsan/ubsan_init_standalone.cc | 8 +++- lib/ubsan/ubsan_init_standalone_preinit.cc | 13 +++++- lib/ubsan/ubsan_signals_standalone.cc | 50 ++++++++++++++++++++++ lib/ubsan/ubsan_signals_standalone.h | 25 +++++++++++ .../TestCases/Linux/allow_user_segv.cc | 1 - .../TestCases/Posix/dedup_token_length_test.cc | 3 +- .../TestCases/Posix/dump_instruction_bytes.cc | 1 - .../Posix/sanitizer_set_report_fd_test.cc | 1 - 9 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 lib/ubsan/ubsan_signals_standalone.cc create mode 100644 lib/ubsan/ubsan_signals_standalone.h diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 4a2957c18..57191c308 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -11,6 +11,7 @@ set(UBSAN_SOURCES set(UBSAN_STANDALONE_SOURCES ubsan_diag_standalone.cc ubsan_init_standalone.cc + ubsan_signals_standalone.cc ) set(UBSAN_CXXABI_SOURCES @@ -77,6 +78,7 @@ if(APPLE) RTUbsan_standalone RTSanitizerCommon RTSanitizerCommonLibc + RTInterception LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} PARENT_TARGET ubsan) endif() @@ -144,6 +146,7 @@ else() RTSanitizerCommonLibc RTUbsan RTUbsan_standalone + RTInterception CFLAGS ${UBSAN_CFLAGS} PARENT_TARGET ubsan) @@ -162,6 +165,7 @@ else() RTSanitizerCommonLibc RTUbsan RTUbsan_standalone + RTInterception CFLAGS ${UBSAN_CFLAGS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} LINK_LIBS ${UBSAN_DYNAMIC_LIBS} diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc index 8e999e3ac..8bd500025 100644 --- a/lib/ubsan/ubsan_init_standalone.cc +++ b/lib/ubsan/ubsan_init_standalone.cc @@ -18,11 +18,17 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "ubsan_init.h" +#include "ubsan_signals_standalone.h" + +namespace __ubsan { class UbsanStandaloneInitializer { public: UbsanStandaloneInitializer() { - __ubsan::InitAsStandalone(); + InitAsStandalone(); + InitializeDeadlySignals(); } }; static UbsanStandaloneInitializer ubsan_standalone_initializer; + +} // namespace __ubsan diff --git a/lib/ubsan/ubsan_init_standalone_preinit.cc b/lib/ubsan/ubsan_init_standalone_preinit.cc index 229ecc5c8..9a8c6884a 100644 --- a/lib/ubsan/ubsan_init_standalone_preinit.cc +++ b/lib/ubsan/ubsan_init_standalone_preinit.cc @@ -19,8 +19,19 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "ubsan_init.h" +#include "ubsan_signals_standalone.h" #if SANITIZER_CAN_USE_PREINIT_ARRAY + +namespace __ubsan { + +static void PreInitAsStandalone() { + InitAsStandalone(); + InitializeDeadlySignals(); +} + +} // namespace __ubsan + __attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)( - void) = __ubsan::InitAsStandalone; + void) = __ubsan::PreInitAsStandalone; #endif // SANITIZER_CAN_USE_PREINIT_ARRAY diff --git a/lib/ubsan/ubsan_signals_standalone.cc b/lib/ubsan/ubsan_signals_standalone.cc new file mode 100644 index 000000000..374857269 --- /dev/null +++ b/lib/ubsan/ubsan_signals_standalone.cc @@ -0,0 +1,50 @@ +//=-- ubsan_signals_standalone.cc +//------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Installs signal handlers and related interceptors for UBSan standalone. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "ubsan_diag.h" +#include "ubsan_init.h" + +#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) +#include "sanitizer_common/sanitizer_signal_interceptors.inc" + +namespace __ubsan { + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp, + sig.context, + common_flags()->fast_unwind_on_fatal); +} + +static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr); +} + +static bool is_initialized = false; + +void InitializeDeadlySignals() { + if (is_initialized) + return; + is_initialized = true; + InitializeSignalInterceptors(); + InstallDeadlySignalHandlers(&UBsanOnDeadlySignal); +} + +} // namespace __ubsan + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_signals_standalone.h b/lib/ubsan/ubsan_signals_standalone.h new file mode 100644 index 000000000..b29c29482 --- /dev/null +++ b/lib/ubsan/ubsan_signals_standalone.h @@ -0,0 +1,25 @@ +//=-- ubsan_signals_standalone.h +//------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Installs signal handlers and related interceptors for UBSan standalone. +// +//===----------------------------------------------------------------------===// + +#ifndef UBSAN_SIGNALS_STANDALONE_H +#define UBSAN_SIGNALS_STANDALONE_H + +namespace __ubsan { + +// Initializes signal handlers and interceptors. +void InitializeDeadlySignals(); + +} // namespace __ubsan + +#endif // UBSAN_SIGNALS_STANDALONE_H diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index 7f0a19027..201407923 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -20,7 +20,6 @@ // Remove when fixed: https://github.com/google/sanitizers/issues/637 // XFAIL: msan // XFAIL: tsan -// XFAIL: ubsan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc index 86ad40bcb..7e93af46d 100644 --- a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -7,10 +7,9 @@ // RUN: env %tool_options='abort_on_error=0, dedup_token_length=3' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --match-full-lines // REQUIRES: stable-runtime -// FIXME: implement SEGV handler in other sanitizers, not just asan. +// FIXME: implement SEGV handler in other sanitizers. // XFAIL: msan // XFAIL: tsan -// XFAIL: ubsan volatile int *null = 0; diff --git a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc index 4cb075807..25e801a10 100644 --- a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc +++ b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc @@ -11,7 +11,6 @@ // FIXME: implement in other sanitizers. // XFAIL: msan // XFAIL: tsan -// XFAIL: ubsan int main() { #if defined(__x86_64__) diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index cdccf97bd..416944fa6 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -9,7 +9,6 @@ // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan // XFAIL: tsan -// XFAIL: ubsan #include #include -- cgit v1.2.1 From a7018c1d070645a9ac6fe476933b02ebf48e9d9c Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 23 Sep 2017 02:47:21 +0000 Subject: [ubsan] Replace CommonSanitizerReportMutex with ScopedErrorReportLock Reviewers: eugenis, alekseyshl Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D38194 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314053 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 2 ++ lib/sanitizer_common/sanitizer_common_libcdep.cc | 4 ++++ lib/ubsan/ubsan_diag.cc | 10 ++++------ lib/ubsan/ubsan_diag.h | 8 ++++++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 0c5ea0999..a65f732eb 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -213,6 +213,8 @@ class ScopedErrorReportLock { public: ScopedErrorReportLock(); ~ScopedErrorReportLock(); + + static void CheckLocked(); }; extern uptr stoptheworld_tracer_pid; diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index cce544dd8..4048960a0 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -334,6 +334,10 @@ ScopedErrorReportLock::~ScopedErrorReportLock() { atomic_store_relaxed(&reporting_thread, 0); } +void ScopedErrorReportLock::CheckLocked() { + CommonSanitizerReportMutex.CheckLocked(); +} + } // namespace __sanitizer SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index e73fe9042..bc170660c 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -337,7 +337,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc, Diag::~Diag() { // All diagnostics should be printed under report mutex. - CommonSanitizerReportMutex.CheckLocked(); + ScopedReport::CheckLocked(); Decorator Decor; InternalScopedString Buffer(1024); @@ -365,17 +365,15 @@ Diag::~Diag() { PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); } +ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); } + ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type) - : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) { - InitAsStandaloneIfNecessary(); - CommonSanitizerReportMutex.Lock(); -} + : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {} ScopedReport::~ScopedReport() { MaybePrintStackTrace(Opts.pc, Opts.bp); MaybeReportErrorSummary(SummaryLoc, Type); - CommonSanitizerReportMutex.Unlock(); if (flags()->halt_on_error) Die(); } diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 2e1983947..72b258628 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -239,6 +239,12 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, /// report. This class ensures that reports from different threads and from /// different sanitizers won't be mixed. class ScopedReport { + struct Initializer { + Initializer(); + }; + Initializer initializer_; + ScopedErrorReportLock report_lock_; + ReportOptions Opts; Location SummaryLoc; ErrorType Type; @@ -246,6 +252,8 @@ class ScopedReport { public: ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type); ~ScopedReport(); + + static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); } }; void InitializeSuppressions(); -- cgit v1.2.1 From 836cd12c06cf3114dcf177f7a9165ee87f825ae1 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sat, 23 Sep 2017 05:09:45 +0000 Subject: [ubsan] Fix assert.cc test by compiling it as C++ git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314057 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/assert.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/assert.cc b/test/sanitizer_common/TestCases/Linux/assert.cc index af0853e6b..f10ddf3ce 100644 --- a/test/sanitizer_common/TestCases/Linux/assert.cc +++ b/test/sanitizer_common/TestCases/Linux/assert.cc @@ -1,7 +1,7 @@ // Test the handle_abort option. // clang-format off -// RUN: %clang %s -o %t +// RUN: %clangxx %s -o %t // RUN: not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_abort=0 not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s // RUN: %env_tool_opts=handle_abort=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s @@ -10,7 +10,6 @@ // FIXME: implement in other sanitizers. // XFAIL: msan // XFAIL: tsan -// XFAIL: ubsan #include #include -- cgit v1.2.1 From ae2601605cdda1bc2730041f48e3b2786ad896e5 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Mon, 25 Sep 2017 13:25:34 +0000 Subject: [mips][compiler-rt] Disable sem_init_glibc.cc for MIPS64. This test can't pass on MIPS64 due to the lack of versioned interceptors for asan and company. The interceptors bind to the earlier version of sem_init rather than the latest version. For MIPS64el this causes an accidental pass while MIPS64 big endian fails due reading back a different 32bit word to what sem_init wrote when the test is corrected to use 64bit atomics. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314100 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc index 523ac9811..d623ccabb 100644 --- a/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc +++ b/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -1,7 +1,7 @@ // RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t // This test depends on the glibc layout of struct sem_t and checks that we // don't leave sem_t::private uninitialized. -// UNSUPPORTED: android, lsan-x86, ubsan +// UNSUPPORTED: android, lsan-x86, ubsan, target-is-mips64, target-is-mips64el #include #include #include -- cgit v1.2.1 From 9230e83455810a9967796d00ac39cfe8d22bb8ef Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 25 Sep 2017 15:12:08 +0000 Subject: [scudo] Scudo thread specific data refactor, part 2 Summary: Following D38139, we now consolidate the TSD definition, merging the shared TSD definition with the exclusive TSD definition. We introduce a boolean set at initializaton denoting the need for the TSD to be unlocked or not. This adds some unused members to the exclusive TSD, but increases consistency and reduces the definitions fragmentation. We remove the fallback mechanism from `scudo_allocator.cpp` and add a fallback TSD in the non-shared version. Since the shared version doesn't require one, this makes overall more sense. There are a couple of additional cosmetic changes: removing the header guards from the remaining `.inc` files, added error string to a `CHECK`. Question to reviewers: I thought about friending `getTSDAndLock` in `ScudoTSD` so that the `FallbackTSD` could `Mutex.Lock()` directly instead of `lock()` which involved zeroing out the `Precedence`, which is unused otherwise. Is it worth doing? Reviewers: alekseyshl, dvyukov, kcc Reviewed By: dvyukov Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D38183 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314110 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 53 ++++++++------------------------ lib/scudo/scudo_tls.h | 39 ++++++++++++++++++++---- lib/scudo/scudo_tls_android.cpp | 2 +- lib/scudo/scudo_tls_android.inc | 7 +---- lib/scudo/scudo_tls_context_android.inc | 54 --------------------------------- lib/scudo/scudo_tls_context_linux.inc | 29 ------------------ lib/scudo/scudo_tls_linux.cpp | 7 ++++- lib/scudo/scudo_tls_linux.inc | 13 ++++---- 8 files changed, 59 insertions(+), 145 deletions(-) delete mode 100644 lib/scudo/scudo_tls_context_android.inc delete mode 100644 lib/scudo/scudo_tls_context_linux.inc diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index e490a469d..606439ea1 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -269,14 +269,6 @@ struct ScudoAllocator { StaticSpinMutex GlobalPrngMutex; ScudoPrng GlobalPrng; - // The fallback caches are used when the thread local caches have been - // 'detroyed' on thread tear-down. They are protected by a Mutex as they can - // be accessed by different threads. - StaticSpinMutex FallbackMutex; - AllocatorCache FallbackAllocatorCache; - ScudoQuarantineCache FallbackQuarantineCache; - ScudoPrng FallbackPrng; - u32 QuarantineChunksUpToSize; bool DeallocationTypeMismatch; @@ -284,8 +276,7 @@ struct ScudoAllocator { bool DeleteSizeMismatch; explicit ScudoAllocator(LinkerInitialized) - : AllocatorQuarantine(LINKER_INITIALIZED), - FallbackQuarantineCache(LINKER_INITIALIZED) {} + : AllocatorQuarantine(LINKER_INITIALIZED) {} void init(const AllocatorOptions &Options) { // Verify that the header offset field can hold the maximum offset. In the @@ -329,8 +320,6 @@ struct ScudoAllocator { QuarantineChunksUpToSize = Options.QuarantineChunksUpToSize; GlobalPrng.init(); Cookie = GlobalPrng.getU64(); - BackendAllocator.initCache(&FallbackAllocatorCache); - FallbackPrng.init(); } // Helper function that checks for a valid Scudo chunk. nullptr isn't. @@ -374,16 +363,9 @@ struct ScudoAllocator { if (FromPrimary) { AllocSize = AlignedSize; ScudoTSD *TSD = getTSDAndLock(); - if (LIKELY(TSD)) { - Salt = TSD->Prng.getU8(); - Ptr = BackendAllocator.allocatePrimary(&TSD->Cache, AllocSize); - TSD->unlock(); - } else { - SpinMutexLock l(&FallbackMutex); - Salt = FallbackPrng.getU8(); - Ptr = BackendAllocator.allocatePrimary(&FallbackAllocatorCache, - AllocSize); - } + Salt = TSD->Prng.getU8(); + Ptr = BackendAllocator.allocatePrimary(&TSD->Cache, AllocSize); + TSD->unlock(); } else { { SpinMutexLock l(&GlobalPrngMutex); @@ -446,13 +428,8 @@ struct ScudoAllocator { void *Ptr = Chunk->getAllocBeg(Header); if (Header->FromPrimary) { ScudoTSD *TSD = getTSDAndLock(); - if (LIKELY(TSD)) { - getBackendAllocator().deallocatePrimary(&TSD->Cache, Ptr); - TSD->unlock(); - } else { - SpinMutexLock Lock(&FallbackMutex); - getBackendAllocator().deallocatePrimary(&FallbackAllocatorCache, Ptr); - } + getBackendAllocator().deallocatePrimary(&TSD->Cache, Ptr); + TSD->unlock(); } else { getBackendAllocator().deallocateSecondary(Ptr); } @@ -467,17 +444,10 @@ struct ScudoAllocator { NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); ScudoTSD *TSD = getTSDAndLock(); - if (LIKELY(TSD)) { - AllocatorQuarantine.Put(getQuarantineCache(TSD), - QuarantineCallback(&TSD->Cache), - Chunk, EstimatedSize); - TSD->unlock(); - } else { - SpinMutexLock l(&FallbackMutex); - AllocatorQuarantine.Put(&FallbackQuarantineCache, - QuarantineCallback(&FallbackAllocatorCache), - Chunk, EstimatedSize); - } + AllocatorQuarantine.Put(getQuarantineCache(TSD), + QuarantineCallback(&TSD->Cache), + Chunk, EstimatedSize); + TSD->unlock(); } } @@ -625,7 +595,8 @@ static void initScudoInternal(const AllocatorOptions &Options) { Instance.init(Options); } -void ScudoTSD::init() { +void ScudoTSD::init(bool Shared) { + UnlockRequired = Shared; getBackendAllocator().initCache(&Cache); Prng.init(); memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder)); diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index a3992e264..57480c2a6 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -24,16 +24,43 @@ namespace __scudo { -// Platform specific base thread context definitions. -#include "scudo_tls_context_android.inc" -#include "scudo_tls_context_linux.inc" - -struct ALIGNED(64) ScudoTSD : public ScudoTSDPlatform { +struct ALIGNED(64) ScudoTSD { AllocatorCache Cache; ScudoPrng Prng; uptr QuarantineCachePlaceHolder[4]; - void init(); + + void init(bool Shared); void commitBack(); + + INLINE bool tryLock() { + if (Mutex.TryLock()) { + atomic_store_relaxed(&Precedence, 0); + return true; + } + if (atomic_load_relaxed(&Precedence) == 0) + atomic_store_relaxed(&Precedence, NanoTime()); + return false; + } + + INLINE void lock() { + Mutex.Lock(); + atomic_store_relaxed(&Precedence, 0); + } + + INLINE void unlock() { + if (!UnlockRequired) + return; + Mutex.Unlock(); + } + + INLINE u64 getPrecedence() { + return atomic_load_relaxed(&Precedence); + } + + private: + bool UnlockRequired; + StaticSpinMutex Mutex; + atomic_uint64_t Precedence; }; void initThread(bool MinimalInit); diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp index 3f215a72f..695a610e9 100644 --- a/lib/scudo/scudo_tls_android.cpp +++ b/lib/scudo/scudo_tls_android.cpp @@ -50,7 +50,7 @@ static void initOnce() { TSDs = reinterpret_cast( MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); for (u32 i = 0; i < NumberOfTSDs; i++) - TSDs[i].init(); + TSDs[i].init(/*Shared=*/true); } void initThread(bool MinimalInit) { diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc index 9f3ef1a23..62855f766 100644 --- a/lib/scudo/scudo_tls_android.inc +++ b/lib/scudo/scudo_tls_android.inc @@ -11,9 +11,6 @@ /// //===----------------------------------------------------------------------===// -#ifndef SCUDO_TLS_ANDROID_H_ -#define SCUDO_TLS_ANDROID_H_ - #ifndef SCUDO_TLS_H_ # error "This file must be included inside scudo_tls.h." #endif // SCUDO_TLS_H_ @@ -30,7 +27,7 @@ ScudoTSD *getTSDAndLockSlow(); ALWAYS_INLINE ScudoTSD *getTSDAndLock() { ScudoTSD *TSD = reinterpret_cast(*get_android_tls_ptr()); - CHECK(TSD); + CHECK(TSD && "No TSD associated with the current thread!"); // Try to lock the currently associated context. if (TSD->tryLock()) return TSD; @@ -39,5 +36,3 @@ ALWAYS_INLINE ScudoTSD *getTSDAndLock() { } #endif // SANITIZER_LINUX && SANITIZER_ANDROID - -#endif // SCUDO_TLS_ANDROID_H_ diff --git a/lib/scudo/scudo_tls_context_android.inc b/lib/scudo/scudo_tls_context_android.inc deleted file mode 100644 index 4787ec7b6..000000000 --- a/lib/scudo/scudo_tls_context_android.inc +++ /dev/null @@ -1,54 +0,0 @@ -//===-- scudo_tls_context_android.inc ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Android specific base thread context definition. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_CONTEXT_ANDROID_INC_ -#define SCUDO_TLS_CONTEXT_ANDROID_INC_ - -#ifndef SCUDO_TLS_H_ -# error "This file must be included inside scudo_tls.h." -#endif // SCUDO_TLS_H_ - -#if SANITIZER_LINUX && SANITIZER_ANDROID - -struct ScudoTSDPlatform { - INLINE bool tryLock() { - if (Mutex.TryLock()) { - atomic_store_relaxed(&Precedence, 0); - return true; - } - if (atomic_load_relaxed(&Precedence) == 0) - atomic_store_relaxed(&Precedence, NanoTime()); - return false; - } - - INLINE void lock() { - Mutex.Lock(); - atomic_store_relaxed(&Precedence, 0); - } - - INLINE void unlock() { - Mutex.Unlock(); - } - - INLINE u64 getPrecedence() { - return atomic_load_relaxed(&Precedence); - } - - private: - StaticSpinMutex Mutex; - atomic_uint64_t Precedence; -}; - -#endif // SANITIZER_LINUX && SANITIZER_ANDROID - -#endif // SCUDO_TLS_CONTEXT_ANDROID_INC_ diff --git a/lib/scudo/scudo_tls_context_linux.inc b/lib/scudo/scudo_tls_context_linux.inc deleted file mode 100644 index 9a24256f2..000000000 --- a/lib/scudo/scudo_tls_context_linux.inc +++ /dev/null @@ -1,29 +0,0 @@ -//===-- scudo_tls_context_linux.inc -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Linux specific base thread context definition. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_CONTEXT_LINUX_INC_ -#define SCUDO_TLS_CONTEXT_LINUX_INC_ - -#ifndef SCUDO_TLS_H_ -# error "This file must be included inside scudo_tls.h." -#endif // SCUDO_TLS_H_ - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - -struct ScudoTSDPlatform { - ALWAYS_INLINE void unlock() {} -}; - -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#endif // SCUDO_TLS_CONTEXT_LINUX_INC_ diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index 845539457..1f51cccbc 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -30,6 +30,10 @@ THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; __attribute__((tls_model("initial-exec"))) THREADLOCAL ScudoTSD TSD; +// Fallback TSD for when the thread isn't initialized yet or is torn down. It +// can be shared between multiple threads and as such must be locked. +ScudoTSD FallbackTSD; + static void teardownThread(void *Ptr) { uptr I = reinterpret_cast(Ptr); // The glibc POSIX thread-local-storage deallocation routine calls user @@ -51,6 +55,7 @@ static void teardownThread(void *Ptr) { static void initOnce() { CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0); initScudo(); + FallbackTSD.init(/*Shared=*/true); } void initThread(bool MinimalInit) { @@ -59,7 +64,7 @@ void initThread(bool MinimalInit) { return; CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( GetPthreadDestructorIterations())), 0); - TSD.init(); + TSD.init(/*Shared=*/false); ScudoThreadState = ThreadInitialized; } diff --git a/lib/scudo/scudo_tls_linux.inc b/lib/scudo/scudo_tls_linux.inc index 492807c58..e0c6deba5 100644 --- a/lib/scudo/scudo_tls_linux.inc +++ b/lib/scudo/scudo_tls_linux.inc @@ -12,9 +12,6 @@ /// //===----------------------------------------------------------------------===// -#ifndef SCUDO_TLS_LINUX_H_ -#define SCUDO_TLS_LINUX_H_ - #ifndef SCUDO_TLS_H_ # error "This file must be included inside scudo_tls.h." #endif // SCUDO_TLS_H_ @@ -31,6 +28,8 @@ extern THREADLOCAL ThreadState ScudoThreadState; __attribute__((tls_model("initial-exec"))) extern THREADLOCAL ScudoTSD TSD; +extern ScudoTSD FallbackTSD; + ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { if (LIKELY(ScudoThreadState != ThreadNotInitialized)) return; @@ -38,11 +37,11 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { } ALWAYS_INLINE ScudoTSD *getTSDAndLock() { - if (UNLIKELY(ScudoThreadState != ThreadInitialized)) - return nullptr; + if (UNLIKELY(ScudoThreadState != ThreadInitialized)) { + FallbackTSD.lock(); + return &FallbackTSD; + } return &TSD; } #endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#endif // SCUDO_TLS_LINUX_H_ -- cgit v1.2.1 From 2c712e9928756c94d307e61bd0b486b473fd81af Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 25 Sep 2017 20:48:51 +0000 Subject: [sanitizer_common] Don't provide sanitizer_procmaps API functions where not defined Summary: Platforms that don't implement procmaps (primarily fuchsia and windows) still expose the procmaps API when including sanitizer_procmaps.h, despite not implementing the functions provided by that header. Ensure that the API is only exposed on platforms that implement it. Reviewers: vitalybuka, alekseyshl, kubamracek Subscribers: llvm-commits, krytarowski Differential Revision: https://reviews.llvm.org/D38187 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314149 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 8 ++++++++ lib/sanitizer_common/sanitizer_fuchsia.cc | 1 - lib/sanitizer_common/sanitizer_fuchsia.h | 4 ---- lib/sanitizer_common/sanitizer_procmaps.h | 15 +++------------ lib/sanitizer_common/sanitizer_win.cc | 1 - lib/sanitizer_common/sanitizer_win.h | 1 - 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index a65f732eb..47b02b149 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,6 +128,14 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); +typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, + /*out*/uptr *stats, uptr stats_size); + +// Parse the contents of /proc/self/smaps and generate a memory profile. +// |cb| is a tool-specific callback that fills the |stats| array containing +// |stats_size| elements. +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size); + // InternalScopedBuffer can be used instead of large stack arrays to // keep frame size low. // FIXME: use InternalAlloc instead of MmapOrDie once diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 708f7f0c5..21fabddb1 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -18,7 +18,6 @@ #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_mutex.h" -#include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include diff --git a/lib/sanitizer_common/sanitizer_fuchsia.h b/lib/sanitizer_common/sanitizer_fuchsia.h index 48d7154f3..18821b4fd 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.h +++ b/lib/sanitizer_common/sanitizer_fuchsia.h @@ -25,10 +25,6 @@ namespace __sanitizer { extern uptr MainThreadStackBase, MainThreadStackSize; extern sanitizer_shadow_bounds_t ShadowBounds; -// TODO(fjricci) Remove this struct by refactoring common functions -// out of sanitizer_procmaps.h -struct MemoryMappingLayoutData {}; - } // namespace __sanitizer #endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 395688c3e..ecd1ad4c8 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -14,13 +14,13 @@ #ifndef SANITIZER_PROCMAPS_H #define SANITIZER_PROCMAPS_H +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC + #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" -#include "sanitizer_fuchsia.h" #include "sanitizer_linux.h" #include "sanitizer_mac.h" #include "sanitizer_mutex.h" -#include "sanitizer_win.h" namespace __sanitizer { @@ -79,19 +79,9 @@ class MemoryMappingLayout { private: void LoadFromCache(); - // FIXME: Hide implementation details for different platforms in - // platform-specific files. MemoryMappingLayoutData data_; }; -typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, - /*out*/uptr *stats, uptr stats_size); - -// Parse the contents of /proc/self/smaps and generate a memory profile. -// |cb| is a tool-specific callback that fills the |stats| array containing -// |stats_size| elements. -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size); - // Returns code range for the specified module. bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end); @@ -102,4 +92,5 @@ uptr ParseHex(const char **p); } // namespace __sanitizer +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC #endif // SANITIZER_PROCMAPS_H diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 4d68f5610..a144db28c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -28,7 +28,6 @@ #include "sanitizer_libc.h" #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" #include "sanitizer_win_defs.h" diff --git a/lib/sanitizer_common/sanitizer_win.h b/lib/sanitizer_common/sanitizer_win.h index 515792054..23e01ab75 100644 --- a/lib/sanitizer_common/sanitizer_win.h +++ b/lib/sanitizer_common/sanitizer_win.h @@ -20,7 +20,6 @@ namespace __sanitizer { // Check based on flags if we should handle the exception. bool IsHandledDeadlyException(DWORD exceptionCode); -struct MemoryMappingLayoutData {}; } // namespace __sanitizer #endif // SANITIZER_WINDOWS -- cgit v1.2.1 From 8c42acfdc8a900102b0ddbadb1040617c4da02e5 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 25 Sep 2017 21:26:34 +0000 Subject: Fix style in sanitizer_procmaps.h git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314157 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index ecd1ad4c8..a44fcbb39 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -92,5 +92,6 @@ uptr ParseHex(const char **p); } // namespace __sanitizer -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || + // SANITIZER_MAC #endif // SANITIZER_PROCMAPS_H -- cgit v1.2.1 From 1f707b9f77ccd90b3a5ca32248d5fdfe177e7852 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 25 Sep 2017 21:51:04 +0000 Subject: Add missing include to sanitizer procmaps git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314162 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_procmaps.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index a44fcbb39..96d0b2f9d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -14,6 +14,8 @@ #ifndef SANITIZER_PROCMAPS_H #define SANITIZER_PROCMAPS_H +#include "sanitizer_platform.h" + #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC #include "sanitizer_common.h" -- cgit v1.2.1 From 03dddb6de705e6d97d6cbadc47c50a5a29171c48 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Tue, 26 Sep 2017 11:49:04 +0000 Subject: [mips][asan] Fix preinstalled_signal.cc test for mips Linux for mips has a non-standard layout for the kernel sigaction struct. Adjust the layout by the minimally amount to get the test to pass, as we don't require the usage of the restorer function. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314200 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/TestCases/Linux/preinstalled_signal.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc index 2beba4e66..ac4ea93a5 100644 --- a/test/asan/TestCases/Linux/preinstalled_signal.cc +++ b/test/asan/TestCases/Linux/preinstalled_signal.cc @@ -32,8 +32,14 @@ void SigHandler(int signum) { handler = "TestSigHandler"; } void SigAction(int, siginfo_t *, void *) { handler = "TestSigAction"; } struct KernelSigaction { + +#if defined(__mips__) + unsigned long flags; + __sighandler_t handler; +#else __sighandler_t handler; unsigned long flags; +#endif void (*restorer)(); char unused[1024]; }; -- cgit v1.2.1 From 1ea789be4f8a6a54b46e36fe8a0eed020b7a93ca Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Tue, 26 Sep 2017 16:12:56 +0000 Subject: Invalidate symbolizer module list from dlopen/dlclose interceptors Summary: The module list should only be invalidated by dlopen and dlclose, so the symbolizer should only re-generate it when we've hit one of those functions. Reviewers: kubamracek, rnk, vitalybuka Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D37268 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314219 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common_interceptors.inc | 3 +++ lib/sanitizer_common/sanitizer_symbolizer.cc | 4 ++++ lib/sanitizer_common/sanitizer_symbolizer.h | 2 ++ lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 9 +++++---- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index b9c182e65..21a405ae4 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -43,6 +43,7 @@ #include "sanitizer_errno.h" #include "sanitizer_placement_new.h" #include "sanitizer_platform_interceptors.h" +#include "sanitizer_symbolizer.h" #include "sanitizer_tls_get_addr.h" #include @@ -5575,6 +5576,7 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) { if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0); COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag); void *res = REAL(dlopen)(filename, flag); + Symbolizer::GetOrInit()->InvalidateModuleList(); COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); return res; } @@ -5583,6 +5585,7 @@ INTERCEPTOR(int, dlclose, void *handle) { void *ctx; COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle); int res = REAL(dlclose)(handle); + Symbolizer::GetOrInit()->InvalidateModuleList(); COMMON_INTERCEPTOR_LIBRARY_UNLOADED(); return res; } diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc index 1cd5b6ee2..672c93668 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer.cc @@ -71,6 +71,10 @@ Symbolizer *Symbolizer::symbolizer_; StaticSpinMutex Symbolizer::init_mu_; LowLevelAllocator Symbolizer::symbolizer_allocator_; +void Symbolizer::InvalidateModuleList() { + modules_fresh_ = false; +} + void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, Symbolizer::EndSymbolizationHook end_hook) { CHECK(start_hook_ == 0 && end_hook_ == 0); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 4fc7742a2..543e27e39 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -121,6 +121,8 @@ class Symbolizer final { const LoadedModule *FindModuleForAddress(uptr address); + void InvalidateModuleList(); + private: // GetModuleNameAndOffsetForPC has to return a string to the caller. // Since the corresponding module might get unloaded later, we should create diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 12369d709..caab4ca35 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -176,14 +176,15 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { return &modules_[i]; } } - // Reload the modules and look up again, if we haven't tried it yet. + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. +#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors. - // It's too aggressive to reload the list of modules each time we fail - // to find a module for a given address. modules_fresh_ = false; return FindModuleForAddress(address); } +#endif return 0; } -- cgit v1.2.1 From 7db641bc3ad521e15e8b97fd37f6e7b4666b4188 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 26 Sep 2017 17:20:02 +0000 Subject: [scudo] Scudo thread specific data refactor, part 3 Summary: Previous parts: D38139, D38183. In this part of the refactor, we abstract the Linux vs Android TSD dissociation in favor of a Exclusive vs Shared one, allowing for easier platform introduction and configuration. Most of this change consist of shuffling the files around to reflect the new organization. We introduce `scudo_platform.h` where platform specific definition lie. This involves the TSD model and the platform specific allocator parameters. In an upcoming CL, those will be configurable via defines, but we currently stick with conservative defaults. Reviewers: alekseyshl, dvyukov Reviewed By: alekseyshl, dvyukov Subscribers: srhines, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D38244 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314224 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/CMakeLists.txt | 4 +- lib/scudo/scudo_allocator.cpp | 2 +- lib/scudo/scudo_allocator.h | 16 +------ lib/scudo/scudo_platform.h | 58 +++++++++++++++++++++++ lib/scudo/scudo_tls.h | 74 ----------------------------- lib/scudo/scudo_tls_android.cpp | 98 --------------------------------------- lib/scudo/scudo_tls_android.inc | 38 --------------- lib/scudo/scudo_tls_linux.cpp | 73 ----------------------------- lib/scudo/scudo_tls_linux.inc | 47 ------------------- lib/scudo/scudo_tsd.h | 71 ++++++++++++++++++++++++++++ lib/scudo/scudo_tsd_exclusive.cpp | 70 ++++++++++++++++++++++++++++ lib/scudo/scudo_tsd_exclusive.inc | 46 ++++++++++++++++++ lib/scudo/scudo_tsd_shared.cpp | 96 ++++++++++++++++++++++++++++++++++++++ lib/scudo/scudo_tsd_shared.inc | 38 +++++++++++++++ 14 files changed, 383 insertions(+), 348 deletions(-) create mode 100644 lib/scudo/scudo_platform.h delete mode 100644 lib/scudo/scudo_tls.h delete mode 100644 lib/scudo/scudo_tls_android.cpp delete mode 100644 lib/scudo/scudo_tls_android.inc delete mode 100644 lib/scudo/scudo_tls_linux.cpp delete mode 100644 lib/scudo/scudo_tls_linux.inc create mode 100644 lib/scudo/scudo_tsd.h create mode 100644 lib/scudo/scudo_tsd_exclusive.cpp create mode 100644 lib/scudo/scudo_tsd_exclusive.inc create mode 100644 lib/scudo/scudo_tsd_shared.cpp create mode 100644 lib/scudo/scudo_tsd_shared.inc diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 14c199fa8..253924147 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -14,8 +14,8 @@ set(SCUDO_SOURCES scudo_interceptors.cpp scudo_new_delete.cpp scudo_termination.cpp - scudo_tls_android.cpp - scudo_tls_linux.cpp + scudo_tsd_exclusive.cpp + scudo_tsd_shared.cpp scudo_utils.cpp) # Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available. diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 606439ea1..077d57747 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -17,7 +17,7 @@ #include "scudo_allocator.h" #include "scudo_crc32.h" #include "scudo_flags.h" -#include "scudo_tls.h" +#include "scudo_tsd.h" #include "scudo_utils.h" #include "sanitizer_common/sanitizer_allocator_checks.h" diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index a5f0ab004..2f317d24a 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -14,11 +14,7 @@ #ifndef SCUDO_ALLOCATOR_H_ #define SCUDO_ALLOCATOR_H_ -#include "sanitizer_common/sanitizer_allocator.h" - -#if !SANITIZER_LINUX -# error "The Scudo hardened allocator is currently only supported on Linux." -#endif +#include "scudo_platform.h" namespace __scudo { @@ -70,14 +66,6 @@ const uptr AlignedChunkHeaderSize = #if SANITIZER_CAN_USE_ALLOCATOR64 const uptr AllocatorSpace = ~0ULL; -# if defined(__aarch64__) && SANITIZER_ANDROID -const uptr AllocatorSize = 0x4000000000ULL; // 256G. -# elif defined(__aarch64__) -const uptr AllocatorSize = 0x10000000000ULL; // 1T. -# else -const uptr AllocatorSize = 0x40000000000ULL; // 4T. -# endif -typedef DefaultSizeClassMap SizeClassMap; struct AP64 { static const uptr kSpaceBeg = AllocatorSpace; static const uptr kSpaceSize = AllocatorSize; @@ -92,14 +80,12 @@ typedef SizeClassAllocator64 PrimaryAllocator; // Currently, the 32-bit Sanitizer allocator has not yet benefited from all the // security improvements brought to the 64-bit one. This makes the 32-bit // version of Scudo slightly less toughened. -static const uptr RegionSizeLog = 20; static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog; # if SANITIZER_WORDSIZE == 32 typedef FlatByteMap ByteMap; # elif SANITIZER_WORDSIZE == 64 typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap; # endif // SANITIZER_WORDSIZE -typedef DefaultSizeClassMap SizeClassMap; struct AP32 { static const uptr kSpaceBeg = 0; static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; diff --git a/lib/scudo/scudo_platform.h b/lib/scudo/scudo_platform.h new file mode 100644 index 000000000..86ddc1a25 --- /dev/null +++ b/lib/scudo/scudo_platform.h @@ -0,0 +1,58 @@ +//===-- scudo_platform.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo platform specific definitions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_PLATFORM_H_ +#define SCUDO_PLATFORM_H_ + +#include "sanitizer_common/sanitizer_allocator.h" + +#if !SANITIZER_LINUX && !SANITIZER_FUCHSIA +# error "The Scudo hardened allocator is not supported on this platform." +#endif + +#if SANITIZER_ANDROID || SANITIZER_FUCHSIA +// Android and Fuchsia use a pool of TSDs shared between threads. +# define SCUDO_TSD_EXCLUSIVE 0 +#elif SANITIZER_LINUX && !SANITIZER_ANDROID +// Non-Android Linux use an exclusive TSD per thread. +# define SCUDO_TSD_EXCLUSIVE 1 +#else +# error "No default TSD model defined for this platform." +#endif // SANITIZER_ANDROID || SANITIZER_FUCHSIA + +namespace __scudo { + +#if SANITIZER_CAN_USE_ALLOCATOR64 +# if defined(__aarch64__) && SANITIZER_ANDROID +const uptr AllocatorSize = 0x2000000000ULL; // 128G. +typedef VeryCompactSizeClassMap SizeClassMap; +# elif defined(__aarch64__) +const uptr AllocatorSize = 0x10000000000ULL; // 1T. +typedef CompactSizeClassMap SizeClassMap; +# else +const uptr AllocatorSize = 0x40000000000ULL; // 4T. +typedef CompactSizeClassMap SizeClassMap; +# endif +#else +# if SANITIZER_ANDROID +static const uptr RegionSizeLog = 19; +typedef VeryCompactSizeClassMap SizeClassMap; +# else +static const uptr RegionSizeLog = 20; +typedef CompactSizeClassMap SizeClassMap; +# endif +#endif // SANITIZER_CAN_USE_ALLOCATOR64 + +} // namespace __scudo + +#endif // SCUDO_PLATFORM_H_ diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h deleted file mode 100644 index 57480c2a6..000000000 --- a/lib/scudo/scudo_tls.h +++ /dev/null @@ -1,74 +0,0 @@ -//===-- scudo_tls.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure definition. -/// Implementation will differ based on the thread local storage primitives -/// offered by the underlying platform. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_H_ -#define SCUDO_TLS_H_ - -#include "scudo_allocator.h" -#include "scudo_utils.h" - -#include "sanitizer_common/sanitizer_linux.h" -#include "sanitizer_common/sanitizer_platform.h" - -namespace __scudo { - -struct ALIGNED(64) ScudoTSD { - AllocatorCache Cache; - ScudoPrng Prng; - uptr QuarantineCachePlaceHolder[4]; - - void init(bool Shared); - void commitBack(); - - INLINE bool tryLock() { - if (Mutex.TryLock()) { - atomic_store_relaxed(&Precedence, 0); - return true; - } - if (atomic_load_relaxed(&Precedence) == 0) - atomic_store_relaxed(&Precedence, NanoTime()); - return false; - } - - INLINE void lock() { - Mutex.Lock(); - atomic_store_relaxed(&Precedence, 0); - } - - INLINE void unlock() { - if (!UnlockRequired) - return; - Mutex.Unlock(); - } - - INLINE u64 getPrecedence() { - return atomic_load_relaxed(&Precedence); - } - - private: - bool UnlockRequired; - StaticSpinMutex Mutex; - atomic_uint64_t Precedence; -}; - -void initThread(bool MinimalInit); - -// Platform specific fastpath functions definitions. -#include "scudo_tls_android.inc" -#include "scudo_tls_linux.inc" - -} // namespace __scudo - -#endif // SCUDO_TLS_H_ diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp deleted file mode 100644 index 695a610e9..000000000 --- a/lib/scudo/scudo_tls_android.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===-- scudo_tls_android.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure implementation for Android. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" - -#if SANITIZER_LINUX && SANITIZER_ANDROID - -#include "scudo_tls.h" - -#include - -namespace __scudo { - -static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; -static pthread_key_t PThreadKey; - -static atomic_uint32_t CurrentIndex; -static ScudoTSD *TSDs; -static u32 NumberOfTSDs; - -// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. -static uptr getNumberOfCPUs() { - cpu_set_t CPUs; - CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); - return CPU_COUNT(&CPUs); -} - -static void initOnce() { - // Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for - // testing, we create an unused key. Since the key_data array follows the tls - // array, it basically gives us the extra entry we need. - // TODO(kostyak): remove and restrict to N and above. - CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); - initScudo(); - NumberOfTSDs = getNumberOfCPUs(); - if (NumberOfTSDs == 0) - NumberOfTSDs = 1; - if (NumberOfTSDs > 32) - NumberOfTSDs = 32; - TSDs = reinterpret_cast( - MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); - for (u32 i = 0; i < NumberOfTSDs; i++) - TSDs[i].init(/*Shared=*/true); -} - -void initThread(bool MinimalInit) { - pthread_once(&GlobalInitialized, initOnce); - // Initial context assignment is done in a plain round-robin fashion. - u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); - ScudoTSD *TSD = &TSDs[Index % NumberOfTSDs]; - *get_android_tls_ptr() = reinterpret_cast(TSD); -} - -ScudoTSD *getTSDAndLockSlow() { - ScudoTSD *TSD; - if (NumberOfTSDs > 1) { - // Go through all the contexts and find the first unlocked one. - for (u32 i = 0; i < NumberOfTSDs; i++) { - TSD = &TSDs[i]; - if (TSD->tryLock()) { - *get_android_tls_ptr() = reinterpret_cast(TSD); - return TSD; - } - } - // No luck, find the one with the lowest Precedence, and slow lock it. - u64 LowestPrecedence = UINT64_MAX; - for (u32 i = 0; i < NumberOfTSDs; i++) { - u64 Precedence = TSDs[i].getPrecedence(); - if (Precedence && Precedence < LowestPrecedence) { - TSD = &TSDs[i]; - LowestPrecedence = Precedence; - } - } - if (LIKELY(LowestPrecedence != UINT64_MAX)) { - TSD->lock(); - *get_android_tls_ptr() = reinterpret_cast(TSD); - return TSD; - } - } - // Last resort, stick with the current one. - TSD = reinterpret_cast(*get_android_tls_ptr()); - TSD->lock(); - return TSD; -} - -} // namespace __scudo - -#endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc deleted file mode 100644 index 62855f766..000000000 --- a/lib/scudo/scudo_tls_android.inc +++ /dev/null @@ -1,38 +0,0 @@ -//===-- scudo_tls_android.inc -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure fastpath functions implementation for Android. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_H_ -# error "This file must be included inside scudo_tls.h." -#endif // SCUDO_TLS_H_ - -#if SANITIZER_LINUX && SANITIZER_ANDROID - -ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { - if (LIKELY(*get_android_tls_ptr())) - return; - initThread(MinimalInit); -} - -ScudoTSD *getTSDAndLockSlow(); - -ALWAYS_INLINE ScudoTSD *getTSDAndLock() { - ScudoTSD *TSD = reinterpret_cast(*get_android_tls_ptr()); - CHECK(TSD && "No TSD associated with the current thread!"); - // Try to lock the currently associated context. - if (TSD->tryLock()) - return TSD; - // If it failed, go the slow path. - return getTSDAndLockSlow(); -} - -#endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp deleted file mode 100644 index 1f51cccbc..000000000 --- a/lib/scudo/scudo_tls_linux.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===-- scudo_tls_linux.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure implementation for platforms supporting -/// thread_local. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - -#include "scudo_tls.h" - -#include - -namespace __scudo { - -static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; -static pthread_key_t PThreadKey; - -__attribute__((tls_model("initial-exec"))) -THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; -__attribute__((tls_model("initial-exec"))) -THREADLOCAL ScudoTSD TSD; - -// Fallback TSD for when the thread isn't initialized yet or is torn down. It -// can be shared between multiple threads and as such must be locked. -ScudoTSD FallbackTSD; - -static void teardownThread(void *Ptr) { - uptr I = reinterpret_cast(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 (I > 1) { - // If pthread_setspecific fails, we will go ahead with the teardown. - if (LIKELY(pthread_setspecific(PThreadKey, - reinterpret_cast(I - 1)) == 0)) - return; - } - TSD.commitBack(); - ScudoThreadState = ThreadTornDown; -} - - -static void initOnce() { - CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0); - initScudo(); - FallbackTSD.init(/*Shared=*/true); -} - -void initThread(bool MinimalInit) { - CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0); - if (UNLIKELY(MinimalInit)) - return; - CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( - GetPthreadDestructorIterations())), 0); - TSD.init(/*Shared=*/false); - ScudoThreadState = ThreadInitialized; -} - -} // namespace __scudo - -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_linux.inc b/lib/scudo/scudo_tls_linux.inc deleted file mode 100644 index e0c6deba5..000000000 --- a/lib/scudo/scudo_tls_linux.inc +++ /dev/null @@ -1,47 +0,0 @@ -//===-- scudo_tls_linux.inc -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// Scudo thread local structure fastpath functions implementation for platforms -/// supporting thread_local. -/// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_TLS_H_ -# error "This file must be included inside scudo_tls.h." -#endif // SCUDO_TLS_H_ - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - -enum ThreadState : u8 { - ThreadNotInitialized = 0, - ThreadInitialized, - ThreadTornDown, -}; -__attribute__((tls_model("initial-exec"))) -extern THREADLOCAL ThreadState ScudoThreadState; -__attribute__((tls_model("initial-exec"))) -extern THREADLOCAL ScudoTSD TSD; - -extern ScudoTSD FallbackTSD; - -ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { - if (LIKELY(ScudoThreadState != ThreadNotInitialized)) - return; - initThread(MinimalInit); -} - -ALWAYS_INLINE ScudoTSD *getTSDAndLock() { - if (UNLIKELY(ScudoThreadState != ThreadInitialized)) { - FallbackTSD.lock(); - return &FallbackTSD; - } - return &TSD; -} - -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tsd.h b/lib/scudo/scudo_tsd.h new file mode 100644 index 000000000..9ee89d399 --- /dev/null +++ b/lib/scudo/scudo_tsd.h @@ -0,0 +1,71 @@ +//===-- scudo_tsd.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread specific data definition. +/// Implementation will differ based on the thread local storage primitives +/// offered by the underlying platform. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TSD_H_ +#define SCUDO_TSD_H_ + +#include "scudo_allocator.h" +#include "scudo_utils.h" + +namespace __scudo { + +struct ALIGNED(64) ScudoTSD { + AllocatorCache Cache; + ScudoPrng Prng; + uptr QuarantineCachePlaceHolder[4]; + + void init(bool Shared); + void commitBack(); + + INLINE bool tryLock() { + if (Mutex.TryLock()) { + atomic_store_relaxed(&Precedence, 0); + return true; + } + if (atomic_load_relaxed(&Precedence) == 0) + atomic_store_relaxed(&Precedence, NanoTime()); + return false; + } + + INLINE void lock() { + Mutex.Lock(); + atomic_store_relaxed(&Precedence, 0); + } + + INLINE void unlock() { + if (!UnlockRequired) + return; + Mutex.Unlock(); + } + + INLINE u64 getPrecedence() { + return atomic_load_relaxed(&Precedence); + } + + private: + bool UnlockRequired; + StaticSpinMutex Mutex; + atomic_uint64_t Precedence; +}; + +void initThread(bool MinimalInit); + +// TSD model specific fastpath functions definitions. +#include "scudo_tsd_exclusive.inc" +#include "scudo_tsd_shared.inc" + +} // namespace __scudo + +#endif // SCUDO_TSD_H_ diff --git a/lib/scudo/scudo_tsd_exclusive.cpp b/lib/scudo/scudo_tsd_exclusive.cpp new file mode 100644 index 000000000..eb4719734 --- /dev/null +++ b/lib/scudo/scudo_tsd_exclusive.cpp @@ -0,0 +1,70 @@ +//===-- scudo_tsd_exclusive.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo exclusive TSD implementation. +/// +//===----------------------------------------------------------------------===// + +#include "scudo_tsd.h" + +#if SCUDO_TSD_EXCLUSIVE + +#include + +namespace __scudo { + +static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; +static pthread_key_t PThreadKey; + +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ScudoTSD TSD; + +// Fallback TSD for when the thread isn't initialized yet or is torn down. It +// can be shared between multiple threads and as such must be locked. +ScudoTSD FallbackTSD; + +static void teardownThread(void *Ptr) { + uptr I = reinterpret_cast(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 (I > 1) { + // If pthread_setspecific fails, we will go ahead with the teardown. + if (LIKELY(pthread_setspecific(PThreadKey, + reinterpret_cast(I - 1)) == 0)) + return; + } + TSD.commitBack(); + ScudoThreadState = ThreadTornDown; +} + + +static void initOnce() { + CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0); + initScudo(); + FallbackTSD.init(/*Shared=*/true); +} + +void initThread(bool MinimalInit) { + CHECK_EQ(pthread_once(&GlobalInitialized, initOnce), 0); + if (UNLIKELY(MinimalInit)) + return; + CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast( + GetPthreadDestructorIterations())), 0); + TSD.init(/*Shared=*/false); + ScudoThreadState = ThreadInitialized; +} + +} // namespace __scudo + +#endif // SCUDO_TSD_EXCLUSIVE diff --git a/lib/scudo/scudo_tsd_exclusive.inc b/lib/scudo/scudo_tsd_exclusive.inc new file mode 100644 index 000000000..567b6a1ed --- /dev/null +++ b/lib/scudo/scudo_tsd_exclusive.inc @@ -0,0 +1,46 @@ +//===-- scudo_tsd_exclusive.inc ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo exclusive TSD fastpath functions implementation. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TSD_H_ +# error "This file must be included inside scudo_tsd.h." +#endif // SCUDO_TSD_H_ + +#if SCUDO_TSD_EXCLUSIVE + +enum ThreadState : u8 { + ThreadNotInitialized = 0, + ThreadInitialized, + ThreadTornDown, +}; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ThreadState ScudoThreadState; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ScudoTSD TSD; + +extern ScudoTSD FallbackTSD; + +ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { + if (LIKELY(ScudoThreadState != ThreadNotInitialized)) + return; + initThread(MinimalInit); +} + +ALWAYS_INLINE ScudoTSD *getTSDAndLock() { + if (UNLIKELY(ScudoThreadState != ThreadInitialized)) { + FallbackTSD.lock(); + return &FallbackTSD; + } + return &TSD; +} + +#endif // SCUDO_TSD_EXCLUSIVE diff --git a/lib/scudo/scudo_tsd_shared.cpp b/lib/scudo/scudo_tsd_shared.cpp new file mode 100644 index 000000000..481635e6a --- /dev/null +++ b/lib/scudo/scudo_tsd_shared.cpp @@ -0,0 +1,96 @@ +//===-- scudo_tsd_shared.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo shared TSD implementation. +/// +//===----------------------------------------------------------------------===// + +#include "scudo_tsd.h" + +#if !SCUDO_TSD_EXCLUSIVE + +#include + +namespace __scudo { + +static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; +static pthread_key_t PThreadKey; + +static atomic_uint32_t CurrentIndex; +static ScudoTSD *TSDs; +static u32 NumberOfTSDs; + +// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. +static uptr getNumberOfCPUs() { + cpu_set_t CPUs; + CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); + return CPU_COUNT(&CPUs); +} + +static void initOnce() { + // Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for + // testing, we create an unused key. Since the key_data array follows the tls + // array, it basically gives us the extra entry we need. + // TODO(kostyak): remove and restrict to N and above. + CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); + initScudo(); + NumberOfTSDs = getNumberOfCPUs(); + if (NumberOfTSDs == 0) + NumberOfTSDs = 1; + if (NumberOfTSDs > 32) + NumberOfTSDs = 32; + TSDs = reinterpret_cast( + MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); + for (u32 i = 0; i < NumberOfTSDs; i++) + TSDs[i].init(/*Shared=*/true); +} + +void initThread(bool MinimalInit) { + pthread_once(&GlobalInitialized, initOnce); + // Initial context assignment is done in a plain round-robin fashion. + u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); + ScudoTSD *TSD = &TSDs[Index % NumberOfTSDs]; + *get_android_tls_ptr() = reinterpret_cast(TSD); +} + +ScudoTSD *getTSDAndLockSlow() { + ScudoTSD *TSD; + if (NumberOfTSDs > 1) { + // Go through all the contexts and find the first unlocked one. + for (u32 i = 0; i < NumberOfTSDs; i++) { + TSD = &TSDs[i]; + if (TSD->tryLock()) { + *get_android_tls_ptr() = reinterpret_cast(TSD); + return TSD; + } + } + // No luck, find the one with the lowest Precedence, and slow lock it. + u64 LowestPrecedence = UINT64_MAX; + for (u32 i = 0; i < NumberOfTSDs; i++) { + u64 Precedence = TSDs[i].getPrecedence(); + if (Precedence && Precedence < LowestPrecedence) { + TSD = &TSDs[i]; + LowestPrecedence = Precedence; + } + } + if (LIKELY(LowestPrecedence != UINT64_MAX)) { + TSD->lock(); + *get_android_tls_ptr() = reinterpret_cast(TSD); + return TSD; + } + } + // Last resort, stick with the current one. + TSD = reinterpret_cast(*get_android_tls_ptr()); + TSD->lock(); + return TSD; +} + +} // namespace __scudo + +#endif // !SCUDO_TSD_EXCLUSIVE diff --git a/lib/scudo/scudo_tsd_shared.inc b/lib/scudo/scudo_tsd_shared.inc new file mode 100644 index 000000000..874942bba --- /dev/null +++ b/lib/scudo/scudo_tsd_shared.inc @@ -0,0 +1,38 @@ +//===-- scudo_tsd_shared.inc ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo shared TSD fastpath functions implementation. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TSD_H_ +# error "This file must be included inside scudo_tsd.h." +#endif // SCUDO_TSD_H_ + +#if !SCUDO_TSD_EXCLUSIVE + +ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { + if (LIKELY(*get_android_tls_ptr())) + return; + initThread(MinimalInit); +} + +ScudoTSD *getTSDAndLockSlow(); + +ALWAYS_INLINE ScudoTSD *getTSDAndLock() { + ScudoTSD *TSD = reinterpret_cast(*get_android_tls_ptr()); + CHECK(TSD && "No TSD associated with the current thread!"); + // Try to lock the currently associated context. + if (TSD->tryLock()) + return TSD; + // If it failed, go the slow path. + return getTSDAndLockSlow(); +} + +#endif // !SCUDO_TSD_EXCLUSIVE -- cgit v1.2.1 From 3ba54520f1476ab17bcb212501c113ebd8a93433 Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Tue, 26 Sep 2017 22:37:08 +0000 Subject: [Builtins] Use 4 byte alignment for __aeabi_memclr. Summary: Align __aeabi_memclr to 4 bytes. All other ARM functions are already aligned to 4-bytes in compiler-rt. (Split off from review D38227) Reviewers: compnerd, peter.smith, srhines, weimingz, rengolin, kristof.beyls Reviewed By: compnerd Subscribers: aemerson, javed.absar, llvm-commits Differential Revision: https://reviews.llvm.org/D38271 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314255 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_memset.S | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/builtins/arm/aeabi_memset.S b/lib/builtins/arm/aeabi_memset.S index 633f59227..b8022d9e6 100644 --- a/lib/builtins/arm/aeabi_memset.S +++ b/lib/builtins/arm/aeabi_memset.S @@ -24,6 +24,7 @@ END_COMPILERRT_FUNCTION(__aeabi_memset) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset) + .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr) mov r2, r1 movs r1, #0 -- cgit v1.2.1 From 6605057457b9799788dd125ec92930f0057f088f Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Wed, 27 Sep 2017 09:29:57 +0000 Subject: [Builtins] ARM: Fix msr assembly instruction use for Thumb2. Summary: MSR instruction in Thumb2 does not support immediate operand. Fix this by moving the condition for V7-M to Thumb2 since V7-M support Thumb2 only. With this change, aeabi_cfcmp.s and aeabi_cdcmp.S files can be assembled in Thumb2 mode. (This is split out from the review D38227). Reviewers: compnerd, peter.smith, srhines, weimingz, rengolin, kristof.beyls Reviewed By: compnerd Subscribers: aemerson, javed.absar, llvm-commits Differential Revision: https://reviews.llvm.org/D38268 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314284 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_cdcmp.S | 2 +- lib/builtins/arm/aeabi_cfcmp.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S index b06f294e2..f18cfa46b 100644 --- a/lib/builtins/arm/aeabi_cdcmp.S +++ b/lib/builtins/arm/aeabi_cdcmp.S @@ -48,7 +48,7 @@ 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__) +#if defined(USE_THUMB_2) mov ip, #APSR_C msr APSR_nzcvq, ip #else diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S index 7bc84073f..fc0dbcaa0 100644 --- a/lib/builtins/arm/aeabi_cfcmp.S +++ b/lib/builtins/arm/aeabi_cfcmp.S @@ -48,7 +48,7 @@ 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__) +#if defined(USE_THUMB_2) mov ip, #APSR_C msr APSR_nzcvq, ip #else -- cgit v1.2.1 From 979ca65606f617f75c2b512eb1a1dfe0c32eb687 Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Wed, 27 Sep 2017 09:33:14 +0000 Subject: [Builtins] ARM: Fix assembling files in thumb mode. Summary: clang does not assemble files in thumb mode unless .thumb declaration is present. Add .thumb/.arm decl to _FUNCTION macros to ensure that files are assembled correctly. Fixes PR 34715. Reviewers: compnerd, peter.smith, srhines, weimingz, rengolin Reviewed By: compnerd Subscribers: aemerson, javed.absar, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D38227 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314285 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 58116114a..8695075b6 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -75,7 +75,7 @@ * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' */ #if defined(__thumb2__) || defined(__thumb__) -#define DEFINE_CODE_STATE .thumb +#define DEFINE_CODE_STATE .thumb SEPARATOR #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR #if defined(__thumb2__) #define USE_THUMB_2 @@ -89,7 +89,7 @@ #define ITE(cond) #endif // defined(__thumb__2) #else // !defined(__thumb2__) && !defined(__thumb__) -#define DEFINE_CODE_STATE .arm +#define DEFINE_CODE_STATE .arm SEPARATOR #define DECLARE_FUNC_ENCODING #define IT(cond) #define ITT(cond) @@ -146,6 +146,7 @@ #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -154,6 +155,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -162,6 +164,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -170,6 +173,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + DEFINE_CODE_STATE \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ -- cgit v1.2.1 From 1df07ed129ea515e7b33c43d06748137a4d044bf Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Wed, 27 Sep 2017 09:49:32 +0000 Subject: [builtins] fix build error on non-ARM for r314285. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314289 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/assembly.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 8695075b6..3f5e59b25 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -132,6 +132,7 @@ #endif #else // !defined(__arm) #define DECLARE_FUNC_ENCODING +#define DEFINE_CODE_STATE #endif #define GLUE2(a, b) a##b -- cgit v1.2.1 From 37865adcd1b536f12eef52f65c5dba0008921834 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 27 Sep 2017 15:38:05 +0000 Subject: [Sanitizers] Allocator: new "release memory to OS" implementation Summary: The current implementation of the allocator returning freed memory back to OS (controlled by allocator_release_to_os_interval_ms flag) requires sorting of the free chunks list, which has two major issues, first, when free list grows to millions of chunks, sorting, even the fastest one, is just too slow, and second, sorting chunks in place is unacceptable for Scudo allocator as it makes allocations more predictable and less secure. The proposed approach is linear in complexity (altough requires quite a bit more temporary memory). The idea is to count the number of free chunks on each memory page and release pages containing free chunks only. It requires one iteration over the free list of chunks and one iteration over the array of page counters. The obvious disadvantage is the allocation of the array of the counters, but even in the worst case we support (4T allocator space, 64 buckets, 16 bytes bucket size, full free list, which leads to 2 bytes per page counter and ~17M page counters), requires just about 34Mb of the intermediate buffer (comparing to ~64Gb of actually allocated chunks) and usually it stays under 100K and released after each use. It is expected to be a relatively rare event, releasing memory back to OS, keeping the buffer between those runs and added complexity of the bookkeeping seems unnesessary here (it can always be improved later, though, never say never). The most interesting problem here is how to calculate the number of chunks falling into each memory page in the bucket. Skipping all the details, there are three cases when the number of chunks per page is constant: 1) P >= C, P % C == 0 --> N = P / C 2) C > P , C % P == 0 --> N = 1 3) C <= P, P % C != 0 && C % (P % C) == 0 --> N = P / C + 1 where P is page size, C is chunk size and N is the number of chunks per page and the rest of the cases, where the number of chunks per page is calculated on the go, during the page counter array iteration. Among the rest, there are still cases where N can be deduced from the page index, but they require not that much less calculations per page than the current "brute force" way and 2/3 of the buckets fall into the first three categories anyway, so, for the sake of simplicity, it was decided to stick to those two variations. It can always be refined and improved later, should we see that brute force way slows us down unacceptably. Reviewers: eugenis, cryptoad, dvyukov Subscribers: kubamracek, mehdi_amini, llvm-commits Differential Revision: https://reviews.llvm.org/D38245 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314311 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary64.h | 345 ++++++++++++++++++--- .../tests/sanitizer_allocator_test.cc | 275 ++++++++++++++++ 2 files changed, 573 insertions(+), 47 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 0c2e72ce7..3110b55b3 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -62,10 +62,10 @@ class SizeClassAllocator64 { // as a 4-byte integer (offset from the region start shifted right by 4). typedef u32 CompactPtrT; static const uptr kCompactPtrScale = 4; - CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) { + CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) const { return static_cast((ptr - base) >> kCompactPtrScale); } - uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) { + uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) const { return base + (static_cast(ptr32) << kCompactPtrScale); } @@ -155,7 +155,7 @@ class SizeClassAllocator64 { space_beg; } - uptr GetRegionBeginBySizeClass(uptr class_id) { + uptr GetRegionBeginBySizeClass(uptr class_id) const { return SpaceBeg() + kRegionSize * class_id; } @@ -294,7 +294,240 @@ class SizeClassAllocator64 { static const uptr kNumClasses = SizeClassMap::kNumClasses; static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded; + // A packed array of counters. Each counter occupies 2^n bits, enough to store + // counter's max_value. Ctor will try to allocate the required buffer via + // mapper->MapPackedCounterArrayBuffer and the caller is expected to check + // whether the initialization was successful by checking IsAllocated() result. + // For the performance sake, none of the accessors check the validity of the + // arguments, it is assumed that index is always in [0, n) range and the value + // is not incremented past max_value. + template + class PackedCounterArray { + public: + PackedCounterArray(u64 num_counters, u64 max_value, MemoryMapperT *mapper) + : n(num_counters), memory_mapper(mapper) { + CHECK_GT(num_counters, 0); + CHECK_GT(max_value, 0); + constexpr u64 kMaxCounterBits = sizeof(*buffer) * 8ULL; + // Rounding counter storage size up to the power of two allows for using + // bit shifts calculating particular counter's index and offset. + uptr counter_size_bits = + RoundUpToPowerOfTwo(MostSignificantSetBitIndex(max_value) + 1); + CHECK_LE(counter_size_bits, kMaxCounterBits); + counter_size_bits_log = Log2(counter_size_bits); + counter_mask = ~0ULL >> (kMaxCounterBits - counter_size_bits); + + uptr packing_ratio = kMaxCounterBits >> counter_size_bits_log; + CHECK_GT(packing_ratio, 0); + packing_ratio_log = Log2(packing_ratio); + bit_offset_mask = packing_ratio - 1; + + buffer_size = + (RoundUpTo(n, 1ULL << packing_ratio_log) >> packing_ratio_log) * + sizeof(*buffer); + buffer = reinterpret_cast( + memory_mapper->MapPackedCounterArrayBuffer(buffer_size)); + } + ~PackedCounterArray() { + if (buffer) { + memory_mapper->UnmapPackedCounterArrayBuffer( + reinterpret_cast(buffer), buffer_size); + } + } + + bool IsAllocated() const { + return !!buffer; + } + + u64 GetCount() const { + return n; + } + + uptr Get(uptr i) const { + DCHECK_LT(i, n); + uptr index = i >> packing_ratio_log; + uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; + return (buffer[index] >> bit_offset) & counter_mask; + } + + void Inc(uptr i) const { + DCHECK_LT(Get(i), counter_mask); + uptr index = i >> packing_ratio_log; + uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; + buffer[index] += 1ULL << bit_offset; + } + + void IncRange(uptr from, uptr to) const { + DCHECK_LE(from, to); + for (uptr i = from; i <= to; i++) + Inc(i); + } + + private: + const u64 n; + u64 counter_size_bits_log; + u64 counter_mask; + u64 packing_ratio_log; + u64 bit_offset_mask; + + MemoryMapperT* const memory_mapper; + u64 buffer_size; + u64* buffer; + }; + + template + class FreePagesRangeTracker { + public: + explicit FreePagesRangeTracker(MemoryMapperT* mapper) + : memory_mapper(mapper), + page_size_scaled_log(Log2(GetPageSizeCached() >> kCompactPtrScale)), + in_the_range(false), current_page(0), current_range_start_page(0) {} + + void NextPage(bool freed) { + if (freed) { + if (!in_the_range) { + current_range_start_page = current_page; + in_the_range = true; + } + } else { + CloseOpenedRange(); + } + current_page++; + } + + void Done() { + CloseOpenedRange(); + } + + private: + void CloseOpenedRange() { + if (in_the_range) { + memory_mapper->ReleasePageRangeToOS( + current_range_start_page << page_size_scaled_log, + current_page << page_size_scaled_log); + in_the_range = false; + } + } + + MemoryMapperT* const memory_mapper; + const uptr page_size_scaled_log; + bool in_the_range; + uptr current_page; + uptr current_range_start_page; + }; + + // Iterates over the free_array to identify memory pages containing freed + // chunks only and returns these pages back to OS. + // allocated_pages_count is the total number of pages allocated for the + // current bucket. + template + static void ReleaseFreeMemoryToOS(CompactPtrT *free_array, + uptr free_array_count, uptr chunk_size, + uptr allocated_pages_count, + MemoryMapperT *memory_mapper) { + const uptr page_size = GetPageSizeCached(); + + // Figure out the number of chunks per page and whether we can take a fast + // path (the number of chunks per page is the same for all pages). + uptr full_pages_chunk_count_max; + bool same_chunk_count_per_page; + if (chunk_size <= page_size && page_size % chunk_size == 0) { + // Same number of chunks per page, no cross overs. + full_pages_chunk_count_max = page_size / chunk_size; + same_chunk_count_per_page = true; + } else if (chunk_size <= page_size && page_size % chunk_size != 0 && + chunk_size % (page_size % chunk_size) == 0) { + // Some chunks are crossing page boundaries, which means that the page + // contains one or two partial chunks, but all pages contain the same + // number of chunks. + full_pages_chunk_count_max = page_size / chunk_size + 1; + same_chunk_count_per_page = true; + } else if (chunk_size <= page_size) { + // Some chunks are crossing page boundaries, which means that the page + // contains one or two partial chunks. + full_pages_chunk_count_max = page_size / chunk_size + 2; + same_chunk_count_per_page = false; + } else if (chunk_size > page_size && chunk_size % page_size == 0) { + // One chunk covers multiple pages, no cross overs. + full_pages_chunk_count_max = 1; + same_chunk_count_per_page = true; + } else if (chunk_size > page_size) { + // One chunk covers multiple pages, Some chunks are crossing page + // boundaries. Some pages contain one chunk, some contain two. + full_pages_chunk_count_max = 2; + same_chunk_count_per_page = false; + } else { + UNREACHABLE("All chunk_size/page_size ratios must be handled."); + } + + PackedCounterArray counters(allocated_pages_count, + full_pages_chunk_count_max, + memory_mapper); + if (!counters.IsAllocated()) + return; + + const uptr chunk_size_scaled = chunk_size >> kCompactPtrScale; + const uptr page_size_scaled = page_size >> kCompactPtrScale; + const uptr page_size_scaled_log = Log2(page_size_scaled); + + // Iterate over free chunks and count how many free chunks affect each + // allocated page. + if (chunk_size <= page_size && page_size % chunk_size == 0) { + // Each chunk affects one page only. + for (uptr i = 0; i < free_array_count; i++) + counters.Inc(free_array[i] >> page_size_scaled_log); + } else { + // In all other cases chunks might affect more than one page. + for (uptr i = 0; i < free_array_count; i++) { + counters.IncRange( + free_array[i] >> page_size_scaled_log, + (free_array[i] + chunk_size_scaled - 1) >> page_size_scaled_log); + } + } + + // Iterate over pages detecting ranges of pages with chunk counters equal + // to the expected number of chunks for the particular page. + FreePagesRangeTracker range_tracker(memory_mapper); + if (same_chunk_count_per_page) { + // Fast path, every page has the same number of chunks affecting it. + for (uptr i = 0; i < counters.GetCount(); i++) + range_tracker.NextPage(counters.Get(i) == full_pages_chunk_count_max); + } else { + // Show path, go through the pages keeping count how many chunks affect + // each page. + const uptr pn = + chunk_size < page_size ? page_size_scaled / chunk_size_scaled : 1; + const uptr pnc = pn * chunk_size_scaled; + // The idea is to increment the current page pointer by the first chunk + // size, middle portion size (the portion of the page covered by chunks + // except the first and the last one) and then the last chunk size, adding + // up the number of chunks on the current page and checking on every step + // whether the page boundary was crossed. + uptr prev_page_boundary = 0; + uptr current_boundary = 0; + for (uptr i = 0; i < counters.GetCount(); i++) { + uptr page_boundary = prev_page_boundary + page_size_scaled; + uptr chunks_per_page = pn; + if (current_boundary < page_boundary) { + if (current_boundary > prev_page_boundary) + chunks_per_page++; + current_boundary += pnc; + if (current_boundary < page_boundary) { + chunks_per_page++; + current_boundary += chunk_size_scaled; + } + } + prev_page_boundary = page_boundary; + + range_tracker.NextPage(counters.Get(i) == chunks_per_page); + } + } + range_tracker.Done(); + } + private: + friend class MemoryMapper; + static const uptr kRegionSize = kSpaceSize / kNumClassesRounded; // FreeArray is the array of free-d chunks (stored as 4-byte offsets). // In the worst case it may reguire kRegionSize/SizeClassMap::kMinSize @@ -359,18 +592,18 @@ class SizeClassAllocator64 { Swap(a[i], a[RandN(rand_state, i + 1)]); } - RegionInfo *GetRegionInfo(uptr class_id) { + RegionInfo *GetRegionInfo(uptr class_id) const { CHECK_LT(class_id, kNumClasses); RegionInfo *regions = reinterpret_cast(SpaceBeg() + kSpaceSize); return ®ions[class_id]; } - uptr GetMetadataEnd(uptr region_beg) { + uptr GetMetadataEnd(uptr region_beg) const { return region_beg + kRegionSize - kFreeArraySize; } - uptr GetChunkIdx(uptr chunk, uptr size) { + uptr GetChunkIdx(uptr chunk, uptr size) const { if (!kUsingConstantSpaceBeg) chunk -= SpaceBeg(); @@ -382,9 +615,8 @@ class SizeClassAllocator64 { return (u32)offset / (u32)size; } - CompactPtrT *GetFreeArray(uptr region_beg) { - return reinterpret_cast(region_beg + kRegionSize - - kFreeArraySize); + CompactPtrT *GetFreeArray(uptr region_beg) const { + return reinterpret_cast(GetMetadataEnd(region_beg)); } bool MapWithCallback(uptr beg, uptr size) { @@ -410,8 +642,8 @@ class SizeClassAllocator64 { uptr num_freed_chunks) { uptr needed_space = num_freed_chunks * sizeof(CompactPtrT); if (region->mapped_free_array < needed_space) { - CHECK_LE(needed_space, kFreeArraySize); uptr new_mapped_free_array = RoundUpTo(needed_space, kFreeArrayMapSize); + CHECK_LE(new_mapped_free_array, kFreeArraySize); uptr current_map_end = reinterpret_cast(GetFreeArray(region_beg)) + region->mapped_free_array; uptr new_map_size = new_mapped_free_array - region->mapped_free_array; @@ -495,22 +727,54 @@ class SizeClassAllocator64 { CHECK_LE(region->allocated_meta, region->mapped_meta); region->exhausted = false; + // TODO(alekseyshl): Consider bumping last_release_at_ns here to prevent + // MaybeReleaseToOS from releasing just allocated pages or protect these + // not yet used chunks some other way. + return true; } - void MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size, - CompactPtrT first, CompactPtrT last) { - uptr beg_ptr = CompactPtrToPointer(region_beg, first); - uptr end_ptr = CompactPtrToPointer(region_beg, last) + chunk_size; - ReleaseMemoryPagesToOS(beg_ptr, end_ptr); - } + class MemoryMapper { + public: + MemoryMapper(const ThisT& base_allocator, uptr class_id) + : allocator(base_allocator), + region_base(base_allocator.GetRegionBeginBySizeClass(class_id)), + released_ranges_count(0) { + } - // Attempts to release some RAM back to OS. The region is expected to be - // locked. - // Algorithm: - // * Sort the chunks. - // * Find ranges fully covered by free-d chunks - // * Release them to OS with madvise. + uptr GetReleasedRangesCount() const { + return released_ranges_count; + } + + uptr MapPackedCounterArrayBuffer(uptr buffer_size) { + // TODO(alekseyshl): The idea to explore is to check if we have enough + // space between num_freed_chunks*sizeof(CompactPtrT) and + // mapped_free_array to fit buffer_size bytes and use that space instead + // of mapping a temporary one. + return reinterpret_cast( + MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters")); + } + + void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) { + UnmapOrDie(reinterpret_cast(buffer), buffer_size); + } + + // Releases [from, to) range of pages back to OS. + void ReleasePageRangeToOS(CompactPtrT from, CompactPtrT to) { + ReleaseMemoryPagesToOS( + allocator.CompactPtrToPointer(region_base, from), + allocator.CompactPtrToPointer(region_base, to)); + released_ranges_count++; + } + + private: + const ThisT& allocator; + const uptr region_base; + uptr released_ranges_count; + }; + + // Attempts to release RAM occupied by freed chunks back to OS. The region is + // expected to be locked. void MaybeReleaseToOS(uptr class_id) { RegionInfo *region = GetRegionInfo(class_id); const uptr chunk_size = ClassIdToSize(class_id); @@ -528,33 +792,20 @@ class SizeClassAllocator64 { if (interval_ms < 0) return; - u64 now_ns = NanoTime(); - if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > now_ns) + if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > NanoTime()) return; // Memory was returned recently. - region->rtoi.last_release_at_ns = now_ns; - uptr region_beg = GetRegionBeginBySizeClass(class_id); - CompactPtrT *free_array = GetFreeArray(region_beg); - SortArray(free_array, n); - - const uptr scaled_chunk_size = chunk_size >> kCompactPtrScale; - const uptr kScaledGranularity = page_size >> kCompactPtrScale; - - uptr range_beg = free_array[0]; - uptr prev = free_array[0]; - for (uptr i = 1; i < n; i++) { - uptr chunk = free_array[i]; - CHECK_GT(chunk, prev); - if (chunk - prev != scaled_chunk_size) { - CHECK_GT(chunk - prev, scaled_chunk_size); - if (prev + scaled_chunk_size - range_beg >= kScaledGranularity) { - MaybeReleaseChunkRange(region_beg, chunk_size, range_beg, prev); - region->rtoi.n_freed_at_last_release = region->stats.n_freed; - region->rtoi.num_releases++; - } - range_beg = chunk; - } - prev = chunk; + MemoryMapper memory_mapper(*this, class_id); + + ReleaseFreeMemoryToOS( + GetFreeArray(GetRegionBeginBySizeClass(class_id)), n, chunk_size, + RoundUpTo(region->allocated_user, page_size) / page_size, + &memory_mapper); + + if (memory_mapper.GetReleasedRangesCount() > 0) { + region->rtoi.n_freed_at_last_release = region->stats.n_freed; + region->rtoi.num_releases += memory_mapper.GetReleasedRangesCount(); } + region->rtoi.last_release_at_ns = NanoTime(); } }; diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index 9ec967bee..23f0cbc97 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -20,6 +20,7 @@ #include "gtest/gtest.h" +#include #include #include #include @@ -1013,6 +1014,280 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) { #endif +#if SANITIZER_CAN_USE_ALLOCATOR64 + +class NoMemoryMapper { + public: + uptr last_request_buffer_size; + + NoMemoryMapper() : last_request_buffer_size(0) {} + + uptr MapPackedCounterArrayBuffer(uptr buffer_size) { + last_request_buffer_size = buffer_size; + return 0; + } + void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {} +}; + +class RedZoneMemoryMapper { + public: + RedZoneMemoryMapper() { + const auto page_size = GetPageSize(); + buffer = MmapOrDie(3ULL * page_size, ""); + MprotectNoAccess(reinterpret_cast(buffer), page_size); + MprotectNoAccess(reinterpret_cast(buffer) + page_size * 2, page_size); + } + ~RedZoneMemoryMapper() { + UnmapOrDie(buffer, 3 * GetPageSize()); + } + + uptr MapPackedCounterArrayBuffer(uptr buffer_size) { + const auto page_size = GetPageSize(); + CHECK_EQ(buffer_size, page_size); + memset(reinterpret_cast(reinterpret_cast(buffer) + page_size), + 0, page_size); + return reinterpret_cast(buffer) + page_size; + } + void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {} + + private: + void *buffer; +}; + +TEST(SanitizerCommon, SizeClassAllocator64PackedCounterArray) { + NoMemoryMapper no_memory_mapper; + typedef Allocator64::PackedCounterArray + NoMemoryPackedCounterArray; + + for (int i = 0; i < 64; i++) { + // Various valid counter's max values packed into one word. + NoMemoryPackedCounterArray counters_2n(1, 1ULL << i, &no_memory_mapper); + EXPECT_EQ(8ULL, no_memory_mapper.last_request_buffer_size); + + // Check the "all bit set" values too. + NoMemoryPackedCounterArray counters_2n1_1(1, ~0ULL >> i, &no_memory_mapper); + EXPECT_EQ(8ULL, no_memory_mapper.last_request_buffer_size); + + // Verify the packing ratio, the counter is expected to be packed into the + // closest power of 2 bits. + NoMemoryPackedCounterArray counters(64, 1ULL << i, &no_memory_mapper); + EXPECT_EQ(8ULL * RoundUpToPowerOfTwo(i + 1), + no_memory_mapper.last_request_buffer_size); + } + + RedZoneMemoryMapper memory_mapper; + typedef Allocator64::PackedCounterArray + RedZonePackedCounterArray; + // Go through 1, 2, 4, 8, .. 64 bits per counter. + for (int i = 0; i < 7; i++) { + // Make sure counters request one memory page for the buffer. + const u64 kNumCounters = (GetPageSize() / 8) * (64 >> i); + RedZonePackedCounterArray counters(kNumCounters, + 1ULL << ((1 << i) - 1), + &memory_mapper); + counters.Inc(0); + for (u64 c = 1; c < kNumCounters - 1; c++) { + ASSERT_EQ(0ULL, counters.Get(c)); + counters.Inc(c); + ASSERT_EQ(1ULL, counters.Get(c - 1)); + } + ASSERT_EQ(0ULL, counters.Get(kNumCounters - 1)); + counters.Inc(kNumCounters - 1); + + if (i > 0) { + counters.IncRange(0, kNumCounters - 1); + for (u64 c = 0; c < kNumCounters; c++) + ASSERT_EQ(2ULL, counters.Get(c)); + } + } +} + +class RangeRecorder { + public: + std::string reported_pages; + + RangeRecorder() + : page_size_scaled_log( + Log2(GetPageSizeCached() >> Allocator64::kCompactPtrScale)), + last_page_reported(0) {} + + void ReleasePageRangeToOS(u32 from, u32 to) { + from >>= page_size_scaled_log; + to >>= page_size_scaled_log; + ASSERT_LT(from, to); + if (!reported_pages.empty()) + ASSERT_LT(last_page_reported, from); + reported_pages.append(from - last_page_reported, '.'); + reported_pages.append(to - from, 'x'); + last_page_reported = to; + } + private: + const uptr page_size_scaled_log; + u32 last_page_reported; +}; + +TEST(SanitizerCommon, SizeClassAllocator64FreePagesRangeTracker) { + typedef Allocator64::FreePagesRangeTracker RangeTracker; + + // 'x' denotes a page to be released, '.' denotes a page to be kept around. + const char* test_cases[] = { + "", + ".", + "x", + "........", + "xxxxxxxxxxx", + "..............xxxxx", + "xxxxxxxxxxxxxxxxxx.....", + "......xxxxxxxx........", + "xxx..........xxxxxxxxxxxxxxx", + "......xxxx....xxxx........", + "xxx..........xxxxxxxx....xxxxxxx", + "x.x.x.x.x.x.x.x.x.x.x.x.", + ".x.x.x.x.x.x.x.x.x.x.x.x", + ".x.x.x.x.x.x.x.x.x.x.x.x.", + "x.x.x.x.x.x.x.x.x.x.x.x.x", + }; + + for (auto test_case : test_cases) { + RangeRecorder range_recorder; + RangeTracker tracker(&range_recorder); + for (int i = 0; test_case[i] != 0; i++) + tracker.NextPage(test_case[i] == 'x'); + tracker.Done(); + // Strip trailing '.'-pages before comparing the results as they are not + // going to be reported to range_recorder anyway. + const char* last_x = strrchr(test_case, 'x'); + std::string expected( + test_case, + last_x == nullptr ? 0 : (last_x - test_case + 1)); + EXPECT_STREQ(expected.c_str(), range_recorder.reported_pages.c_str()); + } +} + +class ReleasedPagesTrackingMemoryMapper { + public: + std::set reported_pages; + + uptr MapPackedCounterArrayBuffer(uptr buffer_size) { + reported_pages.clear(); + return reinterpret_cast(calloc(1, buffer_size)); + } + void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) { + free(reinterpret_cast(buffer)); + } + + void ReleasePageRangeToOS(u32 from, u32 to) { + uptr page_size_scaled = + GetPageSizeCached() >> Allocator64::kCompactPtrScale; + for (u32 i = from; i < to; i += page_size_scaled) + reported_pages.insert(i); + } +}; + +template +void TestReleaseFreeMemoryToOS() { + ReleasedPagesTrackingMemoryMapper memory_mapper; + const uptr kAllocatedPagesCount = 1024; + const uptr page_size = GetPageSizeCached(); + const uptr page_size_scaled = page_size >> Allocator::kCompactPtrScale; + std::mt19937 r; + uint32_t rnd_state = 42; + + for (uptr class_id = 1; class_id <= Allocator::SizeClassMapT::kLargestClassID; + class_id++) { + const uptr chunk_size = Allocator::SizeClassMapT::Size(class_id); + const uptr chunk_size_scaled = chunk_size >> Allocator::kCompactPtrScale; + const uptr max_chunks = + kAllocatedPagesCount * GetPageSizeCached() / chunk_size; + + // Generate the random free list. + std::vector free_array; + bool in_free_range = false; + uptr current_range_end = 0; + for (uptr i = 0; i < max_chunks; i++) { + if (i == current_range_end) { + in_free_range = (my_rand_r(&rnd_state) & 1U) == 1; + current_range_end += my_rand_r(&rnd_state) % 100 + 1; + } + if (in_free_range) + free_array.push_back(i * chunk_size_scaled); + } + if (free_array.empty()) + continue; + // Shuffle free_list to verify that ReleaseFreeMemoryToOS does not depend on + // the list ordering. + std::shuffle(free_array.begin(), free_array.end(), r); + + Allocator::ReleaseFreeMemoryToOS(&free_array[0], free_array.size(), + chunk_size, kAllocatedPagesCount, + &memory_mapper); + + // Verify that there are no released pages touched by used chunks and all + // ranges of free chunks big enough to contain the entire memory pages had + // these pages released. + uptr verified_released_pages = 0; + std::set free_chunks(free_array.begin(), free_array.end()); + + u32 current_chunk = 0; + in_free_range = false; + u32 current_free_range_start = 0; + for (uptr i = 0; i <= max_chunks; i++) { + bool is_free_chunk = free_chunks.find(current_chunk) != free_chunks.end(); + + if (is_free_chunk) { + if (!in_free_range) { + in_free_range = true; + current_free_range_start = current_chunk; + } + } else { + // Verify that this used chunk does not touch any released page. + for (uptr i_page = current_chunk / page_size_scaled; + i_page <= (current_chunk + chunk_size_scaled - 1) / + page_size_scaled; + i_page++) { + bool page_released = + memory_mapper.reported_pages.find(i_page * page_size_scaled) != + memory_mapper.reported_pages.end(); + ASSERT_EQ(false, page_released); + } + + if (in_free_range) { + in_free_range = false; + // Verify that all entire memory pages covered by this range of free + // chunks were released. + u32 page = RoundUpTo(current_free_range_start, page_size_scaled); + while (page + page_size_scaled <= current_chunk) { + bool page_released = + memory_mapper.reported_pages.find(page) != + memory_mapper.reported_pages.end(); + ASSERT_EQ(true, page_released); + verified_released_pages++; + page += page_size_scaled; + } + } + } + + current_chunk += chunk_size_scaled; + } + + ASSERT_EQ(memory_mapper.reported_pages.size(), verified_released_pages); + } +} + +TEST(SanitizerCommon, SizeClassAllocator64ReleaseFreeMemoryToOS) { + TestReleaseFreeMemoryToOS(); +} + +TEST(SanitizerCommon, SizeClassAllocator64CompactReleaseFreeMemoryToOS) { + TestReleaseFreeMemoryToOS(); +} + +TEST(SanitizerCommon, SizeClassAllocator64VeryCompactReleaseFreeMemoryToOS) { + TestReleaseFreeMemoryToOS(); +} + +#endif // SANITIZER_CAN_USE_ALLOCATOR64 + TEST(SanitizerCommon, TwoLevelByteMap) { const u64 kSize1 = 1 << 6, kSize2 = 1 << 12; const u64 n = kSize1 * kSize2; -- cgit v1.2.1 From 9dae4270dd0b0ac280ca5b50393e25841b911377 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 27 Sep 2017 17:10:49 +0000 Subject: [Sanitizer] Disable compact size class tests on Android Fixing test failure on Android introduced in D38245. Compact size class maps defined there are not to be used on Android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314318 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/tests/sanitizer_allocator_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index 23f0cbc97..7b5e3e21f 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -1278,6 +1278,7 @@ TEST(SanitizerCommon, SizeClassAllocator64ReleaseFreeMemoryToOS) { TestReleaseFreeMemoryToOS(); } +#if !SANITIZER_ANDROID TEST(SanitizerCommon, SizeClassAllocator64CompactReleaseFreeMemoryToOS) { TestReleaseFreeMemoryToOS(); } @@ -1285,6 +1286,7 @@ TEST(SanitizerCommon, SizeClassAllocator64CompactReleaseFreeMemoryToOS) { TEST(SanitizerCommon, SizeClassAllocator64VeryCompactReleaseFreeMemoryToOS) { TestReleaseFreeMemoryToOS(); } +#endif // !SANITIZER_ANDROID #endif // SANITIZER_CAN_USE_ALLOCATOR64 -- cgit v1.2.1 From 3ac72d80925e1bc74dfafec727263e4ae45d14fd Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Wed, 27 Sep 2017 17:36:25 +0000 Subject: [ARM] builtins: Replace abort by assert in clear_cache. Summary: __builtion___clear_cache maps to clear_cache function. On Linux, clear_cache functions makes a syscall and does an abort if syscall fails. Replace the abort by an assert so that non-debug builds do not abort if the syscall fails. Fixes PR34588. Reviewers: rengolin, compnerd, srhines, peter.smith, joerg Reviewed By: rengolin Subscribers: aemerson, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D37788 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314322 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/clear_cache.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index e21ac08f8..640cb7572 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -9,6 +9,7 @@ */ #include "int_lib.h" +#include #include #if __APPLE__ @@ -121,9 +122,7 @@ void __clear_cache(void *start, void *end) { : "=r"(start_reg) : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags)); - if (start_reg != 0) { - compilerrt_abort(); - } + assert(start_reg == 0 && "Cache flush syscall failed."); #elif defined(_WIN32) FlushInstructionCache(GetCurrentProcess(), start, end - start); #else -- cgit v1.2.1 From ebab2240598af2c3e750e7934f4ff71158b52384 Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Wed, 27 Sep 2017 19:06:47 +0000 Subject: [builtins] ARM: Revert r314284, r314285 and r314289 Revert r314284, r314285 and r314289 because of a reported breakage in armv7k watchos builder. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314333 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_cdcmp.S | 2 +- lib/builtins/arm/aeabi_cfcmp.S | 2 +- lib/builtins/assembly.h | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S index f18cfa46b..b06f294e2 100644 --- a/lib/builtins/arm/aeabi_cdcmp.S +++ b/lib/builtins/arm/aeabi_cdcmp.S @@ -48,7 +48,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq) // NaN has been ruled out, so __aeabi_cdcmple can't trap bne __aeabi_cdcmple -#if defined(USE_THUMB_2) +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) mov ip, #APSR_C msr APSR_nzcvq, ip #else diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S index fc0dbcaa0..7bc84073f 100644 --- a/lib/builtins/arm/aeabi_cfcmp.S +++ b/lib/builtins/arm/aeabi_cfcmp.S @@ -48,7 +48,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq) // NaN has been ruled out, so __aeabi_cfcmple can't trap bne __aeabi_cfcmple -#if defined(USE_THUMB_2) +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) mov ip, #APSR_C msr APSR_nzcvq, ip #else diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 3f5e59b25..58116114a 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -75,7 +75,7 @@ * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' */ #if defined(__thumb2__) || defined(__thumb__) -#define DEFINE_CODE_STATE .thumb SEPARATOR +#define DEFINE_CODE_STATE .thumb #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR #if defined(__thumb2__) #define USE_THUMB_2 @@ -89,7 +89,7 @@ #define ITE(cond) #endif // defined(__thumb__2) #else // !defined(__thumb2__) && !defined(__thumb__) -#define DEFINE_CODE_STATE .arm SEPARATOR +#define DEFINE_CODE_STATE .arm #define DECLARE_FUNC_ENCODING #define IT(cond) #define ITT(cond) @@ -132,7 +132,6 @@ #endif #else // !defined(__arm) #define DECLARE_FUNC_ENCODING -#define DEFINE_CODE_STATE #endif #define GLUE2(a, b) a##b @@ -147,7 +146,6 @@ #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ - DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -156,7 +154,6 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ - DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -165,7 +162,6 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ - DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -174,7 +170,6 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ - DEFINE_CODE_STATE \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ -- cgit v1.2.1 From 24050b5ddef42f6f3306aa94d4a1f42a7893a9a7 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 27 Sep 2017 20:56:04 +0000 Subject: Add support for custom loaders to symbolizer Change-Id: I5594bd6b216deca2c73cf0a7001f9aec1e803c60 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314342 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 8 +++- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 39 ++++++++++++------ lib/sanitizer_common/sanitizer_mac.cc | 4 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_symbolizer.h | 2 + .../sanitizer_symbolizer_libcdep.cc | 46 +++++++++++++++------- lib/sanitizer_common/sanitizer_win.cc | 6 ++- 9 files changed, 78 insertions(+), 33 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 47b02b149..2000e6c7f 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,9 +727,10 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : modules_(kInitialCapacity) {} + ListOfModules() {} ~ListOfModules() { clear(); } void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } @@ -745,8 +746,11 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } + void clearOrInit() { + modules_.capacity() ? clear() : modules_.Initialize(kInitialCapacity); + } - InternalMmapVector modules_; + InternalMmapVectorNoCtor modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; }; diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 11d8b3ac0..f28d3e86b 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,6 +26,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" #include // for dlsym() #include @@ -424,7 +425,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVector *modules; + InternalMmapVectorNoCtor *modules; bool first; }; @@ -462,21 +463,37 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -void ListOfModules::init() { - clear(); +static bool requiresProcmaps() { #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 - u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(&modules_); - return; - } + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; #endif - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); +} + +static void procmapsInit(InternalMmapVectorNoCtor *modules) { + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clearOrInit(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } +} + +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + clearOrInit(); + if (!requiresProcmaps()) procmapsInit(&modules_); } // getrusage does not give us the current RSS, only the max RSS. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1570ae277..9fead91b9 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,11 +411,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clear(); + clearOrInit(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } +void ListOfModules::fallbackInit() { clear(); } + static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 96d0b2f9d..d462ad841 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVector *modules); + void DumpListOfModules(InternalMmapVectorNoCtor *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 30663e8c6..b9298d4cc 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 786876f04..3b98ff095 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 543e27e39..208362d2f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,6 +119,7 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); + void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); @@ -151,6 +152,7 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; + ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index caab4ca35..8f968e78a 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,29 +163,47 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } +void Symbolizer::RefreshModules() { + modules_.init(); + fallback_modules_.fallbackInit(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - modules_.init(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; + RefreshModules(); modules_were_reloaded = true; } - for (uptr i = 0; i < modules_.size(); i++) { - if (modules_[i].containsAddress(address)) { - return &modules_[i]; - } - } - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - modules_fresh_ = false; - return FindModuleForAddress(address); + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; } #endif - return 0; + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } + return module; } // For now we assume the following protocol: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a144db28c..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clear(); + clearOrInit(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 @@ -583,7 +583,9 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -}; +} + +void ListOfModules::fallbackInit() { clear(); } // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From b5a79d0a6cafbca510ef051589eecc91aaa0a2f4 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 27 Sep 2017 21:10:25 +0000 Subject: [scudo] Temporary disabling the valloc test on armhf Summary: Weird failure where `errno != ENOMEM` on valloc failure. The returned pointer is null since it passes the previous assert, so this shouldn't happen. http://lab.llvm.org:8011/builders/clang-cmake-armv7-a15-full/builds/10931 http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh/builds/2469 Disabling until we figure out what's going on. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: aemerson, srhines, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D38324 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314344 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/scudo/valloc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scudo/valloc.cpp b/test/scudo/valloc.cpp index 8764502a1..514a88449 100644 --- a/test/scudo/valloc.cpp +++ b/test/scudo/valloc.cpp @@ -2,7 +2,7 @@ // RUN: %run %t valid 2>&1 // RUN: not %run %t invalid 2>&1 // RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 -// UNSUPPORTED: android +// UNSUPPORTED: android, armhf-linux // Tests that valloc and pvalloc work as intended. -- cgit v1.2.1 From 5b19f39ab3109f32ced2a4dc95f0624211b1231e Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Wed, 27 Sep 2017 21:35:33 +0000 Subject: Revert "Add support for custom loaders to symbolizer" This broke the windows buildbots, revert for now. This reverts commit 24050b5ddef42f6f3306aa94d4a1f42a7893a9a7. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314347 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 8 +--- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 39 ++++++------------ lib/sanitizer_common/sanitizer_mac.cc | 4 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_symbolizer.h | 2 - .../sanitizer_symbolizer_libcdep.cc | 46 +++++++--------------- lib/sanitizer_common/sanitizer_win.cc | 6 +-- 9 files changed, 33 insertions(+), 78 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 2000e6c7f..47b02b149 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,10 +727,9 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() {} + ListOfModules() : modules_(kInitialCapacity) {} ~ListOfModules() { clear(); } void init(); - void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } @@ -746,11 +745,8 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } - void clearOrInit() { - modules_.capacity() ? clear() : modules_.Initialize(kInitialCapacity); - } - InternalMmapVectorNoCtor modules_; + InternalMmapVector modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; }; diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index f28d3e86b..11d8b3ac0 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,7 +26,6 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" #include // for dlsym() #include @@ -425,7 +424,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVectorNoCtor *modules; + InternalMmapVector *modules; bool first; }; @@ -463,37 +462,21 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -static bool requiresProcmaps() { +void ListOfModules::init() { + clear(); #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 + u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; -#else - return false; -#endif -} - -static void procmapsInit(InternalMmapVectorNoCtor *modules) { - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(modules); -} - -void ListOfModules::init() { - clearOrInit(); - if (requiresProcmaps()) { - procmapsInit(&modules_); - } else { - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); + if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(&modules_); + return; } -} - -// When a custom loader is used, dl_iterate_phdr may not contain the full -// list of modules. Allow callers to fall back to using procmaps. -void ListOfModules::fallbackInit() { - clearOrInit(); - if (!requiresProcmaps()) procmapsInit(&modules_); +#endif + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); } // getrusage does not give us the current RSS, only the max RSS. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 9fead91b9..1570ae277 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,13 +411,11 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clearOrInit(); + clear(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } -void ListOfModules::fallbackInit() { clear(); } - static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index d462ad841..96d0b2f9d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVectorNoCtor *modules); + void DumpListOfModules(InternalMmapVector *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index b9298d4cc..30663e8c6 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 3b98ff095..786876f04 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 208362d2f..543e27e39 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,7 +119,6 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); - void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); @@ -152,7 +151,6 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; - ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 8f968e78a..caab4ca35 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,47 +163,29 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } -void Symbolizer::RefreshModules() { - modules_.init(); - fallback_modules_.fallbackInit(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; -} - -static const LoadedModule *SearchForModule(const ListOfModules &modules, - uptr address) { - for (uptr i = 0; i < modules.size(); i++) { - if (modules[i].containsAddress(address)) { - return &modules[i]; - } - } - return nullptr; -} - const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - RefreshModules(); + modules_.init(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; modules_were_reloaded = true; } - const LoadedModule *module = SearchForModule(modules_, address); - if (module) return module; - - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. + for (uptr i = 0; i < modules_.size(); i++) { + if (modules_[i].containsAddress(address)) { + return &modules_[i]; + } + } + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - RefreshModules(); - module = SearchForModule(modules_, address); - if (module) return module; + modules_fresh_ = false; + return FindModuleForAddress(address); } #endif - - if (fallback_modules_.size()) { - module = SearchForModule(fallback_modules_, address); - } - return module; + return 0; } // For now we assume the following protocol: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..a144db28c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clearOrInit(); + clear(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 @@ -583,9 +583,7 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -} - -void ListOfModules::fallbackInit() { clear(); } +}; // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From bc4debffe955e4713a448c4ee5e321f58c9915d1 Mon Sep 17 00:00:00 2001 From: Dmitry Mikulin Date: Wed, 27 Sep 2017 23:32:01 +0000 Subject: ASan allocates a global data initialization array at the tail end of each compunit's .data section. This vector is not poisoned. Because of this the first symbol of the following section has no left red zone. As a result, ASan cannot detect underflow for such symbols. Poison ASan allocated metadata, it should not be accessible to user code. This fix does not eliminate the problem with missing left red zones but it reduces the set of vulnerable symbols from first symbols in each input data section to first symbols in the output section of the binary. Differential Revision: https://reviews.llvm.org/D38056 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314365 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 4 ++++ test/asan/TestCases/Helpers/underflow.cc | 1 + test/asan/TestCases/global-underflow.cc | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 test/asan/TestCases/Helpers/underflow.cc create mode 100644 test/asan/TestCases/global-underflow.cc diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index eebada804..ed1e4c614 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -384,6 +384,10 @@ void __asan_register_globals(__asan_global *globals, uptr n) { } RegisterGlobal(&globals[i]); } + + // Poison the metadata. It should not be accessible to user code. + PoisonShadow(reinterpret_cast(globals), n * sizeof(__asan_global), + kAsanGlobalRedzoneMagic); } // Unregister an array of globals. diff --git a/test/asan/TestCases/Helpers/underflow.cc b/test/asan/TestCases/Helpers/underflow.cc new file mode 100644 index 000000000..26979482f --- /dev/null +++ b/test/asan/TestCases/Helpers/underflow.cc @@ -0,0 +1 @@ +int YYY[3]={1,2,3}; diff --git a/test/asan/TestCases/global-underflow.cc b/test/asan/TestCases/global-underflow.cc new file mode 100644 index 000000000..4a0351356 --- /dev/null +++ b/test/asan/TestCases/global-underflow.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_asan -O0 %s %p/Helpers/underflow.cc -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s %p/Helpers/underflow.cc -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s %p/Helpers/underflow.cc -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s %p/Helpers/underflow.cc -o %t && not %run %t 2>&1 | FileCheck %s + +int XXX[2] = {2, 3}; +extern int YYY[]; +#include +int main(int argc, char **argv) { + memset(XXX, 0, 2*sizeof(int)); + // CHECK: {{READ of size 4 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*global-underflow.cc:}}[[@LINE+3]] + // CHECK: {{0x.* is located 4 bytes to the left of global variable}} + // CHECK: {{.*YYY.* of size 12}} + int res = YYY[-1]; + return res; +} -- cgit v1.2.1 From 59f023a92f4a75253e53cfbe1efc6f1dbaeb8208 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 28 Sep 2017 00:31:09 +0000 Subject: [ubsan] Merge ubsan_standalone_cxx shared library. Summary: Link everything, including the C++ bits, in the single ubsan_standalone SHARED library. This matches ASan setup. Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D38340 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314369 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ubsan/CMakeLists.txt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 57191c308..34b250696 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -164,6 +164,7 @@ else() OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc RTUbsan + RTUbsan_cxx RTUbsan_standalone RTInterception CFLAGS ${UBSAN_CFLAGS} @@ -171,18 +172,6 @@ else() LINK_LIBS ${UBSAN_DYNAMIC_LIBS} PARENT_TARGET ubsan) - add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx - SHARED - ARCHS ${UBSAN_SUPPORTED_ARCH} - OBJECT_LIBS RTSanitizerCommon - RTSanitizerCommonLibc - RTUbsan - RTUbsan_cxx - CFLAGS ${UBSAN_CXXFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} - LINK_LIBS ${UBSAN_DYNAMIC_LIBS} - PARENT_TARGET ubsan) - set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386) add_sanitizer_rt_symbols(clang_rt.ubsan_standalone -- cgit v1.2.1 From af46bb333e568ca5c737a1e6d058e1d06f9a29a9 Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Thu, 28 Sep 2017 05:29:59 +0000 Subject: [XRay] [compiler-rt] FDR logging arg1 handler Summary: Write out records about logged function call first arguments. D32840 implements the reading of this in llvm-xray. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32844 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314378 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_log_interface.h | 3 + lib/xray/xray_fdr_log_records.h | 1 + lib/xray/xray_fdr_logging.cc | 17 +++- lib/xray/xray_fdr_logging.h | 1 + lib/xray/xray_fdr_logging_impl.h | 130 ++++++++++++++++--------------- lib/xray/xray_trampoline_x86_64.S | 6 +- test/xray/TestCases/Linux/arg1-logger.cc | 6 +- test/xray/TestCases/Linux/fdr-mode.cc | 13 +++- 8 files changed, 106 insertions(+), 71 deletions(-) diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h index cdb20094d..7be9a4a6f 100644 --- a/include/xray/xray_log_interface.h +++ b/include/xray/xray_log_interface.h @@ -159,6 +159,9 @@ struct XRayLogImpl { /// always have a handler for function entry and exit events. In case the /// implementation wants to support arg1 (or other future extensions to XRay /// logging) those MUST be installed by the installed 'log_init' handler. + /// + /// Because we didn't want to change the ABI of this struct, the arg1 handler + /// may be silently overwritten during initialization as well. void (*handle_arg0)(int32_t, XRayEntryType); /// The log implementation provided routine for when __xray_log_flushLog() is diff --git a/lib/xray/xray_fdr_log_records.h b/lib/xray/xray_fdr_log_records.h index 3d6d38892..f475e81cf 100644 --- a/lib/xray/xray_fdr_log_records.h +++ b/lib/xray/xray_fdr_log_records.h @@ -30,6 +30,7 @@ struct alignas(16) MetadataRecord { TSCWrap, WalltimeMarker, CustomEventMarker, + CallArgument, }; // Use 7 bits to identify this record type. /* RecordKinds */ uint8_t RecordKind : 7; diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 6123c3e47..7aebcb224 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -196,9 +196,17 @@ getTimestamp() XRAY_NEVER_INSTRUMENT { void fdrLoggingHandleArg0(int32_t FuncId, XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { auto TSC_CPU = getTimestamp(); - __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), - std::get<1>(TSC_CPU), clock_gettime, - LoggingStatus, *BQ); + __xray_fdr_internal::processFunctionHook( + FuncId, Entry, std::get<0>(TSC_CPU), std::get<1>(TSC_CPU), 0, + clock_gettime, *BQ); +} + +void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry, + uint64_t Arg) XRAY_NEVER_INSTRUMENT { + auto TSC_CPU = getTimestamp(); + __xray_fdr_internal::processFunctionHook( + FuncId, Entry, std::get<0>(TSC_CPU), std::get<1>(TSC_CPU), Arg, + clock_gettime, *BQ); } void fdrLoggingHandleCustomEvent(void *Event, @@ -280,6 +288,9 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; } + // Arg1 handler should go in first to avoid concurrent code accidentally + // falling back to arg0 when it should have ran arg1. + __xray_set_handler_arg1(fdrLoggingHandleArg1); // Install the actual handleArg0 handler after initialising the buffers. __xray_set_handler(fdrLoggingHandleArg0); __xray_set_customevent_handler(fdrLoggingHandleCustomEvent); diff --git a/lib/xray/xray_fdr_logging.h b/lib/xray/xray_fdr_logging.h index 426b54dc7..1639d550a 100644 --- a/lib/xray/xray_fdr_logging.h +++ b/lib/xray/xray_fdr_logging.h @@ -30,6 +30,7 @@ XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, size_t OptionsSize); XRayLogInitStatus fdrLoggingFinalize(); void fdrLoggingHandleArg0(int32_t FuncId, XRayEntryType Entry); +void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry, uint64_t Arg1); XRayLogFlushStatus fdrLoggingFlush(); XRayLogInitStatus fdrLoggingReset(); diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 0e67c7c0e..d23c95041 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -91,19 +91,6 @@ static void writeEOBMetadata(); /// TSC Wrap records are written when a TSC delta encoding scheme overflows. static void writeTSCWrapMetadata(uint64_t TSC); -/// Here's where the meat of the processing happens. The writer captures -/// function entry, exit and tail exit points with a time and will create -/// TSCWrap, NewCPUId and Function records as necessary. The writer might -/// walk backward through its buffer and erase trivial functions to avoid -/// polluting the log and may use the buffer queue to obtain or release a -/// buffer. -static void processFunctionHook(int32_t FuncId, XRayEntryType Entry, - uint64_t TSC, unsigned char CPU, - int (*wall_clock_reader)(clockid_t, - struct timespec *), - __sanitizer::atomic_sint32_t &LoggingStatus, - const std::shared_ptr &BQ); - // Group together thread-local-data in a struct, then hide it behind a function // call so that it can be initialized on first use instead of as a global. struct ThreadLocalData { @@ -331,9 +318,22 @@ inline void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT { writeTSCWrapMetadata(TSC, getThreadLocalData().RecordPtr); } -inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, - XRayEntryType EntryType, - char *&MemPtr) XRAY_NEVER_INSTRUMENT { +// Call Argument metadata records store the arguments to a function in the +// order of their appearance; holes are not supported by the buffer format. +static inline void writeCallArgumentMetadata(uint64_t A) XRAY_NEVER_INSTRUMENT { + auto &TLD = getThreadLocalData(); + MetadataRecord CallArg; + CallArg.Type = uint8_t(RecordType::Metadata); + CallArg.RecordKind = uint8_t(MetadataRecord::RecordKinds::CallArgument); + + std::memcpy(CallArg.Data, &A, sizeof(A)); + std::memcpy(TLD.RecordPtr, &CallArg, sizeof(MetadataRecord)); + TLD.RecordPtr += sizeof(MetadataRecord); +} + +static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, + XRayEntryType EntryType, + char *&MemPtr) XRAY_NEVER_INSTRUMENT { std::aligned_storage::type AlignedFuncRecordBuffer; auto &FuncRecord = @@ -560,6 +560,41 @@ inline bool isLogInitializedAndReady( return true; } // namespace __xray_fdr_internal +// Compute the TSC difference between the time of measurement and the previous +// event. There are a few interesting situations we need to account for: +// +// - The thread has migrated to a different CPU. If this is the case, then +// we write down the following records: +// +// 1. A 'NewCPUId' Metadata record. +// 2. A FunctionRecord with a 0 for the TSCDelta field. +// +// - The TSC delta is greater than the 32 bits we can store in a +// FunctionRecord. In this case we write down the following records: +// +// 1. A 'TSCWrap' Metadata record. +// 2. A FunctionRecord with a 0 for the TSCDelta field. +// +// - The TSC delta is representable within the 32 bits we can store in a +// FunctionRecord. In this case we write down just a FunctionRecord with +// the correct TSC delta. +inline uint32_t writeCurrentCPUTSC(ThreadLocalData &TLD, uint64_t TSC, uint8_t CPU) { + if (CPU != TLD.CurrentCPU) { + // We've moved to a new CPU. + writeNewCPUIdMetadata(CPU, TSC); + return 0; + } + // If the delta is greater than the range for a uint32_t, then we write out + // the TSC wrap metadata entry with the full TSC, and the TSC for the + // function record be 0. + uint64_t Delta = TSC - TLD.LastTSC; + if (Delta <= std::numeric_limits::max()) + return Delta; + + writeTSCWrapMetadata(TSC); + return 0; +} + inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { auto &TLD = getThreadLocalData(); auto BufferStart = static_cast(TLD.Buffer.Buffer); @@ -573,10 +608,15 @@ inline void endBufferIfFull() XRAY_NEVER_INSTRUMENT { thread_local volatile bool Running = false; +/// Here's where the meat of the processing happens. The writer captures +/// function entry, exit and tail exit points with a time and will create +/// TSCWrap, NewCPUId and Function records as necessary. The writer might +/// walk backward through its buffer and erase trivial functions to avoid +/// polluting the log and may use the buffer queue to obtain or release a +/// buffer. inline void processFunctionHook( int32_t FuncId, XRayEntryType Entry, uint64_t TSC, unsigned char CPU, - int (*wall_clock_reader)(clockid_t, struct timespec *), - __sanitizer::atomic_sint32_t &LoggingStatus, + uint64_t Arg1, int (*wall_clock_reader)(clockid_t, struct timespec *), const std::shared_ptr &BQ) XRAY_NEVER_INSTRUMENT { // Prevent signal handler recursion, so in case we're already in a log writing // mode and the signal handler comes in (and is also instrumented) then we @@ -609,10 +649,10 @@ inline void processFunctionHook( // - The least number of bytes we will ever write is 8 // (sizeof(FunctionRecord)) only if the delta between the previous entry // and this entry is within 32 bits. - // - The most number of bytes we will ever write is 8 + 16 = 24. This is - // computed by: + // - The most number of bytes we will ever write is 8 + 16 + 16 = 40. + // This is computed by: // - // sizeof(FunctionRecord) + sizeof(MetadataRecord) + // MaxSize = sizeof(FunctionRecord) + 2 * sizeof(MetadataRecord) // // These arise in the following cases: // @@ -626,6 +666,7 @@ inline void processFunctionHook( // FunctionRecord. // 3. When we learn about a new CPU ID, we need to write down a "new cpu // id" MetadataRecord before writing out the actual FunctionRecord. + // 4. The second MetadataRecord is the optional function call argument. // // - An End-of-Buffer (EOB) MetadataRecord is 16 bytes. // @@ -634,53 +675,18 @@ inline void processFunctionHook( // MetadataRecord. If we don't have enough space after writing as much as 24 // bytes in the end of the buffer, we need to write out the EOB, get a new // Buffer, set it up properly before doing any further writing. - // - if (!prepareBuffer(wall_clock_reader, FunctionRecSize + MetadataRecSize)) { + size_t MaxSize = FunctionRecSize + 2 * MetadataRecSize; + if (!prepareBuffer(wall_clock_reader, MaxSize)) { TLD.LocalBQ = nullptr; return; } - // By this point, we are now ready to write at most 24 bytes (one metadata - // record and one function record). - assert((TLD.RecordPtr + (MetadataRecSize + FunctionRecSize)) - - static_cast(TLD.Buffer.Buffer) >= + // By this point, we are now ready to write up to 40 bytes (explained above). + assert((TLD.RecordPtr + MaxSize) - static_cast(TLD.Buffer.Buffer) >= static_cast(MetadataRecSize) && "Misconfigured BufferQueue provided; Buffer size not large enough."); - // Here we compute the TSC Delta. There are a few interesting situations we - // need to account for: - // - // - The thread has migrated to a different CPU. If this is the case, then - // we write down the following records: - // - // 1. A 'NewCPUId' Metadata record. - // 2. A FunctionRecord with a 0 for the TSCDelta field. - // - // - The TSC delta is greater than the 32 bits we can store in a - // FunctionRecord. In this case we write down the following records: - // - // 1. A 'TSCWrap' Metadata record. - // 2. A FunctionRecord with a 0 for the TSCDelta field. - // - // - The TSC delta is representable within the 32 bits we can store in a - // FunctionRecord. In this case we write down just a FunctionRecord with - // the correct TSC delta. - // - uint32_t RecordTSCDelta = 0; - if (CPU != TLD.CurrentCPU) { - // We've moved to a new CPU. - writeNewCPUIdMetadata(CPU, TSC); - } else { - // If the delta is greater than the range for a uint32_t, then we write out - // the TSC wrap metadata entry with the full TSC, and the TSC for the - // function record be 0. - auto Delta = TSC - TLD.LastTSC; - if (Delta > (1ULL << 32) - 1) - writeTSCWrapMetadata(TSC); - else - RecordTSCDelta = Delta; - } - + auto RecordTSCDelta = writeCurrentCPUTSC(TLD, TSC, CPU); TLD.LastTSC = TSC; TLD.CurrentCPU = CPU; switch (Entry) { @@ -711,6 +717,8 @@ inline void processFunctionHook( } writeFunctionRecord(FuncId, RecordTSCDelta, Entry, TLD.RecordPtr); + if (Entry == XRayEntryType::LOG_ARGS_ENTRY) + writeCallArgumentMetadata(Arg1); // If we've exhausted the buffer by this time, we then release the buffer to // make sure that other threads may start using this buffer. diff --git a/lib/xray/xray_trampoline_x86_64.S b/lib/xray/xray_trampoline_x86_64.S index 9a3bc1c1f..ffbfb5c7e 100644 --- a/lib/xray/xray_trampoline_x86_64.S +++ b/lib/xray/xray_trampoline_x86_64.S @@ -173,11 +173,11 @@ __xray_ArgLoggerEntry: .Larg1entryLog: - // First argument will become the third + // First argument will become the third movq %rdi, %rdx - // XRayEntryType::ENTRY into the second - xorq %rsi, %rsi + // XRayEntryType::LOG_ARGS_ENTRY into the second + mov $0x3, %esi // 32-bit function ID becomes the first movl %r10d, %edi diff --git a/test/xray/TestCases/Linux/arg1-logger.cc b/test/xray/TestCases/Linux/arg1-logger.cc index 955347b15..bf5c8dbcc 100644 --- a/test/xray/TestCases/Linux/arg1-logger.cc +++ b/test/xray/TestCases/Linux/arg1-logger.cc @@ -29,7 +29,7 @@ int main() { __xray_set_handler_arg1(arg1logger); foo(nullptr); - // CHECK: Arg1: 0, XRayEntryType 0 + // CHECK: Arg1: 0, XRayEntryType 3 __xray_remove_handler_arg1(); foo((void *) 0xBADC0DE); @@ -37,7 +37,7 @@ int main() { __xray_set_handler_arg1(arg1logger); foo((void *) 0xDEADBEEFCAFE); - // CHECK-NEXT: Arg1: deadbeefcafe, XRayEntryType 0 + // CHECK-NEXT: Arg1: deadbeefcafe, XRayEntryType 3 foo((void *) -1); - // CHECK-NEXT: Arg1: ffffffffffffffff, XRayEntryType 0 + // CHECK-NEXT: Arg1: ffffffffffffffff, XRayEntryType 3 } diff --git a/test/xray/TestCases/Linux/fdr-mode.cc b/test/xray/TestCases/Linux/fdr-mode.cc index d08a7d492..744c051cf 100644 --- a/test/xray/TestCases/Linux/fdr-mode.cc +++ b/test/xray/TestCases/Linux/fdr-mode.cc @@ -30,6 +30,9 @@ thread_local uint64_t var = 0; [[clang::xray_always_instrument]] void __attribute__((noinline)) fA() { fB(); } +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) fArg(int) { } + int main(int argc, char *argv[]) { using namespace __xray; FDRLoggingOptions Options; @@ -52,6 +55,7 @@ int main(int argc, char *argv[]) { fC(); fB(); fA(); + fArg(1); }); other_thread.join(); std::cout << "Joined" << std::endl; @@ -85,8 +89,15 @@ int main(int argc, char *argv[]) { // TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } // TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } + // Assert that when unwriting is enabled with a high threshold time, all the function records are erased. A CPU switch could erroneously fail this test, but // is unlikely given the test program. -// UNWRITE: header +// Even with a high threshold, arg1 logging is never unwritten. +// UNWRITE: header: +// UNWRITE: records: +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], kind: function-exit, tsc: {{[0-9]+}} } // UNWRITE-NOT: function-enter // UNWRITE-NOT: function-{{exit|tail-exit}} -- cgit v1.2.1 From 2c81ea0cccbda5b123c57889b92922491ba97b01 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 28 Sep 2017 07:32:00 +0000 Subject: tsan: handle signals in pause call git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314384 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 6 ++++++ test/tsan/signal_pause.cc | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/tsan/signal_pause.cc diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 34f49fce5..82a7f371a 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -371,6 +371,11 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { return res; } +TSAN_INTERCEPTOR(int, pause) { + SCOPED_TSAN_INTERCEPTOR(pause); + return BLOCK_REAL(pause)(); +} + // The sole reason tsan wraps atexit callbacks is to establish synchronization // between callback setup and callback execution. struct AtExitCtx { @@ -2583,6 +2588,7 @@ void InitializeInterceptors() { TSAN_INTERCEPT(sleep); TSAN_INTERCEPT(usleep); TSAN_INTERCEPT(nanosleep); + TSAN_INTERCEPT(pause); TSAN_INTERCEPT(gettimeofday); TSAN_INTERCEPT(getaddrinfo); diff --git a/test/tsan/signal_pause.cc b/test/tsan/signal_pause.cc new file mode 100644 index 000000000..cbcef9491 --- /dev/null +++ b/test/tsan/signal_pause.cc @@ -0,0 +1,35 @@ +// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +// Test that pause loop handles signals. + +#include "test.h" +#include +#include + +void handler(int signum) { + write(2, "DONE\n", 5); + _exit(0); +} + +void *thread(void *arg) { + for (;;) + pause(); + return 0; +} + +int main(int argc, char** argv) { + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGUSR1, &act, 0)) { + fprintf(stderr, "sigaction failed %d\n", errno); + return 1; + } + pthread_t th; + pthread_create(&th, 0, thread, 0); + sleep(1); // give it time to block in pause + pthread_kill(th, SIGUSR1); + sleep(10); // signal handler must exit the process while we are here + return 0; +} + +// CHECK: DONE -- cgit v1.2.1 From 4d153fb22be7ea0f60799fb5d46de7473e8b1d7d Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 28 Sep 2017 13:38:58 +0000 Subject: [asan] Unpoison global metadata on dlclose. dlclose itself might touch it, so better return it to the state it was before. I don't know how to create a test for this as it would require chaning dlclose itself. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314415 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_globals.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index ed1e4c614..0db65d010 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -403,6 +403,9 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) { } UnregisterGlobal(&globals[i]); } + + // Unpoison the metadata. + PoisonShadow(reinterpret_cast(globals), n * sizeof(__asan_global), 0); } // This method runs immediately prior to dynamic initialization in each TU, -- cgit v1.2.1 From 81f388fe570e5b6460dd5bc9b9a36b72714eeb68 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 28 Sep 2017 16:58:35 +0000 Subject: Add support for custom loaders to the sanitizer symbolizer Summary: Adds a fallback mode to procmaps when the symbolizer fails to locate a module for a given address by using dl_iterate_phdr. Reviewers: kubamracek, rnk, vitalybuka, eugenis Reviewed By: eugenis Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D37269 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314431 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 10 ++++- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 39 ++++++++++++------ lib/sanitizer_common/sanitizer_mac.cc | 4 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_symbolizer.h | 2 + .../sanitizer_symbolizer_libcdep.cc | 46 +++++++++++++++------- lib/sanitizer_common/sanitizer_win.cc | 6 ++- 9 files changed, 80 insertions(+), 33 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 47b02b149..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,9 +727,10 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : modules_(kInitialCapacity) {} + ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } @@ -745,10 +746,15 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } + void clearOrInit() { + initialized ? clear() : modules_.Initialize(kInitialCapacity); + initialized = true; + } - InternalMmapVector modules_; + InternalMmapVectorNoCtor modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; + bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 11d8b3ac0..f28d3e86b 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,6 +26,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" #include // for dlsym() #include @@ -424,7 +425,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVector *modules; + InternalMmapVectorNoCtor *modules; bool first; }; @@ -462,21 +463,37 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -void ListOfModules::init() { - clear(); +static bool requiresProcmaps() { #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 - u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(&modules_); - return; - } + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; #endif - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); +} + +static void procmapsInit(InternalMmapVectorNoCtor *modules) { + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clearOrInit(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } +} + +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + clearOrInit(); + if (!requiresProcmaps()) procmapsInit(&modules_); } // getrusage does not give us the current RSS, only the max RSS. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1570ae277..9fead91b9 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,11 +411,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clear(); + clearOrInit(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } +void ListOfModules::fallbackInit() { clear(); } + static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 96d0b2f9d..d462ad841 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVector *modules); + void DumpListOfModules(InternalMmapVectorNoCtor *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 30663e8c6..b9298d4cc 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 786876f04..3b98ff095 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 543e27e39..208362d2f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,6 +119,7 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); + void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); @@ -151,6 +152,7 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; + ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index caab4ca35..8f968e78a 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,29 +163,47 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } +void Symbolizer::RefreshModules() { + modules_.init(); + fallback_modules_.fallbackInit(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - modules_.init(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; + RefreshModules(); modules_were_reloaded = true; } - for (uptr i = 0; i < modules_.size(); i++) { - if (modules_[i].containsAddress(address)) { - return &modules_[i]; - } - } - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - modules_fresh_ = false; - return FindModuleForAddress(address); + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; } #endif - return 0; + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } + return module; } // For now we assume the following protocol: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a144db28c..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clear(); + clearOrInit(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 @@ -583,7 +583,9 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -}; +} + +void ListOfModules::fallbackInit() { clear(); } // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From 35bf445122908c454897722b57a81ba320ed915e Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 28 Sep 2017 18:19:44 +0000 Subject: [asan] Fix the bug number in the error message. The link in the "Shadow memory range interleaves with an existing memory mapping" error message was pointing to the wrong bug. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314441 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_shadow_setup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index d65b27ee2..08c009184 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -85,7 +85,7 @@ static void MaybeReportLinuxPIEBug() { #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); Report( - "See https://github.com/google/sanitizers/issues/837 for possible " + "See https://github.com/google/sanitizers/issues/856 for possible " "workarounds.\n"); #endif } -- cgit v1.2.1 From c76c49014f5b65f316833358d89d6c8c8325a900 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Thu, 28 Sep 2017 19:37:17 +0000 Subject: Revert "Add support for custom loaders to the sanitizer symbolizer" This causes the gcc sanitizer buildbot to timeout. This reverts commit 81f388fe570e5b6460dd5bc9b9a36b72714eeb68. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314453 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 10 +---- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 39 ++++++------------ lib/sanitizer_common/sanitizer_mac.cc | 4 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_symbolizer.h | 2 - .../sanitizer_symbolizer_libcdep.cc | 46 +++++++--------------- lib/sanitizer_common/sanitizer_win.cc | 6 +-- 9 files changed, 33 insertions(+), 80 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ee5eca516..47b02b149 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,10 +727,9 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : initialized(false) {} + ListOfModules() : modules_(kInitialCapacity) {} ~ListOfModules() { clear(); } void init(); - void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } @@ -746,15 +745,10 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } - void clearOrInit() { - initialized ? clear() : modules_.Initialize(kInitialCapacity); - initialized = true; - } - InternalMmapVectorNoCtor modules_; + InternalMmapVector modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; - bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index f28d3e86b..11d8b3ac0 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,7 +26,6 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" #include // for dlsym() #include @@ -425,7 +424,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVectorNoCtor *modules; + InternalMmapVector *modules; bool first; }; @@ -463,37 +462,21 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -static bool requiresProcmaps() { +void ListOfModules::init() { + clear(); #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 + u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; -#else - return false; -#endif -} - -static void procmapsInit(InternalMmapVectorNoCtor *modules) { - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(modules); -} - -void ListOfModules::init() { - clearOrInit(); - if (requiresProcmaps()) { - procmapsInit(&modules_); - } else { - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); + if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(&modules_); + return; } -} - -// When a custom loader is used, dl_iterate_phdr may not contain the full -// list of modules. Allow callers to fall back to using procmaps. -void ListOfModules::fallbackInit() { - clearOrInit(); - if (!requiresProcmaps()) procmapsInit(&modules_); +#endif + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); } // getrusage does not give us the current RSS, only the max RSS. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 9fead91b9..1570ae277 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,13 +411,11 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clearOrInit(); + clear(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } -void ListOfModules::fallbackInit() { clear(); } - static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index d462ad841..96d0b2f9d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVectorNoCtor *modules); + void DumpListOfModules(InternalMmapVector *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index b9298d4cc..30663e8c6 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 3b98ff095..786876f04 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 208362d2f..543e27e39 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,7 +119,6 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); - void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); @@ -152,7 +151,6 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; - ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 8f968e78a..caab4ca35 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,47 +163,29 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } -void Symbolizer::RefreshModules() { - modules_.init(); - fallback_modules_.fallbackInit(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; -} - -static const LoadedModule *SearchForModule(const ListOfModules &modules, - uptr address) { - for (uptr i = 0; i < modules.size(); i++) { - if (modules[i].containsAddress(address)) { - return &modules[i]; - } - } - return nullptr; -} - const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - RefreshModules(); + modules_.init(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; modules_were_reloaded = true; } - const LoadedModule *module = SearchForModule(modules_, address); - if (module) return module; - - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. + for (uptr i = 0; i < modules_.size(); i++) { + if (modules_[i].containsAddress(address)) { + return &modules_[i]; + } + } + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - RefreshModules(); - module = SearchForModule(modules_, address); - if (module) return module; + modules_fresh_ = false; + return FindModuleForAddress(address); } #endif - - if (fallback_modules_.size()) { - module = SearchForModule(fallback_modules_, address); - } - return module; + return 0; } // For now we assume the following protocol: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..a144db28c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clearOrInit(); + clear(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 @@ -583,9 +583,7 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -} - -void ListOfModules::fallbackInit() { clear(); } +}; // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From 283e436ec89b4b4a293870e83343f9cab9822f44 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 29 Sep 2017 04:28:11 +0000 Subject: [XRay][compiler-rt][NFC] Remove loggingInitialized() convenience function The function was introduced as a convenience that used to be called in multiple places. Recent refactorings have removed the need to call this function in multiple places, so inlined the implementation in the single place it's defined. Broken out from D38119. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314489 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index d23c95041..4c9c46e03 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -195,13 +195,6 @@ public: } }; -inline bool loggingInitialized( - const __sanitizer::atomic_sint32_t &LoggingStatus) XRAY_NEVER_INSTRUMENT { - return __sanitizer::atomic_load(&LoggingStatus, - __sanitizer::memory_order_acquire) == - XRayLogInitStatus::XRAY_LOG_INITIALIZED; -} - } // namespace inline void writeNewBufferPreamble(pid_t Tid, timespec TS, @@ -528,7 +521,10 @@ inline bool isLogInitializedAndReady( return false; } - if (!loggingInitialized(LoggingStatus) || LBQ->finalizing()) { + if (__sanitizer::atomic_load(&LoggingStatus, + __sanitizer::memory_order_acquire) != + XRayLogInitStatus::XRAY_LOG_INITIALIZED || + LBQ->finalizing()) { writeEOBMetadata(); if (!releaseThreadLocalBuffer(*LBQ)) return false; @@ -578,7 +574,8 @@ inline bool isLogInitializedAndReady( // - The TSC delta is representable within the 32 bits we can store in a // FunctionRecord. In this case we write down just a FunctionRecord with // the correct TSC delta. -inline uint32_t writeCurrentCPUTSC(ThreadLocalData &TLD, uint64_t TSC, uint8_t CPU) { +inline uint32_t writeCurrentCPUTSC(ThreadLocalData &TLD, uint64_t TSC, + uint8_t CPU) { if (CPU != TLD.CurrentCPU) { // We've moved to a new CPU. writeNewCPUIdMetadata(CPU, TSC); -- cgit v1.2.1 From 87e43ef9dee0a57f2fef86e90c24c987faaedb53 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 29 Sep 2017 13:32:39 +0000 Subject: [CMake] Fix configuration on PowerPC with sanitizers TEST_BIG_ENDIAN() performs compile tests that will fail with -nodefaultlibs when building under LLVM_USE_SANITIZER. Differential Revision: https://reviews.llvm.org/D38277 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314512 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/base-config-ix.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 55f322538..45e490481 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -148,7 +148,13 @@ macro(test_targets) endif() endif() elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc") + # Strip out -nodefaultlibs when calling TEST_BIG_ENDIAN. Configuration + # will fail with this option when building with a sanitizer. + cmake_push_check_state() + string(REPLACE "-nodefaultlibs" "" CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN) + cmake_pop_check_state() + if(HOST_IS_BIG_ENDIAN) test_target_arch(powerpc64 "" "-m64") else() -- cgit v1.2.1 From d04247a9f29b0db10a29ffbed8189ca388a7b871 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 15:06:47 +0000 Subject: Refactor android fallback procmaps init. NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314518 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 29 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 11d8b3ac0..da715dc6c 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -462,21 +462,30 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -void ListOfModules::init() { - clear(); +static bool requiresProcmaps() { #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 - u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(&modules_); - return; - } + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; #endif - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); +} + +static void procmapsInit(InternalMmapVector *modules) { + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clear(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } } // getrusage does not give us the current RSS, only the max RSS. -- cgit v1.2.1 From 0c8ffd51348ef23104e19c3d23a5ec63458455de Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 15:14:31 +0000 Subject: Remove recursion from FindModuleForAddress. NFC. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314520 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_symbolizer_libcdep.cc | 35 +++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index caab4ca35..37ac12c34 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,29 +163,42 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } +void Symbolizer::RefreshModules() { + modules_.init(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - modules_.init(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; + RefreshModules(); modules_were_reloaded = true; } - for (uptr i = 0; i < modules_.size(); i++) { - if (modules_[i].containsAddress(address)) { - return &modules_[i]; - } - } + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + // dlopen/dlclose interceptors invalidate the module list, but when // interception is disabled, we need to retry if the lookup fails in // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - modules_fresh_ = false; - return FindModuleForAddress(address); + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; } #endif - return 0; + return module; } // For now we assume the following protocol: -- cgit v1.2.1 From 6858138437b6d264d6a20e25b033cd4f2b23ec55 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 15:17:23 +0000 Subject: Add missing header definition git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314521 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_symbolizer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 543e27e39..95587126c 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,6 +119,7 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); + void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); -- cgit v1.2.1 From 9d26c0129b322037e18d4cc5aac1bf2c914501fd Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 29 Sep 2017 16:02:39 +0000 Subject: Fix cmake file broken by D38277. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314528 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/base-config-ix.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake index 45e490481..5b21b700c 100644 --- a/cmake/base-config-ix.cmake +++ b/cmake/base-config-ix.cmake @@ -151,7 +151,7 @@ macro(test_targets) # Strip out -nodefaultlibs when calling TEST_BIG_ENDIAN. Configuration # will fail with this option when building with a sanitizer. cmake_push_check_state() - string(REPLACE "-nodefaultlibs" "" CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) + string(REPLACE "-nodefaultlibs" "" CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN) cmake_pop_check_state() -- cgit v1.2.1 From 5e66b692b20264b974725665036641a6731f5f75 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 16:47:02 +0000 Subject: Move LoadedModule list to a NoCtor vector and initialize on demand. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314533 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 9 +++++++-- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 6 +++--- lib/sanitizer_common/sanitizer_mac.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 2 +- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 47b02b149..11ee59024 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,7 +727,7 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : modules_(kInitialCapacity) {} + ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); const LoadedModule *begin() const { return modules_.begin(); } @@ -745,10 +745,15 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } + void clearOrInit() { + initialized ? clear() : modules_.Initialize(kInitialCapacity); + initialized = true; + } - InternalMmapVector modules_; + InternalMmapVectorNoCtor modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; + bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index da715dc6c..0f420875d 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -424,7 +424,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVector *modules; + InternalMmapVectorNoCtor *modules; bool first; }; @@ -473,13 +473,13 @@ static bool requiresProcmaps() { #endif } -static void procmapsInit(InternalMmapVector *modules) { +static void procmapsInit(InternalMmapVectorNoCtor *modules) { MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(modules); } void ListOfModules::init() { - clear(); + clearOrInit(); if (requiresProcmaps()) { procmapsInit(&modules_); } else { diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1570ae277..cd63cb42f 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,7 +411,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clear(); + clearOrInit(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 96d0b2f9d..d462ad841 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVector *modules); + void DumpListOfModules(InternalMmapVectorNoCtor *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 30663e8c6..b9298d4cc 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 786876f04..3b98ff095 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a144db28c..84065aa0e 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clear(); + clearOrInit(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 -- cgit v1.2.1 From faf993b377cb1212143ea0659c178f0408582351 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 20:04:29 +0000 Subject: Revert "Move LoadedModule list to a NoCtor vector and initialize on demand." I think this may have introduced a failure on llvm-clang-lld-x86_64-debian-fast This reverts commit r314533 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314552 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 9 ++------- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 6 +++--- lib/sanitizer_common/sanitizer_mac.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 2 +- 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 11ee59024..47b02b149 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,7 +727,7 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : initialized(false) {} + ListOfModules() : modules_(kInitialCapacity) {} ~ListOfModules() { clear(); } void init(); const LoadedModule *begin() const { return modules_.begin(); } @@ -745,15 +745,10 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } - void clearOrInit() { - initialized ? clear() : modules_.Initialize(kInitialCapacity); - initialized = true; - } - InternalMmapVectorNoCtor modules_; + InternalMmapVector modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; - bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 0f420875d..da715dc6c 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -424,7 +424,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVectorNoCtor *modules; + InternalMmapVector *modules; bool first; }; @@ -473,13 +473,13 @@ static bool requiresProcmaps() { #endif } -static void procmapsInit(InternalMmapVectorNoCtor *modules) { +static void procmapsInit(InternalMmapVector *modules) { MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(modules); } void ListOfModules::init() { - clearOrInit(); + clear(); if (requiresProcmaps()) { procmapsInit(&modules_); } else { diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index cd63cb42f..1570ae277 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,7 +411,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clearOrInit(); + clear(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index d462ad841..96d0b2f9d 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVectorNoCtor *modules); + void DumpListOfModules(InternalMmapVector *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index b9298d4cc..30663e8c6 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 3b98ff095..786876f04 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { + InternalMmapVector *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 84065aa0e..a144db28c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clearOrInit(); + clear(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 -- cgit v1.2.1 From c9b5e685aed2bf2bd2faa0566b90196f6e9eb7ba Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Fri, 29 Sep 2017 20:55:06 +0000 Subject: Move LoadedModule list to a NoCtor vector and initialize on demand. Unreverting this patch because llvm-clang-lld-x86_64-debian-fast started passing again before the revert hit. Must've been just a flake. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314556 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 9 +++++++-- lib/sanitizer_common/sanitizer_linux_libcdep.cc | 6 +++--- lib/sanitizer_common/sanitizer_mac.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 +- lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 +- lib/sanitizer_common/sanitizer_win.cc | 2 +- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 47b02b149..11ee59024 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,7 +727,7 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : modules_(kInitialCapacity) {} + ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); const LoadedModule *begin() const { return modules_.begin(); } @@ -745,10 +745,15 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } + void clearOrInit() { + initialized ? clear() : modules_.Initialize(kInitialCapacity); + initialized = true; + } - InternalMmapVector modules_; + InternalMmapVectorNoCtor modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; + bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index da715dc6c..0f420875d 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -424,7 +424,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVector *modules; + InternalMmapVectorNoCtor *modules; bool first; }; @@ -473,13 +473,13 @@ static bool requiresProcmaps() { #endif } -static void procmapsInit(InternalMmapVector *modules) { +static void procmapsInit(InternalMmapVectorNoCtor *modules) { MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(modules); } void ListOfModules::init() { - clear(); + clearOrInit(); if (requiresProcmaps()) { procmapsInit(&modules_); } else { diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1570ae277..cd63cb42f 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,7 +411,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clear(); + clearOrInit(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 96d0b2f9d..d462ad841 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVector *modules); + void DumpListOfModules(InternalMmapVectorNoCtor *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 30663e8c6..b9298d4cc 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 786876f04..3b98ff095 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector *modules) { + InternalMmapVectorNoCtor *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a144db28c..84065aa0e 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clear(); + clearOrInit(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 -- cgit v1.2.1 From 63780036ddaf039747a5491d6dd7c2e3809bb41a Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Mon, 2 Oct 2017 05:03:55 +0000 Subject: [cmake] Add a separate CMake var to control profile runtime Make it possible to control building profile runtime separately from other options. Before r313549, the profile runtime building was controlled along with sanitizers. However, since that commit it is built unconditionally which results in multiple builds for people building different runtimes separately. Differential Revision: https://reviews.llvm.org/D38441 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314646 91177308-0d34-0410-b5e6-96231b3b80d8 --- CMakeLists.txt | 2 ++ lib/CMakeLists.txt | 2 +- test/CMakeLists.txt | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c05403ebf..adb40f292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,8 @@ option(COMPILER_RT_BUILD_XRAY "Build xray" ON) mark_as_advanced(COMPILER_RT_BUILD_XRAY) option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON) mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER) +option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON) +mark_as_advanced(COMPILER_RT_BUILD_PROFILE) option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF) mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a92d0a3f0..b3731f653 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -41,7 +41,7 @@ if(COMPILER_RT_BUILD_SANITIZERS) endforeach() endif() -if (COMPILER_RT_HAS_PROFILE) +if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE) compiler_rt_build_runtime(profile) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e691eab7d..0acf87bc8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,7 +10,7 @@ configure_lit_site_cfg( set(SANITIZER_COMMON_LIT_TEST_DEPS) -if (COMPILER_RT_HAS_PROFILE) +if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile) endif() @@ -72,7 +72,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) endif() endforeach() endif() - if (COMPILER_RT_HAS_PROFILE) + if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE) compiler_rt_test_runtime(profile) endif() if(COMPILER_RT_BUILD_XRAY) -- cgit v1.2.1 From 4f725d63be7f22d79875b4f3794b8d79f0ca039c Mon Sep 17 00:00:00 2001 From: Filipe Cabecinhas Date: Mon, 2 Oct 2017 10:21:26 +0000 Subject: Use %run for running CFI tests Reviewers: pcc, krasin, eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38412 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314659 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/anon-namespace.cpp | 12 ++-- test/cfi/bad-cast.cpp | 104 +++++++++++++++++------------------ test/cfi/bad-split.cpp | 2 +- test/cfi/base-derived-destructor.cpp | 36 ++++++------ test/cfi/multiple-inheritance.cpp | 24 ++++---- test/cfi/nvcall.cpp | 12 ++-- test/cfi/overwrite.cpp | 12 ++-- test/cfi/sibling.cpp | 10 ++-- test/cfi/simple-fail.cpp | 38 ++++++------- test/cfi/simple-pass.cpp | 2 +- test/cfi/stats.cpp | 2 +- test/cfi/target_uninstrumented.cpp | 2 +- test/cfi/two-vcalls.cpp | 2 +- test/cfi/vdtor.cpp | 12 ++-- 14 files changed, 135 insertions(+), 135 deletions(-) diff --git a/test/cfi/anon-namespace.cpp b/test/cfi/anon-namespace.cpp index 8e6c1c115..2a7ed9c0a 100644 --- a/test/cfi/anon-namespace.cpp +++ b/test/cfi/anon-namespace.cpp @@ -1,32 +1,32 @@ // RUN: %clangxx_cfi -c -DTU1 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx_cfi -o %t1 %t1.o %t2.o -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB32 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB32 -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx_cfi -o %t2 %t1.o %t2.o -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB64 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB64 -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx_cfi -o %t3 %t1.o %t2.o -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DBM -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DBM -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx_cfi -o %t4 %t1.o %t2.o -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -c -DTU1 -o %t1.o %s // RUN: %clangxx -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx -o %t5 %t1.o %t2.o -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -c -DTU1 -o %t1.o %s // RUN: %clangxx_cfi_diag -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp // RUN: %clangxx_cfi_diag -o %t6 %t1.o %t2.o -// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism treats classes in the anonymous namespace in // different translation units as having distinct identities. This is done by diff --git a/test/cfi/bad-cast.cpp b/test/cfi/bad-cast.cpp index e2f4f25a4..1c4f19e9e 100644 --- a/test/cfi/bad-cast.cpp +++ b/test/cfi/bad-cast.cpp @@ -1,68 +1,68 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t1 b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t1 c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t1 d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t1 e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t1 f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %expect_crash %t1 g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t1 h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t1 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t1 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t1 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t1 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t1 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t1 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t1 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t1 h 2>&1 | FileCheck --check-prefix=PASS %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t2 b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t2 c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t2 d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t2 e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t2 f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %expect_crash %t2 g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t2 h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t2 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t2 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t2 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t2 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t2 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t2 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t2 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t2 h 2>&1 | FileCheck --check-prefix=PASS %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t3 b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t3 c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t3 d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t3 e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t3 f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %expect_crash %t3 g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t3 h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t3 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t3 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t3 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t3 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t3 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t3 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t3 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t3 h 2>&1 | FileCheck --check-prefix=PASS %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t4 b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t4 c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t4 d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t4 e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t4 f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %expect_crash %t4 g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %t4 h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t4 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t4 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t4 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t4 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t4 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t4 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %run %t4 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %run %t4 h 2>&1 | FileCheck --check-prefix=PASS %s // RUN: %clangxx_cfi -fsanitize=cfi-cast-strict -o %t5 %s -// RUN: %expect_crash %t5 a 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 b 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 c 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 d 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 e 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 f 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 g 2>&1 | FileCheck --check-prefix=FAIL %s -// RUN: %expect_crash %t5 h 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 d 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 e 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 f 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %run %t5 h 2>&1 | FileCheck --check-prefix=FAIL %s // RUN: %clangxx -o %t6 %s -// RUN: %t6 a 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 b 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 c 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 d 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 e 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 f 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 g 2>&1 | FileCheck --check-prefix=PASS %s -// RUN: %t6 h 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 a 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 b 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 c 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 g 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %run %t6 h 2>&1 | FileCheck --check-prefix=PASS %s // RUN: %clangxx_cfi_diag -o %t7 %s -// RUN: %t7 a 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t7 b 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t7 c 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s -// RUN: %t7 g 2>&1 | FileCheck --check-prefix=CFI-DIAG-U %s +// RUN: %run %t7 a 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %run %t7 b 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %run %t7 c 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %run %t7 g 2>&1 | FileCheck --check-prefix=CFI-DIAG-U %s // Tests that the CFI enforcement detects bad casts. diff --git a/test/cfi/bad-split.cpp b/test/cfi/bad-split.cpp index 53504bd27..37e635aef 100644 --- a/test/cfi/bad-split.cpp +++ b/test/cfi/bad-split.cpp @@ -1,5 +1,5 @@ // GlobalSplit used to lose type metadata for classes with virtual bases but no virtual methods. -// RUN: %clangxx_cfi -o %t1 %s && %t1 +// RUN: %clangxx_cfi -o %t1 %s && %run %t1 // UNSUPPORTED: win32 diff --git a/test/cfi/base-derived-destructor.cpp b/test/cfi/base-derived-destructor.cpp index c5e9db109..33c7445d5 100644 --- a/test/cfi/base-derived-destructor.cpp +++ b/test/cfi/base-derived-destructor.cpp @@ -1,56 +1,56 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -o %t5 %s -// RUN: %expect_crash %t5 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t5 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DB32 -o %t6 %s -// RUN: %expect_crash %t6 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t6 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DB64 -o %t7 %s -// RUN: %expect_crash %t7 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t7 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DBM -o %t8 %s -// RUN: %expect_crash %t8 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t8 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -o %t9 %s -// RUN: %expect_crash %t9 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t9 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DB32 -o %t10 %s -// RUN: %expect_crash %t10 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t10 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DB64 -o %t11 %s -// RUN: %expect_crash %t11 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t11 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DBM -o %t12 %s -// RUN: %expect_crash %t12 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t12 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -o %t13 %s -// RUN: %expect_crash %t13 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t13 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DB32 -o %t14 %s -// RUN: %expect_crash %t14 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t14 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DB64 -o %t15 %s -// RUN: %expect_crash %t15 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t15 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DBM -o %t16 %s -// RUN: %expect_crash %t16 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t16 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi_diag -o %t17 %s -// RUN: %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // RUN: %clangxx -o %t18 %s -// RUN: %t18 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t18 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI mechanism crashes the program when making a // base-to-derived cast from a destructor of the base class, diff --git a/test/cfi/multiple-inheritance.cpp b/test/cfi/multiple-inheritance.cpp index a3b2ac56f..b8520d8b0 100644 --- a/test/cfi/multiple-inheritance.cpp +++ b/test/cfi/multiple-inheritance.cpp @@ -1,26 +1,26 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t1 x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 x 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t2 x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 x 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t3 x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 x 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t4 x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 x 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -o %t5 %s -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -o %t6 %s -// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG2 %s -// RUN: %t6 x 2>&1 | FileCheck --check-prefix=CFI-DIAG1 %s +// RUN: %run %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG2 %s +// RUN: %run %t6 x 2>&1 | FileCheck --check-prefix=CFI-DIAG1 %s // Tests that the CFI mechanism is sensitive to multiple inheritance and only // permits calls via virtual tables for the correct base class. diff --git a/test/cfi/nvcall.cpp b/test/cfi/nvcall.cpp index 9d8f5f49f..b61adb1fe 100644 --- a/test/cfi/nvcall.cpp +++ b/test/cfi/nvcall.cpp @@ -1,20 +1,20 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -o %t5 %s -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -o %t6 %s -// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism crashes the program when making a non-virtual // call to an object of the wrong class, by casting a pointer to such an object diff --git a/test/cfi/overwrite.cpp b/test/cfi/overwrite.cpp index 48c0a89c8..7d7ad1c77 100644 --- a/test/cfi/overwrite.cpp +++ b/test/cfi/overwrite.cpp @@ -1,20 +1,20 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash_unless_devirt %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash_unless_devirt %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -o %t5 %s -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -o %t6 %s -// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism crashes the program when a virtual table is // replaced with a compatible table of function pointers that does not belong to diff --git a/test/cfi/sibling.cpp b/test/cfi/sibling.cpp index 601359888..fb6e2f295 100644 --- a/test/cfi/sibling.cpp +++ b/test/cfi/sibling.cpp @@ -1,19 +1,19 @@ // XFAIL: * // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -o %t5 %s -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI enforcement distinguishes between non-overriding siblings. // XFAILed as not implemented yet. diff --git a/test/cfi/simple-fail.cpp b/test/cfi/simple-fail.cpp index 595ca1617..ef36fb08a 100644 --- a/test/cfi/simple-fail.cpp +++ b/test/cfi/simple-fail.cpp @@ -1,59 +1,59 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -o %t5 %s -// RUN: %expect_crash %t5 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t5 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DB32 -o %t6 %s -// RUN: %expect_crash %t6 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t6 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DB64 -o %t7 %s -// RUN: %expect_crash %t7 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t7 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O1 -DBM -o %t8 %s -// RUN: %expect_crash %t8 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t8 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -o %t9 %s -// RUN: %expect_crash %t9 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t9 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DB32 -o %t10 %s -// RUN: %expect_crash %t10 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t10 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DB64 -o %t11 %s -// RUN: %expect_crash %t11 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t11 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O2 -DBM -o %t12 %s -// RUN: %expect_crash %t12 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t12 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -o %t13 %s -// RUN: %expect_crash %t13 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t13 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DB32 -o %t14 %s -// RUN: %expect_crash %t14 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t14 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DB64 -o %t15 %s -// RUN: %expect_crash %t15 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t15 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -O3 -DBM -o %t16 %s -// RUN: %expect_crash %t16 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t16 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi_diag -o %t17 %s -// RUN: %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // RUN: %clangxx -o %t18 %s -// RUN: %t18 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t18 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi -DCHECK_NO_SANITIZE_CFI -o %t19 %s -// RUN: %t19 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t19 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a diff --git a/test/cfi/simple-pass.cpp b/test/cfi/simple-pass.cpp index 4d856eb48..aba09be2d 100644 --- a/test/cfi/simple-pass.cpp +++ b/test/cfi/simple-pass.cpp @@ -1,5 +1,5 @@ // RUN: %clangxx_cfi -o %t %s -// RUN: %t +// RUN: %run %t // Tests that the CFI mechanism does not crash the program when making various // kinds of valid calls involving classes with various different linkages and diff --git a/test/cfi/stats.cpp b/test/cfi/stats.cpp index 566fcfbc2..eb0c2ed95 100644 --- a/test/cfi/stats.cpp +++ b/test/cfi/stats.cpp @@ -1,5 +1,5 @@ // RUN: %clangxx_cfi -g -fsanitize-stats -o %t %s -// RUN: env SANITIZER_STATS_PATH=%t.stats %t +// RUN: env SANITIZER_STATS_PATH=%t.stats %run %t // RUN: sanstats %t.stats | FileCheck %s // FIXME: We currently emit the wrong debug info under devirtualization. diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp index bf20f58e2..b2a1ad74a 100644 --- a/test/cfi/target_uninstrumented.cpp +++ b/test/cfi/target_uninstrumented.cpp @@ -1,6 +1,6 @@ // RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %T/target_uninstrumented-so.so // RUN: %clangxx_cfi_diag -g %s -o %t %T/target_uninstrumented-so.so -// RUN: %t 2>&1 | FileCheck %s +// RUN: %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi // UNSUPPORTED: win32 diff --git a/test/cfi/two-vcalls.cpp b/test/cfi/two-vcalls.cpp index 854b3e005..fbe4d971a 100644 --- a/test/cfi/two-vcalls.cpp +++ b/test/cfi/two-vcalls.cpp @@ -1,5 +1,5 @@ // RUN: %clangxx_cfi_diag -o %t %s -// RUN: %t 2>&1 | FileCheck %s +// RUN: %run %t 2>&1 | FileCheck %s // This test checks that we don't generate two type checks, // if two virtual calls are in the same function. diff --git a/test/cfi/vdtor.cpp b/test/cfi/vdtor.cpp index 522d24c2a..defa4ce15 100644 --- a/test/cfi/vdtor.cpp +++ b/test/cfi/vdtor.cpp @@ -1,20 +1,20 @@ // RUN: %clangxx_cfi -o %t1 %s -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB32 -o %t2 %s -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DB64 -o %t3 %s -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -DBM -o %t4 %s -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %run %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -o %t5 %s -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %run %t5 2>&1 | FileCheck --check-prefix=NCFI %s // RUN: %clangxx_cfi_diag -o %t6 %s -// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s +// RUN: %run %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI enforcement also applies to virtual destructor calls made // via 'delete'. -- cgit v1.2.1 From 4969c048f4eccc701463012626a3fc680bdcf32b Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 2 Oct 2017 14:30:58 +0000 Subject: Add support for custom loaders to the sanitizer symbolizer Summary: Adds a fallback mode to procmaps when the symbolizer fails to locate a module for a given address by using dl_iterate_phdr. Reviewers: kubamracek, rnk, vitalybuka, eugenis Reviewed By: eugenis Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D37269 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314671 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 1 + lib/sanitizer_common/sanitizer_linux_libcdep.cc | 11 +++++++++++ lib/sanitizer_common/sanitizer_mac.cc | 2 ++ lib/sanitizer_common/sanitizer_symbolizer.h | 1 + lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 5 +++++ lib/sanitizer_common/sanitizer_win.cc | 4 +++- 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 11ee59024..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -730,6 +730,7 @@ class ListOfModules { ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 0f420875d..c25b5610e 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -488,6 +488,17 @@ void ListOfModules::init() { } } +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + if (!requiresProcmaps()) { + clearOrInit(); + procmapsInit(&modules_); + } else { + clear(); + } +} + // getrusage does not give us the current RSS, only the max RSS. // Still, this is better than nothing if /proc/self/statm is not available // for some reason, e.g. due to a sandbox. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index cd63cb42f..9fead91b9 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -416,6 +416,8 @@ void ListOfModules::init() { memory_mapping.DumpListOfModules(&modules_); } +void ListOfModules::fallbackInit() { clear(); } + static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 95587126c..208362d2f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -152,6 +152,7 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; + ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 37ac12c34..a4bab668b 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -165,6 +165,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, void Symbolizer::RefreshModules() { modules_.init(); + fallback_modules_.fallbackInit(); RAW_CHECK(modules_.size() > 0); modules_fresh_ = true; } @@ -198,6 +199,10 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { if (module) return module; } #endif + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } return module; } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 84065aa0e..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -583,7 +583,9 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -}; +} + +void ListOfModules::fallbackInit() { clear(); } // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From 6b550d45f492bb21069c2ccdc8561379176def56 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 2 Oct 2017 15:55:11 +0000 Subject: Revert "Add support for custom loaders to the sanitizer symbolizer" This reverts commit r314671, which hangs on the gcc sanitizer buildbot. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314684 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 1 - lib/sanitizer_common/sanitizer_linux_libcdep.cc | 11 ----------- lib/sanitizer_common/sanitizer_mac.cc | 2 -- lib/sanitizer_common/sanitizer_symbolizer.h | 1 - lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 5 ----- lib/sanitizer_common/sanitizer_win.cc | 4 +--- 6 files changed, 1 insertion(+), 23 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ee5eca516..11ee59024 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -730,7 +730,6 @@ class ListOfModules { ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); - void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index c25b5610e..0f420875d 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -488,17 +488,6 @@ void ListOfModules::init() { } } -// When a custom loader is used, dl_iterate_phdr may not contain the full -// list of modules. Allow callers to fall back to using procmaps. -void ListOfModules::fallbackInit() { - if (!requiresProcmaps()) { - clearOrInit(); - procmapsInit(&modules_); - } else { - clear(); - } -} - // getrusage does not give us the current RSS, only the max RSS. // Still, this is better than nothing if /proc/self/statm is not available // for some reason, e.g. due to a sandbox. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 9fead91b9..cd63cb42f 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -416,8 +416,6 @@ void ListOfModules::init() { memory_mapping.DumpListOfModules(&modules_); } -void ListOfModules::fallbackInit() { clear(); } - static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 208362d2f..95587126c 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -152,7 +152,6 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; - ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index a4bab668b..37ac12c34 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -165,7 +165,6 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, void Symbolizer::RefreshModules() { modules_.init(); - fallback_modules_.fallbackInit(); RAW_CHECK(modules_.size() > 0); modules_fresh_ = true; } @@ -199,10 +198,6 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { if (module) return module; } #endif - - if (fallback_modules_.size()) { - module = SearchForModule(fallback_modules_, address); - } return module; } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..84065aa0e 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -583,9 +583,7 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -} - -void ListOfModules::fallbackInit() { clear(); } +}; // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From 3ce56013ccfd444b11b2d5b4769c006fc9517682 Mon Sep 17 00:00:00 2001 From: Francis Ricci Date: Mon, 2 Oct 2017 20:22:16 +0000 Subject: Add support for custom loaders to the sanitizer symbolizer Summary: Adds a fallback mode to procmaps when the symbolizer fails to locate a module for a given address by using dl_iterate_phdr. Reviewers: kubamracek, rnk, vitalybuka, eugenis Reviewed By: eugenis Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D37269 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314713 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 1 + lib/sanitizer_common/sanitizer_linux_libcdep.cc | 13 ++++++++++++- lib/sanitizer_common/sanitizer_mac.cc | 2 ++ lib/sanitizer_common/sanitizer_symbolizer.h | 1 + lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 5 +++++ lib/sanitizer_common/sanitizer_win.cc | 4 +++- 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 11ee59024..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -730,6 +730,7 @@ class ListOfModules { ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 0f420875d..0dc437585 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -474,7 +474,7 @@ static bool requiresProcmaps() { } static void procmapsInit(InternalMmapVectorNoCtor *modules) { - MemoryMappingLayout memory_mapping(false); + MemoryMappingLayout memory_mapping(/*cache_enabled*/true); memory_mapping.DumpListOfModules(modules); } @@ -488,6 +488,17 @@ void ListOfModules::init() { } } +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + if (!requiresProcmaps()) { + clearOrInit(); + procmapsInit(&modules_); + } else { + clear(); + } +} + // getrusage does not give us the current RSS, only the max RSS. // Still, this is better than nothing if /proc/self/statm is not available // for some reason, e.g. due to a sandbox. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index cd63cb42f..9fead91b9 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -416,6 +416,8 @@ void ListOfModules::init() { memory_mapping.DumpListOfModules(&modules_); } +void ListOfModules::fallbackInit() { clear(); } + static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 95587126c..208362d2f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -152,6 +152,7 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; + ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 37ac12c34..a4bab668b 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -165,6 +165,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, void Symbolizer::RefreshModules() { modules_.init(); + fallback_modules_.fallbackInit(); RAW_CHECK(modules_.size() > 0); modules_fresh_ = true; } @@ -198,6 +199,10 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { if (module) return module; } #endif + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } return module; } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 84065aa0e..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -583,7 +583,9 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -}; +} + +void ListOfModules::fallbackInit() { clear(); } // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use -- cgit v1.2.1 From 4ce970d8622ec09b3b4b30c77800198221c75b85 Mon Sep 17 00:00:00 2001 From: Manoj Gupta Date: Mon, 2 Oct 2017 20:56:49 +0000 Subject: [builtins] ARM: Reland fix for assembling builtins in thumb state. Summary: clang does not assemble files in thumb mode unless .thumb declaration is present. Add .thumb/.arm decl to _FUNCTION macros to ensure that files are assembled correctly. Also add a fix to ensure that armv7k-watchos can assemble the aeabi_c{f|d}cmp.S files. Fixes PR 34715. Reviewers: compnerd, peter.smith, srhines, weimingz, rengolin, efriedma, t.p.northover, fjricci Reviewed By: compnerd Subscribers: aemerson, javed.absar, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D38390 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314718 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/arm/aeabi_cdcmp.S | 5 ++++- lib/builtins/arm/aeabi_cfcmp.S | 5 ++++- lib/builtins/assembly.h | 9 +++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S index b06f294e2..87dd03dce 100644 --- a/lib/builtins/arm/aeabi_cdcmp.S +++ b/lib/builtins/arm/aeabi_cdcmp.S @@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq) pop {r0-r3, lr} // NaN has been ruled out, so __aeabi_cdcmple can't trap + // Use "it ne" + unconditional branch to guarantee a supported relocation if + // __aeabi_cdcmple is in a different section for some builds. + IT(ne) bne __aeabi_cdcmple -#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#if defined(USE_THUMB_2) mov ip, #APSR_C msr APSR_nzcvq, ip #else diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S index 7bc84073f..c5fee6b6a 100644 --- a/lib/builtins/arm/aeabi_cfcmp.S +++ b/lib/builtins/arm/aeabi_cfcmp.S @@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq) pop {r0-r3, lr} // NaN has been ruled out, so __aeabi_cfcmple can't trap + // Use "it ne" + unconditional branch to guarantee a supported relocation if + // __aeabi_cfcmple is in a different section for some builds. + IT(ne) bne __aeabi_cfcmple -#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#if defined(USE_THUMB_2) mov ip, #APSR_C msr APSR_nzcvq, ip #else diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h index 58116114a..3f5e59b25 100644 --- a/lib/builtins/assembly.h +++ b/lib/builtins/assembly.h @@ -75,7 +75,7 @@ * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__' */ #if defined(__thumb2__) || defined(__thumb__) -#define DEFINE_CODE_STATE .thumb +#define DEFINE_CODE_STATE .thumb SEPARATOR #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR #if defined(__thumb2__) #define USE_THUMB_2 @@ -89,7 +89,7 @@ #define ITE(cond) #endif // defined(__thumb__2) #else // !defined(__thumb2__) && !defined(__thumb__) -#define DEFINE_CODE_STATE .arm +#define DEFINE_CODE_STATE .arm SEPARATOR #define DECLARE_FUNC_ENCODING #define IT(cond) #define ITT(cond) @@ -132,6 +132,7 @@ #endif #else // !defined(__arm) #define DECLARE_FUNC_ENCODING +#define DEFINE_CODE_STATE #endif #define GLUE2(a, b) a##b @@ -146,6 +147,7 @@ #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -154,6 +156,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -162,6 +165,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -170,6 +174,7 @@ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + DEFINE_CODE_STATE \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ -- cgit v1.2.1 From a1604ad3b4fe626d8466aa397125ea95c358e436 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 3 Oct 2017 06:11:13 +0000 Subject: [XRay][compiler-rt] Use pthread for initializing thread-local data Summary: We avoid using C++11's thread_local keyword on non-trivially destructible objects because it may introduce deadlocks when the C++ runtime registers destructors calling std::malloc(...). The deadlock may happen when the allocator implementation is itself XRay instrumented. To avoid having to call malloc(...) and free(...) in particular, we use pthread_once, pthread_create_key, and pthread_setspecific to instead manually register the cleanup implementation we want. The code this replaces used an RAII type that implements the cleanup functionality in the destructor, that was then initialized as a function-local thread_local object. While it works in usual situations, unfortunately it breaks when using a malloc implementation that itself is XRay-instrumented. Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38073 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314764 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 120 +++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 36 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 4c9c46e03..28e70f891 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -124,43 +125,90 @@ static ThreadLocalData &getThreadLocalData(); static constexpr auto MetadataRecSize = sizeof(MetadataRecord); static constexpr auto FunctionRecSize = sizeof(FunctionRecord); -class ThreadExitBufferCleanup { - std::shared_ptr &Buffers; - BufferQueue::Buffer &Buffer; - -public: - explicit ThreadExitBufferCleanup(std::shared_ptr &BQ, - BufferQueue::Buffer &Buffer) - XRAY_NEVER_INSTRUMENT : Buffers(BQ), - Buffer(Buffer) {} - - ~ThreadExitBufferCleanup() noexcept XRAY_NEVER_INSTRUMENT { - auto &TLD = getThreadLocalData(); - auto &RecordPtr = TLD.RecordPtr; - if (RecordPtr == nullptr) - return; - - // We make sure that upon exit, a thread will write out the EOB - // MetadataRecord in the thread-local log, and also release the buffer to - // the queue. - assert((RecordPtr + MetadataRecSize) - static_cast(Buffer.Buffer) >= - static_cast(MetadataRecSize)); - if (Buffers) { - writeEOBMetadata(); - auto EC = Buffers->releaseBuffer(Buffer); - if (EC != BufferQueue::ErrorCode::Ok) - Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, - BufferQueue::getErrorString(EC)); - Buffers = nullptr; - return; - } - } -}; - +// This function will initialize the thread-local data structure used by the FDR +// logging implementation and return a reference to it. The implementation +// details require a bit of care to maintain. +// +// First, some requirements on the implementation in general: +// +// - XRay handlers should not call any memory allocation routines that may +// delegate to an instrumented implementation. This means functions like +// malloc() and free() should not be called while instrumenting. +// +// - We would like to use some thread-local data initialized on first-use of +// the XRay instrumentation. These allow us to implement unsynchronized +// routines that access resources associated with the thread. +// +// The implementation here uses a few mechanisms that allow us to provide both +// the requirements listed above. We do this by: +// +// 1. Using a thread-local aligned storage buffer for representing the +// ThreadLocalData struct. This data will be uninitialized memory by +// design. +// +// 2. Using pthread_once(...) to initialize the thread-local data structures +// on first use, for every thread. We don't use std::call_once so we don't +// have a reliance on the C++ runtime library. +// +// 3. Registering a cleanup function that gets run at the end of a thread's +// lifetime through pthread_create_key(...). The cleanup function would +// allow us to release the thread-local resources in a manner that would +// let the rest of the XRay runtime implementation handle the records +// written for this thread's active buffer. +// +// We're doing this to avoid using a `thread_local` object that has a +// non-trivial destructor, because the C++ runtime might call std::malloc(...) +// to register calls to destructors. Deadlocks may arise when, for example, an +// externally provided malloc implementation is XRay instrumented, and +// initializing the thread-locals involves calling into malloc. A malloc +// implementation that does global synchronization might be holding a lock for a +// critical section, calling a function that might be XRay instrumented (and +// thus in turn calling into malloc by virtue of registration of the +// thread_local's destructor). +// +// With the approach taken where, we attempt to avoid the potential for +// deadlocks by relying instead on pthread's memory management routines. static ThreadLocalData &getThreadLocalData() { - thread_local ThreadLocalData TLD; - thread_local ThreadExitBufferCleanup Cleanup(TLD.LocalBQ, TLD.Buffer); - return TLD; + thread_local pthread_key_t key; + + // We need aligned, uninitialized storage for the TLS object which is + // trivially destructible. We're going to use this as raw storage and + // placement-new the ThreadLocalData object into it later. + thread_local std::aligned_union<1, ThreadLocalData>::type TLSBuffer; + + // Ensure that we only actually ever do the pthread initialization once. + thread_local bool unused = [] { + new (&TLSBuffer) ThreadLocalData(); + pthread_key_create(&key, +[](void *) { + auto &TLD = *reinterpret_cast(&TLSBuffer); + auto &RecordPtr = TLD.RecordPtr; + auto &Buffers = TLD.LocalBQ; + auto &Buffer = TLD.Buffer; + if (RecordPtr == nullptr) + return; + + // We make sure that upon exit, a thread will write out the EOB + // MetadataRecord in the thread-local log, and also release the buffer + // to the queue. + assert((RecordPtr + MetadataRecSize) - + static_cast(Buffer.Buffer) >= + static_cast(MetadataRecSize)); + if (Buffers) { + writeEOBMetadata(); + auto EC = Buffers->releaseBuffer(Buffer); + if (EC != BufferQueue::ErrorCode::Ok) + Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer, + BufferQueue::getErrorString(EC)); + Buffers = nullptr; + return; + } + }); + pthread_setspecific(key, &TLSBuffer); + return true; + }(); + (void)unused; + + return *reinterpret_cast(&TLSBuffer); } //-----------------------------------------------------------------------------| -- cgit v1.2.1 From dad2946b51de3226184ca0aff641537f3e532857 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 3 Oct 2017 06:11:20 +0000 Subject: fixup: use UNUSED, restore alignment for cache-line friendliness, and report on errors found when pthread_create_key fails git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314765 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging_impl.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index 28e70f891..aec205e8a 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -93,8 +93,10 @@ static void writeEOBMetadata(); static void writeTSCWrapMetadata(uint64_t TSC); // Group together thread-local-data in a struct, then hide it behind a function -// call so that it can be initialized on first use instead of as a global. -struct ThreadLocalData { +// call so that it can be initialized on first use instead of as a global. We +// force the alignment to 64-bytes for x86 cache line alignment, as this +// structure is used in the hot path of implementation. +struct ALIGNED(64) ThreadLocalData { BufferQueue::Buffer Buffer; char *RecordPtr = nullptr; // The number of FunctionEntry records immediately preceding RecordPtr. @@ -174,12 +176,13 @@ static ThreadLocalData &getThreadLocalData() { // We need aligned, uninitialized storage for the TLS object which is // trivially destructible. We're going to use this as raw storage and // placement-new the ThreadLocalData object into it later. - thread_local std::aligned_union<1, ThreadLocalData>::type TLSBuffer; + thread_local std::aligned_storage::type TLSBuffer; // Ensure that we only actually ever do the pthread initialization once. - thread_local bool unused = [] { + thread_local bool UNUSED Unused = [] { new (&TLSBuffer) ThreadLocalData(); - pthread_key_create(&key, +[](void *) { + auto result = pthread_key_create(&key, +[](void *) { auto &TLD = *reinterpret_cast(&TLSBuffer); auto &RecordPtr = TLD.RecordPtr; auto &Buffers = TLD.LocalBQ; @@ -203,10 +206,14 @@ static ThreadLocalData &getThreadLocalData() { return; } }); + if (result != 0) { + Report("Failed to allocate thread-local data through pthread; error=%d", + result); + return false; + } pthread_setspecific(key, &TLSBuffer); return true; }(); - (void)unused; return *reinterpret_cast(&TLSBuffer); } -- cgit v1.2.1 From ebffae6c671e3c5c914395212eea2ce3b5269312 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 3 Oct 2017 06:15:34 +0000 Subject: [XRay][compiler-rt] Use a hand-written circular buffer in BufferQueue Summary: This change removes the dependency on using a std::deque<...> for the storage of the buffers in the buffer queue. We instead implement a fixed-size circular buffer that's resilient to exhaustion, and preserves the semantics of the BufferQueue. We're moving away from using std::deque<...> for two reasons: - We want to remove dependencies on the STL for data structures. - We want the data structure we use to not require re-allocation in the normal course of operation. The internal implementation of the buffer queue uses heap-allocated arrays that are initialized once when the BufferQueue is created, and re-uses slots in the buffer array as buffers are returned in order. We also change the lock used in the implementation to a spinlock instead of a blocking mutex. We reason that since the release operations now take very little time in the critical section, that a spinlock would be appropriate. This change is related to D38073. Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38119 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314766 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 49 +++++++++++++++++++-------- lib/xray/xray_buffer_queue.h | 23 +++++++++---- test/xray/TestCases/Linux/fdr-thread-order.cc | 48 ++++++++++++++++++++------ 3 files changed, 88 insertions(+), 32 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 7ba755ac3..99175a025 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -16,6 +16,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include #include #include @@ -23,18 +24,21 @@ using namespace __xray; using namespace __sanitizer; BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) - : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing{0} { - for (auto &T : Buffers) { + : BufferSize(B), Buffers(new std::tuple[N]()), + BufferCount(N), Finalizing{0}, OwnedBuffers(new void *[N]()), + Next(Buffers.get()), First(nullptr) { + for (size_t i = 0; i < N; ++i) { + auto &T = Buffers[i]; void *Tmp = malloc(BufferSize); if (Tmp == nullptr) { Success = false; return; } - auto &Buf = std::get<0>(T); + std::get<1>(T) = false; Buf.Buffer = Tmp; Buf.Size = B; - OwnedBuffers.emplace(Tmp); + OwnedBuffers[i] = Tmp; } Success = true; } @@ -42,27 +46,43 @@ BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) return ErrorCode::QueueFinalizing; - __sanitizer::BlockingMutexLock Guard(&Mutex); - if (Buffers.empty()) + __sanitizer::SpinMutexLock Guard(&Mutex); + + if (Next == First) return ErrorCode::NotEnoughMemory; - auto &T = Buffers.front(); + + auto &T = *Next; auto &B = std::get<0>(T); Buf = B; - B.Buffer = nullptr; - B.Size = 0; - Buffers.pop_front(); + + if (First == nullptr) + First = Next; + ++Next; + if (Next == (Buffers.get() + BufferCount)) + Next = Buffers.get(); + return ErrorCode::Ok; } BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { - if (OwnedBuffers.count(Buf.Buffer) == 0) + // Blitz through the buffers array to find the buffer. + if (std::none_of(OwnedBuffers.get(), OwnedBuffers.get() + BufferCount, + [&Buf](void *P) { return P == Buf.Buffer; })) return ErrorCode::UnrecognizedBuffer; - __sanitizer::BlockingMutexLock Guard(&Mutex); + __sanitizer::SpinMutexLock Guard(&Mutex); + + // This points to a semantic bug, we really ought to not be releasing more + // buffers than we actually get. + if (First == nullptr || First == Next) + return ErrorCode::NotEnoughMemory; // Now that the buffer has been released, we mark it as "used". - Buffers.emplace(Buffers.end(), Buf, true /* used */); + *First = std::make_tuple(Buf, true); Buf.Buffer = nullptr; Buf.Size = 0; + ++First; + if (First == (Buffers.get() + BufferCount)) + First = Buffers.get(); return ErrorCode::Ok; } @@ -74,7 +94,8 @@ BufferQueue::ErrorCode BufferQueue::finalize() { } BufferQueue::~BufferQueue() { - for (auto &T : Buffers) { + for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + auto &T = *I; auto &Buf = std::get<0>(T); free(Buf.Buffer); } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index bd382a26c..1115b4722 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -17,8 +17,8 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_mutex.h" -#include -#include +#include +#include #include namespace __xray { @@ -36,15 +36,23 @@ public: }; private: + // Size of each individual Buffer. size_t BufferSize; // We use a bool to indicate whether the Buffer has been used in this // freelist implementation. - std::deque> Buffers; - __sanitizer::BlockingMutex Mutex; - std::unordered_set OwnedBuffers; + std::unique_ptr[]> Buffers; + size_t BufferCount; + + __sanitizer::SpinMutex Mutex; __sanitizer::atomic_uint8_t Finalizing; + // Sorted buffer pointers, making it quick to find buffers that we own. + std::unique_ptr OwnedBuffers; + + std::tuple *Next; + std::tuple *First; + public: enum class ErrorCode : unsigned { Ok, @@ -117,8 +125,9 @@ public: /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a /// releaseBuffer(...) operation). template void apply(F Fn) { - __sanitizer::BlockingMutexLock G(&Mutex); - for (const auto &T : Buffers) { + __sanitizer::SpinMutexLock G(&Mutex); + for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + const auto &T = *I; if (std::get<1>(T)) Fn(std::get<0>(T)); } diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 6ac2114a5..8e8c421dc 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -1,37 +1,63 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t // RUN: rm fdr-thread-order.* || true -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false \ +// RUN: xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 \ +// RUN: xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | \ +// RUN: FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" | \ +// RUN: FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux // REQUIRES: built-in-llvm-tree #include "xray/xray_log_interface.h" -#include +#include #include +#include constexpr auto kBufferSize = 16384; constexpr auto kBufferMax = 10; -thread_local uint64_t var = 0; -[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { ++var; } -[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { ++var; } +std::atomic var{0}; + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} int main(int argc, char *argv[]) { using namespace __xray; FDRLoggingOptions Options; + __xray_patch(); assert(__xray_log_init(kBufferSize, kBufferMax, &Options, sizeof(FDRLoggingOptions)) == XRayLogInitStatus::XRAY_LOG_INITIALIZED); - __xray_patch(); - std::thread t1([] { f1(); }); - std::thread t2([] { f2(); }); - t1.join(); - t2.join(); + + std::atomic_thread_fence(std::memory_order_acq_rel); + + { + std::thread t1([] { f1(); }); + std::thread t2([] { f2(); }); + t1.join(); + t2.join(); + } + + std::atomic_thread_fence(std::memory_order_acq_rel); __xray_log_finalize(); __xray_log_flushLog(); + __xray_unpatch(); + return var > 0 ? 0 : 1; // CHECK: {{.*}}XRay: Log file in '{{.*}}' + // CHECK-NOT: Failed } // We want to make sure that the order of the function log doesn't matter. -- cgit v1.2.1 From 8f30a9c5f0810060699ae500140af885e3378b92 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 3 Oct 2017 11:40:54 +0000 Subject: Revert "[XRay][compiler-rt] Use a hand-written circular buffer in BufferQueue" This reverts r314766 (rL314766). Unit tests fail in multiple bots. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314786 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 49 ++++++++------------------- lib/xray/xray_buffer_queue.h | 23 ++++--------- test/xray/TestCases/Linux/fdr-thread-order.cc | 48 ++++++-------------------- 3 files changed, 32 insertions(+), 88 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 99175a025..7ba755ac3 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -16,7 +16,6 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" -#include #include #include @@ -24,21 +23,18 @@ using namespace __xray; using namespace __sanitizer; BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) - : BufferSize(B), Buffers(new std::tuple[N]()), - BufferCount(N), Finalizing{0}, OwnedBuffers(new void *[N]()), - Next(Buffers.get()), First(nullptr) { - for (size_t i = 0; i < N; ++i) { - auto &T = Buffers[i]; + : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing{0} { + for (auto &T : Buffers) { void *Tmp = malloc(BufferSize); if (Tmp == nullptr) { Success = false; return; } + auto &Buf = std::get<0>(T); - std::get<1>(T) = false; Buf.Buffer = Tmp; Buf.Size = B; - OwnedBuffers[i] = Tmp; + OwnedBuffers.emplace(Tmp); } Success = true; } @@ -46,43 +42,27 @@ BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) return ErrorCode::QueueFinalizing; - __sanitizer::SpinMutexLock Guard(&Mutex); - - if (Next == First) + __sanitizer::BlockingMutexLock Guard(&Mutex); + if (Buffers.empty()) return ErrorCode::NotEnoughMemory; - - auto &T = *Next; + auto &T = Buffers.front(); auto &B = std::get<0>(T); Buf = B; - - if (First == nullptr) - First = Next; - ++Next; - if (Next == (Buffers.get() + BufferCount)) - Next = Buffers.get(); - + B.Buffer = nullptr; + B.Size = 0; + Buffers.pop_front(); return ErrorCode::Ok; } BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { - // Blitz through the buffers array to find the buffer. - if (std::none_of(OwnedBuffers.get(), OwnedBuffers.get() + BufferCount, - [&Buf](void *P) { return P == Buf.Buffer; })) + if (OwnedBuffers.count(Buf.Buffer) == 0) return ErrorCode::UnrecognizedBuffer; - __sanitizer::SpinMutexLock Guard(&Mutex); - - // This points to a semantic bug, we really ought to not be releasing more - // buffers than we actually get. - if (First == nullptr || First == Next) - return ErrorCode::NotEnoughMemory; + __sanitizer::BlockingMutexLock Guard(&Mutex); // Now that the buffer has been released, we mark it as "used". - *First = std::make_tuple(Buf, true); + Buffers.emplace(Buffers.end(), Buf, true /* used */); Buf.Buffer = nullptr; Buf.Size = 0; - ++First; - if (First == (Buffers.get() + BufferCount)) - First = Buffers.get(); return ErrorCode::Ok; } @@ -94,8 +74,7 @@ BufferQueue::ErrorCode BufferQueue::finalize() { } BufferQueue::~BufferQueue() { - for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { - auto &T = *I; + for (auto &T : Buffers) { auto &Buf = std::get<0>(T); free(Buf.Buffer); } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 1115b4722..bd382a26c 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -17,8 +17,8 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_mutex.h" -#include -#include +#include +#include #include namespace __xray { @@ -36,23 +36,15 @@ public: }; private: - // Size of each individual Buffer. size_t BufferSize; // We use a bool to indicate whether the Buffer has been used in this // freelist implementation. - std::unique_ptr[]> Buffers; - size_t BufferCount; - - __sanitizer::SpinMutex Mutex; + std::deque> Buffers; + __sanitizer::BlockingMutex Mutex; + std::unordered_set OwnedBuffers; __sanitizer::atomic_uint8_t Finalizing; - // Sorted buffer pointers, making it quick to find buffers that we own. - std::unique_ptr OwnedBuffers; - - std::tuple *Next; - std::tuple *First; - public: enum class ErrorCode : unsigned { Ok, @@ -125,9 +117,8 @@ public: /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a /// releaseBuffer(...) operation). template void apply(F Fn) { - __sanitizer::SpinMutexLock G(&Mutex); - for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { - const auto &T = *I; + __sanitizer::BlockingMutexLock G(&Mutex); + for (const auto &T : Buffers) { if (std::get<1>(T)) Fn(std::get<0>(T)); } diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 8e8c421dc..6ac2114a5 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -1,63 +1,37 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t // RUN: rm fdr-thread-order.* || true -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false \ -// RUN: xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 \ -// RUN: xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | \ -// RUN: FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ -// RUN: "`ls fdr-thread-order.* | head -1`" -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ -// RUN: "`ls fdr-thread-order.* | head -1`" | \ -// RUN: FileCheck %s --check-prefix TRACE +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux // REQUIRES: built-in-llvm-tree #include "xray/xray_log_interface.h" -#include -#include #include +#include constexpr auto kBufferSize = 16384; constexpr auto kBufferMax = 10; -std::atomic var{0}; - -[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { - for (auto i = 0; i < 1 << 20; ++i) - ++var; -} - -[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { - for (auto i = 0; i < 1 << 20; ++i) - ++var; -} +thread_local uint64_t var = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { ++var; } +[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { ++var; } int main(int argc, char *argv[]) { using namespace __xray; FDRLoggingOptions Options; - __xray_patch(); assert(__xray_log_init(kBufferSize, kBufferMax, &Options, sizeof(FDRLoggingOptions)) == XRayLogInitStatus::XRAY_LOG_INITIALIZED); - - std::atomic_thread_fence(std::memory_order_acq_rel); - - { - std::thread t1([] { f1(); }); - std::thread t2([] { f2(); }); - t1.join(); - t2.join(); - } - - std::atomic_thread_fence(std::memory_order_acq_rel); + __xray_patch(); + std::thread t1([] { f1(); }); + std::thread t2([] { f2(); }); + t1.join(); + t2.join(); __xray_log_finalize(); __xray_log_flushLog(); - __xray_unpatch(); - return var > 0 ? 0 : 1; // CHECK: {{.*}}XRay: Log file in '{{.*}}' - // CHECK-NOT: Failed } // We want to make sure that the order of the function log doesn't matter. -- cgit v1.2.1 From 83774b46bba12aacd6275557aea6f050b7161137 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 3 Oct 2017 21:25:07 +0000 Subject: [compiler-rt] Add back ARM EABI aliases where legal. r303188 removed all the uses of aliases for EABI functions from compiler-rt, because some of them had mismatched calling conventions. Obviously, we can't use aliases for functions which don't have the same calling convention, but that's only an issue for floating-point functions with the hardfloat ABI. In other cases, the stubs increase size and reduce performance for no benefit. This patch adds back the aliases, with appropriate checks to make sure they're only used in cases where the calling convention matches. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314851 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/adddf3.c | 5 ++++- lib/builtins/addsf3.c | 5 ++++- lib/builtins/ashldi3.c | 5 +---- lib/builtins/ashrdi3.c | 5 +---- lib/builtins/comparedf2.c | 5 ++++- lib/builtins/comparesf2.c | 5 ++++- lib/builtins/divdf3.c | 5 ++++- lib/builtins/divsf3.c | 5 ++++- lib/builtins/divsi3.c | 5 +---- lib/builtins/extendhfsf2.c | 5 ++++- lib/builtins/extendsfdf2.c | 5 ++++- lib/builtins/fixdfdi.c | 12 +++++------- lib/builtins/fixdfsi.c | 5 ++++- lib/builtins/fixsfdi.c | 12 +++++------- lib/builtins/fixsfsi.c | 5 ++++- lib/builtins/fixunsdfdi.c | 12 +++++------- lib/builtins/fixunsdfsi.c | 5 ++++- lib/builtins/fixunssfdi.c | 12 +++++------- lib/builtins/fixunssfsi.c | 5 ++++- lib/builtins/floatdidf.c | 5 ++++- lib/builtins/floatdisf.c | 5 ++++- lib/builtins/floatsidf.c | 5 ++++- lib/builtins/floatsisf.c | 5 ++++- lib/builtins/floatundidf.c | 5 ++++- lib/builtins/floatundisf.c | 5 ++++- lib/builtins/floatunsidf.c | 5 ++++- lib/builtins/floatunsisf.c | 5 ++++- lib/builtins/int_lib.h | 4 +++- lib/builtins/lshrdi3.c | 5 +---- lib/builtins/muldf3.c | 5 ++++- lib/builtins/muldi3.c | 5 +---- lib/builtins/mulsf3.c | 5 ++++- lib/builtins/negdf2.c | 5 ++++- lib/builtins/negsf2.c | 5 ++++- lib/builtins/subdf3.c | 5 ++++- lib/builtins/subsf3.c | 5 ++++- lib/builtins/truncdfhf2.c | 5 ++++- lib/builtins/truncdfsf2.c | 5 ++++- lib/builtins/truncsfhf2.c | 5 ++++- lib/builtins/udivsi3.c | 5 +---- 40 files changed, 145 insertions(+), 82 deletions(-) diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c index c528e9e21..9a3901312 100644 --- a/lib/builtins/adddf3.c +++ b/lib/builtins/adddf3.c @@ -20,8 +20,11 @@ COMPILER_RT_ABI double __adddf3(double a, double b){ } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI double __aeabi_dadd(double a, double b) { return __adddf3(a, b); } +#else +AEABI_RTABI double __aeabi_dadd(double a, double b) COMPILER_RT_ALIAS(__adddf3); +#endif #endif - diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c index fe570687a..c5c1a41c3 100644 --- a/lib/builtins/addsf3.c +++ b/lib/builtins/addsf3.c @@ -20,8 +20,11 @@ COMPILER_RT_ABI float __addsf3(float a, float b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI float __aeabi_fadd(float a, float b) { return __addsf3(a, b); } +#else +AEABI_RTABI float __aeabi_fadd(float a, float b) COMPILER_RT_ALIAS(__addsf3); +#endif #endif - diff --git a/lib/builtins/ashldi3.c b/lib/builtins/ashldi3.c index fcb0abdb1..a5c183600 100644 --- a/lib/builtins/ashldi3.c +++ b/lib/builtins/ashldi3.c @@ -41,8 +41,5 @@ __ashldi3(di_int a, si_int b) } #if defined(__ARM_EABI__) -AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) { - return __ashldi3(a, b); -} +AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) COMPILER_RT_ALIAS(__ashldi3); #endif - diff --git a/lib/builtins/ashrdi3.c b/lib/builtins/ashrdi3.c index b4ab4c617..84619965e 100644 --- a/lib/builtins/ashrdi3.c +++ b/lib/builtins/ashrdi3.c @@ -42,8 +42,5 @@ __ashrdi3(di_int a, si_int b) } #if defined(__ARM_EABI__) -AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) { - return __ashrdi3(a, b); -} +AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) COMPILER_RT_ALIAS(__ashrdi3); #endif - diff --git a/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c index c5bb169d0..44e5d2b28 100644 --- a/lib/builtins/comparedf2.c +++ b/lib/builtins/comparedf2.c @@ -143,8 +143,11 @@ __gtdf2(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) { return __unorddf2(a, b); } +#else +AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unorddf2); +#endif #endif - diff --git a/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c index 4badb5e1b..43cd6a6a7 100644 --- a/lib/builtins/comparesf2.c +++ b/lib/builtins/comparesf2.c @@ -143,8 +143,11 @@ __gtsf2(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) { return __unordsf2(a, b); } +#else +AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unordsf2); +#endif #endif - diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c index 492e32b85..04a4dc557 100644 --- a/lib/builtins/divdf3.c +++ b/lib/builtins/divdf3.c @@ -183,8 +183,11 @@ __divdf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) { return __divdf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divdf3); +#endif #endif - diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c index aa6289a6d..65294d70f 100644 --- a/lib/builtins/divsf3.c +++ b/lib/builtins/divsf3.c @@ -167,8 +167,11 @@ __divsf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) { return __divsf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divsf3); +#endif #endif - diff --git a/lib/builtins/divsi3.c b/lib/builtins/divsi3.c index 3852e3990..75aea008d 100644 --- a/lib/builtins/divsi3.c +++ b/lib/builtins/divsi3.c @@ -35,8 +35,5 @@ __divsi3(si_int a, si_int b) } #if defined(__ARM_EABI__) -AEABI_RTABI si_int __aeabi_idiv(si_int a, si_int b) { - return __divsi3(a, b); -} +AEABI_RTABI si_int __aeabi_idiv(si_int a, si_int b) COMPILER_RT_ALIAS(__divsi3); #endif - diff --git a/lib/builtins/extendhfsf2.c b/lib/builtins/extendhfsf2.c index e7d9fde8a..d9c0db84b 100644 --- a/lib/builtins/extendhfsf2.c +++ b/lib/builtins/extendhfsf2.c @@ -23,8 +23,11 @@ COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI float __aeabi_h2f(uint16_t a) { return __extendhfsf2(a); } +#else +AEABI_RTABI float __aeabi_h2f(uint16_t a) COMPILER_RT_ALIAS(__extendhfsf2); +#endif #endif - diff --git a/lib/builtins/extendsfdf2.c b/lib/builtins/extendsfdf2.c index b9e7a7471..3d84529a6 100644 --- a/lib/builtins/extendsfdf2.c +++ b/lib/builtins/extendsfdf2.c @@ -17,8 +17,11 @@ COMPILER_RT_ABI double __extendsfdf2(float a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI double __aeabi_f2d(float a) { return __extendsfdf2(a); } +#else +AEABI_RTABI double __aeabi_f2d(float a) COMPILER_RT_ALIAS(__extendsfdf2); +#endif #endif - diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c index 31d76df28..54e312d3c 100644 --- a/lib/builtins/fixdfdi.c +++ b/lib/builtins/fixdfdi.c @@ -45,13 +45,11 @@ __fixdfdi(fp_t a) { #endif #if defined(__ARM_EABI__) -AEABI_RTABI di_int -#if defined(__SOFT_FP__) -__aeabi_d2lz(fp_t a) { -#else -__aeabi_d2lz(double a) { -#endif +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI di_int __aeabi_d2lz(fp_t a) { return __fixdfdi(a); } +#else +AEABI_RTABI di_int __aeabi_d2lz(fp_t a) COMPILER_RT_ALIAS(__fixdfdi); +#endif #endif - diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c index fc316dcd0..5b9588175 100644 --- a/lib/builtins/fixdfsi.c +++ b/lib/builtins/fixdfsi.c @@ -20,8 +20,11 @@ __fixdfsi(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI si_int __aeabi_d2iz(fp_t a) { return __fixdfsi(a); } +#else +AEABI_RTABI si_int __aeabi_d2iz(fp_t a) COMPILER_RT_ALIAS(__fixdfsi); +#endif #endif - diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c index c43473637..32e87c608 100644 --- a/lib/builtins/fixsfdi.c +++ b/lib/builtins/fixsfdi.c @@ -45,13 +45,11 @@ __fixsfdi(fp_t a) { #endif #if defined(__ARM_EABI__) -AEABI_RTABI di_int -#if defined(__SOFT_FP__) -__aeabi_f2lz(fp_t a) { -#else -__aeabi_f2lz(float a) { -#endif +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI di_int __aeabi_f2lz(fp_t a) { return __fixsfdi(a); } +#else +AEABI_RTABI di_int __aeabi_f2lz(fp_t a) COMPILER_RT_ALIAS(__fixsfdi); +#endif #endif - diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c index 3276df966..e94e5f3dc 100644 --- a/lib/builtins/fixsfsi.c +++ b/lib/builtins/fixsfsi.c @@ -20,8 +20,11 @@ __fixsfsi(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI si_int __aeabi_f2iz(fp_t a) { return __fixsfsi(a); } +#else +AEABI_RTABI si_int __aeabi_f2iz(fp_t a) COMPILER_RT_ALIAS(__fixsfsi); +#endif #endif - diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c index b73440970..bfe4dbb25 100644 --- a/lib/builtins/fixunsdfdi.c +++ b/lib/builtins/fixunsdfdi.c @@ -42,13 +42,11 @@ __fixunsdfdi(fp_t a) { #endif #if defined(__ARM_EABI__) -AEABI_RTABI du_int -#if defined(__SOFT_FP__) -__aeabi_d2ulz(fp_t a) { -#else -__aeabi_d2ulz(double a) { -#endif +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) { return __fixunsdfdi(a); } +#else +AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) COMPILER_RT_ALIAS(__fixunsdfdi); +#endif #endif - diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c index bb3d8e0f8..3c5355bea 100644 --- a/lib/builtins/fixunsdfsi.c +++ b/lib/builtins/fixunsdfsi.c @@ -19,8 +19,11 @@ __fixunsdfsi(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) { return __fixunsdfsi(a); } +#else +AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) COMPILER_RT_ALIAS(__fixunsdfsi); +#endif #endif - diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c index 5d92245df..080a25bb1 100644 --- a/lib/builtins/fixunssfdi.c +++ b/lib/builtins/fixunssfdi.c @@ -43,13 +43,11 @@ __fixunssfdi(fp_t a) { #endif #if defined(__ARM_EABI__) -AEABI_RTABI du_int -#if defined(__SOFT_FP__) -__aeabi_f2ulz(fp_t a) { -#else -__aeabi_f2ulz(float a) { -#endif +#if defined(COMPILER_RT_ARMHF_TARGET) +AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) { return __fixunssfdi(a); } +#else +AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) COMPILER_RT_ALIAS(__fixunssfdi); +#endif #endif - diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c index 91d5e8ae5..eca2916a5 100644 --- a/lib/builtins/fixunssfsi.c +++ b/lib/builtins/fixunssfsi.c @@ -23,8 +23,11 @@ __fixunssfsi(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) { return __fixunssfsi(a); } +#else +AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) COMPILER_RT_ALIAS(__fixunssfsi); +#endif #endif - diff --git a/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c index 681fecef9..36b856e07 100644 --- a/lib/builtins/floatdidf.c +++ b/lib/builtins/floatdidf.c @@ -105,8 +105,11 @@ __floatdidf(di_int a) #endif #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI double __aeabi_l2d(di_int a) { return __floatdidf(a); } +#else +AEABI_RTABI double __aeabi_l2d(di_int a) COMPILER_RT_ALIAS(__floatdidf); +#endif #endif - diff --git a/lib/builtins/floatdisf.c b/lib/builtins/floatdisf.c index dd548165c..a2f09eb2e 100644 --- a/lib/builtins/floatdisf.c +++ b/lib/builtins/floatdisf.c @@ -78,8 +78,11 @@ __floatdisf(di_int a) } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI float __aeabi_l2f(di_int a) { return __floatdisf(a); } +#else +AEABI_RTABI float __aeabi_l2f(di_int a) COMPILER_RT_ALIAS(__floatdisf); +#endif #endif - diff --git a/lib/builtins/floatsidf.c b/lib/builtins/floatsidf.c index 2ae395bdc..fe051123c 100644 --- a/lib/builtins/floatsidf.c +++ b/lib/builtins/floatsidf.c @@ -51,8 +51,11 @@ __floatsidf(int a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_i2d(int a) { return __floatsidf(a); } +#else +AEABI_RTABI fp_t __aeabi_i2d(int a) COMPILER_RT_ALIAS(__floatsidf); +#endif #endif - diff --git a/lib/builtins/floatsisf.c b/lib/builtins/floatsisf.c index 08891fcdf..bf087ee3c 100644 --- a/lib/builtins/floatsisf.c +++ b/lib/builtins/floatsisf.c @@ -57,8 +57,11 @@ __floatsisf(int a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_i2f(int a) { return __floatsisf(a); } +#else +AEABI_RTABI fp_t __aeabi_i2f(int a) COMPILER_RT_ALIAS(__floatsisf); +#endif #endif - diff --git a/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c index 6c1a931ef..8bc2a0963 100644 --- a/lib/builtins/floatundidf.c +++ b/lib/builtins/floatundidf.c @@ -104,8 +104,11 @@ __floatundidf(du_int a) #endif #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI double __aeabi_ul2d(du_int a) { return __floatundidf(a); } +#else +AEABI_RTABI double __aeabi_ul2d(du_int a) COMPILER_RT_ALIAS(__floatundidf); +#endif #endif - diff --git a/lib/builtins/floatundisf.c b/lib/builtins/floatundisf.c index 86841a75d..844786ea7 100644 --- a/lib/builtins/floatundisf.c +++ b/lib/builtins/floatundisf.c @@ -75,8 +75,11 @@ __floatundisf(du_int a) } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI float __aeabi_ul2f(du_int a) { return __floatundisf(a); } +#else +AEABI_RTABI float __aeabi_ul2f(du_int a) COMPILER_RT_ALIAS(__floatundisf); +#endif #endif - diff --git a/lib/builtins/floatunsidf.c b/lib/builtins/floatunsidf.c index 8d4807194..75cf6b917 100644 --- a/lib/builtins/floatunsidf.c +++ b/lib/builtins/floatunsidf.c @@ -40,8 +40,11 @@ __floatunsidf(unsigned int a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) { return __floatunsidf(a); } +#else +AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) COMPILER_RT_ALIAS(__floatunsidf); +#endif #endif - diff --git a/lib/builtins/floatunsisf.c b/lib/builtins/floatunsisf.c index f194c046d..29525cced 100644 --- a/lib/builtins/floatunsisf.c +++ b/lib/builtins/floatunsisf.c @@ -48,8 +48,11 @@ __floatunsisf(unsigned int a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) { return __floatunsisf(a); } +#else +AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) COMPILER_RT_ALIAS(__floatunsisf); +#endif #endif - diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h index 9a8092d50..9d09e2dc9 100644 --- a/lib/builtins/int_lib.h +++ b/lib/builtins/int_lib.h @@ -22,9 +22,11 @@ #if defined(__ELF__) #define FNALIAS(alias_name, original_name) \ - void alias_name() __attribute__((alias(#original_name))) + void alias_name() __attribute__((__alias__(#original_name))) +#define COMPILER_RT_ALIAS(aliasee) __attribute__((__alias__(#aliasee))) #else #define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")") +#define COMPILER_RT_ALIAS(aliasee) _Pragma("GCC error(\"alias unsupported on this file format\")") #endif /* ABI macro definitions */ diff --git a/lib/builtins/lshrdi3.c b/lib/builtins/lshrdi3.c index becbbef4e..67b2a7668 100644 --- a/lib/builtins/lshrdi3.c +++ b/lib/builtins/lshrdi3.c @@ -41,8 +41,5 @@ __lshrdi3(di_int a, si_int b) } #if defined(__ARM_EABI__) -AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) { - return __lshrdi3(a, b); -} +AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) COMPILER_RT_ALIAS(__lshrdi3); #endif - diff --git a/lib/builtins/muldf3.c b/lib/builtins/muldf3.c index 59a60190e..1bb103e38 100644 --- a/lib/builtins/muldf3.c +++ b/lib/builtins/muldf3.c @@ -20,8 +20,11 @@ COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) { return __muldf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) COMPILER_RT_ALIAS(__muldf3); +#endif #endif - diff --git a/lib/builtins/muldi3.c b/lib/builtins/muldi3.c index 6818a9e2f..a187315e9 100644 --- a/lib/builtins/muldi3.c +++ b/lib/builtins/muldi3.c @@ -54,8 +54,5 @@ __muldi3(di_int a, di_int b) } #if defined(__ARM_EABI__) -AEABI_RTABI di_int __aeabi_lmul(di_int a, di_int b) { - return __muldi3(a, b); -} +AEABI_RTABI di_int __aeabi_lmul(di_int a, di_int b) COMPILER_RT_ALIAS(__muldi3); #endif - diff --git a/lib/builtins/mulsf3.c b/lib/builtins/mulsf3.c index f141af1ac..1e2cf3e71 100644 --- a/lib/builtins/mulsf3.c +++ b/lib/builtins/mulsf3.c @@ -20,8 +20,11 @@ COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) { return __mulsf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) COMPILER_RT_ALIAS(__mulsf3); +#endif #endif - diff --git a/lib/builtins/negdf2.c b/lib/builtins/negdf2.c index 5e2544cdb..f0bfaad24 100644 --- a/lib/builtins/negdf2.c +++ b/lib/builtins/negdf2.c @@ -20,8 +20,11 @@ __negdf2(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_dneg(fp_t a) { return __negdf2(a); } +#else +AEABI_RTABI fp_t __aeabi_dneg(fp_t a) COMPILER_RT_ALIAS(__negdf2); +#endif #endif - diff --git a/lib/builtins/negsf2.c b/lib/builtins/negsf2.c index f90b34335..05c97d4d5 100644 --- a/lib/builtins/negsf2.c +++ b/lib/builtins/negsf2.c @@ -20,8 +20,11 @@ __negsf2(fp_t a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_fneg(fp_t a) { return __negsf2(a); } +#else +AEABI_RTABI fp_t __aeabi_fneg(fp_t a) COMPILER_RT_ALIAS(__negsf2); +#endif #endif - diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c index 38340dfab..a892fa603 100644 --- a/lib/builtins/subdf3.c +++ b/lib/builtins/subdf3.c @@ -22,8 +22,11 @@ __subdf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) { return __subdf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) COMPILER_RT_ALIAS(__subdf3); +#endif #endif - diff --git a/lib/builtins/subsf3.c b/lib/builtins/subsf3.c index 34276b144..4b2786177 100644 --- a/lib/builtins/subsf3.c +++ b/lib/builtins/subsf3.c @@ -22,8 +22,11 @@ __subsf3(fp_t a, fp_t b) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) { return __subsf3(a, b); } +#else +AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) COMPILER_RT_ALIAS(__subsf3); +#endif #endif - diff --git a/lib/builtins/truncdfhf2.c b/lib/builtins/truncdfhf2.c index 4bb71aa17..8354a41b8 100644 --- a/lib/builtins/truncdfhf2.c +++ b/lib/builtins/truncdfhf2.c @@ -16,8 +16,11 @@ COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI uint16_t __aeabi_d2h(double a) { return __truncdfhf2(a); } +#else +AEABI_RTABI uint16_t __aeabi_d2h(double a) COMPILER_RT_ALIAS(__truncdfhf2); +#endif #endif - diff --git a/lib/builtins/truncdfsf2.c b/lib/builtins/truncdfsf2.c index 8bf58bb23..195d3e065 100644 --- a/lib/builtins/truncdfsf2.c +++ b/lib/builtins/truncdfsf2.c @@ -16,8 +16,11 @@ COMPILER_RT_ABI float __truncdfsf2(double a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI float __aeabi_d2f(double a) { return __truncdfsf2(a); } +#else +AEABI_RTABI float __aeabi_d2f(double a) COMPILER_RT_ALIAS(__truncdfsf2); +#endif #endif - diff --git a/lib/builtins/truncsfhf2.c b/lib/builtins/truncsfhf2.c index f6ce1fa1d..9c84ab4f9 100644 --- a/lib/builtins/truncsfhf2.c +++ b/lib/builtins/truncsfhf2.c @@ -22,8 +22,11 @@ COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) { } #if defined(__ARM_EABI__) +#if defined(COMPILER_RT_ARMHF_TARGET) AEABI_RTABI uint16_t __aeabi_f2h(float a) { return __truncsfhf2(a); } +#else +AEABI_RTABI uint16_t __aeabi_f2h(float a) COMPILER_RT_ALIAS(__truncsfhf2); +#endif #endif - diff --git a/lib/builtins/udivsi3.c b/lib/builtins/udivsi3.c index 8eccf102c..bb720f8c3 100644 --- a/lib/builtins/udivsi3.c +++ b/lib/builtins/udivsi3.c @@ -64,8 +64,5 @@ __udivsi3(su_int n, su_int d) } #if defined(__ARM_EABI__) -AEABI_RTABI su_int __aeabi_uidiv(su_int n, su_int d) { - return __udivsi3(n, d); -} +AEABI_RTABI su_int __aeabi_uidiv(su_int n, su_int d) COMPILER_RT_ALIAS(__udivsi3); #endif - -- cgit v1.2.1 From 640d7d1f97a1804a0833c2d1d7220fb50bab746a Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Wed, 4 Oct 2017 05:12:00 +0000 Subject: [XRay] [compiler-rt] make sure single threaded programs get traced too Summary: When the XRay user calls the API to finish writing the log, the thread which is calling the API still hasn't finished and therefore won't get its trace written. Add a test for only the main thread to check this. Reviewers: dberris Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38493 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314875 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 10 +++++++ test/xray/TestCases/Linux/fdr-single-thread.cc | 37 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/xray/TestCases/Linux/fdr-single-thread.cc diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 7aebcb224..bd79893f6 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -116,6 +116,16 @@ XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT { reinterpret_cast(B.Buffer) + B.Size); } }); + + // The buffer for this particular thread would have been finalised after + // we've written everything to disk, and we'd lose the thread's trace. + auto &TLD = __xray::__xray_fdr_internal::getThreadLocalData(); + if (TLD.Buffer.Buffer != nullptr) { + __xray::__xray_fdr_internal::writeEOBMetadata(); + auto Start = reinterpret_cast(TLD.Buffer.Buffer); + retryingWriteAll(Fd, Start, Start + TLD.Buffer.Size); + } + __sanitizer::atomic_store(&LogFlushStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, __sanitizer::memory_order_release); diff --git a/test/xray/TestCases/Linux/fdr-single-thread.cc b/test/xray/TestCases/Linux/fdr-single-thread.cc new file mode 100644 index 000000000..30d834e57 --- /dev/null +++ b/test/xray/TestCases/Linux/fdr-single-thread.cc @@ -0,0 +1,37 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS=XRAY_OPTIONS="verbosity=1 patch_premain=true \ +// RUN: xray_naive_log=false xray_fdr_log=true \ +// RUN: xray_fdr_log_func_duration_threshold_us=0 \ +// RUN: xray_logfile_base=fdr-logging-1thr-" %run %t 2>&1 +// RUN: %llvm_xray convert --output-format=yaml --symbolize --instr_map=%t \ +// RUN: "`ls fdr-logging-1thr-* | head -n1`" | FileCheck %s +// RUN: rm fdr-logging-1thr-* +// +// REQUIRES: x86_64-linux + +#include "xray/xray_log_interface.h" +#include + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fn() { } + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Opts; + + auto status = __xray_log_init(kBufferSize, kBufferMax, &Opts, sizeof(Opts)); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + + __xray_patch(); + fn(); + __xray_unpatch(); + assert(__xray_log_finalize() == XRAY_LOG_FINALIZED); + assert(__xray_log_flushLog() == XRAY_LOG_FLUSHED); + return 0; +} + +// CHECK: records: +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], kind: function-exit, tsc: {{[0-9]+}} } -- cgit v1.2.1 From 06f288ce325d14aeee9b3887cfc7862f0c1735ba Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 4 Oct 2017 05:20:13 +0000 Subject: [XRay][compiler-rt] Use a hand-written circular buffer in BufferQueue Summary: This change removes the dependency on using a std::deque<...> for the storage of the buffers in the buffer queue. We instead implement a fixed-size circular buffer that's resilient to exhaustion, and preserves the semantics of the BufferQueue. We're moving away from using std::deque<...> for two reasons: - We want to remove dependencies on the STL for data structures. - We want the data structure we use to not require re-allocation in the normal course of operation. The internal implementation of the buffer queue uses heap-allocated arrays that are initialized once when the BufferQueue is created, and re-uses slots in the buffer array as buffers are returned in order. We also change the lock used in the implementation to a spinlock instead of a blocking mutex. We reason that since the release operations now take very little time in the critical section, that a spinlock would be appropriate. This change is related to D38073. This change is a re-submit with the following changes: - Keeping track of the live buffers with a counter independent of the pointers keeping track of the extents of the circular buffer. - Additional documentation of what the data members are meant to represent. Reviewers: dblaikie, kpw, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38119 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314877 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 47 ++++++++++++++++++-------- lib/xray/xray_buffer_queue.h | 30 +++++++++++++---- test/xray/TestCases/Linux/fdr-thread-order.cc | 48 +++++++++++++++++++++------ 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 7ba755ac3..b049ab375 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -16,6 +16,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include #include #include @@ -23,18 +24,21 @@ using namespace __xray; using namespace __sanitizer; BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) - : BufferSize(B), Buffers(N), Mutex(), OwnedBuffers(), Finalizing{0} { - for (auto &T : Buffers) { + : BufferSize(B), Buffers(new std::tuple[N]()), + BufferCount(N), Finalizing{0}, OwnedBuffers(new void *[N]()), + Next(Buffers.get()), First(Buffers.get()), LiveBuffers(0) { + for (size_t i = 0; i < N; ++i) { + auto &T = Buffers[i]; void *Tmp = malloc(BufferSize); if (Tmp == nullptr) { Success = false; return; } - auto &Buf = std::get<0>(T); + std::get<1>(T) = false; Buf.Buffer = Tmp; Buf.Size = B; - OwnedBuffers.emplace(Tmp); + OwnedBuffers[i] = Tmp; } Success = true; } @@ -42,27 +46,41 @@ BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) return ErrorCode::QueueFinalizing; - __sanitizer::BlockingMutexLock Guard(&Mutex); - if (Buffers.empty()) + __sanitizer::SpinMutexLock Guard(&Mutex); + if (LiveBuffers == BufferCount) return ErrorCode::NotEnoughMemory; - auto &T = Buffers.front(); + + auto &T = *Next; auto &B = std::get<0>(T); Buf = B; - B.Buffer = nullptr; - B.Size = 0; - Buffers.pop_front(); + ++LiveBuffers; + + First = Next; + if (++Next == (Buffers.get() + BufferCount)) + Next = Buffers.get(); + return ErrorCode::Ok; } BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { - if (OwnedBuffers.count(Buf.Buffer) == 0) + // Blitz through the buffers array to find the buffer. + if (std::none_of(OwnedBuffers.get(), OwnedBuffers.get() + BufferCount, + [&Buf](void *P) { return P == Buf.Buffer; })) return ErrorCode::UnrecognizedBuffer; - __sanitizer::BlockingMutexLock Guard(&Mutex); + __sanitizer::SpinMutexLock Guard(&Mutex); + + // This points to a semantic bug, we really ought to not be releasing more + // buffers than we actually get. + if (LiveBuffers == 0) + return ErrorCode::NotEnoughMemory; // Now that the buffer has been released, we mark it as "used". - Buffers.emplace(Buffers.end(), Buf, true /* used */); + *First = std::make_tuple(Buf, true); Buf.Buffer = nullptr; Buf.Size = 0; + --LiveBuffers; + if (++First == (Buffers.get() + BufferCount)) + First = Buffers.get(); return ErrorCode::Ok; } @@ -74,7 +92,8 @@ BufferQueue::ErrorCode BufferQueue::finalize() { } BufferQueue::~BufferQueue() { - for (auto &T : Buffers) { + for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + auto &T = *I; auto &Buf = std::get<0>(T); free(Buf.Buffer); } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index bd382a26c..05e22eece 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -17,8 +17,8 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_mutex.h" -#include -#include +#include +#include #include namespace __xray { @@ -36,15 +36,30 @@ public: }; private: + // Size of each individual Buffer. size_t BufferSize; // We use a bool to indicate whether the Buffer has been used in this // freelist implementation. - std::deque> Buffers; - __sanitizer::BlockingMutex Mutex; - std::unordered_set OwnedBuffers; + std::unique_ptr[]> Buffers; + size_t BufferCount; + + __sanitizer::SpinMutex Mutex; __sanitizer::atomic_uint8_t Finalizing; + // Pointers to buffers managed/owned by the BufferQueue. + std::unique_ptr OwnedBuffers; + + // Pointer to the next buffer to be handed out. + std::tuple *Next; + + // Pointer to the entry in the array where the next released buffer will be + // placed. + std::tuple *First; + + // Count of buffers that have been handed out through 'getBuffer'. + size_t LiveBuffers; + public: enum class ErrorCode : unsigned { Ok, @@ -117,8 +132,9 @@ public: /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a /// releaseBuffer(...) operation). template void apply(F Fn) { - __sanitizer::BlockingMutexLock G(&Mutex); - for (const auto &T : Buffers) { + __sanitizer::SpinMutexLock G(&Mutex); + for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + const auto &T = *I; if (std::get<1>(T)) Fn(std::get<0>(T)); } diff --git a/test/xray/TestCases/Linux/fdr-thread-order.cc b/test/xray/TestCases/Linux/fdr-thread-order.cc index 6ac2114a5..8e8c421dc 100644 --- a/test/xray/TestCases/Linux/fdr-thread-order.cc +++ b/test/xray/TestCases/Linux/fdr-thread-order.cc @@ -1,37 +1,63 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t // RUN: rm fdr-thread-order.* || true -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-thread-order.* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false \ +// RUN: xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 \ +// RUN: xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | \ +// RUN: FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" | \ +// RUN: FileCheck %s --check-prefix TRACE // RUN: rm fdr-thread-order.* // FIXME: Make llvm-xray work on non-x86_64 as well. // REQUIRES: x86_64-linux // REQUIRES: built-in-llvm-tree #include "xray/xray_log_interface.h" -#include +#include #include +#include constexpr auto kBufferSize = 16384; constexpr auto kBufferMax = 10; -thread_local uint64_t var = 0; -[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { ++var; } -[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { ++var; } +std::atomic var{0}; + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} int main(int argc, char *argv[]) { using namespace __xray; FDRLoggingOptions Options; + __xray_patch(); assert(__xray_log_init(kBufferSize, kBufferMax, &Options, sizeof(FDRLoggingOptions)) == XRayLogInitStatus::XRAY_LOG_INITIALIZED); - __xray_patch(); - std::thread t1([] { f1(); }); - std::thread t2([] { f2(); }); - t1.join(); - t2.join(); + + std::atomic_thread_fence(std::memory_order_acq_rel); + + { + std::thread t1([] { f1(); }); + std::thread t2([] { f2(); }); + t1.join(); + t2.join(); + } + + std::atomic_thread_fence(std::memory_order_acq_rel); __xray_log_finalize(); __xray_log_flushLog(); + __xray_unpatch(); + return var > 0 ? 0 : 1; // CHECK: {{.*}}XRay: Log file in '{{.*}}' + // CHECK-NOT: Failed } // We want to make sure that the order of the function log doesn't matter. -- cgit v1.2.1 From a16d35ab9a371ca82f039a5cdd2ac308d0f58e80 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 4 Oct 2017 06:02:12 +0000 Subject: [XRay][compiler-rt] Fix logical failure in BufferQueue::getBuffer() Follow-up to D38119. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314878 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index b049ab375..61a0add0e 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -55,7 +55,6 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { Buf = B; ++LiveBuffers; - First = Next; if (++Next == (Buffers.get() + BufferCount)) Next = Buffers.get(); @@ -81,6 +80,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { --LiveBuffers; if (++First == (Buffers.get() + BufferCount)) First = Buffers.get(); + return ErrorCode::Ok; } -- cgit v1.2.1 From 9433990fcfd399354addc756602a8391b66bf788 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 4 Oct 2017 23:35:14 +0000 Subject: [sanitizer] Move cxx-abi library earlier in link flags. Summary: This change moves cxx-abi library in asan/ubsan/dd link command line ahead of other libraries, such as pthread/rt/dl/c/gcc. Given that cxx-abi may be the full libstdc++/libc++, it makes sense for it to be ahead of libc and libgcc, at least. The real motivation is Android, where in the arm32 NDK toolchain libstdc++.a is actually a linker script that tries to sneak LLVM's libunwind ahead of libgcc's. Wrong library order breaks unwinding. Reviewers: srhines, danalbert Subscribers: aemerson, kubamracek, mgorny, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D38520 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314948 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/CMakeLists.txt | 4 +--- lib/tsan/dd/CMakeLists.txt | 4 +--- lib/ubsan/CMakeLists.txt | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index bdf92f838..1bd449057 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -67,7 +67,7 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS) -set(ASAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) +set(ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) @@ -75,8 +75,6 @@ append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS) -list(APPEND ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) - # Compile ASan sources into an object library. add_compiler_rt_object_libraries(RTAsan_dynamic diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt index 4c9508183..07fc30053 100644 --- a/lib/tsan/dd/CMakeLists.txt +++ b/lib/tsan/dd/CMakeLists.txt @@ -10,14 +10,12 @@ set(DD_SOURCES dd_interceptors.cc ) -set(DD_LINKLIBS ${SANITIZER_COMMON_LINK_LIBS}) +set(DD_LINKLIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) -list(APPEND DD_LINKLIBS ${SANITIZER_CXX_ABI_LIBRARY}) - add_custom_target(dd) # Deadlock detector is currently supported on 64-bit Linux only. if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID) diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 34b250696..644b598c5 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -35,15 +35,13 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) -set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) +set(UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS}) append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS) -list(APPEND UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY}) - add_compiler_rt_component(ubsan) if(APPLE) -- cgit v1.2.1 From 3d259d64333b61fc5ecd68824caed82750855f99 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Thu, 5 Oct 2017 05:45:51 +0000 Subject: [XRay][compiler-rt] Write out arg1 payload in naive mode logging Summary: This change allows the XRay basic (naive) mode logging implementation to start writing the payload entries through the arg1 logging handler. This implementation writes out the records that the llvm-xray tool and the trace reader library will start processing in D38550. This introduces a new payload record type which logs the data through the in-memory buffer. It uses the same size/alignment that the normal XRay record entries use. We use a new record type to indicate these new entries, so that the trace reader library in LLVM can start reading these entries. Depends on D38550. Reviewers: pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38551 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314968 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/xray/xray_records.h | 30 ++++++++++- lib/xray/xray_inmemory_log.cc | 120 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 135 insertions(+), 15 deletions(-) diff --git a/include/xray/xray_records.h b/include/xray/xray_records.h index 98e54cb69..d4b7b4c31 100644 --- a/include/xray/xray_records.h +++ b/include/xray/xray_records.h @@ -67,13 +67,14 @@ static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes"); enum RecordTypes { NORMAL = 0, + ARG_PAYLOAD = 1, }; struct alignas(32) XRayRecord { // This is the type of the record being written. We use 16 bits to allow us to // treat this as a discriminant, and so that the first 4 bytes get packed // properly. See RecordTypes for more supported types. - uint16_t RecordType = 0; + uint16_t RecordType = RecordTypes::NORMAL; // The CPU where the thread is running. We assume number of CPUs <= 256. uint8_t CPU = 0; @@ -82,6 +83,7 @@ struct alignas(32) XRayRecord { // ENTER = 0 // EXIT = 1 // TAIL_EXIT = 2 + // ENTER_ARG = 3 uint8_t Type = 0; // The function ID for the record. @@ -99,6 +101,32 @@ struct alignas(32) XRayRecord { static_assert(sizeof(XRayRecord) == 32, "XRayRecord != 32 bytes"); +struct alignas(32) XRayArgPayload { + // We use the same 16 bits as a discriminant for the records in the log here + // too, and so that the first 4 bytes are packed properly. + uint16_t RecordType = RecordTypes::ARG_PAYLOAD; + + // Add a few bytes to pad. + uint8_t Padding[2] = {}; + + // The function ID for the record. + int32_t FuncId = 0; + + // The thread ID for the currently running thread. + uint32_t TId = 0; + + // Add more padding. + uint8_t Padding2[4] = {}; + + // The argument payload. + uint64_t Arg = 0; + + // The rest of this record ought to be left as padding. + uint8_t TailPadding[8] = {}; +} __attribute__((packed)); + +static_assert(sizeof(XRayArgPayload) == 32, "XRayArgPayload != 32 bytes"); + } // namespace __xray #endif // XRAY_XRAY_RECORDS_H diff --git a/lib/xray/xray_inmemory_log.cc b/lib/xray/xray_inmemory_log.cc index 3d8ecda6f..188bae642 100644 --- a/lib/xray/xray_inmemory_log.cc +++ b/lib/xray/xray_inmemory_log.cc @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include +#include #include #include #include @@ -82,14 +83,14 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { // Test for required CPU features and cache the cycle frequency static bool TSCSupported = probeRequiredCPUFeatures(); - static uint64_t CycleFrequency = TSCSupported ? getTSCFrequency() - : __xray::NanosecondsPerSecond; + static uint64_t CycleFrequency = + TSCSupported ? getTSCFrequency() : __xray::NanosecondsPerSecond; // Since we're here, we get to write the header. We set it up so that the // header will only be written once, at the start, and let the threads // logging do writes which just append. XRayFileHeader Header; - Header.Version = 2; // Version 2 includes tail exit records. + Header.Version = 2; // Version 2 includes tail exit records. Header.Type = FileTypes::NAIVE_LOG; Header.CycleFrequency = CycleFrequency; @@ -102,26 +103,43 @@ static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT { return F; } +using Buffer = + std::aligned_storage::type; + +static constexpr size_t BuffLen = 1024; +thread_local size_t Offset = 0; + +Buffer (&getThreadLocalBuffer())[BuffLen] XRAY_NEVER_INSTRUMENT { + thread_local static Buffer InMemoryBuffer[BuffLen] = {}; + return InMemoryBuffer; +} + +pid_t getTId() XRAY_NEVER_INSTRUMENT { + thread_local pid_t TId = syscall(SYS_gettid); + return TId; +} + +int getGlobalFd() XRAY_NEVER_INSTRUMENT { + static int Fd = __xray_OpenLogFile(); + return Fd; +} + +thread_local volatile bool RecusionGuard = false; template void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT { - using Buffer = - std::aligned_storage::type; - static constexpr size_t BuffLen = 1024; - thread_local static Buffer InMemoryBuffer[BuffLen] = {}; - thread_local static size_t Offset = 0; - static int Fd = __xray_OpenLogFile(); + auto &InMemoryBuffer = getThreadLocalBuffer(); + int Fd = getGlobalFd(); if (Fd == -1) return; thread_local __xray::ThreadExitFlusher Flusher( Fd, reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer), Offset); - thread_local pid_t TId = syscall(SYS_gettid); // Use a simple recursion guard, to handle cases where we're already logging // and for one reason or another, this function gets called again in the same // thread. - thread_local volatile bool RecusionGuard = false; - if (RecusionGuard) return; + if (RecusionGuard) + return; RecusionGuard = true; // First we get the useful data, and stuff it into the already aligned buffer @@ -129,7 +147,7 @@ void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, auto &R = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer)[Offset]; R.RecordType = RecordTypes::NORMAL; R.TSC = ReadTSC(R.CPU); - R.TId = TId; + R.TId = getTId(); R.Type = Type; R.FuncId = FuncId; ++Offset; @@ -144,6 +162,55 @@ void __xray_InMemoryRawLog(int32_t FuncId, XRayEntryType Type, RecusionGuard = false; } +template +void __xray_InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, + uint64_t Arg1, + RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT { + auto &InMemoryBuffer = getThreadLocalBuffer(); + int Fd = getGlobalFd(); + if (Fd == -1) + return; + + // First we check whether there's enough space to write the data consecutively + // in the thread-local buffer. If not, we first flush the buffer before + // attempting to write the two records that must be consecutive. + if (Offset + 2 > BuffLen) { + __sanitizer::SpinMutexLock L(&LogMutex); + auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); + retryingWriteAll(Fd, reinterpret_cast(RecordBuffer), + reinterpret_cast(RecordBuffer + Offset)); + Offset = 0; + } + + // Then we write the "we have an argument" record. + __xray_InMemoryRawLog(FuncId, Type, ReadTSC); + + if (RecusionGuard) + return; + + RecusionGuard = true; + + // And from here on write the arg payload. + __xray::XRayArgPayload R; + R.RecordType = RecordTypes::ARG_PAYLOAD; + R.FuncId = FuncId; + R.TId = getTId(); + R.Arg = Arg1; + auto EntryPtr = + &reinterpret_cast<__xray::XRayArgPayload *>(&InMemoryBuffer)[Offset]; + std::memcpy(EntryPtr, &R, sizeof(R)); + ++Offset; + if (Offset == BuffLen) { + __sanitizer::SpinMutexLock L(&LogMutex); + auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer); + retryingWriteAll(Fd, reinterpret_cast(RecordBuffer), + reinterpret_cast(RecordBuffer + Offset)); + Offset = 0; + } + + RecusionGuard = false; +} + void __xray_InMemoryRawLogRealTSC(int32_t FuncId, XRayEntryType Type) XRAY_NEVER_INSTRUMENT { __xray_InMemoryRawLog(FuncId, Type, __xray::readTSC); @@ -163,13 +230,38 @@ void __xray_InMemoryEmulateTSC(int32_t FuncId, }); } +void __xray_InMemoryRawLogWithArgRealTSC(int32_t FuncId, XRayEntryType Type, + uint64_t Arg1) XRAY_NEVER_INSTRUMENT { + __xray_InMemoryRawLogWithArg(FuncId, Type, Arg1, __xray::readTSC); +} + +void __xray_InMemoryRawLogWithArgEmulateTSC( + int32_t FuncId, XRayEntryType Type, uint64_t Arg1) XRAY_NEVER_INSTRUMENT { + __xray_InMemoryRawLogWithArg( + FuncId, Type, Arg1, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT { + timespec TS; + int result = clock_gettime(CLOCK_REALTIME, &TS); + if (result != 0) { + Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno)); + TS = {0, 0}; + } + CPU = 0; + return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; + }); +} + static auto UNUSED Unused = [] { auto UseRealTSC = probeRequiredCPUFeatures(); if (!UseRealTSC) Report("WARNING: Required CPU features missing for XRay instrumentation, " "using emulation instead.\n"); - if (flags()->xray_naive_log) + if (flags()->xray_naive_log) { + __xray_set_handler_arg1(UseRealTSC + ? __xray_InMemoryRawLogWithArgRealTSC + : __xray_InMemoryRawLogWithArgEmulateTSC); __xray_set_handler(UseRealTSC ? __xray_InMemoryRawLogRealTSC : __xray_InMemoryEmulateTSC); + } + return true; }(); -- cgit v1.2.1 From f4abfe4e8b3ce1faf6767300577a02cfbab6fe2b Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 18:28:04 +0000 Subject: [cfi] Test on all available targets. Summary: Run CFI tests on all targets current toolchain can target. On multiarch Linux, this will run all CFI tests with -m32 and -m64. Reviewers: pcc Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D38572 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315001 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 26 +++++++++++++++++--------- test/cfi/lit.cfg | 7 ++++--- test/cfi/lit.site.cfg.in | 2 ++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 3313fb233..2e2f0f88b 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -8,6 +8,7 @@ macro (add_cfi_test_suites lld thinlto) if (${thinlto}) set(suffix ${suffix}-thinlto) endif() + set(suffix ${suffix}-${CFI_TEST_TARGET_ARCH}) set(CFI_TEST_USE_LLD ${lld}) set(CFI_TEST_USE_THINLTO ${thinlto}) @@ -29,14 +30,21 @@ macro (add_cfi_test_suites lld thinlto) list(APPEND CFI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Devirt${suffix}) endmacro() -if (APPLE) - # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 - add_cfi_test_suites(False False) -elseif(WIN32) - add_cfi_test_suites(True False) - add_cfi_test_suites(True True) -else() - if (CFI_SUPPORTED_ARCH) +set(CFI_TEST_ARCH ${CFI_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(CFI_SUPPORTED_ARCH CFI_TEST_ARCH) +endif() + +foreach(arch ${CFI_TEST_ARCH}) + set(CFI_TEST_TARGET_ARCH ${arch}) + get_test_cc_for_arch(${arch} CFI_TEST_TARGET_CC CFI_TEST_TARGET_CFLAGS) + if (APPLE) + # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741 + add_cfi_test_suites(False False) + elseif(WIN32) + add_cfi_test_suites(True False) + add_cfi_test_suites(True True) + else() add_cfi_test_suites(False False) add_cfi_test_suites(False True) if (COMPILER_RT_HAS_LLD) @@ -44,7 +52,7 @@ else() add_cfi_test_suites(True True) endif() endif() -endif() +endforeach() set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) list(APPEND CFI_TEST_DEPS diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index 314ba5ce9..76cafb855 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -5,12 +5,13 @@ config.name = 'cfi' + config.name_suffix config.suffixes = ['.c', '.cpp', '.test'] config.test_source_root = os.path.dirname(__file__) -clangxx = ' '.join([config.clang] + config.cxx_mode_flags) +clang = ' '.join([config.clang, config.target_cflags]) +clangxx = ' '.join([config.clang, config.target_cflags] + config.cxx_mode_flags) -config.substitutions.append((r"%clang ", ' '.join([config.clang]) + ' ')) +config.substitutions.append((r"%clang ", clang + ' ')) config.substitutions.append((r"%clangxx ", clangxx + ' ')) if config.lto_supported: - clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=cfi ']) + clang_cfi = ' '.join(config.lto_launch + [clang] + config.lto_flags + ['-fsanitize=cfi ']) if config.cfi_lit_test_mode == "Devirt": config.available_features.add('devirt') diff --git a/test/cfi/lit.site.cfg.in b/test/cfi/lit.site.cfg.in index 63611f659..066c915ef 100644 --- a/test/cfi/lit.site.cfg.in +++ b/test/cfi/lit.site.cfg.in @@ -2,6 +2,8 @@ config.name_suffix = "@CFI_TEST_CONFIG_SUFFIX@" config.cfi_lit_test_mode = "@CFI_LIT_TEST_MODE@" +config.target_arch = "@CFI_TEST_TARGET_ARCH@" +config.target_cflags = "@CFI_TEST_TARGET_CFLAGS@" config.use_lld = @CFI_TEST_USE_LLD@ config.use_thinlto = @CFI_TEST_USE_THINLTO@ -- cgit v1.2.1 From ad59ece0e473ce0278ab3516e9d0a757955a5da1 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 19:36:15 +0000 Subject: [cfi] Mark a test as unsupported on darwin. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315007 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/icall/external-call.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cfi/icall/external-call.c b/test/cfi/icall/external-call.c index e90c7e042..27c447878 100644 --- a/test/cfi/icall/external-call.c +++ b/test/cfi/icall/external-call.c @@ -4,7 +4,8 @@ // This test uses jump tables containing PC-relative references to external // symbols, which the Mach-O object writer does not currently support. -// XFAIL: darwin +// The test passes on i386 Darwin and fails on x86_64, hence unsupported instead of xfail. +// UNSUPPORTED: darwin #include #include -- cgit v1.2.1 From 576e896664c918a2c5372f4fde6339ae20b0e807 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 20:00:07 +0000 Subject: [sanitizer] Move %ld_flags_rpath_exe to common and use it in more tests. Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D38527 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315010 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 15 --------------- test/cfi/target_uninstrumented.cpp | 6 +++--- test/lit.common.cfg | 15 +++++++++++++++ .../TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 213693e6f..fc8daaaf0 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -178,21 +178,6 @@ config.substitutions.append( ("%libdl", libdl_flag) ) config.available_features.add("asan-" + config.bits + "-bits") -if config.host_os == 'Darwin': - config.substitutions.append( ("%ld_flags_rpath_exe", '-Wl,-rpath,@executable_path/ %dynamiclib') ) - config.substitutions.append( ("%ld_flags_rpath_so", '-install_name @rpath/`basename %dynamiclib`') ) -elif config.host_os == 'FreeBSD': - config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-z,origin -Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) - config.substitutions.append( ("%ld_flags_rpath_so", '') ) -elif config.host_os == 'Linux': - config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) - config.substitutions.append( ("%ld_flags_rpath_so", '') ) - -# Must be defined after the substitutions that use %dynamiclib. -config.substitutions.append( ("%dynamiclib", '%T/%xdynamiclib_filename') ) -config.substitutions.append( ("%xdynamiclib_filename", 'lib%xdynamiclib_namespec.so') ) -config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) - # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL # because the test hangs. Adding armhf as we now have two modes. if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64': diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp index b2a1ad74a..5df0738c0 100644 --- a/test/cfi/target_uninstrumented.cpp +++ b/test/cfi/target_uninstrumented.cpp @@ -1,5 +1,5 @@ -// RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %T/target_uninstrumented-so.so -// RUN: %clangxx_cfi_diag -g %s -o %t %T/target_uninstrumented-so.so +// RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_diag -g %s -o %t %ld_flags_rpath_exe // RUN: %run %t 2>&1 | FileCheck %s // REQUIRES: cxxabi @@ -32,7 +32,7 @@ void A::f() {} int main(int argc, char *argv[]) { void *p = create_B(); // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type - // CHECK: invalid vtable in module {{.*}}target_uninstrumented-so.so + // CHECK: invalid vtable in module {{.*}}libtarget_uninstrumented.cpp.dynamic.so A *a = (A *)p; memset(p, 0, sizeof(A)); // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 5667e12a2..dc1a6034f 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -280,3 +280,18 @@ if platform.system() == 'Windows': # of large mmap'd regions (terabytes) by the kernel. if platform.system() == 'Darwin': lit_config.parallelism_groups["darwin-64bit-sanitizer"] = 3 + +if config.host_os == 'Darwin': + config.substitutions.append( ("%ld_flags_rpath_exe", '-Wl,-rpath,@executable_path/ %dynamiclib') ) + config.substitutions.append( ("%ld_flags_rpath_so", '-install_name @rpath/`basename %dynamiclib`') ) +elif config.host_os == 'FreeBSD': + config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-z,origin -Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) + config.substitutions.append( ("%ld_flags_rpath_so", '') ) +elif config.host_os == 'Linux': + config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") ) + config.substitutions.append( ("%ld_flags_rpath_so", '') ) + +# Must be defined after the substitutions that use %dynamiclib. +config.substitutions.append( ("%dynamiclib", '%T/%xdynamiclib_filename') ) +config.substitutions.append( ("%xdynamiclib_filename", 'lib%xdynamiclib_namespec.so') ) +config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) diff --git a/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp b/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp index e8d510694..7bc19bdae 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp @@ -1,5 +1,5 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -I%p/Helpers -g %s -fPIC -shared -o %t-lib.so -DBUILD_SO -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -I%p/Helpers -g %s -O3 -o %t %t-lib.so +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -I%p/Helpers -g %s -fPIC -shared -o %dynamiclib -DBUILD_SO %ld_flags_rpath_so +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -I%p/Helpers -g %s -O3 -o %t %ld_flags_rpath_exe // RUN: %run %t // // REQUIRES: cxxabi -- cgit v1.2.1 From cb012eb231943326483c08eb476ee509e3d7cc8a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 20:00:19 +0000 Subject: [asan] Use full binary path in the Android test runner. Summary: This prevents the confusion when there are similarly named tests in different configurations (like in test/sanitizer_common). Reviewers: vitalybuka Subscribers: srhines, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D38526 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315011 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/android_commands/android_common.py | 9 +++++++-- test/sanitizer_common/android_commands/android_run.py | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/sanitizer_common/android_commands/android_common.py b/test/sanitizer_common/android_commands/android_common.py index 41994bb87..fc26ee258 100644 --- a/test/sanitizer_common/android_commands/android_common.py +++ b/test/sanitizer_common/android_commands/android_common.py @@ -1,4 +1,4 @@ -import os, subprocess, tempfile +import os, sys, subprocess, tempfile import time ANDROID_TMPDIR = '/data/local/tmp/Output' @@ -8,6 +8,11 @@ verbose = False if os.environ.get('ANDROID_RUN_VERBOSE') == '1': verbose = True +def host_to_device_path(path): + rel = os.path.relpath(path, "/") + dev = os.path.join(ANDROID_TMPDIR, rel) + return dev + def adb(args, attempts = 1): if verbose: print args @@ -37,5 +42,5 @@ def pull_from_device(path): return text def push_to_device(path): - dst_path = os.path.join(ANDROID_TMPDIR, os.path.basename(path)) + dst_path = host_to_device_path(path) adb(['push', path, dst_path], 5) diff --git a/test/sanitizer_common/android_commands/android_run.py b/test/sanitizer_common/android_commands/android_run.py index a7f45b9f9..faa05e248 100755 --- a/test/sanitizer_common/android_commands/android_run.py +++ b/test/sanitizer_common/android_commands/android_run.py @@ -5,8 +5,7 @@ from android_common import * ANDROID_TMPDIR = '/data/local/tmp/Output' -here = os.path.abspath(os.path.dirname(sys.argv[0])) -device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) +device_binary = host_to_device_path(sys.argv[0]) def build_env(): args = [] -- cgit v1.2.1 From a7688a2f53cc72a27ab18a80217e0fc08b91252c Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 20:45:12 +0000 Subject: [asan] Add --enable-new-dtags in tests on Android. The dynamic loader does not accept DT_RPATH; it wants DT_RUNPATH. This is a temporary fix until D38430 lands. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315020 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index dc1a6034f..2058120e0 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -55,7 +55,7 @@ config.available_features.add(compiler_id) # BFD linker in 64-bit android toolchains fails to find libm.so, which is a # transitive shared library dependency (via asan runtime). if config.android: - config.target_cflags += " -lm" + config.target_cflags += " -lm -Wl,--enable-new-dtags" # Clear some environment variables that might affect Clang. possibly_dangerous_env_vars = ['ASAN_OPTIONS', 'DFSAN_OPTIONS', 'LSAN_OPTIONS', -- cgit v1.2.1 From 11ad3b8e2ddac18fc697e434ef5b98966e8f6feb Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 5 Oct 2017 21:38:33 +0000 Subject: [LSan] Detect dynamic loader by its base address. Summary: Relanding D33859, which was reverted because it has "broken LOTS of ARM/AArch64 bots for two days". If it breaks something again, please provide some pointers to broken bots, not just revert it, otherwise it's very hard to reason what's wrong with this commit. Whenever possible (Linux + glibc 2.16+), detect dynamic loader module by its base address, not by the module name matching. The current name matching approach fails on some configurations. Reviewers: eugenis Subscribers: aemerson, kubamracek, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D38600 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315024 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 5 +++-- lib/lsan/lsan_common_linux.cc | 23 +++++++++++++++++------ lib/sanitizer_common/sanitizer_linux.cc | 10 ---------- lib/sanitizer_common/sanitizer_platform.h | 9 +++++++++ 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 622aae734..651bbe1f3 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -411,8 +411,9 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { } } -// On Linux, handles dynamically allocated TLS blocks by treating all chunks -// allocated from ld-linux.so as reachable. +// On Linux, treats all chunks allocated from ld-linux.so as reachable, which +// covers dynamically allocated TLS blocks, internal dynamic loader's loaded +// modules accounting etc. // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. // They are allocated with a __libc_memalign() call in allocate_and_init() // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 5042c7b3a..5acff0b2d 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -23,6 +23,10 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#if SANITIZER_USE_GETAUXVAL +#include +#endif // SANITIZER_USE_GETAUXVAL + namespace __lsan { static const char kLinkerName[] = "ld"; @@ -30,8 +34,12 @@ static const char kLinkerName[] = "ld"; static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; -static bool IsLinker(const char* full_name) { - return LibraryNameIs(full_name, kLinkerName); +static bool IsLinker(const LoadedModule& module) { +#if SANITIZER_USE_GETAUXVAL + return module.base_address() == getauxval(AT_BASE); +#else + return LibraryNameIs(module.full_name(), kLinkerName); +#endif // SANITIZER_USE_GETAUXVAL } __attribute__((tls_model("initial-exec"))) @@ -49,22 +57,25 @@ void InitializePlatformSpecificModules() { ListOfModules modules; modules.init(); for (LoadedModule &module : modules) { - if (!IsLinker(module.full_name())) continue; + if (!IsLinker(module)) + continue; if (linker == nullptr) { linker = reinterpret_cast(linker_placeholder); *linker = module; module = LoadedModule(); } else { VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " - "TLS will not be handled correctly.\n", kLinkerName); + "TLS and other allocations originating from linker might be " + "falsely reported as leaks.\n", kLinkerName); linker->clear(); linker = nullptr; return; } } if (linker == nullptr) { - VReport(1, "LeakSanitizer: Dynamic linker not found. " - "TLS will not be handled correctly.\n"); + VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " + "allocations originating from linker might be falsely reported " + "as leaks.\n"); } } diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 48c53d46d..f239b4fba 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -93,16 +93,6 @@ extern char **environ; // provided by crt1 #include #endif -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif - #if SANITIZER_USE_GETAUXVAL #include #endif diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 81d9164c3..763d6e01b 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -282,5 +282,14 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif #endif // SANITIZER_PLATFORM_H -- cgit v1.2.1 From 2edf2374329a4748bad03d6a6517ec89b1e472de Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 5 Oct 2017 22:07:21 +0000 Subject: [cfi] Disable tests with lld on i386. bin/ld.lld: error: ubsan_handlers.cc:(.debug_info+0x80D5D): has non-ABS reloc Bug pending. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315027 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 2e2f0f88b..c7fadde53 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -47,7 +47,7 @@ foreach(arch ${CFI_TEST_ARCH}) else() add_cfi_test_suites(False False) add_cfi_test_suites(False True) - if (COMPILER_RT_HAS_LLD) + if (COMPILER_RT_HAS_LLD AND NOT arch STREQUAL "i386") add_cfi_test_suites(True False) add_cfi_test_suites(True True) endif() -- cgit v1.2.1 From 590a32da41f486f5d834ccc9af1d337565b6a675 Mon Sep 17 00:00:00 2001 From: Max Moroz Date: Thu, 5 Oct 2017 22:41:03 +0000 Subject: [libFuzzer] Disable experimental clang coverage support by default. Summary: It can be enabled via "-use_clang_coverage=1" flag. Reason for disabling: libFuzzer resets Clang Counters and makes it impossible to generate coverage report for a regular fuzz target (i.e. not standalone build). Reviewers: kcc Reviewed By: kcc Subscribers: kcc Differential Revision: https://reviews.llvm.org/D38604 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315029 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerDriver.cpp | 1 + lib/fuzzer/FuzzerFlags.def | 1 + lib/fuzzer/FuzzerLoop.cpp | 1 + lib/fuzzer/FuzzerOptions.h | 1 + lib/fuzzer/FuzzerTracePC.h | 5 ++++- test/fuzzer/fprofile-instr-generate.test | 7 +++++++ 6 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/fuzzer/fprofile-instr-generate.test diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index cc995348e..dcf8d505f 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -604,6 +604,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; Options.DumpCoverage = Flags.dump_coverage; + Options.UseClangCoverage = Flags.use_clang_coverage; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; if (Flags.exit_on_item) diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index 790b5783d..a23818fd5 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -131,6 +131,7 @@ FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") +FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index ec126024e..4ccfe3f2a 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -122,6 +122,7 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); TPC.SetUseCounters(Options.UseCounters); TPC.SetUseValueProfile(Options.UseValueProfile); + TPC.SetUseClangCoverage(Options.UseClangCoverage); if (Options.Verbosity) TPC.PrintModuleInfo(); diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index bfac3b685..ddf6e4201 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -52,6 +52,7 @@ struct FuzzingOptions { bool PrintCorpusStats = false; bool PrintCoverage = false; bool DumpCoverage = false; + bool UseClangCoverage = false; bool DetectLeaks = true; int TraceMalloc = 0; bool HandleAbrt = false; diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index 743db5483..b3c9b9861 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -80,6 +80,7 @@ class TracePC { template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); void SetUseCounters(bool UC) { UseCounters = UC; } + void SetUseClangCoverage(bool UCC) { UseClangCoverage = UCC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; } @@ -92,7 +93,8 @@ class TracePC { memset(Counters(), 0, GetNumPCs()); ClearExtraCounters(); ClearInlineCounters(); - ClearClangCounters(); + if (UseClangCoverage) + ClearClangCounters(); } void ClearInlineCounters(); @@ -133,6 +135,7 @@ class TracePC { private: bool UseCounters = false; bool UseValueProfile = false; + bool UseClangCoverage = false; bool DoPrintNewPCs = false; size_t NumPrintNewFuncs = 0; diff --git a/test/fuzzer/fprofile-instr-generate.test b/test/fuzzer/fprofile-instr-generate.test new file mode 100644 index 000000000..2a3ec96f1 --- /dev/null +++ b/test/fuzzer/fprofile-instr-generate.test @@ -0,0 +1,7 @@ +# Test libFuzzer + -fprofile-instr-generate +REQUIRES: linux +RUN: %cpp_compiler %S/SimpleTest.cpp -fsanitize-coverage=0 -fprofile-instr-generate -o %t-SimpleTest-fprofile-instr-generate +CHECK-NOT: INFO: Loaded 1 modules +CHECK: INFO: {{.*}} Clang Coverage Counters +CHECK: BINGO +RUN: not %t-SimpleTest-fprofile-instr-generate -runs=1000000 -seed=1 -use_clang_coverage=1 2>&1 | FileCheck %s -- cgit v1.2.1 From 2d21e8df3faee7f35589618ac36ad71d2c20908a Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 5 Oct 2017 22:53:17 +0000 Subject: Revert "[LSan] Detect dynamic loader by its base address." This reverts commit r315024. Breaks sysconf_interceptor_bypass_test.cc git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315031 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_common.cc | 5 ++--- lib/lsan/lsan_common_linux.cc | 23 ++++++----------------- lib/sanitizer_common/sanitizer_linux.cc | 10 ++++++++++ lib/sanitizer_common/sanitizer_platform.h | 9 --------- 4 files changed, 18 insertions(+), 29 deletions(-) diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 651bbe1f3..622aae734 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -411,9 +411,8 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { } } -// On Linux, treats all chunks allocated from ld-linux.so as reachable, which -// covers dynamically allocated TLS blocks, internal dynamic loader's loaded -// modules accounting etc. +// On Linux, handles dynamically allocated TLS blocks by treating all chunks +// allocated from ld-linux.so as reachable. // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. // They are allocated with a __libc_memalign() call in allocate_and_init() // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 5acff0b2d..5042c7b3a 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -23,10 +23,6 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#if SANITIZER_USE_GETAUXVAL -#include -#endif // SANITIZER_USE_GETAUXVAL - namespace __lsan { static const char kLinkerName[] = "ld"; @@ -34,12 +30,8 @@ static const char kLinkerName[] = "ld"; static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; -static bool IsLinker(const LoadedModule& module) { -#if SANITIZER_USE_GETAUXVAL - return module.base_address() == getauxval(AT_BASE); -#else - return LibraryNameIs(module.full_name(), kLinkerName); -#endif // SANITIZER_USE_GETAUXVAL +static bool IsLinker(const char* full_name) { + return LibraryNameIs(full_name, kLinkerName); } __attribute__((tls_model("initial-exec"))) @@ -57,25 +49,22 @@ void InitializePlatformSpecificModules() { ListOfModules modules; modules.init(); for (LoadedModule &module : modules) { - if (!IsLinker(module)) - continue; + if (!IsLinker(module.full_name())) continue; if (linker == nullptr) { linker = reinterpret_cast(linker_placeholder); *linker = module; module = LoadedModule(); } else { VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " - "TLS and other allocations originating from linker might be " - "falsely reported as leaks.\n", kLinkerName); + "TLS will not be handled correctly.\n", kLinkerName); linker->clear(); linker = nullptr; return; } } if (linker == nullptr) { - VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " - "allocations originating from linker might be falsely reported " - "as leaks.\n"); + VReport(1, "LeakSanitizer: Dynamic linker not found. " + "TLS will not be handled correctly.\n"); } } diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index f239b4fba..48c53d46d 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -93,6 +93,16 @@ extern char **environ; // provided by crt1 #include #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif + #if SANITIZER_USE_GETAUXVAL #include #endif diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 763d6e01b..81d9164c3 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -282,14 +282,5 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif #endif // SANITIZER_PLATFORM_H -- cgit v1.2.1 From b3c632084941e7b9669416f91c7f90b7fcd49645 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 6 Oct 2017 00:00:53 +0000 Subject: [asan] Use gold linker in android tests. Replace a partial workaround for ld.bfd strangeness with the ultimate one: -fuse-ld=gold. Reason: ld.bfd problem gets worse with libc++-based NDK toolchain. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315039 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 2058120e0..a16fb3307 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -55,7 +55,7 @@ config.available_features.add(compiler_id) # BFD linker in 64-bit android toolchains fails to find libm.so, which is a # transitive shared library dependency (via asan runtime). if config.android: - config.target_cflags += " -lm -Wl,--enable-new-dtags" + config.target_cflags += " -fuse-ld=gold -Wl,--enable-new-dtags" # Clear some environment variables that might affect Clang. possibly_dangerous_env_vars = ['ASAN_OPTIONS', 'DFSAN_OPTIONS', 'LSAN_OPTIONS', -- cgit v1.2.1 From e9b56a34017060f38e481ae24a23acf43043fb4f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 6 Oct 2017 20:51:51 +0000 Subject: [sanitizer] Test ubsan and cfi on android. Summary: Enable check-cfi and check-ubsan on Android. Check-ubsan includes standalone and ubsan+asan, but not tsan or msan. Cross-dso cfi tests are disabled for now. Reviewers: vitalybuka, pcc Subscribers: srhines, kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D38608 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315105 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/cfi/cross-dso/lit.local.cfg | 2 +- test/cfi/lit.cfg | 4 ++-- test/cfi/stats.cpp | 3 +++ test/lit.common.cfg | 2 +- test/sanitizer_common/android_commands/android_run.py | 2 +- test/ubsan/CMakeLists.txt | 2 +- test/ubsan/TestCases/Integer/suppressions.cpp | 1 + test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg | 2 +- test/ubsan/lit.common.cfg | 5 ++++- 10 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 2c395c0fe..78892c675 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -208,7 +208,7 @@ set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) -set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64}) +set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64}) set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le) diff --git a/test/cfi/cross-dso/lit.local.cfg b/test/cfi/cross-dso/lit.local.cfg index 57271b807..4fd9b2852 100644 --- a/test/cfi/cross-dso/lit.local.cfg +++ b/test/cfi/cross-dso/lit.local.cfg @@ -5,5 +5,5 @@ def getRoot(config): root = getRoot(config) -if root.host_os not in ['Linux']: +if root.host_os not in ['Linux'] or config.android: config.unsupported = True diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index 76cafb855..c2102f08b 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -5,8 +5,8 @@ config.name = 'cfi' + config.name_suffix config.suffixes = ['.c', '.cpp', '.test'] config.test_source_root = os.path.dirname(__file__) -clang = ' '.join([config.clang, config.target_cflags]) -clangxx = ' '.join([config.clang, config.target_cflags] + config.cxx_mode_flags) +clang = ' '.join([config.compile_wrapper, config.clang, config.target_cflags]) +clangxx = ' '.join([config.compile_wrapper, config.clang, config.target_cflags] + config.cxx_mode_flags) config.substitutions.append((r"%clang ", clang + ' ')) config.substitutions.append((r"%clangxx ", clangxx + ' ')) diff --git a/test/cfi/stats.cpp b/test/cfi/stats.cpp index eb0c2ed95..56cc2dd51 100644 --- a/test/cfi/stats.cpp +++ b/test/cfi/stats.cpp @@ -5,6 +5,9 @@ // FIXME: We currently emit the wrong debug info under devirtualization. // UNSUPPORTED: devirt +// FIXME: %t.stats must be transferred from device to host for this to work on Android. +// XFAIL: android + struct ABase {}; struct A : ABase { diff --git a/test/lit.common.cfg b/test/lit.common.cfg index a16fb3307..bd4f3ac56 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -55,7 +55,7 @@ config.available_features.add(compiler_id) # BFD linker in 64-bit android toolchains fails to find libm.so, which is a # transitive shared library dependency (via asan runtime). if config.android: - config.target_cflags += " -fuse-ld=gold -Wl,--enable-new-dtags" + config.target_cflags += " -pie -fuse-ld=gold -Wl,--enable-new-dtags" # Clear some environment variables that might affect Clang. possibly_dangerous_env_vars = ['ASAN_OPTIONS', 'DFSAN_OPTIONS', 'LSAN_OPTIONS', diff --git a/test/sanitizer_common/android_commands/android_run.py b/test/sanitizer_common/android_commands/android_run.py index faa05e248..1c4f4057f 100755 --- a/test/sanitizer_common/android_commands/android_run.py +++ b/test/sanitizer_common/android_commands/android_run.py @@ -12,7 +12,7 @@ def build_env(): # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) for (key, value) in os.environ.items(): - if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS', 'SCUDO_OPTIONS']: + if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS', 'SCUDO_OPTIONS', 'UBSAN_OPTIONS']: args.append('%s="%s"' % (key, value)) return ' '.join(args) diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt index f4b73e87f..02088c35d 100644 --- a/test/ubsan/CMakeLists.txt +++ b/test/ubsan/CMakeLists.txt @@ -35,7 +35,7 @@ foreach(arch ${UBSAN_TEST_ARCH}) if(COMPILER_RT_HAS_MSAN AND ";${MSAN_SUPPORTED_ARCH};" MATCHES ";${arch};") add_ubsan_testsuite("MemorySanitizer" msan ${arch}) endif() - if(COMPILER_RT_HAS_TSAN AND ";${TSAN_SUPPORTED_ARCH};" MATCHES ";${arch};") + if(COMPILER_RT_HAS_TSAN AND ";${TSAN_SUPPORTED_ARCH};" MATCHES ";${arch};" AND NOT ANDROID) add_ubsan_testsuite("ThreadSanitizer" tsan ${arch}) endif() endforeach() diff --git a/test/ubsan/TestCases/Integer/suppressions.cpp b/test/ubsan/TestCases/Integer/suppressions.cpp index a9e660111..f72d82edf 100644 --- a/test/ubsan/TestCases/Integer/suppressions.cpp +++ b/test/ubsan/TestCases/Integer/suppressions.cpp @@ -3,6 +3,7 @@ // Suppression by symbol name (unsigned-integer-overflow:do_overflow below) // requires the compiler-rt runtime to be able to symbolize stack addresses. // REQUIRES: can-symbolize +// UNSUPPORTED: android // Fails without any suppression. // RUN: %env_ubsan_opts=halt_on_error=1 not %run %t 2>&1 | FileCheck %s diff --git a/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg index 27c61a343..a10159995 100644 --- a/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg +++ b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg @@ -1,3 +1,3 @@ # The function type checker is only supported on x86 and x86_64 for now. -if config.root.host_arch not in ['x86', 'x86_64']: +if config.target_arch not in ['x86', 'x86_64']: config.unsupported = True diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index e165e72ed..8365194d8 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -46,6 +46,9 @@ if config.host_os == 'Darwin': # much slower. Let's override this and run lit tests with 'abort_on_error=0'. default_ubsan_opts += ['abort_on_error=0'] default_ubsan_opts += ['log_to_syslog=0'] +elif config.android: + default_ubsan_opts += ['abort_on_error=0'] + default_ubsan_opts_str = ':'.join(default_ubsan_opts) if default_ubsan_opts_str: config.environment['UBSAN_OPTIONS'] = default_ubsan_opts_str @@ -55,7 +58,7 @@ config.substitutions.append(('%env_ubsan_opts=', 'env UBSAN_OPTIONS=' + default_ubsan_opts_str)) def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " target_cflags = [get_required_attr(config, "target_cflags")] clang_ubsan_cflags += target_cflags -- cgit v1.2.1 From 8501b0e87655065c6668db3eac37ea08bd4f712f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 6 Oct 2017 20:53:40 +0000 Subject: Factor out default_(a|ub)sanitizer_opts in lit. Reviewers: vitalybuka Subscribers: srhines, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D38644 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315106 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 34 ++++++++++++---------------------- test/lit.common.cfg | 10 +++++++++- test/ubsan/lit.common.cfg | 9 +-------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index fc8daaaf0..ad4e6a49d 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -31,29 +31,19 @@ def push_dynamic_library_lookup_path(config, new_path): config.name = 'AddressSanitizer' + config.name_suffix # Platform-specific default ASAN_OPTIONS for lit tests. -default_asan_opts = '' -if config.host_os == 'Darwin': - # On Darwin, we default to `abort_on_error=1`, which would make tests run - # much slower. Let's override this and run lit tests with 'abort_on_error=0'. - # Also, make sure we do not overwhelm the syslog while testing. - default_asan_opts = 'abort_on_error=0' - default_asan_opts += ':log_to_syslog=0' - - # On Darwin, leak checking is not enabled by default. Enable for x86_64 - # tests to prevent regressions - if config.target_arch == 'x86_64': - default_asan_opts += ':detect_leaks=1' -elif config.android: - # The same as on Darwin, we default to "abort_on_error=1" which slows down - # testing. Also, all existing tests are using "not" instead of "not --crash" - # which does not work for abort()-terminated programs. - default_asan_opts = 'abort_on_error=0' - -if default_asan_opts: - config.environment['ASAN_OPTIONS'] = default_asan_opts - default_asan_opts += ':' +default_asan_opts = list(config.default_sanitizer_opts) + +# On Darwin, leak checking is not enabled by default. Enable for x86_64 +# tests to prevent regressions +if config.host_os == 'Darwin' and config.target_arch == 'x86_64': + default_asan_opts += ['detect_leaks=1'] + +default_asan_opts_str = ':'.join(default_asan_opts) +if default_asan_opts_str: + config.environment['ASAN_OPTIONS'] = default_asan_opts_str + default_asan_opts_str += ':' config.substitutions.append(('%env_asan_opts=', - 'env ASAN_OPTIONS=' + default_asan_opts)) + 'env ASAN_OPTIONS=' + default_asan_opts_str)) # Setup source root. config.test_source_root = os.path.dirname(__file__) diff --git a/test/lit.common.cfg b/test/lit.common.cfg index bd4f3ac56..9636f9211 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -11,7 +11,6 @@ import subprocess import lit.formats import lit.util - # Choose between lit's internal shell pipeline runner and a real shell. If # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") @@ -295,3 +294,12 @@ elif config.host_os == 'Linux': config.substitutions.append( ("%dynamiclib", '%T/%xdynamiclib_filename') ) config.substitutions.append( ("%xdynamiclib_filename", 'lib%xdynamiclib_namespec.so') ) config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') ) + +config.default_sanitizer_opts = [] +if config.host_os == 'Darwin': + # On Darwin, we default to `abort_on_error=1`, which would make tests run + # much slower. Let's override this and run lit tests with 'abort_on_error=0'. + config.default_sanitizer_opts += ['abort_on_error=0'] + config.default_sanitizer_opts += ['log_to_syslog=0'] +elif config.android: + config.default_sanitizer_opts += ['abort_on_error=0'] diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 8365194d8..718d66741 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -14,7 +14,7 @@ def get_required_attr(config, attr_name): # Setup source root. config.test_source_root = os.path.dirname(__file__) -default_ubsan_opts = [] +default_ubsan_opts = list(config.default_sanitizer_opts) # Choose between standalone and UBSan+ASan modes. ubsan_lit_test_mode = get_required_attr(config, 'ubsan_lit_test_mode') if ubsan_lit_test_mode == "Standalone": @@ -41,13 +41,6 @@ else: if config.target_arch == 's390x': # On SystemZ we need -mbackchain to make the fast unwinder work. clang_ubsan_cflags.append("-mbackchain") -if config.host_os == 'Darwin': - # On Darwin, we default to `abort_on_error=1`, which would make tests run - # much slower. Let's override this and run lit tests with 'abort_on_error=0'. - default_ubsan_opts += ['abort_on_error=0'] - default_ubsan_opts += ['log_to_syslog=0'] -elif config.android: - default_ubsan_opts += ['abort_on_error=0'] default_ubsan_opts_str = ':'.join(default_ubsan_opts) if default_ubsan_opts_str: -- cgit v1.2.1 From 83fd3a8510401f7e7a6f1eb82022b967be9718f0 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 7 Oct 2017 00:04:24 +0000 Subject: [asan] Disable wcslen test on 32-bit Android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315132 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/asan_str_test.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index 964f6da02..5cf4e05c8 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -95,6 +95,9 @@ TEST(AddressSanitizer, StrLenOOBTest) { free(heap_string); } +// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling +// the interceptor. +#if !defined(__ANDROID__) || defined(__LP64__) TEST(AddressSanitizer, WcsLenTest) { EXPECT_EQ(0U, wcslen(Ident(L""))); size_t hello_len = 13; @@ -106,6 +109,7 @@ TEST(AddressSanitizer, WcsLenTest) { EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0)); free(heap_string); } +#endif #if SANITIZER_TEST_HAS_STRNLEN TEST(AddressSanitizer, StrNLenOOBTest) { @@ -629,5 +633,3 @@ TEST(AddressSanitizer, StrtolOOBTest) { RunStrtolOOBTest(&CallStrtol); } #endif - - -- cgit v1.2.1 From f41e67051268425df1cbbc1a208b8eba03875885 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 7 Oct 2017 01:46:36 +0000 Subject: [ubsan] Add a static runtime on Darwin As a follow-up to r315142, this makes it possible to use ubsan with a static runtime on Darwin. I've also added a new StandaloneStatic testing configuration so the new setup can be tested. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315143 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 15 +++++++++++++++ lib/sanitizer_common/sanitizer_internal_defs.h | 2 ++ lib/ubsan/CMakeLists.txt | 12 ++++++++++++ test/ubsan/CMakeLists.txt | 9 +++++++++ test/ubsan/TestCases/Misc/coverage-levels.cc | 1 + test/ubsan/lit.common.cfg | 4 ++++ 6 files changed, 43 insertions(+) diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 3b77adc75..691bf3b1f 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -199,6 +199,21 @@ add_compiler_rt_object_libraries(RTSanitizerCommonLibc CFLAGS ${SANITIZER_CFLAGS} DEFS ${SANITIZER_COMMON_DEFINITIONS}) +set(SANITIZER_NO_WEAK_HOOKS_CFLAGS ${SANITIZER_CFLAGS}) +append("-DSANITIZER_SUPPORTS_WEAK_HOOKS=0" SANITIZER_NO_WEAK_HOOKS_CFLAGS) +add_compiler_rt_object_libraries(RTSanitizerCommonNoHooks + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_SOURCES} + CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonLibcNoHooks + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_LIBCDEP_SOURCES} + CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) + if(WIN32) add_compiler_rt_object_libraries(SanitizerCommonWeakInterception ${SANITIZER_COMMON_SUPPORTED_OS} diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 0889034e1..003a3c7a9 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -64,11 +64,13 @@ // SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that // will evaluate to a null pointer when not defined. +#ifndef SANITIZER_SUPPORTS_WEAK_HOOKS #if (SANITIZER_LINUX || SANITIZER_MAC) && !SANITIZER_GO # define SANITIZER_SUPPORTS_WEAK_HOOKS 1 #else # define SANITIZER_SUPPORTS_WEAK_HOOKS 0 #endif +#endif // SANITIZER_SUPPORTS_WEAK_HOOKS // For some weak hooks that will be called very often and we want to avoid the // overhead of executing the default implementation when it is not necessary, // we can use the flag SANITIZER_SUPPORTS_WEAK_HOOKS to only define the default diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 644b598c5..911bd3ebc 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -79,6 +79,18 @@ if(APPLE) RTInterception LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} PARENT_TARGET ubsan) + + add_compiler_rt_runtime(clang_rt.ubsan + STATIC + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan + RTUbsan_standalone + RTSanitizerCommonNoHooks + RTSanitizerCommonLibcNoHooks + RTInterception + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + PARENT_TARGET ubsan) endif() else() diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt index 02088c35d..14e7f3cfe 100644 --- a/test/ubsan/CMakeLists.txt +++ b/test/ubsan/CMakeLists.txt @@ -40,6 +40,15 @@ foreach(arch ${UBSAN_TEST_ARCH}) endif() endforeach() +if(APPLE) + foreach(arch ${UBSAN_TEST_ARCH}) + set(UBSAN_TEST_TARGET_ARCH ${arch}) + get_test_cc_for_arch(${arch} UBSAN_TEST_TARGET_CC UBSAN_TEST_TARGET_CFLAGS) + append("-lc++abi" UBSAN_TEST_TARGET_CFLAGS) + add_ubsan_testsuite("StandaloneStatic" ubsan ${arch}) + endforeach() +endif() + add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests" ${UBSAN_TESTSUITES} DEPENDS ${UBSAN_TEST_DEPS}) diff --git a/test/ubsan/TestCases/Misc/coverage-levels.cc b/test/ubsan/TestCases/Misc/coverage-levels.cc index f96b487a4..05c19937d 100644 --- a/test/ubsan/TestCases/Misc/coverage-levels.cc +++ b/test/ubsan/TestCases/Misc/coverage-levels.cc @@ -22,6 +22,7 @@ // Coverage is not yet implemented in TSan. // XFAIL: ubsan-tsan +// UNSUPPORTED: ubsan-standalone-static volatile int sink; int main(int argc, char **argv) { diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 718d66741..8c6801e2c 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -21,6 +21,10 @@ if ubsan_lit_test_mode == "Standalone": config.name = 'UBSan-Standalone-' + config.target_arch config.available_features.add("ubsan-standalone") clang_ubsan_cflags = [] +elif ubsan_lit_test_mode == "StandaloneStatic": + config.name = 'UBSan-StandaloneStatic-' + config.target_arch + config.available_features.add("ubsan-standalone-static") + clang_ubsan_cflags = ['-static-libsan'] elif ubsan_lit_test_mode == "AddressSanitizer": config.name = 'UBSan-ASan-' + config.target_arch config.available_features.add("ubsan-asan") -- cgit v1.2.1 From 3d16ad721458f4efd52e3bb1ba53a75e001ea4bc Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 7 Oct 2017 03:44:46 +0000 Subject: Use list(APPEND) instead of append() append() seems to be available with the version of cmake I'm using, but not on the bots: http://green.lab.llvm.org/green//job/clang-stage1-configure-RA/39354 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315144 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 691bf3b1f..e62b24544 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -200,7 +200,7 @@ add_compiler_rt_object_libraries(RTSanitizerCommonLibc DEFS ${SANITIZER_COMMON_DEFINITIONS}) set(SANITIZER_NO_WEAK_HOOKS_CFLAGS ${SANITIZER_CFLAGS}) -append("-DSANITIZER_SUPPORTS_WEAK_HOOKS=0" SANITIZER_NO_WEAK_HOOKS_CFLAGS) +list(APPEND SANITIZER_NO_WEAK_HOOKS_CFLAGS "-DSANITIZER_SUPPORTS_WEAK_HOOKS=0") add_compiler_rt_object_libraries(RTSanitizerCommonNoHooks ${OS_OPTION} ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} -- cgit v1.2.1 From 748c5c76201a02659765ab322a33302c866397c7 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Sat, 7 Oct 2017 20:20:42 +0000 Subject: cmake: Fix one more usage of append() append() isn't available with some cmake versions, so I need to use a different construct. I missed this case in r315144. http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA/39355 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315157 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt index 14e7f3cfe..5843e0cb8 100644 --- a/test/ubsan/CMakeLists.txt +++ b/test/ubsan/CMakeLists.txt @@ -44,7 +44,7 @@ if(APPLE) foreach(arch ${UBSAN_TEST_ARCH}) set(UBSAN_TEST_TARGET_ARCH ${arch}) get_test_cc_for_arch(${arch} UBSAN_TEST_TARGET_CC UBSAN_TEST_TARGET_CFLAGS) - append("-lc++abi" UBSAN_TEST_TARGET_CFLAGS) + set(UBSAN_TEST_TARGET_CFLAGS "${UBSAN_TEST_TARGET_CFLAGS} -lc++abi") add_ubsan_testsuite("StandaloneStatic" ubsan ${arch}) endforeach() endif() -- cgit v1.2.1 From b9f54537f9f2134b5b2f9a7f43da162fdab9cd4d Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 9 Oct 2017 17:07:47 +0000 Subject: Make the cfi target available on more platforms. On non-Linux targets it just installs the blacklist. Differential Revision: https://reviews.llvm.org/D38661 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315215 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 3 +-- lib/cfi/CMakeLists.txt | 60 ++++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 78892c675..e4976ce6d 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -559,8 +559,7 @@ else() set(COMPILER_RT_HAS_SAFESTACK FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux") +if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH) set(COMPILER_RT_HAS_CFI TRUE) else() set(COMPILER_RT_HAS_CFI FALSE) diff --git a/lib/cfi/CMakeLists.txt b/lib/cfi/CMakeLists.txt index 206400201..6c5314456 100644 --- a/lib/cfi/CMakeLists.txt +++ b/lib/cfi/CMakeLists.txt @@ -1,37 +1,39 @@ add_compiler_rt_component(cfi) -set(CFI_SOURCES cfi.cc) +if(OS_NAME MATCHES "Linux") + set(CFI_SOURCES cfi.cc) -include_directories(..) + include_directories(..) -set(CFI_CFLAGS - ${SANITIZER_COMMON_CFLAGS} -) + set(CFI_CFLAGS + ${SANITIZER_COMMON_CFLAGS} + ) -set(CFI_DIAG_CFLAGS - -DCFI_ENABLE_DIAG=1 -) + set(CFI_DIAG_CFLAGS + -DCFI_ENABLE_DIAG=1 + ) -foreach(arch ${CFI_SUPPORTED_ARCH}) - add_compiler_rt_runtime(clang_rt.cfi - STATIC - ARCHS ${arch} - SOURCES ${CFI_SOURCES} - OBJECT_LIBS RTInterception - RTSanitizerCommon - RTSanitizerCommonLibc - CFLAGS ${CFI_CFLAGS} - PARENT_TARGET cfi) - add_compiler_rt_runtime(clang_rt.cfi_diag - STATIC - ARCHS ${arch} - SOURCES ${CFI_SOURCES} - OBJECT_LIBS RTInterception - RTSanitizerCommon - RTSanitizerCommonLibc - RTUbsan - CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS} - PARENT_TARGET cfi) -endforeach() + foreach(arch ${CFI_SUPPORTED_ARCH}) + add_compiler_rt_runtime(clang_rt.cfi + STATIC + ARCHS ${arch} + SOURCES ${CFI_SOURCES} + OBJECT_LIBS RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + CFLAGS ${CFI_CFLAGS} + PARENT_TARGET cfi) + add_compiler_rt_runtime(clang_rt.cfi_diag + STATIC + ARCHS ${arch} + SOURCES ${CFI_SOURCES} + OBJECT_LIBS RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTUbsan + CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS} + PARENT_TARGET cfi) + endforeach() +endif() add_compiler_rt_resource_file(cfi_blacklist cfi_blacklist.txt cfi) -- cgit v1.2.1 From 5c1865cfabd146b23bd74d83befb32c628ce8938 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Mon, 9 Oct 2017 17:11:44 +0000 Subject: Limit CFI blacklist entries to specific CFI mode Summary: Since D37924 and D37925 were merged, it's now possible to specify individual sanitizers or CFI modes in sanitizer blacklists. Update the CFI blacklist entries to only apply to cfi-unrelated-cast checks. Reviewers: eugenis, pcc Reviewed By: eugenis Subscribers: kcc Differential Revision: https://reviews.llvm.org/D38385 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315216 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/cfi/cfi_blacklist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index 5b10b13de..d8c9d49e3 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -1,3 +1,4 @@ +[cfi-unrelated-cast] # std::get_temporary_buffer, likewise (libstdc++, libc++). fun:_ZSt20get_temporary_buffer* fun:_ZNSt3__120get_temporary_buffer* -- cgit v1.2.1 From 23784812b2aab862b02722a045a426d48b442100 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 9 Oct 2017 17:45:03 +0000 Subject: [ubsan] Disable one test on Android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315220 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/vptr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index 21d762ee1..1db41ddd0 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -27,6 +27,8 @@ // REQUIRES: stable-runtime, cxxabi // UNSUPPORTED: win32 +// Suppressions file not pushed to the device. +// UNSUPPORTED: android #include #include #include -- cgit v1.2.1 From 1da2a1c414e6da10d5c781422d2874f8d7e4ba28 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 9 Oct 2017 18:29:52 +0000 Subject: [sanitizer] Don't intercept signal and sigaction on Fuchsia Fuchsia doesn't support signals, so don't use interceptors for signal or sigaction. Differential Revision: https://reviews.llvm.org/D38669 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315227 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_platform_interceptors.h | 2 +- lib/ubsan/ubsan_signals_standalone.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 897aeddca..1b802703f 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -389,7 +389,7 @@ #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX -#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS) +#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/ubsan/ubsan_signals_standalone.cc b/lib/ubsan/ubsan_signals_standalone.cc index 374857269..60527f858 100644 --- a/lib/ubsan/ubsan_signals_standalone.cc +++ b/lib/ubsan/ubsan_signals_standalone.cc @@ -24,6 +24,9 @@ namespace __ubsan { +#if SANITIZER_FUCHSIA +void InitializeDeadlySignals() {} +#else static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp, @@ -44,6 +47,7 @@ void InitializeDeadlySignals() { InitializeSignalInterceptors(); InstallDeadlySignalHandlers(&UBsanOnDeadlySignal); } +#endif } // namespace __ubsan -- cgit v1.2.1 From e21fc332775e7288a719d8b8ddb18772002d0c62 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 9 Oct 2017 22:52:13 +0000 Subject: [ubsan] Fix Asan internal alloc corruption in PR33221 test. MAP_FIXED discards the existing mapping at the given address. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315247 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp index e026e8d05..a5e61c2d2 100644 --- a/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp +++ b/test/ubsan/TestCases/TypeCheck/Linux/PR33221.cpp @@ -22,7 +22,7 @@ public: int main() { int page_size = getpagesize(); - void *non_accessible = mmap(nullptr, page_size, PROT_NONE, + void *non_accessible = mmap(nullptr, page_size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (non_accessible == MAP_FAILED) -- cgit v1.2.1 From 7904451feadc8f766fd194b6d798b5c6ffabd069 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 10 Oct 2017 12:44:20 +0000 Subject: [XRay][compiler-rt] Fix rdtscp support check for x86_64 Follow-up to D29438. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315306 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_x86_64.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index 3c12682cc..e17f00ac3 100644 --- a/lib/xray/xray_x86_64.cc +++ b/lib/xray/xray_x86_64.cc @@ -258,9 +258,9 @@ bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { // We check whether rdtscp support is enabled. According to the x86_64 manual, // level should be set at 0x80000001, and we should have a look at bit 27 in - // EDX. That's 0x8000000 (or 1u << 26). + // EDX. That's 0x8000000 (or 1u << 27). __get_cpuid(0x80000001, &EAX, &EBX, &ECX, &EDX); - if (!(EDX & (1u << 26))) { + if (!(EDX & (1u << 27))) { Report("Missing rdtscp support.\n"); return false; } -- cgit v1.2.1 From 35440ac3db816e1397830b654115672b7a21d0f2 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 10 Oct 2017 14:58:09 +0000 Subject: [sanitizer] Move the errno/ENOMEM allocator checks logic to separate .cc Summary: The fact that `sanitizer_allocator_checks.h` is including `sanitizer_errno.h` creates complications for future changes, where it would conflict with `errno.h` definitions on Android and Fuchsia (macro redefinition). By moving the portion that sets errno in the checks to a separate compilation unit, we avoid the inclusion of the header there, which solves the issue. Not that it is not vital to have that function in a header as it is called as a result of an unlikely event, and doesn't need to be inlined. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: kubamracek, llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D38706 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315319 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 1 + lib/sanitizer_common/sanitizer_allocator_checks.cc | 23 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_allocator_checks.h | 9 +++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.cc diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index e62b24544..749c71a74 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -3,6 +3,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_allocator.cc + sanitizer_allocator_checks.cc sanitizer_common.cc sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.cc b/lib/sanitizer_common/sanitizer_allocator_checks.cc new file mode 100644 index 000000000..dc263dbef --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_checks.cc @@ -0,0 +1,23 @@ +//===-- sanitizer_allocator_checks.cc ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno.h" + +namespace __sanitizer { + +void SetErrnoToENOMEM() { + errno = errno_ENOMEM; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index b72f541a4..b61a8b2eb 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -15,17 +15,22 @@ #ifndef SANITIZER_ALLOCATOR_CHECKS_H #define SANITIZER_ALLOCATOR_CHECKS_H -#include "sanitizer_errno.h" #include "sanitizer_internal_defs.h" #include "sanitizer_common.h" #include "sanitizer_platform.h" namespace __sanitizer { +// The following is defined in a separate compilation unit to avoid pulling in +// sanitizer_errno.h in this header, which leads to conflicts when other system +// headers include errno.h. This is usually the result of an unlikely event, +// and as such we do not care as much about having it inlined. +void SetErrnoToENOMEM(); + // A common errno setting logic shared by almost all sanitizer allocator APIs. INLINE void *SetErrnoOnNull(void *ptr) { if (UNLIKELY(!ptr)) - errno = errno_ENOMEM; + SetErrnoToENOMEM(); return ptr; } -- cgit v1.2.1 From 5b96e8b6fad1b6f3c3492037d34bc4885f1bbbaa Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Tue, 10 Oct 2017 15:35:11 +0000 Subject: [sanitizer] Revert D38706 Summary: D38706 breaks tsan and the nolibc build. Reverting while working on a fix. Reviewers: alekseyshl Subscribers: kubamracek, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D38739 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315320 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 1 - lib/sanitizer_common/sanitizer_allocator_checks.cc | 23 ---------------------- lib/sanitizer_common/sanitizer_allocator_checks.h | 9 ++------- 3 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.cc diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 749c71a74..e62b24544 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -3,7 +3,6 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_allocator.cc - sanitizer_allocator_checks.cc sanitizer_common.cc sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.cc b/lib/sanitizer_common/sanitizer_allocator_checks.cc deleted file mode 100644 index dc263dbef..000000000 --- a/lib/sanitizer_common/sanitizer_allocator_checks.cc +++ /dev/null @@ -1,23 +0,0 @@ -//===-- sanitizer_allocator_checks.cc ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory -// allocators. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_errno.h" - -namespace __sanitizer { - -void SetErrnoToENOMEM() { - errno = errno_ENOMEM; -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index b61a8b2eb..b72f541a4 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -15,22 +15,17 @@ #ifndef SANITIZER_ALLOCATOR_CHECKS_H #define SANITIZER_ALLOCATOR_CHECKS_H +#include "sanitizer_errno.h" #include "sanitizer_internal_defs.h" #include "sanitizer_common.h" #include "sanitizer_platform.h" namespace __sanitizer { -// The following is defined in a separate compilation unit to avoid pulling in -// sanitizer_errno.h in this header, which leads to conflicts when other system -// headers include errno.h. This is usually the result of an unlikely event, -// and as such we do not care as much about having it inlined. -void SetErrnoToENOMEM(); - // A common errno setting logic shared by almost all sanitizer allocator APIs. INLINE void *SetErrnoOnNull(void *ptr) { if (UNLIKELY(!ptr)) - SetErrnoToENOMEM(); + errno = errno_ENOMEM; return ptr; } -- cgit v1.2.1 From 69abe65f08f043198d583d11978362bf5c4c992a Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 10 Oct 2017 22:11:25 +0000 Subject: XFAIL ubsan/TestCases/TypeCheck/Function/function.cpp on Windows I think it got accidentally enabled in r315105 or thereabouts. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315374 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan/TestCases/TypeCheck/Function/function.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp index 1d631ad4e..25b2bdc32 100644 --- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp +++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp @@ -2,6 +2,7 @@ // RUN: %run %t 2>&1 | FileCheck %s // Verify that we can disable symbolization if needed: // RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM +// XFAIL: win32,win64 #include -- cgit v1.2.1 From 45675f2e9fdf6b595ebc8eefb085c722358a4a32 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 10 Oct 2017 23:37:26 +0000 Subject: Factor out "stable-runtime" feature and enable it on all android. This is a very poorly named feature. I think originally it meant to cover linux only, but the use of it in msan seems to be about any aarch64 platform. Anyway, this change should be NFC on everything except Android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315389 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/asan/lit.cfg | 5 ----- test/lit.common.cfg | 5 +++++ test/msan/Linux/mallinfo.cc | 2 +- test/msan/lit.cfg | 3 --- test/safestack/lit.cfg | 5 ----- test/sanitizer_common/lit.common.cfg | 3 --- test/tsan/lit.cfg | 5 ----- test/ubsan/lit.common.cfg | 5 ----- test/xray/lit.cfg | 5 ----- 9 files changed, 6 insertions(+), 32 deletions(-) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index ad4e6a49d..6a4044a44 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -168,11 +168,6 @@ config.substitutions.append( ("%libdl", libdl_flag) ) config.available_features.add("asan-" + config.bits + "-bits") -# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -# because the test hangs. Adding armhf as we now have two modes. -if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') - # Fast unwinder doesn't work with Thumb if re.search('mthumb', config.target_cflags) is not None: config.available_features.add('fast-unwinder-works') diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 9636f9211..67f6daa47 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -303,3 +303,8 @@ if config.host_os == 'Darwin': config.default_sanitizer_opts += ['log_to_syslog=0'] elif config.android: config.default_sanitizer_opts += ['abort_on_error=0'] + +# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL +# because the test hangs or fails on one configuration and not the other. +if config.android or (config.target_arch not in ['arm', 'armhf', 'aarch64']): + config.available_features.add('stable-runtime') diff --git a/test/msan/Linux/mallinfo.cc b/test/msan/Linux/mallinfo.cc index 545ae934a..b2021c5df 100644 --- a/test/msan/Linux/mallinfo.cc +++ b/test/msan/Linux/mallinfo.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t -// REQUIRES: stable-runtime +// UNSUPPORTED: aarch64-target-arch #include #include diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg index eb0ed4389..c6a384120 100644 --- a/test/msan/lit.cfg +++ b/test/msan/lit.cfg @@ -33,9 +33,6 @@ config.suffixes = ['.c', '.cc', '.cpp'] if config.host_os not in ['Linux']: config.unsupported = True -if config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') - # For mips64, mips64el we have forced store_context_size to 1 because these # archs use slow unwinder which is not async signal safe. Therefore we only # check the first frame since store_context size is 1. diff --git a/test/safestack/lit.cfg b/test/safestack/lit.cfg index 87b678320..10cd8a5a5 100644 --- a/test/safestack/lit.cfg +++ b/test/safestack/lit.cfg @@ -20,8 +20,3 @@ if config.lto_supported: if config.host_os not in ['Linux', 'FreeBSD', 'Darwin', 'NetBSD']: config.unsupported = True - -# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -# because the test fail due some runtime issue. -if config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg index be9a5c4a1..a4a5d4e85 100644 --- a/test/sanitizer_common/lit.common.cfg +++ b/test/sanitizer_common/lit.common.cfg @@ -26,9 +26,6 @@ else: config.available_features.add(config.tool_name) -if config.target_arch not in ['arm', 'armhf', 'aarch64']: - config.available_features.add('stable-runtime') - if config.host_os == 'Linux' and config.tool_name == "lsan" and config.target_arch == 'i386': config.available_features.add("lsan-x86") diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index 0ab62db09..10f31b06e 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -83,10 +83,5 @@ config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm'] if config.host_os not in ['FreeBSD', 'Linux', 'Darwin']: config.unsupported = True -# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -# because the test hangs. -if config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') - if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]: config.parallelism_group = "darwin-64bit-sanitizer" diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 8c6801e2c..f34d5867d 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -73,9 +73,4 @@ config.suffixes = ['.c', '.cc', '.cpp'] if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows', 'NetBSD']: config.unsupported = True -# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -# because the test hangs or fails on one configuration and not the other. -if config.target_arch.startswith('arm') == False and config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') - config.available_features.add('arch=' + config.target_arch) diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg index 2852bdb74..d5e40975d 100644 --- a/test/xray/lit.cfg +++ b/test/xray/lit.cfg @@ -48,8 +48,3 @@ elif '64' not in config.host_arch: config.unsupported = True else: config.unsupported = True - -# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL -# e.g. because the test sometimes passes, sometimes fails. -if config.target_arch != 'aarch64': - config.available_features.add('stable-runtime') -- cgit v1.2.1 From 3fc89a412dd3c51188a9709fb8896434230312e9 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 11 Oct 2017 00:32:03 +0000 Subject: [sanitizer] Re-disable several tests on Android. The tests have been enabled by accident in r315389. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315396 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc | 2 +- test/sanitizer_common/TestCases/Posix/getpass.cc | 2 +- test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc | 2 +- test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc | 2 +- .../sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc | 2 +- test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc index a690193bd..8a05f4b66 100644 --- a/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc +++ b/test/sanitizer_common/TestCases/Linux/decorate_proc_maps.cc @@ -2,7 +2,7 @@ // RUN: %env_tool_opts=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%tool_name // REQUIRES: stable-runtime -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/getpass.cc b/test/sanitizer_common/TestCases/Posix/getpass.cc index 59919a1ae..b91a3d7d5 100644 --- a/test/sanitizer_common/TestCases/Posix/getpass.cc +++ b/test/sanitizer_common/TestCases/Posix/getpass.cc @@ -1,7 +1,7 @@ // RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t | FileCheck %s // REQUIRES: stable-runtime -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan #include #include diff --git a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc index 416944fa6..baa1d9a64 100644 --- a/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ b/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -5,7 +5,7 @@ // RUN: not %run %t %t-out && FileCheck < %t-out %s // REQUIRES: stable-runtime -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan // XFAIL: tsan diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc index b90c93fb3..9604da222 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin // XFAIL: ubsan,tsan -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 // RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc index db1d94e82..7a2eca8bc 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan // XFAIL: tsan,darwin,powerpc64,s390x,mips -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan // RUN: DIR=%t_workdir // RUN: CLANG_ARGS="-O0 -fsanitize-coverage=trace-pc-guard" diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc index cfcb242ca..1adbf653b 100644 --- a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -3,7 +3,7 @@ // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: ubsan,i386-darwin // XFAIL: tsan,powerpc64,s390x,mips -// XFAIL: android && i386-target-arch && asan +// XFAIL: android && asan // RUN: DIR=%t_workdir // RUN: rm -rf $DIR -- cgit v1.2.1 From 452879a466facf705d4f5b12617c2396b5689f35 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 11 Oct 2017 01:44:26 +0000 Subject: [libFuzzer] experimental flag to tweak the corpus distribution. Seems to improve the situation dramatically on the png benchmark and make things worse on a number of micro-puzzles. Needs more A/B testing git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315407 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 32 +++++++++++++++++++++++--------- lib/fuzzer/FuzzerDriver.cpp | 1 + lib/fuzzer/FuzzerFlags.def | 1 + lib/fuzzer/FuzzerLoop.cpp | 3 +++ lib/fuzzer/FuzzerOptions.h | 1 + 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index 2384d5082..c9f7cc9dd 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -36,6 +36,7 @@ struct InputInfo { bool MayDeleteFile = false; bool Reduced = false; Vector UniqFeatureSet; + float FeatureFrequencyScore = 1.0; }; class InputCorpus { @@ -44,6 +45,7 @@ class InputCorpus { InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) { memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); + memset(FeatureFrequency, 0, sizeof(FeatureFrequency)); } ~InputCorpus() { for (auto II : Inputs) @@ -134,6 +136,7 @@ class InputCorpus { Hashes.insert(Sha1ToString(II->Sha1)); II->U = U; II->Reduced = true; + UpdateCorpusDistribution(); } bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } @@ -145,8 +148,6 @@ class InputCorpus { }; // Returns an index of random unit from the corpus to mutate. - // Hypothesis: units added to the corpus last are more likely to be - // interesting. This function gives more weight to the more recent units. size_t ChooseUnitIdxToMutate(Random &Rand) { size_t Idx = static_cast(CorpusDistribution(Rand)); assert(Idx < Inputs.size()); @@ -212,15 +213,22 @@ class InputCorpus { return false; } + void UpdateFeatureFrequency(size_t Idx) { + FeatureFrequency[Idx % kFeatureSetSize]++; + } + float GetFeatureFrequency(size_t Idx) const { + return FeatureFrequency[Idx % kFeatureSetSize]; + } + void UpdateFeatureFrequencyScore(InputInfo *II) { + II->FeatureFrequencyScore = 0.00000001; + for (auto Idx : II->UniqFeatureSet) + II->FeatureFrequencyScore += + 1. / (GetFeatureFrequency(Idx) * GetFeatureFrequency(Idx) + 1.); + } + size_t NumFeatures() const { return NumAddedFeatures; } size_t NumFeatureUpdates() const { return NumUpdatedFeatures; } - void ResetFeatureSet() { - assert(Inputs.empty()); - memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); - memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); - } - private: static const bool FeatureDebug = false; @@ -243,6 +251,10 @@ private: // Updates the probability distribution for the units in the corpus. // Must be called whenever the corpus or unit weights are changed. + // + // Hypothesis: units added to the corpus last are more interesting. + // + // Hypothesis: inputs with infrequent features are more interesting. void UpdateCorpusDistribution() { size_t N = Inputs.size(); assert(N); @@ -250,7 +262,8 @@ private: Weights.resize(N); std::iota(Intervals.begin(), Intervals.end(), 0); for (size_t i = 0; i < N; i++) - Weights[i] = Inputs[i]->NumFeatures * (i + 1); + Weights[i] = + Inputs[i]->NumFeatures * (i + 1) * Inputs[i]->FeatureFrequencyScore; CorpusDistribution = std::piecewise_constant_distribution( Intervals.begin(), Intervals.end(), Weights.begin()); } @@ -266,6 +279,7 @@ private: size_t NumUpdatedFeatures = 0; uint32_t InputSizesPerFeature[kFeatureSetSize]; uint32_t SmallestElementPerFeature[kFeatureSetSize]; + float FeatureFrequency[kFeatureSetSize]; std::string OutputCorpus; }; diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index dcf8d505f..29248dcee 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -605,6 +605,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintCoverage = Flags.print_coverage; Options.DumpCoverage = Flags.dump_coverage; Options.UseClangCoverage = Flags.use_clang_coverage; + Options.UseFeatureFrequency = Flags.use_feature_frequency; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; if (Flags.exit_on_item) diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index a23818fd5..41b94c69c 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -132,6 +132,7 @@ FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") +FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 4ccfe3f2a..c095fed12 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -396,6 +396,7 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, size_t FoundUniqFeaturesOfII = 0; size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); TPC.CollectFeatures([&](size_t Feature) { + Corpus.UpdateFeatureFrequency(Feature); if (Corpus.AddFeature(Feature, Size, Options.Shrink)) UniqFeatureSetTmp.push_back(Feature); if (Options.ReduceInputs && II) @@ -565,6 +566,8 @@ void Fuzzer::MutateAndTestOne() { MD.StartMutationSequence(); auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); + if (Options.UseFeatureFrequency) + Corpus.UpdateFeatureFrequencyScore(&II); const auto &U = II.U; memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); assert(CurrentUnitData); diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index ddf6e4201..e57c7df5b 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -54,6 +54,7 @@ struct FuzzingOptions { bool DumpCoverage = false; bool UseClangCoverage = false; bool DetectLeaks = true; + int UseFeatureFrequency = false; int TraceMalloc = 0; bool HandleAbrt = false; bool HandleBus = false; -- cgit v1.2.1 From 0ba9bf56cb8621d75dee6b9fd93a8293d9ff4a13 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 11 Oct 2017 17:32:38 +0000 Subject: [asan] Tweak test output to diagnose buildbot failures. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315479 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc index 5c8e19a4f..f29cc2614 100644 --- a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc @@ -2,9 +2,13 @@ // RUN: %clangxx -O2 %s -o %t // // Run with limit should fail: -// RUN: %env_tool_opts=hard_rss_limit_mb=100 not %run %t 2>&1 | FileCheck %s +// RUN: %env_tool_opts=hard_rss_limit_mb=100 not %run %t >%t.log 2>&1 +// RUN: cat %t.log +// RUN: cat %t.log | FileCheck %s // This run uses getrusage: -// RUN: %env_tool_opts=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s +// RUN: %env_tool_opts=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t >%t.log 2>&1 +// RUN: cat %t.log +// RUN: cat %t.log | FileCheck %s // // Run w/o limit or with a large enough limit should pass: // RUN: %env_tool_opts=hard_rss_limit_mb=1000 %run %t -- cgit v1.2.1 From f5ee4a4c0f97f94f71d007a18480ca4b6c023075 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 11 Oct 2017 19:01:35 +0000 Subject: [libFuzzer] make -use_feature_frequency less aggressive and enable by default git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315490 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 3 +-- lib/fuzzer/FuzzerFlags.def | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index c9f7cc9dd..385a06531 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -222,8 +222,7 @@ class InputCorpus { void UpdateFeatureFrequencyScore(InputInfo *II) { II->FeatureFrequencyScore = 0.00000001; for (auto Idx : II->UniqFeatureSet) - II->FeatureFrequencyScore += - 1. / (GetFeatureFrequency(Idx) * GetFeatureFrequency(Idx) + 1.); + II->FeatureFrequencyScore += 1. / (GetFeatureFrequency(Idx) + 1.); } size_t NumFeatures() const { return NumAddedFeatures; } diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index 41b94c69c..e21a43d95 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -132,7 +132,7 @@ FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") -FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental") +FUZZER_FLAG_INT(use_feature_frequency, 1, "Experimental/internal") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) -- cgit v1.2.1 From c37be534a252a7cb8e2ab04b15256232394dd7a9 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 11 Oct 2017 19:17:35 +0000 Subject: [sanitizer] Introduce ReservedAddressRange to sanitizer_common In Fuchsia, MmapNoAccess/MmapFixedOrDie are implemented using a global VMAR, which means that MmapNoAccess can only be called once. This works for the sanitizer allocator but *not* for the Scudo allocator. Hence, this changeset introduces a new ReservedAddressRange object to serve as the new API for these calls. In this changeset, the object still calls into the old Mmap implementations. The next changeset two changesets will convert the sanitizer and scudo allocators to use the new APIs, respectively. (ReservedAddressRange will replace the SecondaryHeader in Scudo.) Finally, a last changeset will update the Fuchsia implementation. Patch by Julia Hansbrough Differential Revision: https://reviews.llvm.org/D38759 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315493 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 14 +++++ lib/sanitizer_common/sanitizer_fuchsia.cc | 31 +++++++++++ lib/sanitizer_common/sanitizer_posix_libcdep.cc | 36 +++++++++++++ lib/sanitizer_common/sanitizer_win.cc | 37 +++++++++++++ .../tests/sanitizer_common_test.cc | 62 ++++++++++++++++++++++ 5 files changed, 180 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ee5eca516..f29420c68 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,6 +128,20 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); +class ReservedAddressRange { + public: + uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false); + void Unmap(uptr addr, uptr size); + const void *base() { return base_; } + const uptr size() { return size_; } + + private: + void* base_; + uptr size_; + const char* name_; +}; + typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, /*out*/uptr *stats, uptr stats_size); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 21fabddb1..00a8aabbf 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,6 +236,37 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { return DoAnonymousMmapOrDie(size, mem_type, false, false); } +uptr ReservedAddressRange::Init(uptr init_size, const char* name = nullptr, + uptr fixed_addr = uptr(0)) { + base_ = MmapNoAccess(init_size); + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + bool tolerate_enomem = true) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, + tolerate_enomem)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 4214d91c5..b6b09b5e4 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,6 +337,42 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return (void *)p; } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..762ba46cc 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,6 +235,31 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(uptr fixed_addr, uptr size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -252,6 +277,18 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type); } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 9c62b4593..5efce86ce 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -320,4 +320,66 @@ TEST(SanitizerCommon, GetRandom) { } #endif +TEST(SanitizerCommon, ReservedAddressRangeInit) { + uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*)-1); + UnmapOrDie((void*)res, init_size); + // Should be able to map into the same space now. + ReservedAddressRange address_range2; + uptr res2 = address_range2.Init(init_size, nullptr, res); + CHECK_EQ(res, res2); + + // TODO(flowerhack): Once this is switched to the "real" implementation + // (rather than passing through to MmapNoAccess*), enforce and test "no + // double initializations allowed" +} + +TEST(SanitizerCommon, ReservedAddressRangeMap) { + constexpr uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*) -1); + + // Valid mappings should succeed. + CHECK_EQ(res, address_range.Map(res, init_size)); + + // Valid mappings should be readable. + unsigned char buffer[init_size]; + memcpy(buffer, &res, sizeof(buffer)); + + // Invalid mappings should fail. + EXPECT_DEATH(address_range.Map(res, 0), ".*"); + + // TODO(flowerhack): Once this is switched to the "real" implementation, make + // sure you can only mmap into offsets in the Init range. +} + +TEST(SanitizerCommon, ReservedAddressRangeUnmap) { + uptr PageSize = GetPageSizeCached(); + uptr init_size = PageSize * 4; + ReservedAddressRange address_range; + uptr base_addr = address_range.Init(init_size); + CHECK_NE(base_addr, (void*)-1); + CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); + + // Unmapping at the beginning should succeed. + address_range.Unmap(base_addr, PageSize); + CHECK_EQ(base_addr + PageSize, address_range.base()); + CHECK_EQ(init_size - PageSize, address_range.size()); + + // Unmapping at the end should succeed. + uptr old_size = address_range.size(); + void* old_base = address_range.base(); + uptr new_start = reinterpret_cast(address_range.base()) + + address_range.size() - PageSize; + address_range.Unmap(new_start, PageSize); + CHECK_EQ(old_size - PageSize, address_range.size()); + CHECK_EQ(old_base, address_range.base()); + + // Unmapping in the middle of the ReservedAddressRange should fail. + EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); +} + } // namespace __sanitizer -- cgit v1.2.1 From 7898b35d683484e7e7b4449e1f308794137675fd Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 11 Oct 2017 19:29:14 +0000 Subject: Revert "[sanitizer] Introduce ReservedAddressRange to sanitizer_common" This reverts commit r315493 which is failing to build on sanitizer-windows. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315494 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 14 ----- lib/sanitizer_common/sanitizer_fuchsia.cc | 31 ----------- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 36 ------------- lib/sanitizer_common/sanitizer_win.cc | 37 ------------- .../tests/sanitizer_common_test.cc | 62 ---------------------- 5 files changed, 180 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index f29420c68..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,20 +128,6 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); -class ReservedAddressRange { - public: - uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); - uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false); - void Unmap(uptr addr, uptr size); - const void *base() { return base_; } - const uptr size() { return size_; } - - private: - void* base_; - uptr size_; - const char* name_; -}; - typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, /*out*/uptr *stats, uptr stats_size); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 00a8aabbf..21fabddb1 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,37 +236,6 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { return DoAnonymousMmapOrDie(size, mem_type, false, false); } -uptr ReservedAddressRange::Init(uptr init_size, const char* name = nullptr, - uptr fixed_addr = uptr(0)) { - base_ = MmapNoAccess(init_size); - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, - bool tolerate_enomem = true) { - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, - tolerate_enomem)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index b6b09b5e4..4214d91c5 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,42 +337,6 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return (void *)p; } -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - if (fixed_addr) { - base_ = MmapFixedNoAccess(fixed_addr, size, name); - } else { - base_ = MmapNoAccess(size); - } - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, - bool tolerate_enomem) { - if (tolerate_enomem) { - return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); - } - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 762ba46cc..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,31 +235,6 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, - bool tolerate_enomem) { - if (tolerate_enomem) { - return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); - } - return reinterpret_cast(MmapFixedOrDie(uptr fixed_addr, uptr size)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -277,18 +252,6 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type); } -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - if (fixed_addr) { - base_ = MmapFixedNoAccess(fixed_addr, size, name); - } else { - base_ = MmapNoAccess(size); - } - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - - void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 5efce86ce..9c62b4593 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -320,66 +320,4 @@ TEST(SanitizerCommon, GetRandom) { } #endif -TEST(SanitizerCommon, ReservedAddressRangeInit) { - uptr init_size = 0xffff; - ReservedAddressRange address_range; - uptr res = address_range.Init(init_size); - CHECK_NE(res, (void*)-1); - UnmapOrDie((void*)res, init_size); - // Should be able to map into the same space now. - ReservedAddressRange address_range2; - uptr res2 = address_range2.Init(init_size, nullptr, res); - CHECK_EQ(res, res2); - - // TODO(flowerhack): Once this is switched to the "real" implementation - // (rather than passing through to MmapNoAccess*), enforce and test "no - // double initializations allowed" -} - -TEST(SanitizerCommon, ReservedAddressRangeMap) { - constexpr uptr init_size = 0xffff; - ReservedAddressRange address_range; - uptr res = address_range.Init(init_size); - CHECK_NE(res, (void*) -1); - - // Valid mappings should succeed. - CHECK_EQ(res, address_range.Map(res, init_size)); - - // Valid mappings should be readable. - unsigned char buffer[init_size]; - memcpy(buffer, &res, sizeof(buffer)); - - // Invalid mappings should fail. - EXPECT_DEATH(address_range.Map(res, 0), ".*"); - - // TODO(flowerhack): Once this is switched to the "real" implementation, make - // sure you can only mmap into offsets in the Init range. -} - -TEST(SanitizerCommon, ReservedAddressRangeUnmap) { - uptr PageSize = GetPageSizeCached(); - uptr init_size = PageSize * 4; - ReservedAddressRange address_range; - uptr base_addr = address_range.Init(init_size); - CHECK_NE(base_addr, (void*)-1); - CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); - - // Unmapping at the beginning should succeed. - address_range.Unmap(base_addr, PageSize); - CHECK_EQ(base_addr + PageSize, address_range.base()); - CHECK_EQ(init_size - PageSize, address_range.size()); - - // Unmapping at the end should succeed. - uptr old_size = address_range.size(); - void* old_base = address_range.base(); - uptr new_start = reinterpret_cast(address_range.base()) + - address_range.size() - PageSize; - address_range.Unmap(new_start, PageSize); - CHECK_EQ(old_size - PageSize, address_range.size()); - CHECK_EQ(old_base, address_range.base()); - - // Unmapping in the middle of the ReservedAddressRange should fail. - EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); -} - } // namespace __sanitizer -- cgit v1.2.1 From 18d746da7abb4ada7601ed503990f6fcb9070161 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 11 Oct 2017 20:31:01 +0000 Subject: [libFuzzer] disable use_feature_frequency as it degrades some of the benchmarks too much :( git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315503 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerFlags.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index e21a43d95..efbc06790 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -132,7 +132,7 @@ FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") -FUZZER_FLAG_INT(use_feature_frequency, 1, "Experimental/internal") +FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental/internal") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) -- cgit v1.2.1 From 974d3123218b8f417e0de5af37df30885045b5da Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 11 Oct 2017 20:35:43 +0000 Subject: [X86] Add Knights Mill CPU to cpu_indicator support to match libgcc. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315505 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/builtins/cpu_model.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c index 83ea7a49f..2fd39e15a 100644 --- a/lib/builtins/cpu_model.c +++ b/lib/builtins/cpu_model.c @@ -54,6 +54,7 @@ enum ProcessorTypes { AMD_BTVER1, AMD_BTVER2, AMDFAM17H, + INTEL_KNM, CPU_TYPE_MAX }; @@ -361,6 +362,10 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Type = INTEL_KNL; // knl break; + case 0x85: + *Type = INTEL_KNM; // knm + break; + default: // Unknown family 6 CPU. break; break; -- cgit v1.2.1 From 57e44143e1f8d29e74cc821bad3e71a20c38e43a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 11 Oct 2017 20:46:13 +0000 Subject: [ubsan] Support ubsan-minimal tests on Android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315507 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/ubsan_minimal/lit.common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ubsan_minimal/lit.common.cfg b/test/ubsan_minimal/lit.common.cfg index e8b42bb82..32a1d0b3e 100644 --- a/test/ubsan_minimal/lit.common.cfg +++ b/test/ubsan_minimal/lit.common.cfg @@ -16,7 +16,7 @@ config.test_source_root = os.path.dirname(__file__) config.name = 'UBSan-Minimal-' + config.target_arch def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " target_cflags = [get_required_attr(config, "target_cflags")] clang_ubsan_cflags = ["-fsanitize-minimal-runtime"] + target_cflags -- cgit v1.2.1 From 95281d613eb05756a207ae25643cb94bd5ffdcb0 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 11 Oct 2017 21:20:04 +0000 Subject: [sanitizer] Move the errno/ENOMEM allocator checks logic to separate .cc Summary: This is a new attempt at D38706, which had 2 issues. The first one was that it broke TSan, because `sanitizer_errno.h` was not directly included in `tsan_mman.cc`. This fixes the include. The second one was that it broke the nolibc build, because `__errno_location` couldn't be found. This adds the new .cc to the libcdep list instead of the base one. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: kubamracek, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D38743 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315509 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/CMakeLists.txt | 1 + lib/sanitizer_common/sanitizer_allocator_checks.cc | 23 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_allocator_checks.h | 9 +++++++-- lib/tsan/rtl/tsan_mman.cc | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.cc diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index e62b24544..db077b565 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -58,6 +58,7 @@ set(SANITIZER_NOLIBC_SOURCES set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc + sanitizer_allocator_checks.cc sancov_flags.cc sanitizer_coverage_fuchsia.cc sanitizer_coverage_libcdep_new.cc diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.cc b/lib/sanitizer_common/sanitizer_allocator_checks.cc new file mode 100644 index 000000000..dc263dbef --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_checks.cc @@ -0,0 +1,23 @@ +//===-- sanitizer_allocator_checks.cc ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno.h" + +namespace __sanitizer { + +void SetErrnoToENOMEM() { + errno = errno_ENOMEM; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index b72f541a4..b61a8b2eb 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -15,17 +15,22 @@ #ifndef SANITIZER_ALLOCATOR_CHECKS_H #define SANITIZER_ALLOCATOR_CHECKS_H -#include "sanitizer_errno.h" #include "sanitizer_internal_defs.h" #include "sanitizer_common.h" #include "sanitizer_platform.h" namespace __sanitizer { +// The following is defined in a separate compilation unit to avoid pulling in +// sanitizer_errno.h in this header, which leads to conflicts when other system +// headers include errno.h. This is usually the result of an unlikely event, +// and as such we do not care as much about having it inlined. +void SetErrnoToENOMEM(); + // A common errno setting logic shared by almost all sanitizer allocator APIs. INLINE void *SetErrnoOnNull(void *ptr) { if (UNLIKELY(!ptr)) - errno = errno_ENOMEM; + SetErrnoToENOMEM(); return ptr; } diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc index 8ef031646..19680238b 100644 --- a/lib/tsan/rtl/tsan_mman.cc +++ b/lib/tsan/rtl/tsan_mman.cc @@ -13,6 +13,7 @@ #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "tsan_mman.h" #include "tsan_rtl.h" -- cgit v1.2.1 From c16a15f6ecaface37c1e85811035c25516ce5e41 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 11 Oct 2017 21:22:32 +0000 Subject: Disable profile tests on Android. They never actually worked, but this way they are not included in "check-all". git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315511 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/profile/lit.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 7f0d95a9a..268620747 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -72,3 +72,6 @@ if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: if config.target_arch in ['armv7l']: config.unsupported = True + +if config.android: + config.unsupported = True -- cgit v1.2.1 From e3e1659d13986a80ea90f480ddf5af45f1134c48 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 11 Oct 2017 21:22:45 +0000 Subject: Disable TSan tests on Android. They never passed. This change excludes them from 'check-all'. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315512 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/CMakeLists.txt | 3 ++- lib/tsan/tests/CMakeLists.txt | 2 +- test/tsan/CMakeLists.txt | 2 +- test/tsan/lit.cfg | 3 +++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 5e3bb102b..08974a467 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -222,7 +222,8 @@ endif() # Build libcxx instrumented with TSan. if(COMPILER_RT_HAS_LIBCXX_SOURCES AND - COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang") + COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang" AND + NOT ANDROID) set(libcxx_tsan_deps) foreach(arch ${TSAN_SUPPORTED_ARCH}) get_target_flags_for_arch(${arch} TARGET_CFLAGS) diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index f5e4caef2..ad8d02ed3 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -63,7 +63,7 @@ macro(add_tsan_unittest testname) endif() endmacro() -if(COMPILER_RT_CAN_EXECUTE_TESTS) +if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) add_subdirectory(rtl) add_subdirectory(unit) endif() diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index a68908612..af329562d 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) endif() if(COMPILER_RT_HAS_LIBCXX_SOURCES AND COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang" - AND NOT APPLE) + AND NOT APPLE AND NOT ANDROID) list(APPEND TSAN_TEST_DEPS libcxx_tsan) set(TSAN_HAS_LIBCXX True) else() diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index 10f31b06e..95c7d7cc3 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -83,5 +83,8 @@ config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm'] if config.host_os not in ['FreeBSD', 'Linux', 'Darwin']: config.unsupported = True +if config.android: + config.unsupported = True + if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]: config.parallelism_group = "darwin-64bit-sanitizer" -- cgit v1.2.1 From 8c026f72295bb6b6a9aa0e2673baba6c17b33e26 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 11 Oct 2017 23:41:32 +0000 Subject: Reland "[sanitizer] Introduce ReservedAddressRange to sanitizer_common" In Fuchsia, MmapNoAccess/MmapFixedOrDie are implemented using a global VMAR, which means that MmapNoAccess can only be called once. This works for the sanitizer allocator but *not* for the Scudo allocator. Hence, this changeset introduces a new ReservedAddressRange object to serve as the new API for these calls. In this changeset, the object still calls into the old Mmap implementations. The next changeset two changesets will convert the sanitizer and scudo allocators to use the new APIs, respectively. (ReservedAddressRange will replace the SecondaryHeader in Scudo.) Finally, a last changeset will update the Fuchsia implementation. Patch by Julia Hansbrough Differential Revision: https://reviews.llvm.org/D38437 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315533 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 14 +++++ lib/sanitizer_common/sanitizer_fuchsia.cc | 31 +++++++++++ lib/sanitizer_common/sanitizer_posix_libcdep.cc | 36 +++++++++++++ lib/sanitizer_common/sanitizer_win.cc | 37 +++++++++++++ .../tests/sanitizer_common_test.cc | 62 ++++++++++++++++++++++ 5 files changed, 180 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ee5eca516..14b92d9c4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,6 +128,20 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); +class ReservedAddressRange { + public: + uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false); + void Unmap(uptr addr, uptr size); + void *base() const { return base_; } + uptr size() const { return size_; } + + private: + void* base_; + uptr size_; + const char* name_; +}; + typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, /*out*/uptr *stats, uptr stats_size); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 21fabddb1..00a8aabbf 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,6 +236,37 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { return DoAnonymousMmapOrDie(size, mem_type, false, false); } +uptr ReservedAddressRange::Init(uptr init_size, const char* name = nullptr, + uptr fixed_addr = uptr(0)) { + base_ = MmapNoAccess(init_size); + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + bool tolerate_enomem = true) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, + tolerate_enomem)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 4214d91c5..b6b09b5e4 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,6 +337,42 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return (void *)p; } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..5bbdff951 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,6 +235,31 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), + true); + // Detect overflows. + CHECK_LE(size, (base_as_uptr + size_) - addr); + UnmapOrDie(reinterpret_cast(addr), size); + if (addr_as_void == base_) { + base_ = reinterpret_cast(addr + size); + } + size_ = size_ - size; +} + void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -252,6 +277,18 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type); } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 9c62b4593..5efce86ce 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -320,4 +320,66 @@ TEST(SanitizerCommon, GetRandom) { } #endif +TEST(SanitizerCommon, ReservedAddressRangeInit) { + uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*)-1); + UnmapOrDie((void*)res, init_size); + // Should be able to map into the same space now. + ReservedAddressRange address_range2; + uptr res2 = address_range2.Init(init_size, nullptr, res); + CHECK_EQ(res, res2); + + // TODO(flowerhack): Once this is switched to the "real" implementation + // (rather than passing through to MmapNoAccess*), enforce and test "no + // double initializations allowed" +} + +TEST(SanitizerCommon, ReservedAddressRangeMap) { + constexpr uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*) -1); + + // Valid mappings should succeed. + CHECK_EQ(res, address_range.Map(res, init_size)); + + // Valid mappings should be readable. + unsigned char buffer[init_size]; + memcpy(buffer, &res, sizeof(buffer)); + + // Invalid mappings should fail. + EXPECT_DEATH(address_range.Map(res, 0), ".*"); + + // TODO(flowerhack): Once this is switched to the "real" implementation, make + // sure you can only mmap into offsets in the Init range. +} + +TEST(SanitizerCommon, ReservedAddressRangeUnmap) { + uptr PageSize = GetPageSizeCached(); + uptr init_size = PageSize * 4; + ReservedAddressRange address_range; + uptr base_addr = address_range.Init(init_size); + CHECK_NE(base_addr, (void*)-1); + CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); + + // Unmapping at the beginning should succeed. + address_range.Unmap(base_addr, PageSize); + CHECK_EQ(base_addr + PageSize, address_range.base()); + CHECK_EQ(init_size - PageSize, address_range.size()); + + // Unmapping at the end should succeed. + uptr old_size = address_range.size(); + void* old_base = address_range.base(); + uptr new_start = reinterpret_cast(address_range.base()) + + address_range.size() - PageSize; + address_range.Unmap(new_start, PageSize); + CHECK_EQ(old_size - PageSize, address_range.size()); + CHECK_EQ(old_base, address_range.base()); + + // Unmapping in the middle of the ReservedAddressRange should fail. + EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); +} + } // namespace __sanitizer -- cgit v1.2.1 From 286d9a10aba57923d2a1c193b930580f34f3123b Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 12 Oct 2017 03:23:31 +0000 Subject: Revert r315533 "Reland "[sanitizer] Introduce ReservedAddressRange to sanitizer_common"" The SanitizerCommon.ReservedAddressRangeUnmap test fails on Windows: FAIL: SanitizerCommon-Unit :: ./Sanitizer-x86_64-Test.exe/SanitizerCommon.ReservedAddressRangeUnmap (34003 of 35554) ******************** TEST 'SanitizerCommon-Unit :: ./Sanitizer-x86_64-Test.exe/SanitizerCommon.ReservedAddressRangeUnmap' FAILED ******************** Note: Google Test filter = SanitizerCommon.ReservedAddressRangeUnmap [==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from SanitizerCommon [ RUN ] SanitizerCommon.ReservedAddressRangeUnmap ==3780==ERROR: SanitizerTool failed to deallocate 0x1000 (4096) bytes at address 0x0000000c3000 (error code: 487) ==3780==Sanitizer CHECK failed: E:\b\build\slave\win_upload_clang\build\src\third_party\llvm\projects\compiler-rt\lib\sanitizer_common\sanitizer_win.cc:129 (("unable to unmap" && 0)) != (0) (0, 0) ******************** Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. Testing Time: 299.76s ******************** Failing Tests (1): SanitizerCommon-Unit :: ./Sanitizer-x86_64-Test.exe/SanitizerCommon.ReservedAddressRangeUnmap > In Fuchsia, MmapNoAccess/MmapFixedOrDie are implemented using a global > VMAR, which means that MmapNoAccess can only be called once. This works > for the sanitizer allocator but *not* for the Scudo allocator. > > Hence, this changeset introduces a new ReservedAddressRange object to > serve as the new API for these calls. In this changeset, the object > still calls into the old Mmap implementations. > > The next changeset two changesets will convert the sanitizer and scudo > allocators to use the new APIs, respectively. (ReservedAddressRange will > replace the SecondaryHeader in Scudo.) > > Finally, a last changeset will update the Fuchsia implementation. > > Patch by Julia Hansbrough > > Differential Revision: https://reviews.llvm.org/D38437 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315553 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 14 ----- lib/sanitizer_common/sanitizer_fuchsia.cc | 31 ----------- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 36 ------------- lib/sanitizer_common/sanitizer_win.cc | 37 ------------- .../tests/sanitizer_common_test.cc | 62 ---------------------- 5 files changed, 180 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 14b92d9c4..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,20 +128,6 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); -class ReservedAddressRange { - public: - uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); - uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false); - void Unmap(uptr addr, uptr size); - void *base() const { return base_; } - uptr size() const { return size_; } - - private: - void* base_; - uptr size_; - const char* name_; -}; - typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, /*out*/uptr *stats, uptr stats_size); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 00a8aabbf..21fabddb1 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,37 +236,6 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { return DoAnonymousMmapOrDie(size, mem_type, false, false); } -uptr ReservedAddressRange::Init(uptr init_size, const char* name = nullptr, - uptr fixed_addr = uptr(0)) { - base_ = MmapNoAccess(init_size); - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, - bool tolerate_enomem = true) { - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, - tolerate_enomem)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index b6b09b5e4..4214d91c5 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,42 +337,6 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return (void *)p; } -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - if (fixed_addr) { - base_ = MmapFixedNoAccess(fixed_addr, size, name); - } else { - base_ = MmapNoAccess(size); - } - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, - bool tolerate_enomem) { - if (tolerate_enomem) { - return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); - } - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 5bbdff951..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,31 +235,6 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, - bool tolerate_enomem) { - if (tolerate_enomem) { - return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); - } - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - void* addr_as_void = reinterpret_cast(addr); - uptr base_as_uptr = reinterpret_cast(base_); - // Only unmap at the beginning or end of the range. - CHECK_EQ((addr_as_void == base_) || (addr + size == base_as_uptr + size_), - true); - // Detect overflows. - CHECK_LE(size, (base_as_uptr + size_) - addr); - UnmapOrDie(reinterpret_cast(addr), size); - if (addr_as_void == base_) { - base_ = reinterpret_cast(addr + size); - } - size_ = size_ - size; -} - void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -277,18 +252,6 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type); } -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - if (fixed_addr) { - base_ = MmapFixedNoAccess(fixed_addr, size, name); - } else { - base_ = MmapNoAccess(size); - } - size_ = size; - name_ = name; - return reinterpret_cast(base_); -} - - void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 5efce86ce..9c62b4593 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -320,66 +320,4 @@ TEST(SanitizerCommon, GetRandom) { } #endif -TEST(SanitizerCommon, ReservedAddressRangeInit) { - uptr init_size = 0xffff; - ReservedAddressRange address_range; - uptr res = address_range.Init(init_size); - CHECK_NE(res, (void*)-1); - UnmapOrDie((void*)res, init_size); - // Should be able to map into the same space now. - ReservedAddressRange address_range2; - uptr res2 = address_range2.Init(init_size, nullptr, res); - CHECK_EQ(res, res2); - - // TODO(flowerhack): Once this is switched to the "real" implementation - // (rather than passing through to MmapNoAccess*), enforce and test "no - // double initializations allowed" -} - -TEST(SanitizerCommon, ReservedAddressRangeMap) { - constexpr uptr init_size = 0xffff; - ReservedAddressRange address_range; - uptr res = address_range.Init(init_size); - CHECK_NE(res, (void*) -1); - - // Valid mappings should succeed. - CHECK_EQ(res, address_range.Map(res, init_size)); - - // Valid mappings should be readable. - unsigned char buffer[init_size]; - memcpy(buffer, &res, sizeof(buffer)); - - // Invalid mappings should fail. - EXPECT_DEATH(address_range.Map(res, 0), ".*"); - - // TODO(flowerhack): Once this is switched to the "real" implementation, make - // sure you can only mmap into offsets in the Init range. -} - -TEST(SanitizerCommon, ReservedAddressRangeUnmap) { - uptr PageSize = GetPageSizeCached(); - uptr init_size = PageSize * 4; - ReservedAddressRange address_range; - uptr base_addr = address_range.Init(init_size); - CHECK_NE(base_addr, (void*)-1); - CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); - - // Unmapping at the beginning should succeed. - address_range.Unmap(base_addr, PageSize); - CHECK_EQ(base_addr + PageSize, address_range.base()); - CHECK_EQ(init_size - PageSize, address_range.size()); - - // Unmapping at the end should succeed. - uptr old_size = address_range.size(); - void* old_base = address_range.base(); - uptr new_start = reinterpret_cast(address_range.base()) + - address_range.size() - PageSize; - address_range.Unmap(new_start, PageSize); - CHECK_EQ(old_size - PageSize, address_range.size()); - CHECK_EQ(old_base, address_range.base()); - - // Unmapping in the middle of the ReservedAddressRange should fail. - EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); -} - } // namespace __sanitizer -- cgit v1.2.1 From 389cffef8d650b3dd60e9f76badb083c241fbd0b Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Thu, 12 Oct 2017 15:01:09 +0000 Subject: [scudo] Allow for non-Android Shared TSD platforms, part 1 Summary: This first part just prepares the grounds for part 2 and doesn't add any new functionality. It mostly consists of small refactors: - move the `pthread.h` include higher as it will be used in the headers; - use `errno.h` in `scudo_allocator.cpp` instead of the sanitizer one, update the `errno` assignments accordingly (otherwise it creates conflicts on some platforms due to `pthread.h` including `errno.h`); - introduce and use `getCurrentTSD` and `setCurrentTSD` for the shared TSD model code; Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits, srhines Differential Revision: https://reviews.llvm.org/D38826 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315583 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.cpp | 12 ++++++------ lib/scudo/scudo_tsd.h | 2 ++ lib/scudo/scudo_tsd_exclusive.cpp | 2 -- lib/scudo/scudo_tsd_shared.cpp | 15 ++++++++------- lib/scudo/scudo_tsd_shared.inc | 8 ++++++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 077d57747..472017dff 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -22,9 +22,9 @@ #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" -#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_quarantine.h" +#include #include namespace __scudo { @@ -640,7 +640,7 @@ void *scudoValloc(uptr Size) { void *scudoPvalloc(uptr Size) { uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) { - errno = errno_ENOMEM; + errno = ENOMEM; return Instance.handleBadRequest(); } // pvalloc(0) should allocate one page. @@ -650,7 +650,7 @@ void *scudoPvalloc(uptr Size) { void *scudoMemalign(uptr Alignment, uptr Size) { if (UNLIKELY(!IsPowerOfTwo(Alignment))) { - errno = errno_EINVAL; + errno = EINVAL; return Instance.handleBadRequest(); } return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign)); @@ -659,18 +659,18 @@ void *scudoMemalign(uptr Alignment, uptr Size) { int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) { if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) { Instance.handleBadRequest(); - return errno_EINVAL; + return EINVAL; } void *Ptr = Instance.allocate(Size, Alignment, FromMemalign); if (UNLIKELY(!Ptr)) - return errno_ENOMEM; + return ENOMEM; *MemPtr = Ptr; return 0; } void *scudoAlignedAlloc(uptr Alignment, uptr Size) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) { - errno = errno_EINVAL; + errno = EINVAL; return Instance.handleBadRequest(); } return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc)); diff --git a/lib/scudo/scudo_tsd.h b/lib/scudo/scudo_tsd.h index 9ee89d399..d78eb496f 100644 --- a/lib/scudo/scudo_tsd.h +++ b/lib/scudo/scudo_tsd.h @@ -19,6 +19,8 @@ #include "scudo_allocator.h" #include "scudo_utils.h" +#include + namespace __scudo { struct ALIGNED(64) ScudoTSD { diff --git a/lib/scudo/scudo_tsd_exclusive.cpp b/lib/scudo/scudo_tsd_exclusive.cpp index eb4719734..1084dfac9 100644 --- a/lib/scudo/scudo_tsd_exclusive.cpp +++ b/lib/scudo/scudo_tsd_exclusive.cpp @@ -15,8 +15,6 @@ #if SCUDO_TSD_EXCLUSIVE -#include - namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; diff --git a/lib/scudo/scudo_tsd_shared.cpp b/lib/scudo/scudo_tsd_shared.cpp index 481635e6a..54aec842a 100644 --- a/lib/scudo/scudo_tsd_shared.cpp +++ b/lib/scudo/scudo_tsd_shared.cpp @@ -15,8 +15,6 @@ #if !SCUDO_TSD_EXCLUSIVE -#include - namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; @@ -51,12 +49,15 @@ static void initOnce() { TSDs[i].init(/*Shared=*/true); } +ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { + *get_android_tls_ptr() = reinterpret_cast(TSD); +} + void initThread(bool MinimalInit) { pthread_once(&GlobalInitialized, initOnce); // Initial context assignment is done in a plain round-robin fashion. u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); - ScudoTSD *TSD = &TSDs[Index % NumberOfTSDs]; - *get_android_tls_ptr() = reinterpret_cast(TSD); + setCurrentTSD(&TSDs[Index % NumberOfTSDs]); } ScudoTSD *getTSDAndLockSlow() { @@ -66,7 +67,7 @@ ScudoTSD *getTSDAndLockSlow() { for (u32 i = 0; i < NumberOfTSDs; i++) { TSD = &TSDs[i]; if (TSD->tryLock()) { - *get_android_tls_ptr() = reinterpret_cast(TSD); + setCurrentTSD(TSD); return TSD; } } @@ -81,12 +82,12 @@ ScudoTSD *getTSDAndLockSlow() { } if (LIKELY(LowestPrecedence != UINT64_MAX)) { TSD->lock(); - *get_android_tls_ptr() = reinterpret_cast(TSD); + setCurrentTSD(TSD); return TSD; } } // Last resort, stick with the current one. - TSD = reinterpret_cast(*get_android_tls_ptr()); + TSD = getCurrentTSD(); TSD->lock(); return TSD; } diff --git a/lib/scudo/scudo_tsd_shared.inc b/lib/scudo/scudo_tsd_shared.inc index 874942bba..9b9c3a2ec 100644 --- a/lib/scudo/scudo_tsd_shared.inc +++ b/lib/scudo/scudo_tsd_shared.inc @@ -17,8 +17,12 @@ #if !SCUDO_TSD_EXCLUSIVE +ALWAYS_INLINE ScudoTSD* getCurrentTSD() { + return reinterpret_cast(*get_android_tls_ptr()); +} + ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { - if (LIKELY(*get_android_tls_ptr())) + if (LIKELY(getCurrentTSD())) return; initThread(MinimalInit); } @@ -26,7 +30,7 @@ ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { ScudoTSD *getTSDAndLockSlow(); ALWAYS_INLINE ScudoTSD *getTSDAndLock() { - ScudoTSD *TSD = reinterpret_cast(*get_android_tls_ptr()); + ScudoTSD *TSD = getCurrentTSD(); CHECK(TSD && "No TSD associated with the current thread!"); // Try to lock the currently associated context. if (TSD->tryLock()) -- cgit v1.2.1 From c0ec5c621d76199dd09f2ff75160f29b5e17b014 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 12 Oct 2017 18:34:20 +0000 Subject: [asan] Disable a flaky test on android. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315602 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/sanitizer_common/TestCases/Linux/allow_user_segv.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index 201407923..6e0977faf 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -21,6 +21,9 @@ // XFAIL: msan // XFAIL: tsan +// Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. +// UNSUPPORTED: android + #include #include #include -- cgit v1.2.1 From a09806de6549f1723c5d404e6e7fbf2b9e3cac12 Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Thu, 12 Oct 2017 18:51:37 +0000 Subject: [cmake] Fix skipping DEPS (typo) in sanitizer_test_compile() Fix typo in variable assignment inside sanitizer_test_compile() that resulted in TEST_DEPS parameter not being included in the clang_compile() call. Spotted by George Karpenkov in D38444. Differential Revision: https://reviews.llvm.org/D38838 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315604 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/Modules/CompilerRTCompile.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index 872f1a065..556ee7896 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -51,7 +51,7 @@ function(sanitizer_test_compile obj_list source arch) endif() clang_compile(${output_obj} ${source} CFLAGS ${TEST_CFLAGS} ${TARGET_CFLAGS} - DEPS ${TEST_COMPILE_DEPS}) + DEPS ${COMPILE_DEPS}) list(APPEND ${obj_list} ${output_obj}) set("${obj_list}" "${${obj_list}}" PARENT_SCOPE) endfunction() -- cgit v1.2.1 From c02f2d0abbbccad81ea7dadbd55516f9e171833f Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Thu, 12 Oct 2017 18:51:41 +0000 Subject: [cmake] [interception] Remove duplicate gtest from test COMPILE_DEPS Fix the gtest dependency to be included in DEPS only, rather than in COMPILE_DEPS + DEPS. The former variable is apparently used to provide unconditional dependencies, while the latter are only used for non-standalone builds. Since they are concatenated, specifying gtest in both is redundant. Furthermore, including it in COMPILE_DEPS causes build failure for standalone builds where 'gtest' target is not present. Differential Revision: https://reviews.llvm.org/D38839 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315605 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index 782066753..1da0a455b 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -89,7 +89,7 @@ macro(add_interception_tests_for_arch arch) InterceptionUnitTests "Interception-${arch}-Test" ${arch} RUNTIME ${INTERCEPTION_COMMON_LIB} SOURCES ${INTERCEPTION_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} - COMPILE_DEPS gtest ${INTERCEPTION_TEST_HEADERS} + COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS} DEPS gtest CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON}) -- cgit v1.2.1 From fbade2dae1aeb44f5b9a1a52d77a4f9e98b1e233 Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Thu, 12 Oct 2017 21:07:43 +0000 Subject: [cmake] [asan] Remove unnecessary gtest dep from dynamic tests Remove the redundant dependency on 'gtest' target from the dynamic tests in non-MSVC environment. The tests reuse compiled objects from ASAN_INST_TEST_OBJECTS, and therefore they have been built against gtest already. This both fixes the spurious dependency on 'gtest' target that breaks stand-alone builds, and brings the dynamic tests more in line with regular tests which do not pass this dependency to add_compiler_rt_test() through generate_compiler_rt_tests(). Differential Revision: https://reviews.llvm.org/D38840 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315620 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index f8b9f4584..40732080f 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -205,7 +205,7 @@ function(add_asan_tests arch test_runtime) add_compiler_rt_test(AsanDynamicUnitTests "${dynamic_test_name}" "${arch}" SUBDIR "dynamic" OBJECTS ${ASAN_INST_TEST_OBJECTS} - DEPS gtest asan ${ASAN_INST_TEST_OBJECTS} + DEPS asan ${ASAN_INST_TEST_OBJECTS} LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS} ) endif() -- cgit v1.2.1 From 44c688de4e166daaf2829fee8b49c9cf9812853b Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Thu, 12 Oct 2017 22:24:58 +0000 Subject: [sanitizer] Workaround a Linux kernel bug in hard_rss_limit_mb_test. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315632 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/hard_rss_limit_mb_test.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc index f29cc2614..3c875c179 100644 --- a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc @@ -2,13 +2,9 @@ // RUN: %clangxx -O2 %s -o %t // // Run with limit should fail: -// RUN: %env_tool_opts=hard_rss_limit_mb=100 not %run %t >%t.log 2>&1 -// RUN: cat %t.log -// RUN: cat %t.log | FileCheck %s +// RUN: %env_tool_opts=hard_rss_limit_mb=100 not %run %t 2>&1 | FileCheck %s // This run uses getrusage: -// RUN: %env_tool_opts=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t >%t.log 2>&1 -// RUN: cat %t.log -// RUN: cat %t.log | FileCheck %s +// RUN: %env_tool_opts=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s // // Run w/o limit or with a large enough limit should pass: // RUN: %env_tool_opts=hard_rss_limit_mb=1000 %run %t @@ -31,7 +27,10 @@ volatile char *sink[kNumAllocs]; int main(int argc, char **argv) { for (int i = 0; i < kNumAllocs; i++) { if ((i % 1000) == 0) { - fprintf(stderr, "[%d]\n", i); + // Don't write to stderr! Doing that triggers a kernel race condition + // between this thread and the rss-limit thread, and may lose part of the + // output. See https://lkml.org/lkml/2014/2/17/324. + printf("[%d]\n", i); } char *x = new char[kAllocSize]; memset(x, 0, kAllocSize); -- cgit v1.2.1 From 617d610c7925d1914bc0be8d895c3ee60c48c6bc Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 13 Oct 2017 01:12:23 +0000 Subject: [libFuzzer] tweam use_feature_frequency to be less aggressive; run a dummy input before the seed corpus git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315657 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerCorpus.h | 20 +++++++++++++++++--- lib/fuzzer/FuzzerLoop.cpp | 7 ++++--- test/fuzzer/FlagsTest.cpp | 2 +- test/fuzzer/fuzzer-flags.test | 8 ++++---- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h index 385a06531..2da929835 100644 --- a/lib/fuzzer/FuzzerCorpus.h +++ b/lib/fuzzer/FuzzerCorpus.h @@ -220,9 +220,11 @@ class InputCorpus { return FeatureFrequency[Idx % kFeatureSetSize]; } void UpdateFeatureFrequencyScore(InputInfo *II) { - II->FeatureFrequencyScore = 0.00000001; + const float kMin = 0.01, kMax = 100.; + II->FeatureFrequencyScore = kMin; for (auto Idx : II->UniqFeatureSet) II->FeatureFrequencyScore += 1. / (GetFeatureFrequency(Idx) + 1.); + II->FeatureFrequencyScore = Min(II->FeatureFrequencyScore, kMax); } size_t NumFeatures() const { return NumAddedFeatures; } @@ -261,8 +263,20 @@ private: Weights.resize(N); std::iota(Intervals.begin(), Intervals.end(), 0); for (size_t i = 0; i < N; i++) - Weights[i] = - Inputs[i]->NumFeatures * (i + 1) * Inputs[i]->FeatureFrequencyScore; + Weights[i] = Inputs[i]->NumFeatures + ? (i + 1) * Inputs[i]->FeatureFrequencyScore + : 0.; + if (FeatureDebug) { + for (size_t i = 0; i < N; i++) + Printf("%zd ", Inputs[i]->NumFeatures); + Printf("NUM\n"); + for (size_t i = 0; i < N; i++) + Printf("%f ", Inputs[i]->FeatureFrequencyScore); + Printf("SCORE\n"); + for (size_t i = 0; i < N; i++) + Printf("%f ", Weights[i]); + Printf("Weights\n"); + } CorpusDistribution = std::piecewise_constant_distribution( Intervals.begin(), Intervals.end(), Weights.begin()); } diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index c095fed12..30844e328 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -621,6 +621,10 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); assert(MaxInputLen > 0); + // Test the callback with empty input and never try it again. + uint8_t dummy = 0; + ExecuteCallback(&dummy, 0); + if (SizedFiles.empty()) { Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); Unit U({'\n'}); // Valid ASCII input. @@ -648,9 +652,6 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { } } - // Test the callback with empty input and never try it again. - uint8_t dummy; - ExecuteCallback(&dummy, 0); PrintStats("INITED"); if (Corpus.empty()) { diff --git a/test/fuzzer/FlagsTest.cpp b/test/fuzzer/FlagsTest.cpp index ac64b9d48..6eeac177b 100644 --- a/test/fuzzer/FlagsTest.cpp +++ b/test/fuzzer/FlagsTest.cpp @@ -28,5 +28,5 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { for (auto Flag : Flags) fprintf(stderr, "%s ", Flag.c_str()); fprintf(stderr, "\n"); - exit(0); + return 0; } diff --git a/test/fuzzer/fuzzer-flags.test b/test/fuzzer/fuzzer-flags.test index 59c8d1536..b812b0169 100644 --- a/test/fuzzer/fuzzer-flags.test +++ b/test/fuzzer/fuzzer-flags.test @@ -1,19 +1,19 @@ RUN: %cpp_compiler %S/FlagsTest.cpp -o %t-FlagsTest -RUN: not %t-FlagsTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR +RUN: %t-FlagsTest -runs=10 -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags FOO_BAR: BINGO -RUN: not %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH +RUN: %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)? DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus RUN: %t-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL NO_INTERNAL-NOT: internal flag -RUN: not %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU +RUN: %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU PASSTHRU: BINGO --foo-bar --baz -help=1 test RUN: mkdir -p %t/T0 %t/T1 RUN: echo z > %t/T1/z -RUN: not %t-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE +RUN: %t-FlagsTest -runs=10 --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test -- cgit v1.2.1 From cb11821c26e019476a12f31757083c2cde4f3262 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 13 Oct 2017 18:38:10 +0000 Subject: [Sanitizers] Add more details to ASan allocator stats report. Summary: . Reviewers: cryptoad Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D38834 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315730 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_memory_profile.cc | 3 +++ .../sanitizer_allocator_primary64.h | 24 ++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc index 05846c37c..603284c8c 100644 --- a/lib/asan/asan_memory_profile.cc +++ b/lib/asan/asan_memory_profile.cc @@ -107,6 +107,9 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, __lsan::ForEachChunk(ChunkCallback, &hp); uptr *Arg = reinterpret_cast(argument); hp.Print(Arg[0], Arg[1]); + + if (Verbosity()) + __asan_print_accumulated_stats(); } } // namespace __asan diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 3110b55b3..931e01c28 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -223,11 +223,14 @@ class SizeClassAllocator64 { uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id); Printf( "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " - "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd\n", + "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd " + "last released: %6zdK region: 0x%zx\n", region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), region->mapped_user >> 10, region->stats.n_allocated, region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, - rss >> 10, region->rtoi.num_releases); + rss >> 10, region->rtoi.num_releases, + region->rtoi.last_released_bytes >> 10, + SpaceBeg() + kRegionSize * class_id); } void PrintStats() { @@ -563,6 +566,7 @@ class SizeClassAllocator64 { uptr n_freed_at_last_release; uptr num_releases; u64 last_release_at_ns; + u64 last_released_bytes; }; struct RegionInfo { @@ -739,13 +743,18 @@ class SizeClassAllocator64 { MemoryMapper(const ThisT& base_allocator, uptr class_id) : allocator(base_allocator), region_base(base_allocator.GetRegionBeginBySizeClass(class_id)), - released_ranges_count(0) { + released_ranges_count(0), + released_bytes(0) { } uptr GetReleasedRangesCount() const { return released_ranges_count; } + uptr GetReleasedBytes() const { + return released_bytes; + } + uptr MapPackedCounterArrayBuffer(uptr buffer_size) { // TODO(alekseyshl): The idea to explore is to check if we have enough // space between num_freed_chunks*sizeof(CompactPtrT) and @@ -761,16 +770,18 @@ class SizeClassAllocator64 { // Releases [from, to) range of pages back to OS. void ReleasePageRangeToOS(CompactPtrT from, CompactPtrT to) { - ReleaseMemoryPagesToOS( - allocator.CompactPtrToPointer(region_base, from), - allocator.CompactPtrToPointer(region_base, to)); + const uptr from_page = allocator.CompactPtrToPointer(region_base, from); + const uptr to_page = allocator.CompactPtrToPointer(region_base, to); + ReleaseMemoryPagesToOS(from_page, to_page); released_ranges_count++; + released_bytes += to_page - from_page; } private: const ThisT& allocator; const uptr region_base; uptr released_ranges_count; + uptr released_bytes; }; // Attempts to release RAM occupied by freed chunks back to OS. The region is @@ -805,6 +816,7 @@ class SizeClassAllocator64 { if (memory_mapper.GetReleasedRangesCount() > 0) { region->rtoi.n_freed_at_last_release = region->stats.n_freed; region->rtoi.num_releases += memory_mapper.GetReleasedRangesCount(); + region->rtoi.last_released_bytes = memory_mapper.GetReleasedBytes(); } region->rtoi.last_release_at_ns = NanoTime(); } -- cgit v1.2.1 From e972b4cb282b92b0c15356660c4a95593066ef8c Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 13 Oct 2017 20:55:31 +0000 Subject: [scudo] Allow for non-Android Shared TSD platforms, part 2 Summary: Follow up to D38826. We introduce `pthread_{get,set}specific` versions of `{get,set}CurrentTSD` to allow for non Android platforms to use the Shared TSD model. We now allow `SCUDO_TSD_EXCLUSIVE` to be defined at compile time. A couple of things: - I know that `#if SANITIZER_ANDROID` is not ideal within a function, but in the end I feel it looks more compact and clean than going the .inc route; I am open to an alternative if anyone has one; - `SCUDO_TSD_EXCLUSIVE=1` requires ELF TLS support (and not emutls as this uses malloc). I haven't found anything to enforce that, so it's currently not checked. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: srhines, llvm-commits Differential Revision: https://reviews.llvm.org/D38854 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315751 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_platform.h | 24 +++++++++++++++++------- lib/scudo/scudo_tsd_shared.cpp | 10 +++++----- lib/scudo/scudo_tsd_shared.inc | 6 ++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/scudo/scudo_platform.h b/lib/scudo/scudo_platform.h index 86ddc1a25..095d6ef19 100644 --- a/lib/scudo/scudo_platform.h +++ b/lib/scudo/scudo_platform.h @@ -20,15 +20,25 @@ # error "The Scudo hardened allocator is not supported on this platform." #endif -#if SANITIZER_ANDROID || SANITIZER_FUCHSIA +#define SCUDO_TSD_EXCLUSIVE_SUPPORTED (!SANITIZER_ANDROID && !SANITIZER_FUCHSIA) + +#ifndef SCUDO_TSD_EXCLUSIVE +// SCUDO_TSD_EXCLUSIVE wasn't defined, use a default TSD model for the platform. +# if SANITIZER_ANDROID || SANITIZER_FUCHSIA // Android and Fuchsia use a pool of TSDs shared between threads. -# define SCUDO_TSD_EXCLUSIVE 0 -#elif SANITIZER_LINUX && !SANITIZER_ANDROID +# define SCUDO_TSD_EXCLUSIVE 0 +# elif SANITIZER_LINUX && !SANITIZER_ANDROID // Non-Android Linux use an exclusive TSD per thread. -# define SCUDO_TSD_EXCLUSIVE 1 -#else -# error "No default TSD model defined for this platform." -#endif // SANITIZER_ANDROID || SANITIZER_FUCHSIA +# define SCUDO_TSD_EXCLUSIVE 1 +# else +# error "No default TSD model defined for this platform." +# endif // SANITIZER_ANDROID || SANITIZER_FUCHSIA +#endif // SCUDO_TSD_EXCLUSIVE + +// If the exclusive TSD model is chosen, make sure the platform supports it. +#if SCUDO_TSD_EXCLUSIVE && !SCUDO_TSD_EXCLUSIVE_SUPPORTED +# error "The exclusive TSD model is not supported on this platform." +#endif namespace __scudo { diff --git a/lib/scudo/scudo_tsd_shared.cpp b/lib/scudo/scudo_tsd_shared.cpp index 54aec842a..6ee2f84a0 100644 --- a/lib/scudo/scudo_tsd_shared.cpp +++ b/lib/scudo/scudo_tsd_shared.cpp @@ -18,7 +18,7 @@ namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; -static pthread_key_t PThreadKey; +pthread_key_t PThreadKey; static atomic_uint32_t CurrentIndex; static ScudoTSD *TSDs; @@ -32,10 +32,6 @@ static uptr getNumberOfCPUs() { } static void initOnce() { - // Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for - // testing, we create an unused key. Since the key_data array follows the tls - // array, it basically gives us the extra entry we need. - // TODO(kostyak): remove and restrict to N and above. CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); initScudo(); NumberOfTSDs = getNumberOfCPUs(); @@ -50,7 +46,11 @@ static void initOnce() { } ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { +#if SANITIZER_ANDROID *get_android_tls_ptr() = reinterpret_cast(TSD); +#else + CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast(TSD)), 0); +#endif // SANITIZER_ANDROID } void initThread(bool MinimalInit) { diff --git a/lib/scudo/scudo_tsd_shared.inc b/lib/scudo/scudo_tsd_shared.inc index 9b9c3a2ec..79fcd651e 100644 --- a/lib/scudo/scudo_tsd_shared.inc +++ b/lib/scudo/scudo_tsd_shared.inc @@ -17,8 +17,14 @@ #if !SCUDO_TSD_EXCLUSIVE +extern pthread_key_t PThreadKey; + ALWAYS_INLINE ScudoTSD* getCurrentTSD() { +#if SANITIZER_ANDROID return reinterpret_cast(*get_android_tls_ptr()); +#else + return reinterpret_cast(pthread_getspecific(PThreadKey)); +#endif // SANITIZER_ANDROID } ALWAYS_INLINE void initThreadMaybe(bool MinimalInit = false) { -- cgit v1.2.1 From b1ac0a6f5296ba472af22fc3e62b011f6ea9d40f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 13 Oct 2017 21:02:16 +0000 Subject: LowerTypeTests: Give imported symbols a type with size 0 so that they are not assumed not to alias. It is possible for both a base and a derived class to be satisfied with a unique vtable. If a program contains casts of the same pointer to both of those types, the CFI checks will be lowered to this (with ThinLTO): if (p != &__typeid_base_global_addr) trap(); if (p != &__typeid_derived_global_addr) trap(); The optimizer may then use the first condition combined with the assumption that __typeid_base_global_addr and __typeid_derived_global_addr may not alias to optimize away the second comparison, resulting in an unconditional trap. This patch fixes the bug by giving imported globals the type [0 x i8]*, which prevents the optimizer from assuming that they do not alias. Differential Revision: https://reviews.llvm.org/D38873 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315753 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/vtable-may-alias.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/cfi/vtable-may-alias.cpp diff --git a/test/cfi/vtable-may-alias.cpp b/test/cfi/vtable-may-alias.cpp new file mode 100644 index 000000000..f63b53b8c --- /dev/null +++ b/test/cfi/vtable-may-alias.cpp @@ -0,0 +1,25 @@ +// RUN: %clangxx_cfi -o %t %s +// RUN: %run %t + +// In this example, both __typeid_A_global_addr and __typeid_B_global_addr will +// refer to the same address. Make sure that the compiler does not assume that +// they do not alias. + +struct A { + virtual void f() = 0; +}; + +struct B : A { + virtual void f() {} +}; + +__attribute__((weak)) void foo(void *p) { + B *b = (B *)p; + A *a = (A *)b; + a->f(); +} + +int main() { + B b; + foo(&b); +} -- cgit v1.2.1 From 837886eaee21ee20cb1469625538cd3ac3324dcc Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 13 Oct 2017 21:57:43 +0000 Subject: [Sanitizers] Always build libFuzzer with frame pointers. Lacking frame pointers, sanitized fuzzers collect bogus stack traces and the set of stack traces grows indefinitely, leading to OOMs. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315770 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt index 4c5b73f98..e442b645e 100644 --- a/lib/fuzzer/CMakeLists.txt +++ b/lib/fuzzer/CMakeLists.txt @@ -32,6 +32,8 @@ CHECK_CXX_SOURCE_COMPILES(" set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer LIBFUZZER_CFLAGS) + if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage") list(APPEND LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters) endif() -- cgit v1.2.1 From 397451f723cfa74d29d82599e8f468a3c630df0b Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 13 Oct 2017 23:33:12 +0000 Subject: [cfi] Use %ld_flags_rpath_* substitutions in tests (NFC) git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315775 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/cross-dso/icall/diag.cpp | 16 +++---- test/cfi/cross-dso/icall/icall-from-dso.cpp | 8 ++-- test/cfi/cross-dso/icall/icall.cpp | 8 ++-- test/cfi/cross-dso/simple-fail.cpp | 68 ++++++++++++++--------------- test/cfi/cross-dso/simple-pass.cpp | 40 ++++++++--------- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/test/cfi/cross-dso/icall/diag.cpp b/test/cfi/cross-dso/icall/diag.cpp index c9ca28cbf..579ee8356 100644 --- a/test/cfi/cross-dso/icall/diag.cpp +++ b/test/cfi/cross-dso/icall/diag.cpp @@ -6,8 +6,8 @@ // * otherwise, the callee decides between trap/recover/norecover. // Full-recover. -// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_cfi_dso_diag -g %s -o %t %t-so.so +// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso_diag -g %s -o %t %ld_flags_rpath_exe // RUN: %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \ // RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER @@ -23,9 +23,9 @@ // Trap on icall, no-recover on cast. // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \ -// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \ -// RUN: -g %s -o %t %t-so.so +// RUN: -g %s -o %t %ld_flags_rpath_exe // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \ // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL @@ -40,9 +40,9 @@ // Caller: recover on everything. // The same as in the previous case, behaviour is decided by the callee. // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \ -// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so // RUN: %clangxx_cfi_dso_diag \ -// RUN: -g %s -o %t %t-so.so +// RUN: -g %s -o %t %ld_flags_rpath_exe // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \ // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL @@ -57,9 +57,9 @@ // Caller wins. // cfi-nvcall is non-trapping in the main executable to link the diagnostic runtime library. // RUN: %clangxx_cfi_dso_diag \ -// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so // RUN: %clangxx_cfi_dso -fno-sanitize-trap=cfi-nvcall \ -// RUN: -g %s -o %t %t-so.so +// RUN: -g %s -o %t %ld_flags_rpath_exe // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \ // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL diff --git a/test/cfi/cross-dso/icall/icall-from-dso.cpp b/test/cfi/cross-dso/icall/icall-from-dso.cpp index 93cf4f676..125e030b5 100644 --- a/test/cfi/cross-dso/icall/icall-from-dso.cpp +++ b/test/cfi/cross-dso/icall/icall-from-dso.cpp @@ -1,8 +1,8 @@ -// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso %s -o %t %ld_flags_rpath_exe && %expect_crash %t 2>&1 | FileCheck %s -// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t2-so.so -// RUN: %clangxx_cfi_dso_diag -g %s -o %t2 %t2-so.so && %t2 2>&1 | FileCheck %s --check-prefix=CFI-DIAG +// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso_diag -g %s -o %t %ld_flags_rpath_exe && %t 2>&1 | FileCheck %s --check-prefix=CFI-DIAG #include diff --git a/test/cfi/cross-dso/icall/icall.cpp b/test/cfi/cross-dso/icall/icall.cpp index 6017b8014..9e9bfd07e 100644 --- a/test/cfi/cross-dso/icall/icall.cpp +++ b/test/cfi/cross-dso/icall/icall.cpp @@ -1,8 +1,8 @@ -// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_cfi_dso %s -o %t %t-so.so && %expect_crash %t 2>&1 | FileCheck %s +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso %s -o %t %ld_flags_rpath_exe && %expect_crash %t 2>&1 | FileCheck %s -// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t2-so.so -// RUN: %clangxx_cfi_dso_diag -g %s -o %t2 %t2-so.so && %t2 2>&1 | FileCheck %s --check-prefix=CFI-DIAG +// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso_diag -g %s -o %t %ld_flags_rpath_exe && %t 2>&1 | FileCheck %s --check-prefix=CFI-DIAG #include diff --git a/test/cfi/cross-dso/simple-fail.cpp b/test/cfi/cross-dso/simple-fail.cpp index 276b67d4b..93503ebe5 100644 --- a/test/cfi/cross-dso/simple-fail.cpp +++ b/test/cfi/cross-dso/simple-fail.cpp @@ -1,37 +1,37 @@ -// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so -// RUN: %clangxx_cfi_dso %s -o %t1 %t1-so.so -// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t1 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s - -// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so -// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 %t2-so.so -// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t2 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s - -// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so -// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 %t3-so.so -// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t3 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s - -// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so -// RUN: %clangxx_cfi_dso -DBM %s -o %t4 %t4-so.so -// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %expect_crash %t4 x 2>&1 | FileCheck --check-prefix=CFI-CAST %s - -// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t5-so.so -// RUN: %clangxx -DBM %s -o %t5 %t5-so.so -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s - -// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t6-so.so -// RUN: %clangxx_cfi_dso -DBM %s -o %t6 %t6-so.so -// RUN: %t6 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t6 x 2>&1 | FileCheck --check-prefix=NCFI %s - -// RUN: %clangxx_cfi_dso_diag -DSHARED_LIB %s -fPIC -shared -o %t7-so.so -// RUN: %clangxx_cfi_dso_diag %s -o %t7 %t7-so.so -// RUN: %t7 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL %s -// RUN: %t7 x 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL --check-prefix=CFI-DIAG-CAST %s +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso %s -o %t %ld_flags_rpath_exe +// RUN: %expect_crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DB32 %s -o %t %ld_flags_rpath_exe +// RUN: %expect_crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DB64 %s -o %t %ld_flags_rpath_exe +// RUN: %expect_crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DBM %s -o %t %ld_flags_rpath_exe +// RUN: %expect_crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t x 2>&1 | FileCheck --check-prefix=CFI-CAST %s + +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx -DBM %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t x 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DBM %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t x 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_dso_diag -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso_diag %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL %s +// RUN: %t x 2>&1 | FileCheck --check-prefix=CFI-DIAG-CALL --check-prefix=CFI-DIAG-CAST %s // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a diff --git a/test/cfi/cross-dso/simple-pass.cpp b/test/cfi/cross-dso/simple-pass.cpp index 42f7a2734..6ce64713a 100644 --- a/test/cfi/cross-dso/simple-pass.cpp +++ b/test/cfi/cross-dso/simple-pass.cpp @@ -1,23 +1,23 @@ -// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %t1-so.so -// RUN: %clangxx_cfi_dso %s -o %t1 %t1-so.so -// RUN: %t1 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %t2-so.so -// RUN: %clangxx_cfi_dso -DB32 %s -o %t2 %t2-so.so -// RUN: %t2 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %t3-so.so -// RUN: %clangxx_cfi_dso -DB64 %s -o %t3 %t3-so.so -// RUN: %t3 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %t4-so.so -// RUN: %clangxx_cfi_dso -DBM %s -o %t4 %t4-so.so -// RUN: %t4 2>&1 | FileCheck --check-prefix=CFI %s - -// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %t5-so.so -// RUN: %clangxx -DBM %s -o %t5 %t5-so.so -// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx_cfi_dso -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -g %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB32 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DB32 %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DB64 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DB64 %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_dso -DBM -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_cfi_dso -DBM %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -DBM -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx -DBM %s -o %t %ld_flags_rpath_exe +// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t x 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a -- cgit v1.2.1 From 3fd72382cc317e2e7c5758c17169c0aa7748285a Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 13 Oct 2017 23:57:08 +0000 Subject: [asan] Deflake one test by running it 3 times. The test seems to trigger an android platform bug under load. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315777 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/allow_user_segv.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index 6e0977faf..c1d896465 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -4,16 +4,34 @@ // clang-format off // RUN: %clangxx -O0 %s -o %t +// RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ +// RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ +// RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ // RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ +// RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ +// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ +// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ +// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 // clang-format on @@ -21,9 +39,6 @@ // XFAIL: msan // XFAIL: tsan -// Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. -// UNSUPPORTED: android - #include #include #include -- cgit v1.2.1 From aa529e36fb04cb7dc7d26e7ef2c5bd97d1b2638a Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 14 Oct 2017 00:07:11 +0000 Subject: [libFuzzer] print a better warning if we hit the ld bug git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315778 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerTracePC.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 78f0d4171..5e9f9f2f6 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -124,9 +124,11 @@ void TracePC::PrintModuleInfo() { if ((NumGuards && NumGuards != NumPCsInPCTables) || (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) { - Printf("ERROR: The size of coverage PC tables does not match the" - " number of instrumented PCs. This might be a bug in the compiler," - " please contact the libFuzzer developers.\n"); + Printf("ERROR: The size of coverage PC tables does not match the\n" + "number of instrumented PCs. This might be a compiler bug,\n" + "please contact the libFuzzer developers.\n" + "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n" + "for possible workarounds (tl;dr: don't use the old GNU ld)\n"); _Exit(1); } } -- cgit v1.2.1 From bb3e2cf04a77924335c5e05600b2a287daac8de4 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sat, 14 Oct 2017 21:38:13 +0000 Subject: [xray] Fix CMake for X-RAY tests Correctly depend on llvm-xray, make sure unit tests are being run. Differential Revision: https://reviews.llvm.org/D38917 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315827 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt index f88024b9f..e54e63f27 100644 --- a/lib/xray/tests/CMakeLists.txt +++ b/lib/xray/tests/CMakeLists.txt @@ -20,13 +20,14 @@ macro(add_xray_unittest testname) generate_compiler_rt_tests(TEST_OBJECTS XRayUnitTests "${testname}-${arch}-Test" "${arch}" SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} - DEPS gtest xray + DEPS gtest xray llvm-xray CFLAGS ${XRAY_UNITTEST_CFLAGS} LINK_FLAGS -fxray-instrument ${TARGET_LINK_FLAGS} -lstdc++ -lm ${CMAKE_THREAD_LIBS_INIT} -lpthread -ldl -lrt) + set_target_properties(XRayUnitTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endforeach() endif() endmacro() -- cgit v1.2.1 From 2323ab971abf58ef526fef84eeb8b9fc8b83e2b2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Sun, 15 Oct 2017 04:18:29 +0000 Subject: [asan] Increase kHandlerStackSize for TracerThreadSignalHandler 4096 is not enough on some platform, e.g. Debian 4.9.0-3-amd64 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315844 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 7e89d0cc8..e1cb6f76f 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -263,7 +263,7 @@ static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) { } // Size of alternative stack for signal handlers in the tracer thread. -static const int kHandlerStackSize = 4096; +static const int kHandlerStackSize = 8192; // This function will be run as a cloned task. static int TracerThread(void* argument) { -- cgit v1.2.1 From c7837d890a8bb1fff24931552dd0d2f10cb82ae1 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 16 Oct 2017 17:06:13 +0000 Subject: [scudo] Do not include sanitizer_posix.h if not on a Posix platform Summary: Move the `sanitizer_posix.h` include within the `SANITIZER_ANDROID` `#if`, otherwise this errors when built on non-Posix platforms (eg: Fuchsia). Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38956 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315917 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index 71d1b2e1b..093eafe8e 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -13,8 +13,6 @@ #include "scudo_utils.h" -#include "sanitizer_common/sanitizer_posix.h" - #include #if defined(__x86_64__) || defined(__i386__) # include @@ -23,6 +21,8 @@ # if SANITIZER_ANDROID && __ANDROID_API__ < 18 // getauxval() was introduced with API level 18 on Android. Emulate it using // /proc/self/auxv for lower API levels. +# include "sanitizer_common/sanitizer_posix.h" + # include # define AT_HWCAP 16 -- cgit v1.2.1 From 1e1c09d32ef392045ccb8cfadb9b29c905eae2c0 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 16 Oct 2017 18:03:11 +0000 Subject: [cfi] Test cross-dso CFI on Android. Reviewers: vitalybuka, pcc Subscribers: llvm-commits, srhines Differential Revision: https://reviews.llvm.org/D38911 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315922 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/cfi/cross-dso/lit.local.cfg | 6 +++++- test/cfi/cross-dso/shadow_is_read_only.cpp | 3 +++ test/cfi/cross-dso/stats.cpp | 3 +++ test/cfi/cross-dso/util/cfi_stubs.h | 30 ++++++++++++++++++++++++++++++ test/cfi/lit.cfg | 5 +++++ test/lit.common.cfg | 13 +++++++++++++ 6 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/cfi/cross-dso/util/cfi_stubs.h diff --git a/test/cfi/cross-dso/lit.local.cfg b/test/cfi/cross-dso/lit.local.cfg index 4fd9b2852..afdac4246 100644 --- a/test/cfi/cross-dso/lit.local.cfg +++ b/test/cfi/cross-dso/lit.local.cfg @@ -5,5 +5,9 @@ def getRoot(config): root = getRoot(config) -if root.host_os not in ['Linux'] or config.android: +if root.host_os not in ['Linux']: + config.unsupported = True + +# Android O (API level 26) has support for cross-dso cfi in libdl.so. +if config.android and 'android-26' not in config.available_features: config.unsupported = True diff --git a/test/cfi/cross-dso/shadow_is_read_only.cpp b/test/cfi/cross-dso/shadow_is_read_only.cpp index 65aec826c..8811506af 100644 --- a/test/cfi/cross-dso/shadow_is_read_only.cpp +++ b/test/cfi/cross-dso/shadow_is_read_only.cpp @@ -12,6 +12,9 @@ // Tests that shadow is read-only most of the time. // REQUIRES: cxxabi +// Uses private API that is not available on Android. +// UNSUPPORTED: android + #include #include #include diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp index 975a1ff9f..09a7217bf 100644 --- a/test/cfi/cross-dso/stats.cpp +++ b/test/cfi/cross-dso/stats.cpp @@ -6,6 +6,9 @@ // CFI-icall is not implemented in thinlto mode => ".cfi" suffixes are missing // in sanstats output. +// FIXME: %t.stats must be transferred from device to host for this to work on Android. +// XFAIL: android + struct ABase {}; struct A : ABase { diff --git a/test/cfi/cross-dso/util/cfi_stubs.h b/test/cfi/cross-dso/util/cfi_stubs.h new file mode 100644 index 000000000..b742074f0 --- /dev/null +++ b/test/cfi/cross-dso/util/cfi_stubs.h @@ -0,0 +1,30 @@ +// This is a hack to access CFI interface that Android has in libdl.so on +// device, but not in the NDK. +#include +#include +#include + +typedef void (*cfi_slowpath_ty)(uint64_t, void *); +typedef void (*cfi_slowpath_diag_ty)(uint64_t, void *, void *); + +static cfi_slowpath_ty cfi_slowpath; +static cfi_slowpath_diag_ty cfi_slowpath_diag; + +__attribute__((constructor(0), no_sanitize("cfi"))) static void init() { + cfi_slowpath = (cfi_slowpath_ty)dlsym(RTLD_NEXT, "__cfi_slowpath"); + cfi_slowpath_diag = + (cfi_slowpath_diag_ty)dlsym(RTLD_NEXT, "__cfi_slowpath_diag"); + if (!cfi_slowpath || !cfi_slowpath_diag) abort(); +} + +extern "C" { +__attribute__((visibility("hidden"), no_sanitize("cfi"))) void __cfi_slowpath( + uint64_t Type, void *Addr) { + cfi_slowpath(Type, Addr); +} + +__attribute__((visibility("hidden"), no_sanitize("cfi"))) void +__cfi_slowpath_diag(uint64_t Type, void *Addr, void *Diag) { + cfi_slowpath_diag(Type, Addr, Diag); +} +} diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index c2102f08b..301d932ec 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -24,6 +24,8 @@ if config.lto_supported: diag = '-fno-sanitize-trap=cfi -fsanitize-recover=cfi ' non_dso = '-fvisibility=hidden ' dso = '-fsanitize-cfi-cross-dso -fvisibility=default ' + if config.android: + dso += '-include ' + config.test_source_root + '/cross-dso/util/cfi_stubs.h ' config.substitutions.append((r"%clang_cfi ", clang_cfi + non_dso)) config.substitutions.append((r"%clangxx_cfi ", clang_cfi + cxx + non_dso)) config.substitutions.append((r"%clang_cfi_diag ", clang_cfi + non_dso + diag)) @@ -33,5 +35,8 @@ if config.lto_supported: else: config.unsupported = True +if config.default_sanitizer_opts: + config.environment['UBSAN_OPTIONS'] = ':'.join(config.default_sanitizer_opts) + if lit_config.params.get('check_supported', None) and config.unsupported: raise BaseException("Tests unsupported") diff --git a/test/lit.common.cfg b/test/lit.common.cfg index 67f6daa47..26fbea046 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -201,6 +201,19 @@ if config.host_os == 'Darwin': else: config.substitutions.append( ("%macos_min_target_10_11", "") ) +if config.android: + adb = os.environ.get('ADB', 'adb') + try: + android_api_level_str = subprocess.check_output([adb, "shell", "getprop", "ro.build.version.sdk"]).rstrip() + except (subprocess.CalledProcessError, OSError): + lit_config.fatal("Failed to read ro.build.version.sdk (using '%s' as adb)" % adb) + try: + android_api_level = int(android_api_level_str) + except ValueError: + lit_config.fatal("Failed to read ro.build.version.sdk (using '%s' as adb): got '%s'" % (adb, android_api_level_str)) + if android_api_level >= 26: + config.available_features.add('android-26') + sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): config.available_features.add("has_sancovcc") -- cgit v1.2.1 From 4276b6704ef74a1af2fa7598759d2c7d6cdeddb4 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 17 Oct 2017 10:33:24 +0000 Subject: [XRay][compiler-rt] Always place the CPU record first for every buffer Summary: In FDR Mode, when we set up a new buffer for a thread that's just overflowed, we must place the CPU identifier with the TSC record as the first record. This is so that we can reconstruct all the function entry/exit with deltas rooted on a TSC record for the CPU at the beginning of the buffer. Without doing this, the tools are rejecting the log for cases when we've overflown and have different buffers that don't have the CPU and TSC records as the first entry in the buffers. Reviewers: pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38995 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@315987 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 14 +++++++------- lib/xray/xray_fdr_logging_impl.h | 11 +++++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index bd79893f6..90eb6c572 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -206,17 +206,17 @@ getTimestamp() XRAY_NEVER_INSTRUMENT { void fdrLoggingHandleArg0(int32_t FuncId, XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { auto TSC_CPU = getTimestamp(); - __xray_fdr_internal::processFunctionHook( - FuncId, Entry, std::get<0>(TSC_CPU), std::get<1>(TSC_CPU), 0, - clock_gettime, *BQ); + __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), + std::get<1>(TSC_CPU), 0, + clock_gettime, *BQ); } void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry, uint64_t Arg) XRAY_NEVER_INSTRUMENT { auto TSC_CPU = getTimestamp(); - __xray_fdr_internal::processFunctionHook( - FuncId, Entry, std::get<0>(TSC_CPU), std::get<1>(TSC_CPU), Arg, - clock_gettime, *BQ); + __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), + std::get<1>(TSC_CPU), Arg, + clock_gettime, *BQ); } void fdrLoggingHandleCustomEvent(void *Event, @@ -248,7 +248,7 @@ void fdrLoggingHandleCustomEvent(void *Event, // - The metadata record we're going to write. (16 bytes) // - The additional data we're going to write. Currently, that's the size of // the event we're going to dump into the log as free-form bytes. - if (!prepareBuffer(clock_gettime, MetadataRecSize + EventSize)) { + if (!prepareBuffer(TSC, CPU, clock_gettime, MetadataRecSize + EventSize)) { TLD.LocalBQ = nullptr; return; } diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index aec205e8a..f7c77c6c2 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -532,7 +532,8 @@ inline bool releaseThreadLocalBuffer(BufferQueue &BQArg) { return true; } -inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, +inline bool prepareBuffer(uint64_t TSC, unsigned char CPU, + int (*wall_clock_reader)(clockid_t, struct timespec *), size_t MaxSize) XRAY_NEVER_INSTRUMENT { auto &TLD = getThreadLocalData(); @@ -549,6 +550,9 @@ inline bool prepareBuffer(int (*wall_clock_reader)(clockid_t, return false; } setupNewBuffer(wall_clock_reader); + + // Always write the CPU metadata as the first record in the buffer. + writeNewCPUIdMetadata(CPU, TSC); } return true; } @@ -599,6 +603,9 @@ inline bool isLogInitializedAndReady( } setupNewBuffer(wall_clock_reader); + + // Always write the CPU metadata as the first record in the buffer. + writeNewCPUIdMetadata(CPU, TSC); } if (TLD.CurrentCPU == std::numeric_limits::max()) { @@ -728,7 +735,7 @@ inline void processFunctionHook( // bytes in the end of the buffer, we need to write out the EOB, get a new // Buffer, set it up properly before doing any further writing. size_t MaxSize = FunctionRecSize + 2 * MetadataRecSize; - if (!prepareBuffer(wall_clock_reader, MaxSize)) { + if (!prepareBuffer(TSC, CPU, wall_clock_reader, MaxSize)) { TLD.LocalBQ = nullptr; return; } -- cgit v1.2.1 From d935076a8d858596911bc7638dd2db162e0a9cae Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 17 Oct 2017 19:57:48 +0000 Subject: Revert "[asan] Deflake one test by running it 3 times." Disable this test on Android/x86 only. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316023 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/allow_user_segv.cc | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc index c1d896465..ab6b7d75f 100644 --- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -4,34 +4,16 @@ // clang-format off // RUN: %clangxx -O0 %s -o %t -// RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ -// RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ -// RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ // RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ -// RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ -// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ -// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ -// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ -// RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 || \ // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ -// RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 || \ // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ -// RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 || \ // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 // clang-format on @@ -39,6 +21,9 @@ // XFAIL: msan // XFAIL: tsan +// Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. +// UNSUPPORTED: android && i386-target-arch + #include #include #include -- cgit v1.2.1 From 98adaa2097783c0fe3a4c948397e3f2182dcc5d2 Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Wed, 18 Oct 2017 00:22:01 +0000 Subject: Use O_BINARY when opening GCDA file on Windows Summary: Fixes https://bugs.llvm.org/show_bug.cgi?id=34922. Apparently, the mode in **fdopen** gets simply ignored and Windows only cares about the mode of the original **open**. I have verified this both with the simple case from bug 34922 and with a full Firefox build. Reviewers: zturner Reviewed By: zturner Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D38984 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316048 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/profile/GCDAProfiling.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index 138af6ec4..8c92546bd 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -37,6 +37,9 @@ #ifndef MAP_FILE #define MAP_FILE 0 #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif #endif #if defined(__FreeBSD__) && defined(__i386__) @@ -238,17 +241,17 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4], /* Try just opening the file. */ new_file = 0; - fd = open(filename, O_RDWR); + fd = open(filename, O_RDWR | O_BINARY); if (fd == -1) { /* Try opening the file, creating it if necessary. */ new_file = 1; mode = "w+b"; - fd = open(filename, O_RDWR | O_CREAT, 0644); + fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644); if (fd == -1) { /* Try creating the directories first then opening the file. */ __llvm_profile_recursive_mkdir(filename); - fd = open(filename, O_RDWR | O_CREAT, 0644); + fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644); if (fd == -1) { /* Bah! It's hopeless. */ int errnum = errno; -- cgit v1.2.1 From 87a6e96366be745ed2a37c772b9bd24387134b72 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 20 Oct 2017 12:08:53 +0000 Subject: [tsan] Add Mutex annotation flag for constant-initialized __tsan_mutex_linker_init behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new flag, _⁠_tsan_mutex_not_static, which has the opposite sense of _⁠_tsan_mutex_linker_init. When the new _⁠_tsan_mutex_not_static flag is passed to _⁠_tsan_mutex_destroy, tsan ignores the destruction unless the mutex was also created with the _⁠_tsan_mutex_not_static flag. This is useful for constructors that otherwise woud set _⁠_tsan_mutex_linker_init but cannot, because they are declared constexpr. Google has a custom mutex with two constructors, a "linker initialized" constructor that relies on zero-initialization and sets ⁠_⁠_tsan_mutex_linker_init, and a normal one which sets no tsan flags. The "linker initialized" constructor is morally constexpr, but we can't declare it constexpr because of the need to call into tsan as a side effect. With this new flag, the normal c'tor can set _⁠_tsan_mutex_not_static, the "linker initialized" constructor can rely on tsan's lazy initialization, and _⁠_tsan_mutex_destroy can still handle both cases correctly. Author: Greg Falcon (gfalcon) Reviewed in: https://reviews.llvm.org/D39095 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316209 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/tsan_interface.h | 6 ++++++ lib/tsan/rtl/tsan_rtl_mutex.cc | 4 +++- lib/tsan/rtl/tsan_sync.h | 4 +++- test/tsan/custom_mutex.h | 10 ++++++---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h index 5ea09ab5c..530885014 100644 --- a/include/sanitizer/tsan_interface.h +++ b/include/sanitizer/tsan_interface.h @@ -44,6 +44,11 @@ const unsigned __tsan_mutex_linker_init = 1 << 0; const unsigned __tsan_mutex_write_reentrant = 1 << 1; // Mutex is read reentrant. const unsigned __tsan_mutex_read_reentrant = 1 << 2; +// Mutex does not have static storage duration, and must not be used after +// its destructor runs. The opposite of __tsan_mutex_linker_init. +// If this flag is passed to __tsan_mutex_destroy, then the destruction +// is ignored unless this flag was previously set on the mutex. +const unsigned __tsan_mutex_not_static = 1 << 8; // Mutex operation flags: @@ -70,6 +75,7 @@ void __tsan_mutex_create(void *addr, unsigned flags); // Annotate destruction of a mutex. // Supported flags: // - __tsan_mutex_linker_init +// - __tsan_mutex_not_static void __tsan_mutex_destroy(void *addr, unsigned flags); // Annotate start of lock operation. diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc index 2f8581162..152b965ad 100644 --- a/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -84,7 +84,9 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); if (s == 0) return; - if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit)) { + if ((flagz & MutexFlagLinkerInit) + || s->IsFlagSet(MutexFlagLinkerInit) + || ((flagz & MutexFlagNotStatic) && !s->IsFlagSet(MutexFlagNotStatic))) { // Destroy is no-op for linker-initialized mutexes. s->mtx.Unlock(); return; diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h index b83c09ff7..9039970bc 100644 --- a/lib/tsan/rtl/tsan_sync.h +++ b/lib/tsan/rtl/tsan_sync.h @@ -34,6 +34,7 @@ enum MutexFlags { MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock + MutexFlagNotStatic = 1 << 8, // __tsan_mutex_not_static // The following flags are runtime private. // Mutex API misuse was detected, so don't report any more. @@ -43,7 +44,8 @@ enum MutexFlags { // Must list all mutex creation flags. MutexCreationFlagMask = MutexFlagLinkerInit | MutexFlagWriteReentrant | - MutexFlagReadReentrant, + MutexFlagReadReentrant | + MutexFlagNotStatic, }; struct SyncVar { diff --git a/test/tsan/custom_mutex.h b/test/tsan/custom_mutex.h index e3ac7a9a5..8e226a170 100644 --- a/test/tsan/custom_mutex.h +++ b/test/tsan/custom_mutex.h @@ -6,15 +6,16 @@ // A very primitive mutex annotated with tsan annotations. class Mutex { public: - Mutex(bool prof, unsigned flags) + Mutex(bool prof, unsigned create_flags, unsigned destroy_flags=0) : prof_(prof) , locked_(false) - , seq_(0) { - __tsan_mutex_create(this, flags); + , seq_(0) + , destroy_flags_(destroy_flags) { + __tsan_mutex_create(this, create_flags); } ~Mutex() { - __tsan_mutex_destroy(this, 0); + __tsan_mutex_destroy(this, destroy_flags_); } void Lock() { @@ -57,6 +58,7 @@ class Mutex { const bool prof_; std::atomic locked_; int seq_; + unsigned destroy_flags_; // This models mutex profiling subsystem. static Mutex prof_mu_; -- cgit v1.2.1 From 2b3e0d328bdd251a00c840dbbae0d13e35cd50e4 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 20 Oct 2017 12:10:21 +0000 Subject: tsan: add tests missed in r316209 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316210 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tsan/custom_mutex4.cc | 33 +++++++++++++++++++++++++++++++++ test/tsan/custom_mutex5.cc | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 test/tsan/custom_mutex4.cc create mode 100644 test/tsan/custom_mutex5.cc diff --git a/test/tsan/custom_mutex4.cc b/test/tsan/custom_mutex4.cc new file mode 100644 index 000000000..539a8be80 --- /dev/null +++ b/test/tsan/custom_mutex4.cc @@ -0,0 +1,33 @@ +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +#include + +// Test that the destruction events of a mutex are ignored when the +// annotations request this. +// +// Use after destruction is UB, but __tsan_mutex_linker_init and +// __tsan_mutex_not_static exist to support global variables of mutex type, +// which might be accessed during program shutdown after the class's destructor +// has run. + +int main() { + std::aligned_storage::type mu1_store; + Mutex* mu1 = reinterpret_cast(&mu1_store); + new(&mu1_store) Mutex(false, __tsan_mutex_linker_init); + mu1->Lock(); + mu1->~Mutex(); + mu1->Unlock(); + + std::aligned_storage::type mu2_store; + Mutex* mu2 = reinterpret_cast(&mu2_store); + new(&mu2_store) Mutex(false, 0, __tsan_mutex_not_static); + mu2->Lock(); + mu2->~Mutex(); + mu2->Unlock(); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: DONE diff --git a/test/tsan/custom_mutex5.cc b/test/tsan/custom_mutex5.cc new file mode 100644 index 000000000..ad906e38a --- /dev/null +++ b/test/tsan/custom_mutex5.cc @@ -0,0 +1,33 @@ +// RUN: %clangxx_tsan -O1 --std=c++11 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "custom_mutex.h" + +#include + +// Test that we detect the destruction of an in-use mutex when the +// thread annotations don't otherwise disable the check. + +int main() { + std::aligned_storage::type mu1_store; + Mutex* mu1 = reinterpret_cast(&mu1_store); + new(&mu1_store) Mutex(false, 0); + mu1->Lock(); + mu1->~Mutex(); + mu1->Unlock(); + + std::aligned_storage::type mu2_store; + Mutex* mu2 = reinterpret_cast(&mu2_store); + new(&mu2_store) + Mutex(false, __tsan_mutex_not_static, __tsan_mutex_not_static); + mu2->Lock(); + mu2->~Mutex(); + mu2->Unlock(); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex +// CHECK: main {{.*}}custom_mutex5.cc:14 +// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex +// CHECK: main {{.*}}custom_mutex5.cc:22 +// CHECK: DONE -- cgit v1.2.1 From 59dbe326d4bcc31f36ba363e08cad5c022f5fcc3 Mon Sep 17 00:00:00 2001 From: Nitesh Jain Date: Sun, 22 Oct 2017 09:37:50 +0000 Subject: [Compiler-rt][MIPS] Fix cross build for XRAY. Reviewers: dberris, sdardis Subscribers: jaydeep, bhushan, llvm-commits Differential Revision: https://reviews.llvm.org/D38021 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316286 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/xray/CMakeLists.txt b/lib/xray/CMakeLists.txt index 6d24ba8bf..42f5ee69a 100644 --- a/lib/xray/CMakeLists.txt +++ b/lib/xray/CMakeLists.txt @@ -60,6 +60,12 @@ include_directories(../../include) set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS}) set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1) + +if (NOT MSVC AND NOT DEFINED TARGET_FLAGS) + set(TARGET_FLAGS ${CMAKE_CXX_FLAGS}) + separate_arguments(TARGET_FLAGS) +endif() + append_list_if( COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS) append_list_if( @@ -67,7 +73,7 @@ append_list_if( add_compiler_rt_object_libraries(RTXray ARCHS ${XRAY_SUPPORTED_ARCH} - SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} + SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} ${TARGET_FLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) add_compiler_rt_component(xray) @@ -82,7 +88,7 @@ foreach(arch ${XRAY_SUPPORTED_ARCH}) STATIC ARCHS ${arch} SOURCES ${${arch}_SOURCES} - CFLAGS ${XRAY_CFLAGS} + CFLAGS ${XRAY_CFLAGS} ${TARGET_FLAGS} DEFS ${XRAY_COMMON_DEFINITIONS} OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} PARENT_TARGET xray) -- cgit v1.2.1 From e378f8791d2d42e4c3f26033ba20a1bf4b43d2d5 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 23 Oct 2017 16:27:47 +0000 Subject: [scudo] Add a shared runtime Summary: Up to now, the Scudo cmake target only provided a static library that had to be linked to an executable to benefit from the hardened allocator. This introduces a shared library as well, that can be LD_PRELOAD'ed. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D38980 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316342 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/CMakeLists.txt | 23 ++++++++++++++++++++--- test/scudo/lit.cfg | 13 +++++++------ test/scudo/preload.cpp | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 test/scudo/preload.cpp diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 253924147..0d6314680 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -30,15 +30,32 @@ if (COMPILER_RT_HAS_MCRC_FLAG) endif() if(COMPILER_RT_HAS_SCUDO) + set(SCUDO_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + append_list_if(COMPILER_RT_HAS_LIBDL dl SCUDO_DYNAMIC_LIBS) + append_list_if(COMPILER_RT_HAS_LIBRT rt SCUDO_DYNAMIC_LIBS) + append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_DYNAMIC_LIBS) + append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_DYNAMIC_LIBS) + foreach(arch ${SCUDO_SUPPORTED_ARCH}) add_compiler_rt_runtime(clang_rt.scudo STATIC ARCHS ${arch} SOURCES ${SCUDO_SOURCES} - $ - $ - $ + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception + CFLAGS ${SCUDO_CFLAGS} + PARENT_TARGET scudo) + + add_compiler_rt_runtime(clang_rt.scudo + SHARED + ARCHS ${arch} + SOURCES ${SCUDO_SOURCES} + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception CFLAGS ${SCUDO_CFLAGS} + LINK_LIBS ${SCUDO_DYNAMIC_LIBS} PARENT_TARGET scudo) endforeach() endif() diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index bd9e6aa31..f4b864777 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -8,10 +8,10 @@ config.name = 'Scudo' + config.name_suffix # Setup source root. config.test_source_root = os.path.dirname(__file__) -# Path to the static library -base_lib = os.path.join(config.compiler_rt_libdir, - "libclang_rt.scudo-%s.a" % config.target_arch) -whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % base_lib +# Path to the shared & static libraries +shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.so" % config.target_arch) +static_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.a" % config.target_arch) +whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo # Test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] @@ -35,8 +35,9 @@ def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " # Add clang substitutions. -config.substitutions.append(("%clang_scudo ", - build_invocation(c_flags) + whole_archive)) +config.substitutions.append(("%clang ", build_invocation(c_flags))) +config.substitutions.append(("%clang_scudo ", build_invocation(c_flags) + whole_archive)) +config.substitutions.append(("%shared_libscudo", shared_libscudo)) # Platform-specific default SCUDO_OPTIONS for lit tests. default_scudo_opts = '' diff --git a/test/scudo/preload.cpp b/test/scudo/preload.cpp new file mode 100644 index 000000000..0da507b3c --- /dev/null +++ b/test/scudo/preload.cpp @@ -0,0 +1,20 @@ +// Test that the preloaded runtime works without linking the static library. + +// RUN: %clang %s -o %t +// RUN: env LD_PRELOAD=%shared_libscudo not %run %t 2>&1 | FileCheck %s + +// This way of setting LD_PRELOAD does not work with Android test runner. +// REQUIRES: !android + +#include +#include + +int main(int argc, char *argv[]) { + void *p = malloc(sizeof(int)); + assert(p); + free(p); + free(p); + return 0; +} + +// CHECK: ERROR: invalid chunk state -- cgit v1.2.1 From a21db44b446dc6e7db373e6cc4c57c9cdbd768c9 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 23 Oct 2017 17:12:07 +0000 Subject: [Sanitizers] New sanitizer API to purge allocator quarantine. Summary: Purging allocator quarantine and returning memory to OS might be desired between fuzzer iterations since, most likely, the quarantine is not going to catch bugs in the code under fuzz, but reducing RSS might significantly prolong the fuzzing session. Reviewers: cryptoad Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D39153 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316347 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/allocator_interface.h | 7 +++++ lib/asan/asan_allocator.cc | 20 +++++++++++++ .../sanitizer_allocator_combined.h | 4 +++ .../sanitizer_allocator_interface.h | 3 ++ .../sanitizer_allocator_primary32.h | 4 +++ .../sanitizer_allocator_primary64.h | 25 +++++++++++----- .../sanitizer_common_interface.inc | 1 + lib/sanitizer_common/sanitizer_quarantine.h | 33 +++++++++++++--------- test/asan/TestCases/Linux/release_to_os_test.cc | 18 ++++++++---- 9 files changed, 89 insertions(+), 26 deletions(-) diff --git a/include/sanitizer/allocator_interface.h b/include/sanitizer/allocator_interface.h index 522063161..2d35804b3 100644 --- a/include/sanitizer/allocator_interface.h +++ b/include/sanitizer/allocator_interface.h @@ -76,6 +76,13 @@ extern "C" { void (*malloc_hook)(const volatile void *, size_t), void (*free_hook)(const volatile void *)); + /* Drains allocator quarantines (calling thread's and global ones), returns + freed memory back to OS and releases other non-essential internal allocator + resources in attempt to reduce process RSS. + Currently available with ASan only. + */ + void __sanitizer_purge_allocator(); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index c98f9a89c..4b7e84ca5 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -716,6 +716,22 @@ struct Allocator { return AsanChunkView(m1); } + void Purge() { + AsanThread *t = GetCurrentThread(); + if (t) { + AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); + quarantine.DrainAndRecycle(GetQuarantineCache(ms), + QuarantineCallback(GetAllocatorCache(ms))); + } + { + SpinMutexLock l(&fallback_mutex); + quarantine.DrainAndRecycle(&fallback_quarantine_cache, + QuarantineCallback(&fallback_allocator_cache)); + } + + allocator.ForceReleaseToOS(); + } + void PrintStats() { allocator.PrintStats(); quarantine.PrintStats(); @@ -1011,6 +1027,10 @@ uptr __sanitizer_get_allocated_size(const void *p) { return allocated_size; } +void __sanitizer_purge_allocator() { + instance.Purge(); +} + #if !SANITIZER_SUPPORTS_WEAK_HOOKS // Provide default (no-op) implementation of malloc hooks. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h index efd25cadf..0d8a2a174 100644 --- a/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -77,6 +77,10 @@ class CombinedAllocator { primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms); } + void ForceReleaseToOS() { + primary_.ForceReleaseToOS(); + } + void Deallocate(AllocatorCache *cache, void *p) { if (!p) return; if (primary_.PointerIsMine(p)) diff --git a/lib/sanitizer_common/sanitizer_allocator_interface.h b/lib/sanitizer_common/sanitizer_allocator_interface.h index 13910e719..2f5ce3151 100644 --- a/lib/sanitizer_common/sanitizer_allocator_interface.h +++ b/lib/sanitizer_common/sanitizer_allocator_interface.h @@ -38,6 +38,9 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_free_hook(void *ptr); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void +__sanitizer_purge_allocator(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts); } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index 8f8a71d67..8abf2f9f5 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -120,6 +120,10 @@ class SizeClassAllocator32 { // This is empty here. Currently only implemented in 64-bit allocator. } + void ForceReleaseToOS() { + // Currently implemented in 64-bit allocator only. + } + void *MapWithCallback(uptr size) { void *res = MmapOrDie(size, "SizeClassAllocator32"); MapUnmapCallback().OnMap((uptr)res, size); diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 931e01c28..1635efe83 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -92,6 +92,13 @@ class SizeClassAllocator64 { memory_order_relaxed); } + void ForceReleaseToOS() { + for (uptr class_id = 1; class_id < kNumClasses; class_id++) { + BlockingMutexLock l(&GetRegionInfo(class_id)->mutex); + MaybeReleaseToOS(class_id, true /*force*/); + } + } + static bool CanAllocate(uptr size, uptr alignment) { return size <= SizeClassMap::kMaxSize && alignment <= SizeClassMap::kMaxSize; @@ -116,7 +123,7 @@ class SizeClassAllocator64 { region->num_freed_chunks = new_num_freed_chunks; region->stats.n_freed += n_chunks; - MaybeReleaseToOS(class_id); + MaybeReleaseToOS(class_id, false /*force*/); } NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id, @@ -786,7 +793,7 @@ class SizeClassAllocator64 { // Attempts to release RAM occupied by freed chunks back to OS. The region is // expected to be locked. - void MaybeReleaseToOS(uptr class_id) { + void MaybeReleaseToOS(uptr class_id, bool force) { RegionInfo *region = GetRegionInfo(class_id); const uptr chunk_size = ClassIdToSize(class_id); const uptr page_size = GetPageSizeCached(); @@ -799,12 +806,16 @@ class SizeClassAllocator64 { return; // Nothing new to release. } - s32 interval_ms = ReleaseToOSIntervalMs(); - if (interval_ms < 0) - return; + if (!force) { + s32 interval_ms = ReleaseToOSIntervalMs(); + if (interval_ms < 0) + return; - if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > NanoTime()) - return; // Memory was returned recently. + if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > + NanoTime()) { + return; // Memory was returned recently. + } + } MemoryMapper memory_mapper(*this, class_id); diff --git a/lib/sanitizer_common/sanitizer_common_interface.inc b/lib/sanitizer_common/sanitizer_common_interface.inc index 550427c90..2568df3a5 100644 --- a/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/lib/sanitizer_common/sanitizer_common_interface.inc @@ -34,6 +34,7 @@ INTERFACE_FUNCTION(__sanitizer_get_heap_size) INTERFACE_FUNCTION(__sanitizer_get_ownership) INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) +INTERFACE_FUNCTION(__sanitizer_purge_allocator) INTERFACE_FUNCTION(__sanitizer_print_memory_profile) INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook) INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook) diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h index db38867ce..886445a27 100644 --- a/lib/sanitizer_common/sanitizer_quarantine.h +++ b/lib/sanitizer_common/sanitizer_quarantine.h @@ -87,15 +87,14 @@ class Quarantine { // is zero (it allows us to perform just one atomic read per Put() call). CHECK((size == 0 && cache_size == 0) || cache_size != 0); - atomic_store(&max_size_, size, memory_order_relaxed); - atomic_store(&min_size_, size / 10 * 9, - memory_order_relaxed); // 90% of max size. - atomic_store(&max_cache_size_, cache_size, memory_order_relaxed); + atomic_store_relaxed(&max_size_, size); + atomic_store_relaxed(&min_size_, size / 10 * 9); // 90% of max size. + atomic_store_relaxed(&max_cache_size_, cache_size); } - uptr GetSize() const { return atomic_load(&max_size_, memory_order_relaxed); } + uptr GetSize() const { return atomic_load_relaxed(&max_size_); } uptr GetCacheSize() const { - return atomic_load(&max_cache_size_, memory_order_relaxed); + return atomic_load_relaxed(&max_cache_size_); } void Put(Cache *c, Callback cb, Node *ptr, uptr size) { @@ -117,7 +116,16 @@ class Quarantine { cache_.Transfer(c); } if (cache_.Size() > GetSize() && recycle_mutex_.TryLock()) - Recycle(cb); + Recycle(atomic_load_relaxed(&min_size_), cb); + } + + void NOINLINE DrainAndRecycle(Cache *c, Callback cb) { + { + SpinMutexLock l(&cache_mutex_); + cache_.Transfer(c); + } + recycle_mutex_.Lock(); + Recycle(0, cb); } void PrintStats() const { @@ -139,9 +147,8 @@ class Quarantine { Cache cache_; char pad2_[kCacheLineSize]; - void NOINLINE Recycle(Callback cb) { + void NOINLINE Recycle(uptr min_size, Callback cb) { Cache tmp; - uptr min_size = atomic_load(&min_size_, memory_order_relaxed); { SpinMutexLock l(&cache_mutex_); // Go over the batches and merge partially filled ones to @@ -201,7 +208,7 @@ class QuarantineCache { // Total memory used, including internal accounting. uptr Size() const { - return atomic_load(&size_, memory_order_relaxed); + return atomic_load_relaxed(&size_); } // Memory used for internal accounting. @@ -225,7 +232,7 @@ class QuarantineCache { list_.append_back(&from_cache->list_); SizeAdd(from_cache->Size()); - atomic_store(&from_cache->size_, 0, memory_order_relaxed); + atomic_store_relaxed(&from_cache->size_, 0); } void EnqueueBatch(QuarantineBatch *b) { @@ -296,10 +303,10 @@ class QuarantineCache { atomic_uintptr_t size_; void SizeAdd(uptr add) { - atomic_store(&size_, Size() + add, memory_order_relaxed); + atomic_store_relaxed(&size_, Size() + add); } void SizeSub(uptr sub) { - atomic_store(&size_, Size() - sub, memory_order_relaxed); + atomic_store_relaxed(&size_, Size() - sub); } }; diff --git a/test/asan/TestCases/Linux/release_to_os_test.cc b/test/asan/TestCases/Linux/release_to_os_test.cc index c85bcbb7f..3e28ffde4 100644 --- a/test/asan/TestCases/Linux/release_to_os_test.cc +++ b/test/asan/TestCases/Linux/release_to_os_test.cc @@ -1,18 +1,21 @@ // Tests ASAN_OPTIONS=allocator_release_to_os=1 -// // RUN: %clangxx_asan -std=c++11 %s -o %t // RUN: %env_asan_opts=allocator_release_to_os_interval_ms=0 %run %t 2>&1 | FileCheck %s --check-prefix=RELEASE // RUN: %env_asan_opts=allocator_release_to_os_interval_ms=-1 %run %t 2>&1 | FileCheck %s --check-prefix=NO_RELEASE -// +// RUN: %env_asan_opts=allocator_release_to_os_interval_ms=-1 %run %t force 2>&1 | FileCheck %s --check-prefix=FORCE_RELEASE + // REQUIRES: x86_64-target-arch -#include -#include + #include -#include #include #include +#include +#include +#include +#include +#include #include void MallocReleaseStress() { @@ -39,10 +42,13 @@ void MallocReleaseStress() { delete[] p; } -int main() { +int main(int argc, char **argv) { MallocReleaseStress(); + if (argc > 1 && !strcmp("force", argv[1])) + __sanitizer_purge_allocator(); __asan_print_accumulated_stats(); } // RELEASE: mapped:{{.*}}releases: {{[1-9]}} // NO_RELEASE: mapped:{{.*}}releases: 0 +// FORCE_RELEASE: mapped:{{.*}}releases: {{[1-9]}} -- cgit v1.2.1 From 328d6584aa2edc93bbe82f3ccedef452f1a94fa4 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Mon, 23 Oct 2017 17:13:24 +0000 Subject: Revert "[Compiler-rt][MIPS] Fix cross build for XRAY." Breaks build: http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux/builds/4677/steps/build%20with%20ninja/logs/stdio In file included from compiler-rt/lib/xray/xray_fdr_logging.cc:34: In file included from compiler-rt/lib/xray/xray_fdr_logging_impl.h:36: In file included from compiler-rt/lib/xray/xray_flags.h:18: compiler-rt/lib/xray/../sanitizer_common/sanitizer_flag_parser.h:23:7: error: '__sanitizer::FlagHandlerBase' has virtual functions but non-virtual destructor [-Werror,-Wnon-virtual-dtor] class FlagHandlerBase { git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316348 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/xray/CMakeLists.txt b/lib/xray/CMakeLists.txt index 42f5ee69a..6d24ba8bf 100644 --- a/lib/xray/CMakeLists.txt +++ b/lib/xray/CMakeLists.txt @@ -60,12 +60,6 @@ include_directories(../../include) set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS}) set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1) - -if (NOT MSVC AND NOT DEFINED TARGET_FLAGS) - set(TARGET_FLAGS ${CMAKE_CXX_FLAGS}) - separate_arguments(TARGET_FLAGS) -endif() - append_list_if( COMPILER_RT_HAS_XRAY_COMPILER_FLAG XRAY_SUPPORTED=1 XRAY_COMMON_DEFINITIONS) append_list_if( @@ -73,7 +67,7 @@ append_list_if( add_compiler_rt_object_libraries(RTXray ARCHS ${XRAY_SUPPORTED_ARCH} - SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} ${TARGET_FLAGS} + SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) add_compiler_rt_component(xray) @@ -88,7 +82,7 @@ foreach(arch ${XRAY_SUPPORTED_ARCH}) STATIC ARCHS ${arch} SOURCES ${${arch}_SOURCES} - CFLAGS ${XRAY_CFLAGS} ${TARGET_FLAGS} + CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS} OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS} PARENT_TARGET xray) -- cgit v1.2.1 From d93cb79ee54b601d00a1852e78895ae236857262 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 23 Oct 2017 17:58:16 +0000 Subject: [Sanitizers] Add total primary allocator RSS to allocator report. Summary: . Reviewers: cryptoad Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D39131 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316356 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_primary64.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 1635efe83..bb2b917f6 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -241,22 +241,28 @@ class SizeClassAllocator64 { } void PrintStats() { + uptr rss_stats[kNumClasses]; + for (uptr class_id = 0; class_id < kNumClasses; class_id++) + rss_stats[class_id] = SpaceBeg() + kRegionSize * class_id; + GetMemoryProfile(FillMemoryProfile, rss_stats, kNumClasses); + uptr total_mapped = 0; + uptr total_rss = 0; uptr n_allocated = 0; uptr n_freed = 0; for (uptr class_id = 1; class_id < kNumClasses; class_id++) { RegionInfo *region = GetRegionInfo(class_id); - total_mapped += region->mapped_user; + if (region->mapped_user != 0) { + total_mapped += region->mapped_user; + total_rss += rss_stats[class_id]; + } n_allocated += region->stats.n_allocated; n_freed += region->stats.n_freed; } - Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; " - "remains %zd\n", - total_mapped >> 20, n_allocated, n_allocated - n_freed); - uptr rss_stats[kNumClasses]; - for (uptr class_id = 0; class_id < kNumClasses; class_id++) - rss_stats[class_id] = SpaceBeg() + kRegionSize * class_id; - GetMemoryProfile(FillMemoryProfile, rss_stats, kNumClasses); + + Printf("Stats: SizeClassAllocator64: %zdM mapped (%zdM rss) in " + "%zd allocations; remains %zd\n", total_mapped >> 20, + total_rss >> 20, n_allocated, n_allocated - n_freed); for (uptr class_id = 1; class_id < kNumClasses; class_id++) PrintStats(class_id, rss_stats[class_id]); } -- cgit v1.2.1 From 4b9f44eeb084b0aa8ed0e8ddc5da8a3f13e5a764 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 23 Oct 2017 22:04:30 +0000 Subject: [libFuzzer] Periodically purge allocator's quarantine to prolong fuzzing sessions. Summary: Fuzzing targets that allocate/deallocate a lot of memory tend to consume a lot of RSS when ASan quarantine is enabled. Purging quarantine between iterations and returning memory to OS keeps RSS down and should not reduce the quarantine effectiveness provided the fuzz target does not preserve state between iterations (in this case this feature can be turned off). Based on D39153. Reviewers: vitalybuka Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39155 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316382 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerDriver.cpp | 1 + lib/fuzzer/FuzzerExtFunctions.def | 1 + lib/fuzzer/FuzzerFlags.def | 4 ++++ lib/fuzzer/FuzzerInternal.h | 3 +++ lib/fuzzer/FuzzerLoop.cpp | 23 ++++++++++++++++++++++- lib/fuzzer/FuzzerOptions.h | 1 + 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index 29248dcee..18c73ca75 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -578,6 +578,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.ReloadIntervalSec = Flags.reload; Options.OnlyASCII = Flags.only_ascii; Options.DetectLeaks = Flags.detect_leaks; + Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval; Options.TraceMalloc = Flags.trace_malloc; Options.RssLimitMb = Flags.rss_limit_mb; if (Flags.runs >= 0) diff --git a/lib/fuzzer/FuzzerExtFunctions.def b/lib/fuzzer/FuzzerExtFunctions.def index 3bc5302c3..25a655bfd 100644 --- a/lib/fuzzer/FuzzerExtFunctions.def +++ b/lib/fuzzer/FuzzerExtFunctions.def @@ -33,6 +33,7 @@ EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, (void (*malloc_hook)(const volatile void *, size_t), void (*free_hook)(const volatile void *)), false); +EXT_FUNC(__sanitizer_purge_allocator, void, (), false); EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false); EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); EXT_FUNC(__sanitizer_symbolize_pc, void, diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index efbc06790..e4bca46f0 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -114,6 +114,10 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " "Be careful, this will also close e.g. asan's stderr/stdout.") FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " "try to detect memory leaks during fuzzing (i.e. not only at shut down).") +FUZZER_FLAG_INT(purge_allocator_interval, 1, "Purge allocator caches and " + "quarantines every seconds. When rss_limit_mb is specified (>0), " + "purging starts when RSS exceeds 50% of rss_limit_mb. Pass " + "purge_allocator_interval=-1 to disable this functionality.") FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " "If >= 2 will also print stack traces.") FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h index 34fdeb821..97c14085e 100644 --- a/lib/fuzzer/FuzzerInternal.h +++ b/lib/fuzzer/FuzzerInternal.h @@ -96,6 +96,7 @@ private: void CrashOnOverwrittenData(); void InterruptCallback(); void MutateAndTestOne(); + void PurgeAllocator(); void ReportNewCoverage(InputInfo *II, const Unit &U); void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size); void WriteToOutputCorpus(const Unit &U); @@ -124,6 +125,8 @@ private: bool HasMoreMallocsThanFrees = false; size_t NumberOfLeakDetectionAttempts = 0; + system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now(); + UserCallback CB; InputCorpus &Corpus; MutationDispatcher &MD; diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 30844e328..58e8168d1 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -587,7 +587,7 @@ void Fuzzer::MutateAndTestOne() { size_t NewSize = 0; NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); assert(NewSize > 0 && "Mutator returned empty unit"); - assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); + assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit"); Size = NewSize; II.NumExecutedMutations++; if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) @@ -598,6 +598,25 @@ void Fuzzer::MutateAndTestOne() { } } +void Fuzzer::PurgeAllocator() { + if (Options.PurgeAllocatorIntervalSec < 0 || + !EF->__sanitizer_purge_allocator) { + return; + } + if (duration_cast(system_clock::now() - + LastAllocatorPurgeAttemptTime).count() < + Options.PurgeAllocatorIntervalSec) { + return; + } + + if (Options.RssLimitMb <= 0 || + GetPeakRSSMb() > static_cast(Options.RssLimitMb) / 2) { + EF->__sanitizer_purge_allocator(); + } + + LastAllocatorPurgeAttemptTime = system_clock::now(); +} + void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { const size_t kMaxSaneLen = 1 << 20; const size_t kMinDefaultLen = 4096; @@ -699,6 +718,8 @@ void Fuzzer::Loop(const Vector &CorpusDirs) { // Perform several mutations and runs. MutateAndTestOne(); + + PurgeAllocator(); } PrintStats("DONE ", "\n"); diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h index e57c7df5b..73953e154 100644 --- a/lib/fuzzer/FuzzerOptions.h +++ b/lib/fuzzer/FuzzerOptions.h @@ -54,6 +54,7 @@ struct FuzzingOptions { bool DumpCoverage = false; bool UseClangCoverage = false; bool DetectLeaks = true; + int PurgeAllocatorIntervalSec = 1; int UseFeatureFrequency = false; int TraceMalloc = 0; bool HandleAbrt = false; -- cgit v1.2.1 From ed5545d851416c54828787c615f8f87334ce855c Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Mon, 23 Oct 2017 23:24:33 +0000 Subject: [Sanitizers-libFuzzer] Addressing coding style issues. Summary: The result of clang-format and few manual changes (as prompted on D39155). Reviewers: vitalybuka Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39211 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316395 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 81 +++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 58e8168d1..d3ac4ce7e 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -135,10 +135,11 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, memset(BaseSha1, 0, sizeof(BaseSha1)); } -Fuzzer::~Fuzzer() { } +Fuzzer::~Fuzzer() {} void Fuzzer::AllocateCurrentUnitData() { - if (CurrentUnitData || MaxInputLen == 0) return; + if (CurrentUnitData || MaxInputLen == 0) + return; CurrentUnitData = new uint8_t[MaxInputLen]; } @@ -148,7 +149,8 @@ void Fuzzer::StaticDeathCallback() { } void Fuzzer::DumpCurrentUnit(const char *Prefix) { - if (!CurrentUnitData) return; // Happens when running individual inputs. + if (!CurrentUnitData) + return; // Happens when running individual inputs. MD.PrintMutationSequence(); Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); size_t UnitSize = CurrentUnitSize; @@ -201,7 +203,7 @@ void Fuzzer::CrashCallback() { Printf("SUMMARY: libFuzzer: deadly signal\n"); DumpCurrentUnit("crash-"); PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. + _Exit(Options.ErrorExitCode); // Stop right now. } void Fuzzer::ExitCallback() { @@ -216,11 +218,10 @@ void Fuzzer::ExitCallback() { _Exit(Options.ErrorExitCode); } - void Fuzzer::InterruptCallback() { Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); PrintFinalStats(); - _Exit(0); // Stop right now, don't perform any at-exit actions. + _Exit(0); // Stop right now, don't perform any at-exit actions. } NO_SANITIZE_MEMORY @@ -228,7 +229,8 @@ void Fuzzer::AlarmCallback() { assert(Options.UnitTimeoutSec > 0); // In Windows Alarm callback is executed by a different thread. #if !LIBFUZZER_WINDOWS - if (!InFuzzingThread()) return; + if (!InFuzzingThread()) + return; #endif if (!RunningCB) return; // We have not started running units yet. @@ -274,11 +276,11 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { if (size_t N = TPC.GetTotalPCCoverage()) Printf(" cov: %zd", N); if (size_t N = Corpus.NumFeatures()) - Printf( " ft: %zd", N); + Printf(" ft: %zd", N); if (!Corpus.empty()) { Printf(" corp: %zd", Corpus.NumActiveUnits()); if (size_t N = Corpus.SizeInBytes()) { - if (N < (1<<14)) + if (N < (1 << 14)) Printf("/%zdb", N); else if (N < (1 << 24)) Printf("/%zdKb", N >> 10); @@ -301,7 +303,8 @@ void Fuzzer::PrintFinalStats() { TPC.DumpCoverage(); if (Options.PrintCorpusStats) Corpus.PrintStats(); - if (!Options.PrintFinalStats) return; + if (!Options.PrintFinalStats) + return; size_t ExecPerSec = execPerSec(); Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); @@ -330,7 +333,8 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { if (!Options.ExitOnSrcPos.empty()) { static auto *PCsSet = new Set; auto HandlePC = [&](uintptr_t PC) { - if (!PCsSet->insert(PC).second) return; + if (!PCsSet->insert(PC).second) + return; std::string Descr = DescribePC("%F %L", PC + 1); if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { Printf("INFO: found line matching '%s', exiting.\n", @@ -350,7 +354,8 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { } void Fuzzer::RereadOutputCorpus(size_t MaxSize) { - if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; + if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) + return; Vector AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, &EpochOfLastReadOfOutputCorpus, MaxSize, @@ -388,7 +393,8 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, InputInfo *II) { - if (!Size) return false; + if (!Size) + return false; ExecuteCallback(Data, Size); @@ -512,11 +518,10 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { II->NumSuccessfullMutations++; MD.RecordSuccessfulMutationSequence(); - PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : - "NEW "); + PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW "); WriteToOutputCorpus(U); NumberOfNewUnitsAdded++; - CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. + CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. LastCorpusUpdateRun = TotalNumberOfRuns; LastCorpusUpdateTime = system_clock::now(); } @@ -525,19 +530,23 @@ void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { // executed before calling this function. void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, bool DuringInitialCorpusExecution) { - if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. - if (!Options.DetectLeaks) return; + if (!HasMoreMallocsThanFrees) + return; // mallocs==frees, a leak is unlikely. + if (!Options.DetectLeaks) + return; if (!DuringInitialCorpusExecution && - TotalNumberOfRuns >= Options.MaxNumberOfRuns) return; + TotalNumberOfRuns >= Options.MaxNumberOfRuns) + return; if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || !(EF->__lsan_do_recoverable_leak_check)) - return; // No lsan. + return; // No lsan. // Run the target once again, but with lsan disabled so that if there is // a real leak we do not report it twice. EF->__lsan_disable(); ExecuteCallback(Data, Size); EF->__lsan_enable(); - if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. + if (!HasMoreMallocsThanFrees) + return; // a leak is unlikely. if (NumberOfLeakDetectionAttempts++ > 1000) { Options.DetectLeaks = false; Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" @@ -558,7 +567,7 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, CurrentUnitSize = Size; DumpCurrentUnit("leak-"); PrintFinalStats(); - _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. + _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. } } @@ -599,20 +608,16 @@ void Fuzzer::MutateAndTestOne() { } void Fuzzer::PurgeAllocator() { - if (Options.PurgeAllocatorIntervalSec < 0 || - !EF->__sanitizer_purge_allocator) { + if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator) return; - } if (duration_cast(system_clock::now() - - LastAllocatorPurgeAttemptTime).count() < - Options.PurgeAllocatorIntervalSec) { + LastAllocatorPurgeAttemptTime) + .count() < Options.PurgeAllocatorIntervalSec) return; - } if (Options.RssLimitMb <= 0 || - GetPeakRSSMb() > static_cast(Options.RssLimitMb) / 2) { + GetPeakRSSMb() > static_cast(Options.RssLimitMb) / 2) EF->__sanitizer_purge_allocator(); - } LastAllocatorPurgeAttemptTime = system_clock::now(); } @@ -671,7 +676,6 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector &CorpusDirs) { } } - PrintStats("INITED"); if (Corpus.empty()) { Printf("ERROR: no interesting inputs were found. " @@ -696,13 +700,14 @@ void Fuzzer::Loop(const Vector &CorpusDirs) { } if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) break; - if (TimedOut()) break; + if (TimedOut()) + break; // Update TmpMaxMutationLen if (Options.ExperimentalLenControl) { if (TmpMaxMutationLen < MaxMutationLen && - (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && - duration_cast(Now - LastCorpusUpdateTime).count() >= 1)) { + (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && + duration_cast(Now - LastCorpusUpdateTime).count() >= 1)) { LastCorpusUpdateRun = TotalNumberOfRuns; LastCorpusUpdateTime = Now; TmpMaxMutationLen = @@ -727,7 +732,8 @@ void Fuzzer::Loop(const Vector &CorpusDirs) { } void Fuzzer::MinimizeCrashLoop(const Unit &U) { - if (U.size() <= 1) return; + if (U.size() <= 1) + return; while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { MD.StartMutationSequence(); memcpy(CurrentUnitData, U.data(), U.size()); @@ -756,7 +762,8 @@ void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { if (Data[i] != OtherData[i]) break; Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " - "offset %zd\n", GetPid(), Size, OtherSize, i); + "offset %zd\n", + GetPid(), Size, OtherSize, i); DumpCurrentUnit("mismatch-"); Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); PrintFinalStats(); @@ -779,4 +786,4 @@ void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { assert(fuzzer::F); fuzzer::F->AnnounceOutput(Data, Size); } -} // extern "C" +} // extern "C" -- cgit v1.2.1 From 6c9ee8c61a70980db9abd1cc481473b11eb206ef Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 24 Oct 2017 01:39:59 +0000 Subject: [XRay][compiler-rt] Remove C++ STL from the buffer queue implementation Summary: This change removes the dependency on C++ standard library types/functions in the implementation of the buffer queue. This is an incremental step in resolving llvm.org/PR32274. Reviewers: dblaikie, pelikan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39175 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316406 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 60 +++++++++++++++++++++++------------------- lib/xray/xray_buffer_queue.h | 61 +++++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index 61a0add0e..c42bba322 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -13,29 +13,30 @@ // //===----------------------------------------------------------------------===// #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 -#include -#include - using namespace __xray; using namespace __sanitizer; -BufferQueue::BufferQueue(std::size_t B, std::size_t N, bool &Success) - : BufferSize(B), Buffers(new std::tuple[N]()), - BufferCount(N), Finalizing{0}, OwnedBuffers(new void *[N]()), - Next(Buffers.get()), First(Buffers.get()), LiveBuffers(0) { +BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) + : BufferSize(B), + Buffers(new BufferRep[N]()), + BufferCount(N), + Finalizing{0}, + OwnedBuffers(new void *[N]()), + Next(Buffers), + First(Buffers), + LiveBuffers(0) { for (size_t i = 0; i < N; ++i) { auto &T = Buffers[i]; - void *Tmp = malloc(BufferSize); + void *Tmp = InternalAlloc(BufferSize); if (Tmp == nullptr) { Success = false; return; } - auto &Buf = std::get<0>(T); - std::get<1>(T) = false; + auto &Buf = T.Buffer; Buf.Buffer = Tmp; Buf.Size = B; OwnedBuffers[i] = Tmp; @@ -47,39 +48,42 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) return ErrorCode::QueueFinalizing; __sanitizer::SpinMutexLock Guard(&Mutex); - if (LiveBuffers == BufferCount) - return ErrorCode::NotEnoughMemory; + if (LiveBuffers == BufferCount) return ErrorCode::NotEnoughMemory; auto &T = *Next; - auto &B = std::get<0>(T); + auto &B = T.Buffer; Buf = B; ++LiveBuffers; - if (++Next == (Buffers.get() + BufferCount)) - Next = Buffers.get(); + if (++Next == (Buffers + BufferCount)) Next = Buffers; return ErrorCode::Ok; } BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { // Blitz through the buffers array to find the buffer. - if (std::none_of(OwnedBuffers.get(), OwnedBuffers.get() + BufferCount, - [&Buf](void *P) { return P == Buf.Buffer; })) - return ErrorCode::UnrecognizedBuffer; + bool Found = false; + for (auto I = OwnedBuffers, E = OwnedBuffers + BufferCount; I != E; ++I) { + if (*I == Buf.Buffer) { + Found = true; + break; + } + } + if (!Found) return ErrorCode::UnrecognizedBuffer; + __sanitizer::SpinMutexLock Guard(&Mutex); // This points to a semantic bug, we really ought to not be releasing more // buffers than we actually get. - if (LiveBuffers == 0) - return ErrorCode::NotEnoughMemory; + if (LiveBuffers == 0) return ErrorCode::NotEnoughMemory; // Now that the buffer has been released, we mark it as "used". - *First = std::make_tuple(Buf, true); + First->Buffer = Buf; + First->Used = true; Buf.Buffer = nullptr; Buf.Size = 0; --LiveBuffers; - if (++First == (Buffers.get() + BufferCount)) - First = Buffers.get(); + if (++First == (Buffers + BufferCount)) First = Buffers; return ErrorCode::Ok; } @@ -92,9 +96,11 @@ BufferQueue::ErrorCode BufferQueue::finalize() { } BufferQueue::~BufferQueue() { - for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { auto &T = *I; - auto &Buf = std::get<0>(T); - free(Buf.Buffer); + auto &Buf = T.Buffer; + InternalFree(Buf.Buffer); } + delete[] Buffers; + delete[] OwnedBuffers; } diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 05e22eece..1634a21e6 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -15,11 +15,9 @@ #ifndef XRAY_BUFFER_QUEUE_H #define XRAY_BUFFER_QUEUE_H +#include #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_mutex.h" -#include -#include -#include namespace __xray { @@ -29,38 +27,45 @@ namespace __xray { /// the "flight data recorder" (FDR) mode to support ongoing XRay function call /// trace collection. class BufferQueue { -public: + public: struct Buffer { void *Buffer = nullptr; size_t Size = 0; }; -private: + private: + struct BufferRep { + // The managed buffer. + Buffer Buffer; + + // This is true if the buffer has been returned to the available queue, and + // is considered "used" by another thread. + bool Used = false; + }; + // Size of each individual Buffer. size_t BufferSize; - // We use a bool to indicate whether the Buffer has been used in this - // freelist implementation. - std::unique_ptr[]> Buffers; + BufferRep *Buffers; size_t BufferCount; __sanitizer::SpinMutex Mutex; __sanitizer::atomic_uint8_t Finalizing; // Pointers to buffers managed/owned by the BufferQueue. - std::unique_ptr OwnedBuffers; + void **OwnedBuffers; // Pointer to the next buffer to be handed out. - std::tuple *Next; + BufferRep *Next; // Pointer to the entry in the array where the next released buffer will be // placed. - std::tuple *First; + BufferRep *First; // Count of buffers that have been handed out through 'getBuffer'. size_t LiveBuffers; -public: + public: enum class ErrorCode : unsigned { Ok, NotEnoughMemory, @@ -71,16 +76,16 @@ public: static const char *getErrorString(ErrorCode E) { switch (E) { - case ErrorCode::Ok: - return "(none)"; - case ErrorCode::NotEnoughMemory: - return "no available buffers in the queue"; - case ErrorCode::QueueFinalizing: - return "queue already finalizing"; - case ErrorCode::UnrecognizedBuffer: - return "buffer being returned not owned by buffer queue"; - case ErrorCode::AlreadyFinalized: - return "queue already finalized"; + case ErrorCode::Ok: + return "(none)"; + case ErrorCode::NotEnoughMemory: + return "no available buffers in the queue"; + case ErrorCode::QueueFinalizing: + return "queue already finalizing"; + case ErrorCode::UnrecognizedBuffer: + return "buffer being returned not owned by buffer queue"; + case ErrorCode::AlreadyFinalized: + return "queue already finalized"; } return "unknown error"; } @@ -131,12 +136,12 @@ public: /// Applies the provided function F to each Buffer in the queue, only if the /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a /// releaseBuffer(...) operation). - template void apply(F Fn) { + template + void apply(F Fn) { __sanitizer::SpinMutexLock G(&Mutex); - for (auto I = Buffers.get(), E = Buffers.get() + BufferCount; I != E; ++I) { + for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { const auto &T = *I; - if (std::get<1>(T)) - Fn(std::get<0>(T)); + if (T.Used) Fn(T.Buffer); } } @@ -144,6 +149,6 @@ public: ~BufferQueue(); }; -} // namespace __xray +} // namespace __xray -#endif // XRAY_BUFFER_QUEUE_H +#endif // XRAY_BUFFER_QUEUE_H -- cgit v1.2.1 From 9ec9a9fd8b3abfc1cd978d95c8be40785d40ee17 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 24 Oct 2017 02:36:32 +0000 Subject: [XRay][compiler-rt] Fixup shadowing Follow-up to D39175. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316409 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 6 +++--- lib/xray/xray_buffer_queue.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index c42bba322..d6ba7a71c 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -78,7 +78,7 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { if (LiveBuffers == 0) return ErrorCode::NotEnoughMemory; // Now that the buffer has been released, we mark it as "used". - First->Buffer = Buf; + First->Buff = Buf; First->Used = true; Buf.Buffer = nullptr; Buf.Size = 0; @@ -98,8 +98,8 @@ BufferQueue::ErrorCode BufferQueue::finalize() { BufferQueue::~BufferQueue() { for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { auto &T = *I; - auto &Buf = T.Buffer; - InternalFree(Buf.Buffer); + auto &Buf = T.Buff; + InternalFree(Buf.Buff); } delete[] Buffers; delete[] OwnedBuffers; diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 1634a21e6..7bad02699 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -36,7 +36,7 @@ class BufferQueue { private: struct BufferRep { // The managed buffer. - Buffer Buffer; + Buffer Buff; // This is true if the buffer has been returned to the available queue, and // is considered "used" by another thread. -- cgit v1.2.1 From e6931d5834fef14f661e8ca88563e3a2beb6feee Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 24 Oct 2017 02:43:49 +0000 Subject: [XRay][compiler-rt] More fixups. Follow-up to D39175. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316410 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_buffer_queue.cc | 6 +++--- lib/xray/xray_buffer_queue.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc index d6ba7a71c..34bf3cfd8 100644 --- a/lib/xray/xray_buffer_queue.cc +++ b/lib/xray/xray_buffer_queue.cc @@ -36,7 +36,7 @@ BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) Success = false; return; } - auto &Buf = T.Buffer; + auto &Buf = T.Buff; Buf.Buffer = Tmp; Buf.Size = B; OwnedBuffers[i] = Tmp; @@ -51,7 +51,7 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { if (LiveBuffers == BufferCount) return ErrorCode::NotEnoughMemory; auto &T = *Next; - auto &B = T.Buffer; + auto &B = T.Buff; Buf = B; ++LiveBuffers; @@ -99,7 +99,7 @@ BufferQueue::~BufferQueue() { for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { auto &T = *I; auto &Buf = T.Buff; - InternalFree(Buf.Buff); + InternalFree(Buf.Buffer); } delete[] Buffers; delete[] OwnedBuffers; diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h index 7bad02699..9257657a3 100644 --- a/lib/xray/xray_buffer_queue.h +++ b/lib/xray/xray_buffer_queue.h @@ -141,7 +141,7 @@ class BufferQueue { __sanitizer::SpinMutexLock G(&Mutex); for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { const auto &T = *I; - if (T.Used) Fn(T.Buffer); + if (T.Used) Fn(T.Buff); } } -- cgit v1.2.1 From e9b5a2559d63c029f8af63870ddd1892cfe019f3 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 24 Oct 2017 18:22:07 +0000 Subject: [asan] Add more x86 prologue decodings to handle x64 VC 2017 CRT Fixes atoi and strtol interception. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316482 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception_win.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index 3e593c98f..23402e555 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -553,7 +553,10 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x246c8948: // 48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp case 0x245c8948: // 48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx case 0x24748948: // 48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi + case 0x244C8948: // 48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx return 5; + case 0x24648348: // 48 83 64 24 XX : and QWORD PTR [rsp + XX], YY + return 6; } #else -- cgit v1.2.1 From f49c63699ef9867eb0127ee4a66dd5508870688d Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 24 Oct 2017 19:45:59 +0000 Subject: On FreeBSD, skip the first entry in the dl_iterate_phdr list. Summary: Similar to NetBSD, in FreeBSD, the first returned entry when callbacks are done via dl_iterate_phdr will return the main program. Ignore that entry when checking that the dynamic ASan lib is loaded first. Reviewers: eugenis, krytarowski, emaste, joerg Reviewed By: eugenis, krytarowski Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D39253 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316487 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 9ebfea254..a949a9888 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -105,7 +105,7 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) return 0; -#if SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD // Ignore first entry (the main program) char **p = (char **)data; if (!(*p)) { -- cgit v1.2.1 From 826256f983123262c717265dcb991d7ea3bfbcdc Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Wed, 25 Oct 2017 05:19:20 +0000 Subject: [XRay][compiler-rt][NFC] Clean up xray log files before running test Improves the test behaviour in the face of failure. Without this change the fdr-single-thread.cc test may leave around artefacts of a previous failing run since the cleanup doesn't happen if any of the intermediary steps fail. Non-functional change. Subscribers: llvm-commits git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316548 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/xray/TestCases/Linux/fdr-single-thread.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/xray/TestCases/Linux/fdr-single-thread.cc b/test/xray/TestCases/Linux/fdr-single-thread.cc index 30d834e57..dd50f485f 100644 --- a/test/xray/TestCases/Linux/fdr-single-thread.cc +++ b/test/xray/TestCases/Linux/fdr-single-thread.cc @@ -1,4 +1,5 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm fdr-logging-1thr-* || true // RUN: XRAY_OPTIONS=XRAY_OPTIONS="verbosity=1 patch_premain=true \ // RUN: xray_naive_log=false xray_fdr_log=true \ // RUN: xray_fdr_log_func_duration_threshold_us=0 \ -- cgit v1.2.1 From 6f634ed9c3f52ef54e4e294b2f8765dd1bdce9f2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 25 Oct 2017 08:05:13 +0000 Subject: [tsan] Fix warnings in tsan_interceptors.cc from expansion of variadic macros C99 technically requires the rest arguments to be used in C variadic macros. This presents a problem with the macro SCOPED_TSAN_INTERCEPTOR when func takes no arguments. This happens with the function pause. Like other void argument functions, we pass in a fake argument to avoid this warning. Author: Alex Langford (xiaobai) Reviewed in: https://reviews.llvm.org/D39151 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316558 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 82a7f371a..908378ff4 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -371,9 +371,9 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { return res; } -TSAN_INTERCEPTOR(int, pause) { - SCOPED_TSAN_INTERCEPTOR(pause); - return BLOCK_REAL(pause)(); +TSAN_INTERCEPTOR(int, pause, int fake) { + SCOPED_TSAN_INTERCEPTOR(pause, fake); + return BLOCK_REAL(pause)(fake); } // The sole reason tsan wraps atexit callbacks is to establish synchronization -- cgit v1.2.1 From d8ac58ba4113c97e6a33e063e03bd907cb82ea47 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 25 Oct 2017 16:54:12 +0000 Subject: [asan] Don't print rows of shadow bytes outside shadow memory Summary: They might not be mapped on some platforms such as Win64. In particular, this happens if the user address is null. There will not be any shadow memory 5*16 bytes before the user address. This happens on Win64 in the error_report_callback.cc test case. It's not clear why this isn't a problem on Linux as well. Fixes PR35058 Reviewers: vitalybuka Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D39260 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316589 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_errors.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index d42a86850..dee666d54 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -422,9 +422,14 @@ static void PrintShadowMemoryForAddress(uptr addr) { InternalScopedString str(4096 * 8); str.append("Shadow bytes around the buggy address:\n"); for (int i = -5; i <= 5; i++) { + uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row; + // Skip rows that would be outside the shadow range. This can happen when + // the user address is near the bottom, top, or shadow gap of the address + // space. + if (!AddrIsInShadow(row_shadow_addr)) continue; const char *prefix = (i == 0) ? "=>" : " "; - PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row), - (u8 *)shadow_addr, n_bytes_per_row); + PrintShadowBytes(&str, prefix, (u8 *)row_shadow_addr, (u8 *)shadow_addr, + n_bytes_per_row); } if (flags()->print_legend) PrintLegend(&str); Printf("%s", str.data()); -- cgit v1.2.1 From 16cd8b12c079582001d7adc5e25de51927a79463 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 25 Oct 2017 17:09:05 +0000 Subject: Add NetBSD improvements in sanitizers Summary: Changes: * Add initial msan stub support. * Handle NetBSD specific pthread_setname_np(3). * NetBSD supports __attribute__((tls_model("initial-exec"))), define it in SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE. * Add ReExec() specific bits for NetBSD. * Simplify code and add syscall64 and syscall_ptr for !NetBSD. * Correct bunch of syscall wrappers for NetBSD. * Disable test/tsan/map32bit on NetBSD as not applicable. * Port test/tsan/strerror_r to a POSIX-compliant OSes. * Disable __libc_stack_end on NetBSD. * Disable ReadNullSepFileToArray() on NetBSD. * Define struct_ElfW_Phdr_sz, detected missing symbol by msan. * Change type of __sanitizer_FILE from void to char. This helps to reuse this type as an array. Long term it will be properly implemented along with SANITIZER_HAS_STRUCT_FILE setting to 1. * Add initial NetBSD support in lib/tsan/go/buildgo.sh. * Correct referencing stdout and stderr in tsan_interceptors.cc on NetBSD. * Document NetBSD x86_64 specific virtual memory layout in tsan_platform.h. * Port tests/rtl/tsan_test_util_posix.cc to NetBSD. * Enable NetBSD tests in test/msan/lit.cfg. * Enable NetBSD tests in test/tsan/lit.cfg. Sponsored by Reviewers: joerg, vitalybuka, eugenis, kcc, dvyukov Reviewed By: dvyukov Subscribers: #sanitizers, llvm-commits, kubamracek Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D39124 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316591 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 38 +++---- lib/msan/msan_linux.cc | 6 +- .../sanitizer_common_interceptors.inc | 13 ++- lib/sanitizer_common/sanitizer_internal_defs.h | 2 +- lib/sanitizer_common/sanitizer_linux.cc | 122 ++++++++++----------- .../sanitizer_platform_limits_netbsd.cc | 2 + .../sanitizer_platform_limits_netbsd.h | 2 +- lib/sanitizer_common/sanitizer_syscall_generic.inc | 4 + lib/tsan/go/buildgo.sh | 15 +++ lib/tsan/rtl/tsan_interceptors.cc | 14 ++- lib/tsan/rtl/tsan_platform.h | 13 +++ lib/tsan/rtl/tsan_platform_linux.cc | 5 +- lib/tsan/tests/rtl/tsan_test_util_posix.cc | 4 +- test/msan/lit.cfg | 3 +- test/tsan/lit.cfg | 3 +- test/tsan/map32bit.cc | 5 +- test/tsan/strerror_r.cc | 3 +- 17 files changed, 152 insertions(+), 102 deletions(-) diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 4bf7fcbee..d14ebb30d 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -118,7 +118,7 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { #define CHECK_UNPOISONED_STRING(x, n) \ CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n)) -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { ENSURE_MSAN_INITED(); @@ -168,7 +168,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; return msan_memalign(alignment, size, &stack); @@ -196,7 +196,7 @@ INTERCEPTOR(void *, valloc, SIZE_T size) { return msan_valloc(size, &stack); } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void *, pvalloc, SIZE_T size) { GET_MALLOC_STACK_TRACE; return msan_pvalloc(size, &stack); @@ -212,7 +212,7 @@ INTERCEPTOR(void, free, void *ptr) { MsanDeallocate(&stack, ptr); } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void, cfree, void *ptr) { GET_MALLOC_STACK_TRACE; if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return; @@ -227,7 +227,7 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { return __sanitizer_get_allocated_size(ptr); } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD // This function actually returns a struct by value, but we can't unpoison a // temporary! The following is equivalent on all supported platforms but // aarch64 (which uses a different register for sret value). We have a test @@ -246,7 +246,7 @@ INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) { #define MSAN_MAYBE_INTERCEPT_MALLINFO #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, mallopt, int cmd, int value) { return -1; } @@ -255,7 +255,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) { #define MSAN_MAYBE_INTERCEPT_MALLOPT #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void, malloc_stats, void) { // FIXME: implement, but don't call REAL(malloc_stats)! } @@ -308,7 +308,7 @@ INTERCEPTOR(char *, strdup, char *src) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(char *, __strdup, char *src) { ENSURE_MSAN_INITED(); GET_STORE_STACK_TRACE; @@ -473,7 +473,7 @@ INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format, INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc); } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format, __sanitizer_tm *tm, void *loc) { INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm, @@ -495,7 +495,7 @@ INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, loc); } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, __sanitizer_tm *tm, void *loc) { INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm, @@ -614,7 +614,7 @@ INTERCEPTOR(int, putenv, char *string) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) { ENSURE_MSAN_INITED(); int res = REAL(__fxstat)(magic, fd, buf); @@ -627,7 +627,7 @@ INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) { #define MSAN_MAYBE_INTERCEPT___FXSTAT #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) { ENSURE_MSAN_INITED(); int res = REAL(__fxstat64)(magic, fd, buf); @@ -640,7 +640,7 @@ INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) { #define MSAN_MAYBE_INTERCEPT___FXSTAT64 #endif -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) { ENSURE_MSAN_INITED(); int res = REAL(fstatat)(fd, pathname, buf, flags); @@ -659,7 +659,7 @@ INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf, # define MSAN_INTERCEPT_FSTATAT INTERCEPT_FUNCTION(__fxstatat) #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf, int flags) { ENSURE_MSAN_INITED(); @@ -706,7 +706,7 @@ INTERCEPTOR(char *, fgets, char *s, int size, void *stream) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) { ENSURE_MSAN_INITED(); char *res = REAL(fgets_unlocked)(s, size, stream); @@ -729,7 +729,7 @@ INTERCEPTOR(int, getrlimit, int resource, void *rlim) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, getrlimit64, int resource, void *rlim) { if (msan_init_is_running) return REAL(getrlimit64)(resource, rlim); ENSURE_MSAN_INITED(); @@ -805,7 +805,7 @@ INTERCEPTOR(int, gethostname, char *name, SIZE_T len) { return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents, int timeout) { ENSURE_MSAN_INITED(); @@ -820,7 +820,7 @@ INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents, #define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents, int timeout, void *sigmask) { ENSURE_MSAN_INITED(); @@ -909,7 +909,7 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, return res; } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { ENSURE_MSAN_INITED(); diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc index 0a687f620..a1191a100 100644 --- a/lib/msan/msan_linux.cc +++ b/lib/msan/msan_linux.cc @@ -9,11 +9,11 @@ // // This file is a part of MemorySanitizer. // -// Linux- and FreeBSD-specific code. +// Linux-, NetBSD- and FreeBSD-specific code. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD #include "msan.h" #include "msan_thread.h" @@ -213,4 +213,4 @@ void MsanTSDDtor(void *tsd) { } // namespace __msan -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 21a405ae4..321126c10 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4405,7 +4405,7 @@ INTERCEPTOR(char *, tempnam, char *dir, char *pfx) { #define INIT_TEMPNAM #endif -#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP +#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && !SANITIZER_NETBSD INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name); @@ -4414,6 +4414,17 @@ INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { return REAL(pthread_setname_np)(thread, name); } #define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); +#elif SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && SANITIZER_NETBSD +INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name, void *arg) { + void *ctx; + char newname[32]; // PTHREAD_MAX_NAMELEN_NP=32 + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name, arg); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + internal_snprintf(newname, sizeof(newname), name, arg); + COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, newname); + return REAL(pthread_setname_np)(thread, name, arg); +} +#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); #else #define INIT_PTHREAD_SETNAME_NP #endif diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index 003a3c7a9..dcc8db414 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -36,7 +36,7 @@ #endif // TLS is handled differently on different platforms -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_NETBSD # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ __attribute__((tls_model("initial-exec"))) thread_local #else diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 48c53d46d..6ea185817 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -87,7 +87,9 @@ extern char **environ; // provided by crt1 #include // For NAME_MAX #include extern char **environ; // provided by crt1 -#endif // SANITIZER_NETBSD +#include +extern struct ps_strings *__ps_strings; +#endif // SANITIZER_NETBSD #if !SANITIZER_ANDROID #include @@ -174,11 +176,11 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, #endif // !SANITIZER_S390 uptr internal_munmap(void *addr, uptr length) { - return internal_syscall(SYSCALL(munmap), (uptr)addr, length); + return internal_syscall_ptr(SYSCALL(munmap), (uptr)addr, length); } int internal_mprotect(void *addr, uptr length, int prot) { - return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); + return internal_syscall_ptr(SYSCALL(mprotect), (uptr)addr, length, prot); } uptr internal_close(fd_t fd) { @@ -189,7 +191,7 @@ uptr internal_open(const char *filename, int flags) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); #else - return internal_syscall(SYSCALL(open), (uptr)filename, flags); + return internal_syscall_ptr(SYSCALL(open), (uptr)filename, flags); #endif } @@ -198,36 +200,28 @@ uptr internal_open(const char *filename, int flags, u32 mode) { return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, mode); #else - return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); + return internal_syscall_ptr(SYSCALL(open), (uptr)filename, flags, mode); #endif } uptr internal_read(fd_t fd, void *buf, uptr count) { sptr res; -#if SANITIZER_NETBSD - HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(read), fd, buf, count)); -#else - HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, + HANDLE_EINTR(res, (sptr)internal_syscall_ptr(SYSCALL(read), fd, (uptr)buf, count)); -#endif return res; } uptr internal_write(fd_t fd, const void *buf, uptr count) { sptr res; -#if SANITIZER_NETBSD - HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(write), fd, buf, count)); -#else - HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, + HANDLE_EINTR(res, (sptr)internal_syscall_ptr(SYSCALL(write), fd, (uptr)buf, count)); -#endif return res; } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; #if SANITIZER_NETBSD - HANDLE_EINTR(res, internal_syscall(SYSCALL(ftruncate), fd, 0, (s64)size)); + HANDLE_EINTR(res, internal_syscall64(SYSCALL(ftruncate), fd, 0, (s64)size)); #else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); @@ -304,7 +298,7 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { uptr internal_stat(const char *path, void *buf) { #if SANITIZER_FREEBSD || SANITIZER_NETBSD - return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, + return internal_syscall_ptr(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, @@ -329,7 +323,7 @@ uptr internal_stat(const char *path, void *buf) { uptr internal_lstat(const char *path, void *buf) { #if SANITIZER_NETBSD - return internal_syscall(SYSCALL(lstat), path, buf); + return internal_syscall_ptr(SYSCALL(lstat), path, buf); #elif SANITIZER_FREEBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); @@ -355,15 +349,15 @@ uptr internal_lstat(const char *path, void *buf) { } uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_NETBSD -# if SANITIZER_MIPS64 +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +# if SANITIZER_MIPS64 && !SANITIZER_NETBSD // For mips64, fstat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); kernel_stat_to_stat(&kbuf, (struct stat *)buf); return res; # else - return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); + return internal_syscall_ptr(SYSCALL(fstat), fd, (uptr)buf); # endif #else struct stat64 buf64; @@ -389,13 +383,11 @@ uptr internal_dup2(int oldfd, int newfd) { } uptr internal_readlink(const char *path, char *buf, uptr bufsize) { -#if SANITIZER_NETBSD - return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize); -#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, bufsize); #else - return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); + return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize); #endif } @@ -403,7 +395,7 @@ uptr internal_unlink(const char *path) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); #else - return internal_syscall(SYSCALL(unlink), (uptr)path); + return internal_syscall_ptr(SYSCALL(unlink), (uptr)path); #endif } @@ -412,7 +404,7 @@ uptr internal_rename(const char *oldpath, const char *newpath) { return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath); #else - return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); + return internal_syscall_ptr(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); #endif } @@ -433,14 +425,14 @@ unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; ts.tv_sec = 1; ts.tv_nsec = 0; - int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts); + int res = internal_syscall_ptr(SYSCALL(nanosleep), &ts, &ts); if (res) return ts.tv_sec; return 0; } uptr internal_execve(const char *filename, char *const argv[], char *const envp[]) { - return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, + return internal_syscall_ptr(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } @@ -474,11 +466,7 @@ u64 NanoTime() { kernel_timeval tv; #endif internal_memset(&tv, 0, sizeof(tv)); -#if SANITIZER_NETBSD - internal_syscall_ptr(SYSCALL(gettimeofday), &tv, NULL); -#else - internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0); -#endif + internal_syscall_ptr(SYSCALL(gettimeofday), &tv, 0); return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } @@ -524,13 +512,13 @@ const char *GetEnv(const char *name) { #endif } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD extern "C" { SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } #endif -#if !SANITIZER_GO && !SANITIZER_FREEBSD +#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; @@ -556,7 +544,22 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, #endif static void GetArgsAndEnv(char ***argv, char ***envp) { -#if !SANITIZER_FREEBSD +#if SANITIZER_FREEBSD + // On FreeBSD, retrieving the argument and environment arrays is done via the + // kern.ps_strings sysctl, which returns a pointer to a structure containing + // this information. See also . + ps_strings *pss; + size_t sz = sizeof(pss); + if (sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { + Printf("sysctl kern.ps_strings failed\n"); + Die(); + } + *argv = pss->ps_argvstr; + *envp = pss->ps_envstr; +#elif SANITIZER_NETBSD + *argv = __ps_strings->ps_argvstr; + *argv = __ps_strings->ps_envstr; +#else #if !SANITIZER_GO if (&__libc_stack_end) { #endif @@ -571,18 +574,6 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); } #endif -#else - // On FreeBSD, retrieving the argument and environment arrays is done via the - // kern.ps_strings sysctl, which returns a pointer to a structure containing - // this information. See also . - ps_strings *pss; - size_t sz = sizeof(pss); - if (sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { - Printf("sysctl kern.ps_strings failed\n"); - Die(); - } - *argv = pss->ps_argvstr; - *envp = pss->ps_envstr; #endif } @@ -594,8 +585,22 @@ char **GetArgv() { void ReExec() { char **argv, **envp; + const char *pathname = "/proc/self/exe"; + +#if SANITIZER_NETBSD + static const int name[] = { + CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME, + }; + char path[400]; + size_t len; + + len = sizeof(path); + if (sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1) + pathname = path; +#endif + GetArgsAndEnv(&argv, &envp); - uptr rv = internal_execve("/proc/self/exe", argv, envp); + uptr rv = internal_execve(pathname, argv, envp); int rverrno; CHECK_EQ(internal_iserror(rv, &rverrno), true); Printf("execve failed, errno %d\n", rverrno); @@ -698,13 +703,8 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data) { } uptr internal_waitpid(int pid, int *status, int options) { -#if SANITIZER_NETBSD - return internal_syscall(SYSCALL(wait4), pid, status, options, - NULL /* rusage */); -#else - return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, + return internal_syscall_ptr(SYSCALL(wait4), pid, (uptr)status, options, 0 /* rusage */); -#endif } uptr internal_getpid() { @@ -716,14 +716,12 @@ uptr internal_getppid() { } uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { -#if SANITIZER_NETBSD - return internal_syscall(SYSCALL(getdents), fd, dirp, (uptr)count); -#elif SANITIZER_FREEBSD +#if SANITIZER_FREEBSD return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); #else - return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); + return internal_syscall_ptr(SYSCALL(getdents), fd, (uptr)dirp, count); #endif } @@ -742,7 +740,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { #endif uptr internal_sigaltstack(const void *ss, void *oss) { - return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); + return internal_syscall_ptr(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } int internal_fork() { @@ -824,7 +822,7 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) { uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { #if SANITIZER_FREEBSD || SANITIZER_NETBSD - return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); + return internal_syscall_ptr(SYSCALL(sigprocmask), how, set, oldset); #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc index 3be1d371f..342bd0825 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -128,6 +128,8 @@ uptr __sanitizer_in_addr_sz(int af) { return 0; } +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + int glob_nomatch = GLOB_NOMATCH; int glob_altdirfunc = GLOB_ALTDIRFUNC; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h index fe12cd2a5..d2f3a652b 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -313,7 +313,7 @@ struct __sanitizer_wordexp_t { uptr we_nbytes; }; -typedef void __sanitizer_FILE; +typedef char __sanitizer_FILE; #define SANITIZER_HAS_STRUCT_FILE 0 extern int shmctl_ipc_stat; diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc index b1a5941a5..138d5ca90 100644 --- a/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -43,8 +43,12 @@ # endif #elif defined(__x86_64__) && (SANITIZER_FREEBSD || SANITIZER_MAC) # define internal_syscall __syscall +# define internal_syscall64 __syscall +# define internal_syscall_ptr __syscall # else # define internal_syscall syscall +# define internal_syscall64 syscall +# define internal_syscall_ptr syscall #endif bool internal_iserror(uptr retval, int *rverrno) { diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index c27b72afe..62ff0fc38 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -68,6 +68,21 @@ elif [ "`uname -a | grep FreeBSD`" != "" ]; then ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc " +elif [ "`uname -a | grep NetBSD`" != "" ]; then + SUFFIX="netbsd_amd64" + OSCFLAGS="-fno-strict-aliasing -fPIC -Werror" + OSLDFLAGS="-lpthread -fPIC -fpie" + SRCS=" + $SRCS + ../rtl/tsan_platform_linux.cc + ../../sanitizer_common/sanitizer_posix.cc + ../../sanitizer_common/sanitizer_posix_libcdep.cc + ../../sanitizer_common/sanitizer_procmaps_common.cc + ../../sanitizer_common/sanitizer_procmaps_freebsd.cc + ../../sanitizer_common/sanitizer_linux.cc + ../../sanitizer_common/sanitizer_linux_libcdep.cc + ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc + " elif [ "`uname -a | grep Darwin`" != "" ]; then SUFFIX="darwin_amd64" OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -isysroot $(xcodebuild -version -sdk macosx Path) -mmacosx-version-min=10.7" diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 908378ff4..79e243aef 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -43,8 +43,16 @@ using namespace __tsan; // NOLINT #if SANITIZER_NETBSD #define dirfd(dirp) (*(int *)(dirp)) #define fileno_unlocked fileno -#define stdout __sF[1] -#define stderr __sF[2] + +#if _LP64 +#define __sF_size 152 +#else +#define __sF_size 88 +#endif + +#define stdout ((char*)&__sF + (__sF_size * 1)) +#define stderr ((char*)&__sF + (__sF_size * 2)) + #endif #if SANITIZER_ANDROID @@ -99,7 +107,7 @@ extern "C" int dirfd(void *dirp); extern "C" int mallopt(int param, int value); #endif #if SANITIZER_NETBSD -extern __sanitizer_FILE **__sF; +extern __sanitizer_FILE __sF[]; #else extern __sanitizer_FILE *stdout, *stderr; #endif diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index bea1daba3..4b9771359 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -42,6 +42,19 @@ C/C++ on linux/x86_64 and freebsd/x86_64 7b00 0000 0000 - 7c00 0000 0000: heap 7c00 0000 0000 - 7e80 0000 0000: - 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack + +C/C++ on netbsd/amd64 can reuse the same mapping: + * The address space starts from 0x1000 (option with 0x0) and ends with + 0x7f7ffffff000. + * LoAppMem-kHeapMemEnd can be reused as it is. + * No VDSO support. + * No MidAppMem region. + * No additional HeapMem region. + * HiAppMem contains the stack, loader, shared libraries and heap. + * Stack on NetBSD/amd64 has prereserved 128MB. + * Heap grows downwards (top-down). + * ASLR must be disabled per-process or globally. + */ struct Mapping { static const uptr kMetaShadowBeg = 0x300000000000ull; diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index ead1e5704..216eef93c 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -14,11 +14,12 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_FREEBSD +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" @@ -401,4 +402,4 @@ void cur_thread_finalize() { } // namespace __tsan -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD diff --git a/lib/tsan/tests/rtl/tsan_test_util_posix.cc b/lib/tsan/tests/rtl/tsan_test_util_posix.cc index 834a271aa..d00e26dd5 100644 --- a/lib/tsan/tests/rtl/tsan_test_util_posix.cc +++ b/lib/tsan/tests/rtl/tsan_test_util_posix.cc @@ -9,7 +9,7 @@ // // This file is a part of ThreadSanitizer (TSan), a race detector. // -// Test utils, Linux, FreeBSD and Darwin implementation. +// Test utils, Linux, FreeBSD, NetBSD and Darwin implementation. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" @@ -270,7 +270,7 @@ void ScopedThread::Impl::HandleEvent(Event *ev) { } } CHECK_NE(tsan_mop, 0); -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) const int ErrCode = ESOCKTNOSUPPORT; #else const int ErrCode = ECHRNG; diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg index c6a384120..cac260999 100644 --- a/test/msan/lit.cfg +++ b/test/msan/lit.cfg @@ -29,8 +29,7 @@ config.substitutions.append( ("%clangxx_msan ", build_invocation(clang_msan_cxxf # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -# MemorySanitizer tests are currently supported on Linux only. -if config.host_os not in ['Linux']: +if config.host_os not in ['Linux', 'NetBSD']: config.unsupported = True # For mips64, mips64el we have forced store_context_size to 1 because these diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index 95c7d7cc3..f0dc7b67e 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -79,8 +79,7 @@ config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__ # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm'] -# ThreadSanitizer tests are currently supported on FreeBSD, Linux and Darwin. -if config.host_os not in ['FreeBSD', 'Linux', 'Darwin']: +if config.host_os not in ['FreeBSD', 'Linux', 'Darwin', 'NetBSD']: config.unsupported = True if config.android: diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc index 3b4f89900..8aef27bc1 100644 --- a/test/tsan/map32bit.cc +++ b/test/tsan/map32bit.cc @@ -12,8 +12,8 @@ // XFAIL: aarch64 // XFAIL: powerpc64 -// MAP_32BIT doesn't exist on OS X. -// UNSUPPORTED: darwin +// MAP_32BIT doesn't exist on OS X and NetBSD. +// UNSUPPORTED: darwin,netbsd void *Thread(void *ptr) { *(int*)ptr = 42; @@ -45,4 +45,3 @@ int main() { // CHECK: WARNING: ThreadSanitizer: data race // CHECK: DONE - diff --git a/test/tsan/strerror_r.cc b/test/tsan/strerror_r.cc index 06c92d3bb..ad4820130 100644 --- a/test/tsan/strerror_r.cc +++ b/test/tsan/strerror_r.cc @@ -11,7 +11,8 @@ char buffer[1000]; void *Thread(void *p) { - return strerror_r(TEST_ERROR, buffer, sizeof(buffer)); + strerror_r(TEST_ERROR, buffer, sizeof(buffer)); + return buffer; } int main() { -- cgit v1.2.1 From 00b60424097c569e185a667969d054db7004cd0c Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 25 Oct 2017 17:21:37 +0000 Subject: [Sanitizers] ASan: detect new/delete calls with mismatched alignment. ASan allocator stores the requested alignment for new and new[] calls and on delete and delete[] verifies that alignments do match. The representable alignments are: default alignment, 8, 16, 32, 64, 128, 256 and 512 bytes. Alignments > 512 are stored as 512, hence two different alignments > 512 will pass the check (possibly masking the bug), but limited memory requirements deemed to be a resonable tradeoff for relaxed conditions. The feature is controlled by new_delete_type_mismatch flag, the same one protecting new/delete matching size check. Differential revision: https://reviews.llvm.org/D38574 Issue: https://github.com/google/sanitizers/issues/799 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316595 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 54 ++++++-- lib/asan/asan_allocator.h | 5 +- lib/asan/asan_descriptions.cc | 1 + lib/asan/asan_descriptions.h | 1 + lib/asan/asan_errors.cc | 28 +++- lib/asan/asan_errors.h | 16 ++- lib/asan/asan_new_delete.cc | 102 +++++++------- lib/asan/asan_report.cc | 7 +- lib/asan/asan_report.h | 3 +- test/asan/TestCases/Linux/aligned_delete_test.cc | 168 +++++++++++++++++++++++ 10 files changed, 298 insertions(+), 87 deletions(-) create mode 100644 test/asan/TestCases/Linux/aligned_delete_test.cc diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 4b7e84ca5..bc9b896f9 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -84,7 +84,10 @@ struct ChunkHeader { // This field is used for small sizes. For large sizes it is equal to // SizeClassMap::kMaxSize and the actual size is stored in the // SecondaryAllocator's metadata. - u32 user_requested_size; + u32 user_requested_size : 29; + // align < 8 -> 0 + // else -> log2(min(align, 512)) - 2 + u32 user_requested_alignment_log : 3; u32 alloc_context_id; }; @@ -351,6 +354,20 @@ struct Allocator { return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz)); } + static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) { + if (user_requested_alignment < 8) + return 0; + if (user_requested_alignment > 512) + user_requested_alignment = 512; + return Log2(user_requested_alignment) - 2; + } + + static uptr ComputeUserAlignment(uptr user_requested_alignment_log) { + if (user_requested_alignment_log == 0) + return 0; + return 1LL << (user_requested_alignment_log + 2); + } + // We have an address between two chunks, and we want to report just one. AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk, AsanChunk *right_chunk) { @@ -385,6 +402,8 @@ struct Allocator { Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; + const uptr user_requested_alignment_log = + ComputeUserRequestedAlignmentLog(alignment); if (alignment < min_alignment) alignment = min_alignment; if (size == 0) { @@ -472,6 +491,7 @@ struct Allocator { meta[0] = size; meta[1] = chunk_beg; } + m->user_requested_alignment_log = user_requested_alignment_log; m->alloc_context_id = StackDepotPut(*stack); @@ -573,8 +593,8 @@ struct Allocator { } } - void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack, - AllocType alloc_type) { + void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment, + BufferedStackTrace *stack, AllocType alloc_type) { uptr p = reinterpret_cast(ptr); if (p == 0) return; @@ -601,11 +621,14 @@ struct Allocator { ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, (AllocType)alloc_type); } - } - - if (delete_size && flags()->new_delete_type_mismatch && - delete_size != m->UsedSize()) { - ReportNewDeleteSizeMismatch(p, delete_size, stack); + } else { + if (flags()->new_delete_type_mismatch && + (alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) && + ((delete_size && delete_size != m->UsedSize()) || + ComputeUserRequestedAlignmentLog(delete_alignment) != + m->user_requested_alignment_log)) { + ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack); + } } QuarantineChunk(m, ptr, stack); @@ -631,7 +654,7 @@ struct Allocator { // If realloc() races with free(), we may start copying freed memory. // However, we will report racy double-free later anyway. REAL(memcpy)(new_ptr, old_ptr, memcpy_size); - Deallocate(old_ptr, 0, stack, FROM_MALLOC); + Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC); } return new_ptr; } @@ -766,6 +789,9 @@ bool AsanChunkView::IsQuarantined() const { uptr AsanChunkView::Beg() const { return chunk_->Beg(); } uptr AsanChunkView::End() const { return Beg() + UsedSize(); } uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); } +u32 AsanChunkView::UserRequestedAlignment() const { + return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log); +} uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; } uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; } AllocType AsanChunkView::GetAllocType() const { @@ -818,12 +844,12 @@ void PrintInternalAllocatorStats() { } void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { - instance.Deallocate(ptr, 0, stack, alloc_type); + instance.Deallocate(ptr, 0, 0, stack, alloc_type); } -void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, - AllocType alloc_type) { - instance.Deallocate(ptr, size, stack, alloc_type); +void asan_delete(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack, AllocType alloc_type) { + instance.Deallocate(ptr, size, alignment, stack, alloc_type); } void *asan_malloc(uptr size, BufferedStackTrace *stack) { @@ -839,7 +865,7 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); if (size == 0) { if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { - instance.Deallocate(p, 0, stack, FROM_MALLOC); + instance.Deallocate(p, 0, 0, stack, FROM_MALLOC); return nullptr; } // Allocate a size of 1 if we shouldn't free() on Realloc to 0 diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 615e34fa6..26483db4c 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -58,6 +58,7 @@ class AsanChunkView { uptr Beg() const; // First byte of user memory. uptr End() const; // Last byte of user memory. uptr UsedSize() const; // Size requested by the user. + u32 UserRequestedAlignment() const; // Originally requested alignment. uptr AllocTid() const; uptr FreeTid() const; bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } @@ -197,8 +198,8 @@ struct AsanThreadLocalMallocStorage { void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type); void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); -void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, - AllocType alloc_type); +void asan_delete(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack, AllocType alloc_type); void *asan_malloc(uptr size, BufferedStackTrace *stack); void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc index 5662e6b34..0a4fb82fd 100644 --- a/lib/asan/asan_descriptions.cc +++ b/lib/asan/asan_descriptions.cc @@ -122,6 +122,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr, } descr->chunk_begin = chunk.Beg(); descr->chunk_size = chunk.UsedSize(); + descr->user_requested_alignment = chunk.UserRequestedAlignment(); descr->alloc_type = chunk.GetAllocType(); } diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h index 006a240ac..cd278add8 100644 --- a/lib/asan/asan_descriptions.h +++ b/lib/asan/asan_descriptions.h @@ -102,6 +102,7 @@ struct ChunkAccess { sptr offset; uptr chunk_begin; uptr chunk_size; + u32 user_requested_alignment : 12; u32 access_type : 2; u32 alloc_type : 2; }; diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index dee666d54..6413b987b 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -63,7 +63,7 @@ void ErrorDoubleFree::Print() { ReportErrorSummary(scariness.GetDescription(), &stack); } -void ErrorNewDeleteSizeMismatch::Print() { +void ErrorNewDeleteTypeMismatch::Print() { Decorator d; Printf("%s", d.Warning()); char tname[128]; @@ -73,10 +73,28 @@ void ErrorNewDeleteSizeMismatch::Print() { scariness.GetDescription(), addr_description.addr, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s object passed to delete has wrong type:\n", d.Default()); - Printf( - " size of the allocated type: %zd bytes;\n" - " size of the deallocated type: %zd bytes.\n", - addr_description.chunk_access.chunk_size, delete_size); + if (delete_size != 0) { + Printf( + " size of the allocated type: %zd bytes;\n" + " size of the deallocated type: %zd bytes.\n", + addr_description.chunk_access.chunk_size, delete_size); + } + const uptr user_alignment = + addr_description.chunk_access.user_requested_alignment; + if (delete_alignment != user_alignment) { + char user_alignment_str[32]; + char delete_alignment_str[32]; + internal_snprintf(user_alignment_str, sizeof(user_alignment_str), + "%zd bytes", user_alignment); + internal_snprintf(delete_alignment_str, sizeof(delete_alignment_str), + "%zd bytes", delete_alignment); + static const char *kDefaultAlignment = "default-aligned"; + Printf( + " alignment of the allocated type: %s;\n" + " alignment of the deallocated type: %s.\n", + user_alignment > 0 ? user_alignment_str : kDefaultAlignment, + delete_alignment > 0 ? delete_alignment_str : kDefaultAlignment); + } CHECK_GT(free_stack->size, 0); scariness.Print(); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index b35cb259c..518ba0c69 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -71,17 +71,19 @@ struct ErrorDoubleFree : ErrorBase { void Print(); }; -struct ErrorNewDeleteSizeMismatch : ErrorBase { - // ErrorNewDeleteSizeMismatch doesn't own the stack trace. +struct ErrorNewDeleteTypeMismatch : ErrorBase { + // ErrorNewDeleteTypeMismatch doesn't own the stack trace. const BufferedStackTrace *free_stack; HeapAddressDescription addr_description; uptr delete_size; + uptr delete_alignment; // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor - ErrorNewDeleteSizeMismatch() = default; - ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, - uptr delete_size_) - : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) { + ErrorNewDeleteTypeMismatch() = default; + ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, + uptr delete_size_, uptr delete_alignment_) + : ErrorBase(tid), free_stack(stack), delete_size(delete_size_), + delete_alignment(delete_alignment_) { GetHeapAddressInformation(addr, 1, &addr_description); scariness.Clear(); scariness.Scare(10, "new-delete-type-mismatch"); @@ -293,7 +295,7 @@ struct ErrorGeneric : ErrorBase { #define ASAN_FOR_EACH_ERROR_KIND(macro) \ macro(DeadlySignal) \ macro(DoubleFree) \ - macro(NewDeleteSizeMismatch) \ + macro(NewDeleteTypeMismatch) \ macro(FreeNotMalloced) \ macro(AllocTypeMismatch) \ macro(MallocUsableSizeNotOwned) \ diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index e68c7f3e2..072f027ad 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -125,77 +125,69 @@ INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); } -#endif +#endif // !SANITIZER_MAC #define OPERATOR_DELETE_BODY(type) \ GET_STACK_TRACE_FREE;\ - asan_free(ptr, &stack, type); + asan_delete(ptr, 0, 0, &stack, type); + +#define OPERATOR_DELETE_BODY_SIZE(type) \ + GET_STACK_TRACE_FREE;\ + asan_delete(ptr, size, 0, &stack, type); + +#define OPERATOR_DELETE_BODY_ALIGN(type) \ + GET_STACK_TRACE_FREE;\ + asan_delete(ptr, 0, static_cast(align), &stack, type); + +#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ + GET_STACK_TRACE_FREE;\ + asan_delete(ptr, size, static_cast(align), &stack, type); #if !SANITIZER_MAC CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr) NOEXCEPT { - OPERATOR_DELETE_BODY(FROM_NEW); -} +void operator delete(void *ptr) NOEXCEPT +{ OPERATOR_DELETE_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr) NOEXCEPT { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} +void operator delete[](void *ptr) NOEXCEPT +{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW); -} +void operator delete(void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} +void operator delete[](void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, size_t size) NOEXCEPT { - GET_STACK_TRACE_FREE; - asan_sized_free(ptr, size, &stack, FROM_NEW); -} +void operator delete(void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, size_t size) NOEXCEPT { - GET_STACK_TRACE_FREE; - asan_sized_free(ptr, size, &stack, FROM_NEW_BR); -} +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, std::align_val_t) NOEXCEPT { - OPERATOR_DELETE_BODY(FROM_NEW); -} +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, std::align_val_t) NOEXCEPT { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW); -} +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} +void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE -void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT { - GET_STACK_TRACE_FREE; - asan_sized_free(ptr, size, &stack, FROM_NEW); -} +void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE -void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT { - GET_STACK_TRACE_FREE; - asan_sized_free(ptr, size, &stack, FROM_NEW_BR); -} +void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); } #else // SANITIZER_MAC -INTERCEPTOR(void, _ZdlPv, void *ptr) { - OPERATOR_DELETE_BODY(FROM_NEW); -} -INTERCEPTOR(void, _ZdaPv, void *ptr) { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} -INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW); -} -INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) { - OPERATOR_DELETE_BODY(FROM_NEW_BR); -} -#endif +INTERCEPTOR(void, _ZdlPv, void *ptr) +{ OPERATOR_DELETE_BODY(FROM_NEW); } +INTERCEPTOR(void, _ZdaPv, void *ptr) +{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } +INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FROM_NEW); } +INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } +#endif // !SANITIZER_MAC diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index cda93f3e6..42fae9c73 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -216,11 +216,12 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { in_report.ReportError(error); } -void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, +void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size, + uptr delete_alignment, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; - ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, - delete_size); + ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, + delete_size, delete_alignment); in_report.ReportError(error); } diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index 324e454ea..f2cdad47e 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -47,7 +47,8 @@ bool ParseFrameDescription(const char *frame_descr, void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); void ReportDeadlySignal(const SignalContext &sig); -void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, +void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size, + uptr delete_alignment, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); diff --git a/test/asan/TestCases/Linux/aligned_delete_test.cc b/test/asan/TestCases/Linux/aligned_delete_test.cc new file mode 100644 index 000000000..5b9455e56 --- /dev/null +++ b/test/asan/TestCases/Linux/aligned_delete_test.cc @@ -0,0 +1,168 @@ +// RUN: %clangxx_asan -std=c++1z -faligned-allocation -fsanitize-recover=address -O0 %s -o %t +// RUN: %env_asan_opts=new_delete_type_mismatch=1:halt_on_error=false:detect_leaks=false %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=new_delete_type_mismatch=0 %run %t + +// RUN: %clangxx_asan -std=c++1z -faligned-allocation -fsized-deallocation -fsanitize-recover=address -O0 %s -o %t +// RUN: %env_asan_opts=new_delete_type_mismatch=1:halt_on_error=false:detect_leaks=false %run %t 2>&1 | FileCheck %s +// RUN: %env_asan_opts=new_delete_type_mismatch=0 %run %t + +// REQUIRES: asan-static-runtime + +#include + +// Define all new/delete to do not depend on the version provided by the +// plaform. The implementation is provided by ASan anyway. + +namespace std { +struct nothrow_t {}; +static const nothrow_t nothrow; +enum class align_val_t : size_t {}; +} // namespace std + +void *operator new(size_t); +void *operator new[](size_t); +void *operator new(size_t, std::nothrow_t const&); +void *operator new[](size_t, std::nothrow_t const&); +void *operator new(size_t, std::align_val_t); +void *operator new[](size_t, std::align_val_t); +void *operator new(size_t, std::align_val_t, std::nothrow_t const&); +void *operator new[](size_t, std::align_val_t, std::nothrow_t const&); + +void operator delete(void*) throw(); +void operator delete[](void*) throw(); +void operator delete(void*, std::nothrow_t const&); +void operator delete[](void*, std::nothrow_t const&); +void operator delete(void*, size_t) throw(); +void operator delete[](void*, size_t) throw(); +void operator delete(void*, std::align_val_t) throw(); +void operator delete[](void*, std::align_val_t) throw(); +void operator delete(void*, std::align_val_t, std::nothrow_t const&); +void operator delete[](void*, std::align_val_t, std::nothrow_t const&); +void operator delete(void*, size_t, std::align_val_t) throw(); +void operator delete[](void*, size_t, std::align_val_t) throw(); + + +template +inline T* break_optimization(T *arg) { + __asm__ __volatile__("" : : "r" (arg) : "memory"); + return arg; +} + + +struct S12 { int a, b, c; }; +struct alignas(128) S12_128 { int a, b, c; }; +struct alignas(256) S12_256 { int a, b, c; }; +struct alignas(512) S1024_512 { char a[1024]; }; +struct alignas(1024) S1024_1024 { char a[1024]; }; + + +int main(int argc, char **argv) { + fprintf(stderr, "Testing valid cases\n"); + + delete break_optimization(new S12); + operator delete(break_optimization(new S12), std::nothrow); + delete [] break_optimization(new S12[100]); + operator delete[](break_optimization(new S12[100]), std::nothrow); + + delete break_optimization(new S12_128); + operator delete(break_optimization(new S12_128), + std::align_val_t(alignof(S12_128))); + operator delete(break_optimization(new S12_128), + std::align_val_t(alignof(S12_128)), std::nothrow); + operator delete(break_optimization(new S12_128), sizeof(S12_128), + std::align_val_t(alignof(S12_128))); + + delete [] break_optimization(new S12_128[100]); + operator delete[](break_optimization(new S12_128[100]), + std::align_val_t(alignof(S12_128))); + operator delete[](break_optimization(new S12_128[100]), + std::align_val_t(alignof(S12_128)), std::nothrow); + operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]), + std::align_val_t(alignof(S12_128))); + + fprintf(stderr, "Done\n"); + // CHECK: Testing valid cases + // CHECK-NEXT: Done + + // Explicit mismatched calls. + + operator delete(break_optimization(new S12_128), std::nothrow); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 128 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + operator delete(break_optimization(new S12_128), sizeof(S12_128)); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 128 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + operator delete[](break_optimization(new S12_128[100]), std::nothrow); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 128 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100])); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 128 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + // Various mismatched alignments. + + delete break_optimization(reinterpret_cast(new S12_256)); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 256 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + delete break_optimization(reinterpret_cast(new S12)); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: default-aligned; + // CHECK: alignment of the deallocated type: 256 bytes. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + delete break_optimization(reinterpret_cast(new S12_256)); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 256 bytes; + // CHECK: alignment of the deallocated type: 128 bytes. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + delete [] break_optimization(reinterpret_cast(new S12_256[100])); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 256 bytes; + // CHECK: alignment of the deallocated type: default-aligned. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + delete [] break_optimization(reinterpret_cast(new S12[100])); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: default-aligned; + // CHECK: alignment of the deallocated type: 256 bytes. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + delete [] break_optimization(reinterpret_cast(new S12_256[100])); + // CHECK: AddressSanitizer: new-delete-type-mismatch + // CHECK: object passed to delete has wrong type: + // CHECK: alignment of the allocated type: 256 bytes; + // CHECK: alignment of the deallocated type: 128 bytes. + // CHECK: SUMMARY: AddressSanitizer: new-delete-type-mismatch + + // Push ASan limits, the current limitation is that it cannot differentiate + // alignments above 512 bytes. + fprintf(stderr, "Checking alignments >= 512 bytes\n"); + delete break_optimization(reinterpret_cast(new S1024_1024)); + fprintf(stderr, "Done\n"); + // CHECK: Checking alignments >= 512 bytes + // CHECK-NEXT: Done +} -- cgit v1.2.1 From e625e66b75c013d6fdb12955e8bc4be8f41a25c1 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 25 Oct 2017 17:24:56 +0000 Subject: [sanitizer] Random shuffling of chunks for the 32-bit Primary Allocator Summary: The 64-bit primary has had random shuffling of chunks for a while, this implements it for the 32-bit primary. Scudo is currently the only user of `kRandomShuffleChunks`. This change consists of a few modifications: - move the random shuffling functions out of the 64-bit primary to `sanitizer_common.h`. Alternatively I could move them to `sanitizer_allocator.h` as they are only used in the allocator, I don't feel strongly either way; - small change in the 64-bit primary to make the `rand_state` initialization `UNLIKELY`; - addition of a `rand_state` in the 32-bit primary's `SizeClassInfo` and shuffling of chunks when populating the free list. - enabling the `random_shuffle.cpp` test on platforms using the 32-bit primary for Scudo. Some comments on why the shuffling is done that way. Initially I just implemented a `Shuffle` function in the `TransferBatch` which was simpler but I came to realize this wasn't good enough: for chunks of 10000 bytes for example, with a `CompactSizeClassMap`, a batch holds only 1 chunk, meaning shuffling the batch has no effect, while a region is usually 1MB, eg: 104 chunks of that size. So I decided to "stage" the newly gathered chunks in a temporary array that would be shuffled prior to placing the chunks in batches. The result is looping twice through n_chunks even if shuffling is not enabled, but I didn't notice any significant significant performance impact. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: srhines, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D39244 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316596 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator.h | 13 ++++++ .../sanitizer_allocator_primary32.h | 54 ++++++++++++++++++---- .../sanitizer_allocator_primary64.h | 18 ++------ test/scudo/random_shuffle.cpp | 2 - 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index 8c5696ea7..38368361d 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -56,6 +56,19 @@ struct NoOpMapUnmapCallback { // Callback type for iterating over chunks. typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); +INLINE u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. + return (*state = *state * 1103515245 + 12345) >> 16; +} + +INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) + +template +INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) { + if (n <= 1) return; + for (u32 i = n - 1; i > 0; i--) + Swap(a[i], a[RandN(rand_state, i + 1)]); +} + #include "sanitizer_allocator_size_class_map.h" #include "sanitizer_allocator_stats.h" #include "sanitizer_allocator_primary64.h" diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h index 8abf2f9f5..6c682aff6 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -268,7 +268,8 @@ class SizeClassAllocator32 { struct SizeClassInfo { SpinMutex mutex; IntrusiveList free_list; - char padding[kCacheLineSize - sizeof(uptr) - + u32 rand_state; + char padding[kCacheLineSize - 2 * sizeof(uptr) - sizeof(IntrusiveList)]; }; COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize); @@ -301,29 +302,62 @@ class SizeClassAllocator32 { return &size_class_info_array[class_id]; } + bool PopulateBatches(AllocatorCache *c, SizeClassInfo *sci, uptr class_id, + TransferBatch **current_batch, uptr max_count, + uptr *pointers_array, uptr count) { + // If using a separate class for batches, we do not need to shuffle it. + if (kRandomShuffleChunks && (!kUseSeparateSizeClassForBatch || + class_id != SizeClassMap::kBatchClassID)) + RandomShuffle(pointers_array, count, &sci->rand_state); + TransferBatch *b = *current_batch; + for (uptr i = 0; i < count; i++) { + if (!b) { + b = c->CreateBatch(class_id, this, (TransferBatch*)pointers_array[i]); + if (UNLIKELY(!b)) + return false; + b->Clear(); + } + b->Add((void*)pointers_array[i]); + if (b->Count() == max_count) { + sci->free_list.push_back(b); + b = nullptr; + } + } + *current_batch = b; + return true; + } + bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, SizeClassInfo *sci, uptr class_id) { uptr size = ClassIdToSize(class_id); uptr reg = AllocateRegion(stat, class_id); if (UNLIKELY(!reg)) return false; + if (kRandomShuffleChunks) + if (UNLIKELY(sci->rand_state == 0)) + // The random state is initialized from ASLR (PIE) and time. + sci->rand_state = reinterpret_cast(sci) ^ NanoTime(); uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = TransferBatch::MaxCached(class_id); CHECK_GT(max_count, 0); TransferBatch *b = nullptr; + const uptr kShuffleArraySize = 48; + uptr shuffle_array[kShuffleArraySize]; + uptr count = 0; for (uptr i = reg; i < reg + n_chunks * size; i += size) { - if (!b) { - b = c->CreateBatch(class_id, this, (TransferBatch*)i); - if (UNLIKELY(!b)) + shuffle_array[count++] = i; + if (count == kShuffleArraySize) { + if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, + shuffle_array, count))) return false; - b->Clear(); - } - b->Add((void*)i); - if (b->Count() == max_count) { - sci->free_list.push_back(b); - b = nullptr; + count = 0; } } + if (count) { + if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, + shuffle_array, count))) + return false; + } if (b) { CHECK_GT(b->Count(), 0); sci->free_list.push_back(b); diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index bb2b917f6..8b7610b2c 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -597,18 +597,6 @@ class SizeClassAllocator64 { }; COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); - u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. - return (*state = *state * 1103515245 + 12345) >> 16; - } - - u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) - - void RandomShuffle(u32 *a, u32 n, u32 *rand_state) { - if (n <= 1) return; - for (u32 i = n - 1; i > 0; i--) - Swap(a[i], a[RandN(rand_state, i + 1)]); - } - RegionInfo *GetRegionInfo(uptr class_id) const { CHECK_LT(class_id, kNumClasses); RegionInfo *regions = @@ -681,8 +669,10 @@ class SizeClassAllocator64 { // Map more space for chunks, if necessary. if (new_space_end > region->mapped_user) { - if (!kUsingConstantSpaceBeg && region->mapped_user == 0) - region->rand_state = static_cast(region_beg >> 12); // From ASLR. + if (!kUsingConstantSpaceBeg && kRandomShuffleChunks) + if (UNLIKELY(region->mapped_user == 0)) + // The random state is initialized from ASLR. + region->rand_state = static_cast(region_beg >> 12); // Do the mmap for the user memory. uptr map_size = kUserMapSize; while (new_space_end > region->mapped_user + map_size) diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index da004484a..54768a578 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -7,8 +7,6 @@ // RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 // RUN: not diff %T/random_shuffle_tmp_dir/out? // RUN: rm -rf %T/random_shuffle_tmp_dir -// UNSUPPORTED: i386-linux,arm-linux,armhf-linux,aarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux -// UNSUPPORTED: android // Tests that the allocator shuffles the chunks before returning to the user. -- cgit v1.2.1 From 27d88dffabfdadc9f7c833ad460c667922e1b0ca Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 25 Oct 2017 17:56:36 +0000 Subject: Try to unbreak Linux sanitizers Add fallback definition of internal_syscall_ptr and internal_syscall64 for Linux/x86_64 and Linux/aarch64. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316598 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc | 3 +++ lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc index 7ab1d7641..1f05ed9b6 100644 --- a/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc +++ b/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc @@ -127,6 +127,9 @@ static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, #define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) +#define internal_syscall_ptr internal_syscall +#define internal_syscall64 internal_syscall + // Helper function used to avoid cobbler errno. bool internal_iserror(uptr retval, int *rverrno) { if (retval >= (uptr)-4095) { diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc index 9853a6a67..327aaa80a 100644 --- a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc +++ b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc @@ -20,6 +20,9 @@ static uptr internal_syscall(u64 nr) { return retval; } +#define internal_syscall_ptr internal_syscall +#define internal_syscall64 internal_syscall + template static uptr internal_syscall(u64 nr, T1 arg1) { u64 retval; -- cgit v1.2.1 From cbdf93a9b677d7f85dc486f1899ca0e764ae8e1d Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 25 Oct 2017 21:40:17 +0000 Subject: [msan] Intercept __strxfrm_l. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316613 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/msan/msan_interceptors.cc | 15 +++++++++++++++ test/msan/__strxfrm_l.cc | 19 +++++++++++++++++++ test/msan/strxfrm.cc | 11 +++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test/msan/__strxfrm_l.cc diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index d14ebb30d..72bb7455d 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -457,6 +457,20 @@ INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n, return res; } +#if SANITIZER_LINUX +INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T n, + void *loc) { + ENSURE_MSAN_INITED(); + CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); + SIZE_T res = REAL(__strxfrm_l)(dest, src, n, loc); + if (res < n) __msan_unpoison(dest, res + 1); + return res; +} +#define MSAN_MAYBE_INTERCEPT___STRXFRM_L INTERCEPT_FUNCTION(__strxfrm_l) +#else +#define MSAN_MAYBE_INTERCEPT___STRXFRM_L +#endif + #define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \ ENSURE_MSAN_INITED(); \ ret_type res = REAL(func)(s, __VA_ARGS__); \ @@ -1521,6 +1535,7 @@ void InitializeInterceptors() { #endif INTERCEPT_FUNCTION(strxfrm); INTERCEPT_FUNCTION(strxfrm_l); + MSAN_MAYBE_INTERCEPT___STRXFRM_L; INTERCEPT_FUNCTION(strftime); INTERCEPT_FUNCTION(strftime_l); MSAN_MAYBE_INTERCEPT___STRFTIME_L; diff --git a/test/msan/__strxfrm_l.cc b/test/msan/__strxfrm_l.cc new file mode 100644 index 000000000..c4eb10efb --- /dev/null +++ b/test/msan/__strxfrm_l.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t +// REQUIRES: x86_64-linux + +#include +#include +#include +#include +#include + +extern "C" decltype(strxfrm_l) __strxfrm_l; + +int main(void) { + char q[10]; + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + size_t n = __strxfrm_l(q, "qwerty", sizeof(q), loc); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, n + 1); + return 0; +} diff --git a/test/msan/strxfrm.cc b/test/msan/strxfrm.cc index 9a30d03c3..94b8c7024 100644 --- a/test/msan/strxfrm.cc +++ b/test/msan/strxfrm.cc @@ -1,14 +1,21 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include +#include #include #include #include int main(void) { - const char *p = "abcdef"; char q[10]; - size_t n = strxfrm(q, p, sizeof(q)); + size_t n = strxfrm(q, "abcdef", sizeof(q)); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, n + 1); + + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + + __msan_poison(&q, sizeof(q)); + n = strxfrm_l(q, "qwerty", sizeof(q), loc); assert(n < sizeof(q)); __msan_check_mem_is_initialized(q, n + 1); return 0; -- cgit v1.2.1 From 56c02e11840e8b5778c17314a26e729bcb701fc1 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 25 Oct 2017 22:00:26 +0000 Subject: [scudo] Remove comment about security of the 32-bit allocator Summary: The 32-bit allocator is now on par with the 64-bit in terms of security (chunks randomization is done, batches separation is done). Unless objection, the comment can go away. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39303 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316620 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_allocator.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 2f317d24a..a517058ab 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -77,9 +77,6 @@ struct AP64 { }; typedef SizeClassAllocator64 PrimaryAllocator; #else -// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the -// security improvements brought to the 64-bit one. This makes the 32-bit -// version of Scudo slightly less toughened. static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog; # if SANITIZER_WORDSIZE == 32 typedef FlatByteMap ByteMap; -- cgit v1.2.1 From f708c0ca7e3f1785d2702a0d0459f4a092718641 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 25 Oct 2017 23:24:45 +0000 Subject: [libFuzzer] trying to make a test more stable on Mac git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316627 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/fuzzer/fuzzer-customcrossover.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzer/fuzzer-customcrossover.test b/test/fuzzer/fuzzer-customcrossover.test index c32079f45..5a78307c7 100644 --- a/test/fuzzer/fuzzer-customcrossover.test +++ b/test/fuzzer/fuzzer-customcrossover.test @@ -1,6 +1,6 @@ RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest -RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=CHECK_CO +RUN: not %t-CustomCrossOverTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=CHECK_CO Disable cross_over, verify that we can't find the target w/o it. RUN: %t-CustomCrossOverTest -seed=1 -runs=1000000 -cross_over=0 2>&1 | FileCheck %s --check-prefix=CHECK_NO_CO -- cgit v1.2.1 From 0480bcea56dc0a6afd46a98f603a8eb8e02c21f1 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 26 Oct 2017 01:22:48 +0000 Subject: [LSan] Adjust LSan allocator limits for PPC64. Summary: Now the limits are the same as for ASan allocator. Reviewers: cryptoad Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39309 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316633 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/lsan/lsan_allocator.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h index 5a0d94c71..4006f7929 100644 --- a/lib/lsan/lsan_allocator.h +++ b/lib/lsan/lsan_allocator.h @@ -68,9 +68,16 @@ struct AP32 { }; typedef SizeClassAllocator32 PrimaryAllocator; #elif defined(__x86_64__) || defined(__powerpc64__) +# if defined(__powerpc64__) +const uptr kAllocatorSpace = 0xa0000000000ULL; +const uptr kAllocatorSize = 0x20000000000ULL; // 2T. +# else +const uptr kAllocatorSpace = 0x600000000000ULL; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +# endif struct AP64 { // Allocator64 parameters. Deliberately using a short name. - static const uptr kSpaceBeg = 0x600000000000ULL; - static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = kAllocatorSize; static const uptr kMetadataSize = sizeof(ChunkMetadata); typedef DefaultSizeClassMap SizeClassMap; typedef NoOpMapUnmapCallback MapUnmapCallback; -- cgit v1.2.1 From 491bcd82b826debac806d27971cc972a6f555564 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 26 Oct 2017 06:08:01 +0000 Subject: [sanitizer] Fix internal symbolized build on Debian 9 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316637 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh index c5865ecfe..0559a2e7e 100755 --- a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +++ b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh @@ -110,12 +110,12 @@ cd ${LIBCXX_BUILD} ninja cxx cxxabi FLAGS="${FLAGS} -fno-rtti -fno-exceptions" +LLVM_FLAGS="${FLAGS} -nostdinc++ -I${ZLIB_BUILD} -I${LIBCXX_BUILD}/include/c++/v1" # Build LLVM. if [[ ! -d ${LLVM_BUILD} ]]; then mkdir -p ${LLVM_BUILD} cd ${LLVM_BUILD} - LLVM_FLAGS="${FLAGS} -I${ZLIB_BUILD} -I${LIBCXX_BUILD}/include/c++/v1" cmake -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=$CC \ @@ -137,7 +137,7 @@ mkdir ${SYMBOLIZER_BUILD} cd ${SYMBOLIZER_BUILD} echo "Compiling..." -SYMBOLIZER_FLAGS="$FLAGS -std=c++11 -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -I${LIBCXX_BUILD}/include/c++/v1" +SYMBOLIZER_FLAGS="$LLVM_FLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++11" $CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cc ${SRC_DIR}/sanitizer_wrappers.cc -c $AR rc symbolizer.a sanitizer_symbolize.o sanitizer_wrappers.o -- cgit v1.2.1 From 9d9424425890eee23a6f2f2fc8042acce47554ca Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 26 Oct 2017 17:59:24 +0000 Subject: [Sanitizers] Set default allocator_release_to_os_interval_ms to 5 seconds Summary: With new release to OS approach (see D38245) it's reasonable to enable it by default. Setting allocator_release_to_os_interval_ms to 5000 seems to be a reasonable default (might be tuned later, based on the feedback). Also delaying the first release to OS in each bucket for at least allocator_release_to_os_interval_ms after the first allocation to prevent just allocated memory to be madvised back to OS and let short lived processes to avoid release to OS overhead altogether. Reviewers: cryptoad Subscribers: kubamracek, llvm-commits, mehdi_amini Differential Revision: https://reviews.llvm.org/D39318 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316683 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_allocator_primary64.h | 10 ++++++++-- lib/sanitizer_common/sanitizer_flags.inc | 10 +++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h index 8b7610b2c..b22f3aba9 100644 --- a/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -669,10 +669,16 @@ class SizeClassAllocator64 { // Map more space for chunks, if necessary. if (new_space_end > region->mapped_user) { - if (!kUsingConstantSpaceBeg && kRandomShuffleChunks) - if (UNLIKELY(region->mapped_user == 0)) + if (UNLIKELY(region->mapped_user == 0)) { + if (!kUsingConstantSpaceBeg && kRandomShuffleChunks) // The random state is initialized from ASLR. region->rand_state = static_cast(region_beg >> 12); + // Postpone the first release to OS attempt for ReleaseToOSIntervalMs, + // preventing just allocated memory from being released sooner than + // necessary and also preventing extraneous ReleaseMemoryPagesToOS calls + // for short lived processes. + region->rtoi.last_release_at_ns = NanoTime(); + } // Do the mmap for the user memory. uptr map_size = kUserMapSize; while (new_space_end > region->mapped_user + map_size) diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index eab33ab45..21876e08f 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -129,11 +129,11 @@ COMMON_FLAG(uptr, soft_rss_limit_mb, 0, " This limit does not affect memory allocations other than" " malloc/new.") COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") -COMMON_FLAG(s32, allocator_release_to_os_interval_ms, kReleaseToOSIntervalNever, - "Experimental. Only affects a 64-bit allocator. If set, tries to " - "release unused memory to the OS, but not more often than this " - "interval (in milliseconds). Negative values mean do not attempt " - "to release memory to the OS.\n") +COMMON_FLAG(s32, allocator_release_to_os_interval_ms, 5000, + "Only affects a 64-bit allocator. If set, tries to release unused " + "memory to the OS, but not more often than this interval (in " + "milliseconds). Negative values mean do not attempt to release " + "memory to the OS.\n") COMMON_FLAG(bool, can_use_proc_maps_statm, true, "If false, do not attempt to read /proc/maps/statm." " Mostly useful for testing sanitizers.") -- cgit v1.2.1 From e27514e613e3e3cfdd4eafb29068a9ca5769f80f Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 26 Oct 2017 20:59:04 +0000 Subject: [LSan] Enable LSan tests on PPC64 Linux. Summary: LSan is functional on PPC64 Linux now, let's enable all tests. One test required ppc specific changes: use_registers.cc. Reviewers: eugenis Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D39316 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316698 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/config-ix.cmake | 2 +- test/lsan/TestCases/use_registers.cc | 5 +++++ test/lsan/lit.common.cfg | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index e4976ce6d..30b308131 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -199,7 +199,7 @@ set(ALL_FUZZER_SUPPORTED_ARCH x86_64) if(APPLE) set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64}) else() - set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32}) + set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32} ${PPC64}) endif() set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64} diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 5d5ede5ce..edcf1ae16 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -38,6 +38,11 @@ void *registers_thread_func(void *arg) { : : "r" (p) ); +#elif defined(__powerpc__) + asm ( "mr 30, %0" + : + : "r" (p) + ); #else #error "Test is not supported on this architecture." #endif diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index 610b1b1ad..a5df951e2 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -68,7 +68,7 @@ config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, and x86_64 Darwin. -supported_linux = config.host_os is 'Linux' and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l'] +supported_linux = config.host_os is 'Linux' and config.host_arch in ['x86_64', 'ppc64', 'ppc64le', 'mips64', 'arm', 'armhf', 'armv7l'] supported_darwin = config.host_os is 'Darwin' and config.target_arch is 'x86_64' if not (supported_linux or supported_darwin): config.unsupported = True -- cgit v1.2.1 From 350302ec8d9c0faa130a6d1266220d27d9f6a523 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Fri, 27 Oct 2017 00:29:40 +0000 Subject: [LSan] Disable a couple of failing tests on PPC64 (pending investigation). git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316720 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/lsan/TestCases/stale_stack_leak.cc | 2 +- test/lsan/TestCases/swapcontext.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc index 635d73814..8c3495854 100644 --- a/test/lsan/TestCases/stale_stack_leak.cc +++ b/test/lsan/TestCases/stale_stack_leak.cc @@ -5,7 +5,7 @@ // RUN: %env_lsan_opts=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s // // x86 passes parameters through stack that may lead to false negatives -// UNSUPPORTED: x86 +// UNSUPPORTED: x86,powerpc64 #include #include diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc index f46897a97..9774f6ce4 100644 --- a/test/lsan/TestCases/swapcontext.cc +++ b/test/lsan/TestCases/swapcontext.cc @@ -4,7 +4,7 @@ // RUN: %clangxx_lsan %s -o %t // RUN: %env_lsan_opts= %run %t 2>&1 // RUN: %env_lsan_opts= not %run %t foo 2>&1 | FileCheck %s -// UNSUPPORTED: arm +// UNSUPPORTED: arm,powerpc64 #include #if defined(__APPLE__) -- cgit v1.2.1 From 0c8987ad277c57f75859487ab81ca85b15db2380 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Fri, 27 Oct 2017 20:10:14 +0000 Subject: [scudo] Allow to specify the maximum number of TSDs at compile time Summary: This introduces `SCUDO_MAX_CACHES` allowing to define an upper bound to the number of `ScudoTSD` created in the Shared TSD model (by default 32U). This name felt clearer than `SCUDO_MAX_TSDS` which is technically what it really is. I am opened to suggestions if that doesn't feel right. Additionally change `getNumberOfCPUs` to return a `u32` to be more consistent. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39338 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316788 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/scudo_platform.h | 5 +++++ lib/scudo/scudo_tsd_shared.cpp | 9 +++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/scudo/scudo_platform.h b/lib/scudo/scudo_platform.h index 095d6ef19..7db1197fd 100644 --- a/lib/scudo/scudo_platform.h +++ b/lib/scudo/scudo_platform.h @@ -40,6 +40,11 @@ # error "The exclusive TSD model is not supported on this platform." #endif +// Maximum number of TSDs that can be created for the Shared model. +#ifndef SCUDO_SHARED_TSD_POOL_SIZE +# define SCUDO_SHARED_TSD_POOL_SIZE 32U +#endif // SCUDO_SHARED_TSD_POOL_SIZE + namespace __scudo { #if SANITIZER_CAN_USE_ALLOCATOR64 diff --git a/lib/scudo/scudo_tsd_shared.cpp b/lib/scudo/scudo_tsd_shared.cpp index 6ee2f84a0..191c9ff13 100644 --- a/lib/scudo/scudo_tsd_shared.cpp +++ b/lib/scudo/scudo_tsd_shared.cpp @@ -25,7 +25,7 @@ static ScudoTSD *TSDs; static u32 NumberOfTSDs; // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. -static uptr getNumberOfCPUs() { +static u32 getNumberOfCPUs() { cpu_set_t CPUs; CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); return CPU_COUNT(&CPUs); @@ -34,11 +34,8 @@ static uptr getNumberOfCPUs() { static void initOnce() { CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); initScudo(); - NumberOfTSDs = getNumberOfCPUs(); - if (NumberOfTSDs == 0) - NumberOfTSDs = 1; - if (NumberOfTSDs > 32) - NumberOfTSDs = 32; + NumberOfTSDs = Min(Max(1U, getNumberOfCPUs()), + static_cast(SCUDO_SHARED_TSD_POOL_SIZE)); TSDs = reinterpret_cast( MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); for (u32 i = 0; i < NumberOfTSDs; i++) -- cgit v1.2.1 From 35f3b0cf471b703311360e8357717653ec490ccb Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Fri, 27 Oct 2017 23:59:41 +0000 Subject: [XRay][compiler-rt] Remove more STL dependenices from FDR mode Summary: This change removes dependencies on STL types: - std::aligned_storage -- we're using manually-aligned character buffers instead for metadata and function records. - std::tuple -- use a plain old struct instead. This is an incremental step in removing all STL references from the compiler-rt implementation of XRay (llvm.org/PR32274). Reviewers: dblaikie, pelikan, kpw Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39277 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316816 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 46 +++++++++++++++++-------------------- lib/xray/xray_fdr_logging_impl.h | 49 +++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 90eb6c572..2ad68cbac 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -15,15 +15,10 @@ // //===----------------------------------------------------------------------===// #include "xray_fdr_logging.h" -#include -#include -#include -#include #include #include #include #include -#include #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" @@ -176,19 +171,22 @@ XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; } -static std::tuple -getTimestamp() XRAY_NEVER_INSTRUMENT { +struct TSCAndCPU { + uint64_t TSC; + unsigned char CPU; +}; + +static TSCAndCPU getTimestamp() XRAY_NEVER_INSTRUMENT { // We want to get the TSC as early as possible, so that we can check whether // we've seen this CPU before. We also do it before we load anything else, to // allow for forward progress with the scheduling. - unsigned char CPU; - uint64_t TSC; + TSCAndCPU Result; // Test once for required CPU features static bool TSCSupported = probeRequiredCPUFeatures(); if (TSCSupported) { - TSC = __xray::readTSC(CPU); + Result.TSC = __xray::readTSC(Result.CPU); } else { // FIXME: This code needs refactoring as it appears in multiple locations timespec TS; @@ -197,34 +195,32 @@ getTimestamp() XRAY_NEVER_INSTRUMENT { Report("clock_gettime(2) return %d, errno=%d", result, int(errno)); TS = {0, 0}; } - CPU = 0; - TSC = TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; + Result.CPU = 0; + Result.TSC = TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec; } - return std::make_tuple(TSC, CPU); + return Result; } void fdrLoggingHandleArg0(int32_t FuncId, XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { - auto TSC_CPU = getTimestamp(); - __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), - std::get<1>(TSC_CPU), 0, - clock_gettime, *BQ); + auto TC = getTimestamp(); + __xray_fdr_internal::processFunctionHook(FuncId, Entry, TC.TSC, + TC.CPU, 0, clock_gettime, *BQ); } void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry, uint64_t Arg) XRAY_NEVER_INSTRUMENT { - auto TSC_CPU = getTimestamp(); - __xray_fdr_internal::processFunctionHook(FuncId, Entry, std::get<0>(TSC_CPU), - std::get<1>(TSC_CPU), Arg, - clock_gettime, *BQ); + auto TC = getTimestamp(); + __xray_fdr_internal::processFunctionHook( + FuncId, Entry, TC.TSC, TC.CPU, Arg, clock_gettime, *BQ); } void fdrLoggingHandleCustomEvent(void *Event, std::size_t EventSize) XRAY_NEVER_INSTRUMENT { using namespace __xray_fdr_internal; - auto TSC_CPU = getTimestamp(); - auto &TSC = std::get<0>(TSC_CPU); - auto &CPU = std::get<1>(TSC_CPU); + auto TC = getTimestamp(); + auto &TSC = TC.TSC; + auto &CPU = TC.CPU; RecursionGuard Guard{Running}; if (!Guard) { assert(Running && "RecursionGuard is buggy!"); @@ -261,7 +257,7 @@ void fdrLoggingHandleCustomEvent(void *Event, CustomEvent.Type = uint8_t(RecordType::Metadata); CustomEvent.RecordKind = uint8_t(MetadataRecord::RecordKinds::CustomEventMarker); - constexpr auto TSCSize = sizeof(std::get<0>(TSC_CPU)); + constexpr auto TSCSize = sizeof(TC.TSC); std::memcpy(&CustomEvent.Data, &ReducedEventSize, sizeof(int32_t)); std::memcpy(&CustomEvent.Data[sizeof(int32_t)], &TSC, TSCSize); std::memcpy(TLD.RecordPtr, &CustomEvent, sizeof(CustomEvent)); diff --git a/lib/xray/xray_fdr_logging_impl.h b/lib/xray/xray_fdr_logging_impl.h index f7c77c6c2..c109d1384 100644 --- a/lib/xray/xray_fdr_logging_impl.h +++ b/lib/xray/xray_fdr_logging_impl.h @@ -18,16 +18,17 @@ #define XRAY_XRAY_FDR_LOGGING_IMPL_H #include -#include +#include #include #include -#include #include -#include #include #include #include +// FIXME: Implement analogues to std::shared_ptr and std::weak_ptr +#include + #include "sanitizer_common/sanitizer_common.h" #include "xray/xray_log_interface.h" #include "xray_buffer_queue.h" @@ -96,7 +97,7 @@ static void writeTSCWrapMetadata(uint64_t TSC); // call so that it can be initialized on first use instead of as a global. We // force the alignment to 64-bytes for x86 cache line alignment, as this // structure is used in the hot path of implementation. -struct ALIGNED(64) ThreadLocalData { +struct alignas(64) ThreadLocalData { BufferQueue::Buffer Buffer; char *RecordPtr = nullptr; // The number of FunctionEntry records immediately preceding RecordPtr. @@ -176,8 +177,8 @@ static ThreadLocalData &getThreadLocalData() { // We need aligned, uninitialized storage for the TLS object which is // trivially destructible. We're going to use this as raw storage and // placement-new the ThreadLocalData object into it later. - thread_local std::aligned_storage::type TLSBuffer; + alignas(alignof(ThreadLocalData)) thread_local unsigned char + TLSBuffer[sizeof(ThreadLocalData)]; // Ensure that we only actually ever do the pthread initialization once. thread_local bool UNUSED Unused = [] { @@ -215,7 +216,7 @@ static ThreadLocalData &getThreadLocalData() { return true; }(); - return *reinterpret_cast(&TLSBuffer); + return *reinterpret_cast(TLSBuffer); } //-----------------------------------------------------------------------------| @@ -255,14 +256,15 @@ public: inline void writeNewBufferPreamble(pid_t Tid, timespec TS, char *&MemPtr) XRAY_NEVER_INSTRUMENT { static constexpr int InitRecordsCount = 2; - std::aligned_storage::type Records[InitRecordsCount]; + alignas(alignof(MetadataRecord)) unsigned char + Records[InitRecordsCount * MetadataRecSize]; { // Write out a MetadataRecord to signify that this is the start of a new // buffer, associated with a particular thread, with a new CPU. For the // data, we have 15 bytes to squeeze as much information as we can. At this // point we only write down the following bytes: // - Thread ID (pid_t, 4 bytes) - auto &NewBuffer = *reinterpret_cast(&Records[0]); + auto &NewBuffer = *reinterpret_cast(Records); NewBuffer.Type = uint8_t(RecordType::Metadata); NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer); std::memcpy(&NewBuffer.Data, &Tid, sizeof(pid_t)); @@ -270,7 +272,8 @@ inline void writeNewBufferPreamble(pid_t Tid, timespec TS, // Also write the WalltimeMarker record. { static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes"); - auto &WalltimeMarker = *reinterpret_cast(&Records[1]); + auto &WalltimeMarker = + *reinterpret_cast(Records + MetadataRecSize); WalltimeMarker.Type = uint8_t(RecordType::Metadata); WalltimeMarker.RecordKind = uint8_t(MetadataRecord::RecordKinds::WalltimeMarker); @@ -382,10 +385,7 @@ static inline void writeCallArgumentMetadata(uint64_t A) XRAY_NEVER_INSTRUMENT { static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, XRayEntryType EntryType, char *&MemPtr) XRAY_NEVER_INSTRUMENT { - std::aligned_storage::type - AlignedFuncRecordBuffer; - auto &FuncRecord = - *reinterpret_cast(&AlignedFuncRecordBuffer); + FunctionRecord FuncRecord; FuncRecord.Type = uint8_t(RecordType::Function); // Only take 28 bits of the function id. FuncRecord.FuncId = FuncId & ~(0x0F << 28); @@ -439,7 +439,7 @@ static inline void writeFunctionRecord(int FuncId, uint32_t TSCDelta, } } - std::memcpy(MemPtr, &AlignedFuncRecordBuffer, sizeof(FunctionRecord)); + std::memcpy(MemPtr, &FuncRecord, sizeof(FunctionRecord)); MemPtr += sizeof(FunctionRecord); } @@ -456,14 +456,10 @@ static uint64_t thresholdTicks() { // "Function Entry" record and any "Tail Call Exit" records after that. static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, uint64_t &LastFunctionEntryTSC, int32_t FuncId) { - using AlignedFuncStorage = - std::aligned_storage::type; auto &TLD = getThreadLocalData(); TLD.RecordPtr -= FunctionRecSize; - AlignedFuncStorage AlignedFuncRecordBuffer; - const auto &FuncRecord = *reinterpret_cast( - std::memcpy(&AlignedFuncRecordBuffer, TLD.RecordPtr, FunctionRecSize)); + FunctionRecord FuncRecord; + std::memcpy(&FuncRecord, TLD.RecordPtr, FunctionRecSize); assert(FuncRecord.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && "Expected to find function entry recording when rewinding."); @@ -485,20 +481,17 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC, auto RewindingTSC = LastTSC; auto RewindingRecordPtr = TLD.RecordPtr - FunctionRecSize; while (TLD.NumTailCalls > 0) { - AlignedFuncStorage TailExitRecordBuffer; // Rewind the TSC back over the TAIL EXIT record. - const auto &ExpectedTailExit = - *reinterpret_cast(std::memcpy( - &TailExitRecordBuffer, RewindingRecordPtr, FunctionRecSize)); + FunctionRecord ExpectedTailExit; + std::memcpy(&ExpectedTailExit, RewindingRecordPtr, FunctionRecSize); assert(ExpectedTailExit.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionTailExit) && "Expected to find tail exit when rewinding."); RewindingRecordPtr -= FunctionRecSize; RewindingTSC -= ExpectedTailExit.TSCDelta; - AlignedFuncStorage FunctionEntryBuffer; - const auto &ExpectedFunctionEntry = *reinterpret_cast( - std::memcpy(&FunctionEntryBuffer, RewindingRecordPtr, FunctionRecSize)); + FunctionRecord ExpectedFunctionEntry; + std::memcpy(&ExpectedFunctionEntry, RewindingRecordPtr, FunctionRecSize); assert(ExpectedFunctionEntry.RecordKind == uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && "Expected to find function entry when rewinding tail call."); -- cgit v1.2.1 From 0efc331375c1858dabff465c9613d101c131b0f6 Mon Sep 17 00:00:00 2001 From: Martin Pelikan Date: Sat, 28 Oct 2017 01:35:07 +0000 Subject: [XRay] [compiler-rt] fix build by including errno.h into FDR mode The build got broken after D39277 (and rL316816) deleted . git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316821 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/xray_fdr_logging.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc index 2ad68cbac..cf27acc24 100644 --- a/lib/xray/xray_fdr_logging.cc +++ b/lib/xray/xray_fdr_logging.cc @@ -17,6 +17,7 @@ #include "xray_fdr_logging.h" #include #include +#include #include #include -- cgit v1.2.1 From a0eba2205796725858d1921bb5c0ce473cba8aa3 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 30 Oct 2017 17:26:13 +0000 Subject: [asan] Intercept heap routines in VS2010 CRT Users have requested that we add it to the list: https://github.com/google/sanitizers/issues/864 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316929 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/interception/interception_win.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index 23402e555..ac0b0505e 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -835,6 +835,7 @@ bool OverrideFunction( static void **InterestingDLLsAvailable() { static const char *InterestingDLLs[] = { "kernel32.dll", + "msvcr100.dll", // VS2010 "msvcr110.dll", // VS2012 "msvcr120.dll", // VS2013 "vcruntime140.dll", // VS2015 -- cgit v1.2.1 From c6577df3ffb9099626a0d8335c38a41362e11f66 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 30 Oct 2017 17:26:57 +0000 Subject: Fix clang warnings in winasan code There are two instances of -Wcast-qual and one of -Wsign-compare. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316930 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_win.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f1a74d3f2..42357f6aa 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -379,7 +379,7 @@ struct ModuleInfo { #if !SANITIZER_GO int CompareModulesBase(const void *pl, const void *pr) { - const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr; + const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; if (l->base_address < r->base_address) return -1; return l->base_address > r->base_address; @@ -794,7 +794,7 @@ void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { // FIXME: Compare with StackWalk64. // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), - (void**)trace, 0); + (void **)&trace_buffer[0], 0); if (size == 0) return; @@ -917,7 +917,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { } bool SignalContext::IsStackOverflow() const { - return GetType() == EXCEPTION_STACK_OVERFLOW; + return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; } void SignalContext::InitPcSpBp() { -- cgit v1.2.1 From c714e4023336fcd72ee34b49d7dc102d9a1f4613 Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 30 Oct 2017 17:56:24 +0000 Subject: Introduce ReservedAddressRange to sanitizer_common. Summary: Fixed version of https://reviews.llvm.org/D38437 (fixes Win/Fuchsia failures). Creating a new revision, since the old one was getting a bit old/crowded. In Fuchsia, MmapNoAccess/MmapFixedOrDie are implemented using a global VMAR, which means that MmapNoAccess can only be called once. This works for the sanitizer allocator but *not* for the Scudo allocator. Hence, this changeset introduces a new ReservedAddressRange object to serve as the new API for these calls. In this changeset, the object still calls into the old Mmap implementations. The next changeset two changesets will convert the sanitizer and scudo allocators to use the new APIs, respectively. (ReservedAddressRange will replace the SecondaryHeader in Scudo.) Finally, a last changeset will update the Fuchsia implementation. Reviewers: alekseyshl, cryptoad, phosek Reviewed By: alekseyshl, cryptoad Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D39072 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316934 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_common.h | 14 +++++ lib/sanitizer_common/sanitizer_fuchsia.cc | 24 ++++++++ lib/sanitizer_common/sanitizer_posix_libcdep.cc | 30 ++++++++++ lib/sanitizer_common/sanitizer_win.cc | 30 ++++++++++ .../tests/sanitizer_common_test.cc | 67 ++++++++++++++++++++++ 5 files changed, 165 insertions(+) diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ee5eca516..14b92d9c4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -128,6 +128,20 @@ void CheckVMASize(); void RunMallocHooks(const void *ptr, uptr size); void RunFreeHooks(const void *ptr); +class ReservedAddressRange { + public: + uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false); + void Unmap(uptr addr, uptr size); + void *base() const { return base_; } + uptr size() const { return size_; } + + private: + void* base_; + uptr size_; + const char* name_; +}; + typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, /*out*/uptr *stats, uptr stats_size); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 21fabddb1..7d3729c68 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,6 +236,30 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { return DoAnonymousMmapOrDie(size, mem_type, false, false); } +uptr ReservedAddressRange::Init(uptr init_size, const char* name, + uptr fixed_addr) { + base_ = MmapNoAccess(init_size); + size_ = init_size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + bool tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, map_size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_)) + CHECK_LE(size, size_); + UnmapOrDie(reinterpret_cast(addr), size); +} + // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 4214d91c5..0ba3ad46b 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,6 +337,36 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return (void *)p; } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap at the beginning or end of the range. + CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_)); + CHECK_LE(size, size_); + UnmapOrDie(reinterpret_cast(addr), size); +} + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 42357f6aa..f3d4d85f7 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -235,6 +235,24 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(uptr fixed_addr, uptr size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + void* addr_as_void = reinterpret_cast(addr); + uptr base_as_uptr = reinterpret_cast(base_); + // Only unmap if it covers the entire range. + CHECK((addr_as_void == base_) && (size == size_)); + UnmapOrDie(reinterpret_cast(addr), size); +} + void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -252,6 +270,18 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type); } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + name_ = name; + return reinterpret_cast(base_); +} + + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 9c62b4593..38170ea6d 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -320,4 +320,71 @@ TEST(SanitizerCommon, GetRandom) { } #endif +TEST(SanitizerCommon, ReservedAddressRangeInit) { + uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*)-1); + UnmapOrDie((void*)res, init_size); + // Should be able to map into the same space now. + ReservedAddressRange address_range2; + uptr res2 = address_range2.Init(init_size, nullptr, res); + CHECK_EQ(res, res2); + + // TODO(flowerhack): Once this is switched to the "real" implementation + // (rather than passing through to MmapNoAccess*), enforce and test "no + // double initializations allowed" +} + +TEST(SanitizerCommon, ReservedAddressRangeMap) { + constexpr uptr init_size = 0xffff; + ReservedAddressRange address_range; + uptr res = address_range.Init(init_size); + CHECK_NE(res, (void*) -1); + + // Valid mappings should succeed. + CHECK_EQ(res, address_range.Map(res, init_size)); + + // Valid mappings should be readable. + unsigned char buffer[init_size]; + memcpy(buffer, reinterpret_cast(res), init_size); + + // Invalid mappings should fail. + EXPECT_DEATH(address_range.Map(res, 0), ".*"); + + // TODO(flowerhack): Once this is switched to the "real" implementation, make + // sure you can only mmap into offsets in the Init range. +} + +TEST(SanitizerCommon, ReservedAddressRangeUnmap) { + uptr PageSize = GetPageSizeCached(); + uptr init_size = PageSize * 4; + ReservedAddressRange address_range; + uptr base_addr = address_range.Init(init_size); + CHECK_NE(base_addr, (void*)-1); + CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); + + // Unmapping the entire range should succeed. + address_range.Unmap(base_addr, PageSize * 4); + + // Remap that range in. + CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); + + // Windows doesn't allow partial unmappings. + #if !SANITIZER_WINDOWS + + // Unmapping at the beginning should succeed. + address_range.Unmap(base_addr, PageSize); + + // Unmapping at the end should succeed. + uptr new_start = reinterpret_cast(address_range.base()) + + address_range.size() - PageSize; + address_range.Unmap(new_start, PageSize); + + #endif + + // Unmapping in the middle of the ReservedAddressRange should fail. + EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); +} + } // namespace __sanitizer -- cgit v1.2.1 From 97cfd35230e2c94336af31395f2d86b978d3486c Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 30 Oct 2017 18:16:05 +0000 Subject: [sanitizer] Fixing an error introduced in D39072 Summary: This should fix the Windows bots after D39072. Reviewers: alekseyshl, flowerhack Reviewed By: flowerhack Subscribers: llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D39426 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316937 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_win.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index f3d4d85f7..b490601a0 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -242,7 +242,7 @@ uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, if (tolerate_enomem) { return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); } - return reinterpret_cast(MmapFixedOrDie(uptr fixed_addr, uptr size)); + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); } void ReservedAddressRange::Unmap(uptr addr, uptr size) { -- cgit v1.2.1 From 7ff86c1f9a06dad5f5590544e7667666dbd162ba Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Mon, 30 Oct 2017 19:06:59 +0000 Subject: Fix warning + death test + failing test on Windows (D39072). Summary: Fixes https://reviews.llvm.org/D39072 Reviewers: cryptoad Reviewed By: cryptoad Subscribers: kubamracek Differential Revision: https://reviews.llvm.org/D39427 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316943 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_win.cc | 4 ++-- lib/sanitizer_common/tests/sanitizer_common_test.cc | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index b490601a0..b2fd8baca 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -249,8 +249,8 @@ void ReservedAddressRange::Unmap(uptr addr, uptr size) { void* addr_as_void = reinterpret_cast(addr); uptr base_as_uptr = reinterpret_cast(base_); // Only unmap if it covers the entire range. - CHECK((addr_as_void == base_) && (size == size_)); - UnmapOrDie(reinterpret_cast(addr), size); + CHECK((addr == base_as_uptr) && (size == size_)); + UnmapOrDie(addr_as_void, size); } void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index 38170ea6d..576649cea 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -349,25 +349,23 @@ TEST(SanitizerCommon, ReservedAddressRangeMap) { unsigned char buffer[init_size]; memcpy(buffer, reinterpret_cast(res), init_size); - // Invalid mappings should fail. - EXPECT_DEATH(address_range.Map(res, 0), ".*"); - // TODO(flowerhack): Once this is switched to the "real" implementation, make // sure you can only mmap into offsets in the Init range. } TEST(SanitizerCommon, ReservedAddressRangeUnmap) { uptr PageSize = GetPageSizeCached(); - uptr init_size = PageSize * 4; + uptr init_size = PageSize * 8; ReservedAddressRange address_range; uptr base_addr = address_range.Init(init_size); CHECK_NE(base_addr, (void*)-1); CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); // Unmapping the entire range should succeed. - address_range.Unmap(base_addr, PageSize * 4); + address_range.Unmap(base_addr, init_size); - // Remap that range in. + // Map a new range. + base_addr = address_range.Init(init_size); CHECK_EQ(base_addr, address_range.Map(base_addr, init_size)); // Windows doesn't allow partial unmappings. @@ -384,7 +382,7 @@ TEST(SanitizerCommon, ReservedAddressRangeUnmap) { #endif // Unmapping in the middle of the ReservedAddressRange should fail. - EXPECT_DEATH(address_range.Unmap(base_addr + 0xf, 0xff), ".*"); + EXPECT_DEATH(address_range.Unmap(base_addr + (PageSize * 2), PageSize), ".*"); } } // namespace __sanitizer -- cgit v1.2.1 From 8ff5640b48c4c4a3b974daa10a5f445e86ed7428 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 30 Oct 2017 21:29:26 +0000 Subject: [sanitizer][Fuchsia] Add a missing semicolon Differential Revision: https://reviews.llvm.org/D39433 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@316959 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/sanitizer_common/sanitizer_fuchsia.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 7d3729c68..a2a532110 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -255,7 +255,7 @@ void ReservedAddressRange::Unmap(uptr addr, uptr size) { void* addr_as_void = reinterpret_cast(addr); uptr base_as_uptr = reinterpret_cast(base_); // Only unmap at the beginning or end of the range. - CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_)) + CHECK((addr_as_void == base_) || (addr + size == base_as_uptr + size_)); CHECK_LE(size, size_); UnmapOrDie(reinterpret_cast(addr), size); } -- cgit v1.2.1 From 8ddc9eb9566b6cafb848d87323303cd5089fa4b2 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 31 Oct 2017 20:49:48 +0000 Subject: [fuzzer] Fix threaded stack printing and nested mallocs Summary: Nested mallocs are possible with internal symbolizer. Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39397 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317034 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 19 +++++++++++++++++ test/fuzzer/TraceMallocThreadedTest.cpp | 22 ++++++++++++++++++++ test/fuzzer/trace-malloc-threaded.test | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 test/fuzzer/TraceMallocThreadedTest.cpp create mode 100644 test/fuzzer/trace-malloc-threaded.test diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d3ac4ce7e..9cb580a30 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #if defined(__has_include) @@ -73,11 +74,24 @@ struct MallocFreeTracer { static MallocFreeTracer AllocTracer; +static thread_local bool IsMallocFreeHookDisabled; +static std::mutex MallocFreeStackMutex; + +struct MallocFreeHookDisabler { + MallocFreeHookDisabler() { IsMallocFreeHookDisabled = true; } + ~MallocFreeHookDisabler() { IsMallocFreeHookDisabled = false; } +}; + ATTRIBUTE_NO_SANITIZE_MEMORY void MallocHook(const volatile void *ptr, size_t size) { + // Avoid nested hooks for mallocs/frees in sanitizer. + if (IsMallocFreeHookDisabled) + return; + MallocFreeHookDisabler Disable; size_t N = AllocTracer.Mallocs++; F->HandleMalloc(size); if (int TraceLevel = AllocTracer.TraceLevel) { + std::lock_guard Lock(MallocFreeStackMutex); Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); @@ -86,8 +100,13 @@ void MallocHook(const volatile void *ptr, size_t size) { ATTRIBUTE_NO_SANITIZE_MEMORY void FreeHook(const volatile void *ptr) { + // Avoid nested hooks for mallocs/frees in sanitizer. + if (IsMallocFreeHookDisabled) + return; + MallocFreeHookDisabler Disable; size_t N = AllocTracer.Frees++; if (int TraceLevel = AllocTracer.TraceLevel) { + std::lock_guard Lock(MallocFreeStackMutex); Printf("FREE[%zd] %p\n", N, ptr); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); diff --git a/test/fuzzer/TraceMallocThreadedTest.cpp b/test/fuzzer/TraceMallocThreadedTest.cpp new file mode 100644 index 000000000..5603af344 --- /dev/null +++ b/test/fuzzer/TraceMallocThreadedTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Check that allocation tracing from different threads does not cause +// interleaving of stack traces. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + auto C = [&] { + volatile void *a = malloc(5639); + free((void *)a); + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} diff --git a/test/fuzzer/trace-malloc-threaded.test b/test/fuzzer/trace-malloc-threaded.test new file mode 100644 index 000000000..11f3f0491 --- /dev/null +++ b/test/fuzzer/trace-malloc-threaded.test @@ -0,0 +1,36 @@ +// FIXME: This test infinite loops on darwin because it crashes +// printing a stack trace repeatedly +UNSUPPORTED: darwin + +RUN: %cpp_compiler %S/TraceMallocThreadedTest.cpp -o %t-TraceMallocThreadedTest + +RUN: %t-TraceMallocThreadedTest -trace_malloc=2 -runs=1 2>&1 | FileCheck %s +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} -- cgit v1.2.1 From 142775ac8314b5a2accfb9832e7226856deddbe9 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Tue, 31 Oct 2017 20:50:07 +0000 Subject: [fuzzer] Script to detect unbalanced allocation in -trace_malloc output Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39466 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317036 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/scripts/unbalanced_allocs.py | 93 ++++++++++++++++++++++++++++++++ test/fuzzer/trace-malloc-unbalanced.test | 27 ++++++++++ 2 files changed, 120 insertions(+) create mode 100755 lib/fuzzer/scripts/unbalanced_allocs.py create mode 100644 test/fuzzer/trace-malloc-unbalanced.test diff --git a/lib/fuzzer/scripts/unbalanced_allocs.py b/lib/fuzzer/scripts/unbalanced_allocs.py new file mode 100755 index 000000000..a4ce18767 --- /dev/null +++ b/lib/fuzzer/scripts/unbalanced_allocs.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +#===- lib/fuzzer/scripts/unbalanced_allocs.py ------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# Post-process -trace_malloc=2 output and printout only allocations and frees +# unbalanced inside of fuzzer runs. +# Usage: +# my_fuzzer -trace_malloc=2 -runs=10 2>&1 | unbalanced_allocs.py -skip=5 +# +#===------------------------------------------------------------------------===# + +import argparse +import sys + +_skip = 0 + +def PrintStack(line, stack): + global _skip + if _skip > 0: + return + print 'Unbalanced ' + line.rstrip(); + for l in stack: + print l.rstrip() + +def ProcessStack(line, f): + stack = [] + while line and line.startswith(' #'): + stack += [line] + line = f.readline() + return line, stack + +def ProcessFree(line, f, allocs): + if not line.startswith('FREE['): + return f.readline() + + addr = int(line.split()[1], 16) + next_line, stack = ProcessStack(f.readline(), f) + if addr in allocs: + del allocs[addr] + else: + PrintStack(line, stack) + return next_line + +def ProcessMalloc(line, f, allocs): + if not line.startswith('MALLOC['): + return ProcessFree(line, f, allocs) + + addr = int(line.split()[1], 16) + assert not addr in allocs + + next_line, stack = ProcessStack(f.readline(), f) + allocs[addr] = (line, stack) + return next_line + +def ProcessRun(line, f): + if not line.startswith('MallocFreeTracer: START'): + return ProcessMalloc(line, f, {}) + + allocs = {} + print line.rstrip() + line = f.readline() + while line: + if line.startswith('MallocFreeTracer: STOP'): + global _skip + _skip = _skip - 1 + for _, (l, s) in allocs.iteritems(): + PrintStack(l, s) + print line.rstrip() + return f.readline() + line = ProcessMalloc(line, f, allocs) + return line + +def ProcessFile(f): + line = f.readline() + while line: + line = ProcessRun(line, f); + +def main(argv): + parser = argparse.ArgumentParser() + parser.add_argument('--skip', default=0, help='number of runs to ignore') + args = parser.parse_args() + global _skip + _skip = int(args.skip) + 1 + ProcessFile(sys.stdin) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/fuzzer/trace-malloc-unbalanced.test b/test/fuzzer/trace-malloc-unbalanced.test new file mode 100644 index 000000000..53b83fb68 --- /dev/null +++ b/test/fuzzer/trace-malloc-unbalanced.test @@ -0,0 +1,27 @@ +// FIXME: This test infinite loops on darwin because it crashes +// printing a stack trace repeatedly +UNSUPPORTED: darwin + +// Verifies lib/fuzzer/scripts/unbalanced_allocs.py script + +RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=100 2>&1 | \ +RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=100 2>&1 | \ +RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s --check-prefixes=CHECK,CHECK2 + +CHECK: MallocFreeTracer: START +CHECK: Unbalanced MALLOC[{{[0-9]+}}] [[PTR:0x[0-9a-f]+]] 4 +CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} +CHECK: MallocFreeTracer: STOP + +CHECK: MallocFreeTracer: START +CHECK: Unbalanced FREE[{{[0-9]+}}] [[PTR]] +CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} +CHECK: MallocFreeTracer: STOP -- cgit v1.2.1 From b3c355d3c87d2ea131fd71836d848fe5aa89d20d Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 1 Nov 2017 00:55:52 +0000 Subject: Revert "[fuzzer] Fix threaded stack printing and nested mallocs" Fails on darwin Revert "[fuzzer] Script to detect unbalanced allocation in -trace_malloc output" Needs previous one. This reverts commit r317034, r317036. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317061 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 19 ------- lib/fuzzer/scripts/unbalanced_allocs.py | 93 -------------------------------- test/fuzzer/TraceMallocThreadedTest.cpp | 22 -------- test/fuzzer/trace-malloc-threaded.test | 36 ------------- test/fuzzer/trace-malloc-unbalanced.test | 27 ---------- 5 files changed, 197 deletions(-) delete mode 100755 lib/fuzzer/scripts/unbalanced_allocs.py delete mode 100644 test/fuzzer/TraceMallocThreadedTest.cpp delete mode 100644 test/fuzzer/trace-malloc-threaded.test delete mode 100644 test/fuzzer/trace-malloc-unbalanced.test diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 9cb580a30..d3ac4ce7e 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #if defined(__has_include) @@ -74,24 +73,11 @@ struct MallocFreeTracer { static MallocFreeTracer AllocTracer; -static thread_local bool IsMallocFreeHookDisabled; -static std::mutex MallocFreeStackMutex; - -struct MallocFreeHookDisabler { - MallocFreeHookDisabler() { IsMallocFreeHookDisabled = true; } - ~MallocFreeHookDisabler() { IsMallocFreeHookDisabled = false; } -}; - ATTRIBUTE_NO_SANITIZE_MEMORY void MallocHook(const volatile void *ptr, size_t size) { - // Avoid nested hooks for mallocs/frees in sanitizer. - if (IsMallocFreeHookDisabled) - return; - MallocFreeHookDisabler Disable; size_t N = AllocTracer.Mallocs++; F->HandleMalloc(size); if (int TraceLevel = AllocTracer.TraceLevel) { - std::lock_guard Lock(MallocFreeStackMutex); Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); @@ -100,13 +86,8 @@ void MallocHook(const volatile void *ptr, size_t size) { ATTRIBUTE_NO_SANITIZE_MEMORY void FreeHook(const volatile void *ptr) { - // Avoid nested hooks for mallocs/frees in sanitizer. - if (IsMallocFreeHookDisabled) - return; - MallocFreeHookDisabler Disable; size_t N = AllocTracer.Frees++; if (int TraceLevel = AllocTracer.TraceLevel) { - std::lock_guard Lock(MallocFreeStackMutex); Printf("FREE[%zd] %p\n", N, ptr); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); diff --git a/lib/fuzzer/scripts/unbalanced_allocs.py b/lib/fuzzer/scripts/unbalanced_allocs.py deleted file mode 100755 index a4ce18767..000000000 --- a/lib/fuzzer/scripts/unbalanced_allocs.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -#===- lib/fuzzer/scripts/unbalanced_allocs.py ------------------------------===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# -# -# Post-process -trace_malloc=2 output and printout only allocations and frees -# unbalanced inside of fuzzer runs. -# Usage: -# my_fuzzer -trace_malloc=2 -runs=10 2>&1 | unbalanced_allocs.py -skip=5 -# -#===------------------------------------------------------------------------===# - -import argparse -import sys - -_skip = 0 - -def PrintStack(line, stack): - global _skip - if _skip > 0: - return - print 'Unbalanced ' + line.rstrip(); - for l in stack: - print l.rstrip() - -def ProcessStack(line, f): - stack = [] - while line and line.startswith(' #'): - stack += [line] - line = f.readline() - return line, stack - -def ProcessFree(line, f, allocs): - if not line.startswith('FREE['): - return f.readline() - - addr = int(line.split()[1], 16) - next_line, stack = ProcessStack(f.readline(), f) - if addr in allocs: - del allocs[addr] - else: - PrintStack(line, stack) - return next_line - -def ProcessMalloc(line, f, allocs): - if not line.startswith('MALLOC['): - return ProcessFree(line, f, allocs) - - addr = int(line.split()[1], 16) - assert not addr in allocs - - next_line, stack = ProcessStack(f.readline(), f) - allocs[addr] = (line, stack) - return next_line - -def ProcessRun(line, f): - if not line.startswith('MallocFreeTracer: START'): - return ProcessMalloc(line, f, {}) - - allocs = {} - print line.rstrip() - line = f.readline() - while line: - if line.startswith('MallocFreeTracer: STOP'): - global _skip - _skip = _skip - 1 - for _, (l, s) in allocs.iteritems(): - PrintStack(l, s) - print line.rstrip() - return f.readline() - line = ProcessMalloc(line, f, allocs) - return line - -def ProcessFile(f): - line = f.readline() - while line: - line = ProcessRun(line, f); - -def main(argv): - parser = argparse.ArgumentParser() - parser.add_argument('--skip', default=0, help='number of runs to ignore') - args = parser.parse_args() - global _skip - _skip = int(args.skip) + 1 - ProcessFile(sys.stdin) - -if __name__ == '__main__': - main(sys.argv) diff --git a/test/fuzzer/TraceMallocThreadedTest.cpp b/test/fuzzer/TraceMallocThreadedTest.cpp deleted file mode 100644 index 5603af344..000000000 --- a/test/fuzzer/TraceMallocThreadedTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Check that allocation tracing from different threads does not cause -// interleaving of stack traces. -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - auto C = [&] { - volatile void *a = malloc(5639); - free((void *)a); - }; - std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), - std::thread(C), std::thread(C), std::thread(C)}; - for (auto &X : T) - X.join(); - return 0; -} diff --git a/test/fuzzer/trace-malloc-threaded.test b/test/fuzzer/trace-malloc-threaded.test deleted file mode 100644 index 11f3f0491..000000000 --- a/test/fuzzer/trace-malloc-threaded.test +++ /dev/null @@ -1,36 +0,0 @@ -// FIXME: This test infinite loops on darwin because it crashes -// printing a stack trace repeatedly -UNSUPPORTED: darwin - -RUN: %cpp_compiler %S/TraceMallocThreadedTest.cpp -o %t-TraceMallocThreadedTest - -RUN: %t-TraceMallocThreadedTest -trace_malloc=2 -runs=1 2>&1 | FileCheck %s -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} - -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} - -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} - -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} - -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} - -CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} -CHECK-NEXT: {{ +\#0 +}} -CHECK-NEXT: {{ +\#1 +}} -CHECK-NEXT: {{ +\#2 +}} diff --git a/test/fuzzer/trace-malloc-unbalanced.test b/test/fuzzer/trace-malloc-unbalanced.test deleted file mode 100644 index 53b83fb68..000000000 --- a/test/fuzzer/trace-malloc-unbalanced.test +++ /dev/null @@ -1,27 +0,0 @@ -// FIXME: This test infinite loops on darwin because it crashes -// printing a stack trace repeatedly -UNSUPPORTED: darwin - -// Verifies lib/fuzzer/scripts/unbalanced_allocs.py script - -RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest - -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=100 2>&1 | \ -RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s - -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=100 2>&1 | \ -RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s --check-prefixes=CHECK,CHECK2 - -CHECK: MallocFreeTracer: START -CHECK: Unbalanced MALLOC[{{[0-9]+}}] [[PTR:0x[0-9a-f]+]] 4 -CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} -CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} -CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} -CHECK: MallocFreeTracer: STOP - -CHECK: MallocFreeTracer: START -CHECK: Unbalanced FREE[{{[0-9]+}}] [[PTR]] -CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} -CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} -CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} -CHECK: MallocFreeTracer: STOP -- cgit v1.2.1 From e8c4cd327a7e9d9f3d9bac156f887d5664384d63 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 1 Nov 2017 03:02:59 +0000 Subject: [fuzzer] Fix threaded stack printing Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39397 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317071 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 5 +++++ test/fuzzer/TraceMallocThreadedTest.cpp | 22 ++++++++++++++++++++ test/fuzzer/trace-malloc-threaded.test | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 test/fuzzer/TraceMallocThreadedTest.cpp create mode 100644 test/fuzzer/trace-malloc-threaded.test diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index d3ac4ce7e..9bea05f18 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #if defined(__has_include) @@ -73,11 +74,14 @@ struct MallocFreeTracer { static MallocFreeTracer AllocTracer; +static std::mutex MallocFreeStackMutex; + ATTRIBUTE_NO_SANITIZE_MEMORY void MallocHook(const volatile void *ptr, size_t size) { size_t N = AllocTracer.Mallocs++; F->HandleMalloc(size); if (int TraceLevel = AllocTracer.TraceLevel) { + std::lock_guard Lock(MallocFreeStackMutex); Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); @@ -88,6 +92,7 @@ ATTRIBUTE_NO_SANITIZE_MEMORY void FreeHook(const volatile void *ptr) { size_t N = AllocTracer.Frees++; if (int TraceLevel = AllocTracer.TraceLevel) { + std::lock_guard Lock(MallocFreeStackMutex); Printf("FREE[%zd] %p\n", N, ptr); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); diff --git a/test/fuzzer/TraceMallocThreadedTest.cpp b/test/fuzzer/TraceMallocThreadedTest.cpp new file mode 100644 index 000000000..5603af344 --- /dev/null +++ b/test/fuzzer/TraceMallocThreadedTest.cpp @@ -0,0 +1,22 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Check that allocation tracing from different threads does not cause +// interleaving of stack traces. +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + auto C = [&] { + volatile void *a = malloc(5639); + free((void *)a); + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} diff --git a/test/fuzzer/trace-malloc-threaded.test b/test/fuzzer/trace-malloc-threaded.test new file mode 100644 index 000000000..11f3f0491 --- /dev/null +++ b/test/fuzzer/trace-malloc-threaded.test @@ -0,0 +1,36 @@ +// FIXME: This test infinite loops on darwin because it crashes +// printing a stack trace repeatedly +UNSUPPORTED: darwin + +RUN: %cpp_compiler %S/TraceMallocThreadedTest.cpp -o %t-TraceMallocThreadedTest + +RUN: %t-TraceMallocThreadedTest -trace_malloc=2 -runs=1 2>&1 | FileCheck %s +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} + +CHECK: {{MALLOC\[[0-9]+] +0x[0-9]+ 5639}} +CHECK-NEXT: {{ +\#0 +}} +CHECK-NEXT: {{ +\#1 +}} +CHECK-NEXT: {{ +\#2 +}} -- cgit v1.2.1 From 60ec9d032df6ac22be15ee06e1559c73cffc22ea Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 1 Nov 2017 15:28:20 +0000 Subject: [scudo] Implement stricter separation of C vs C++ Summary: Initially, Scudo had a monolithic design where both C and C++ functions were living in the same library. This was not necessarily ideal, and with the work on -fsanitize=scudo, it became more apparent that this needed to change. We are splitting the new/delete interceptor in their own C++ library. This allows more flexibility, notably with regard to std::bad_alloc when the work is done. This also allows us to not link new & delete when using pure C. Additionally, we add the UBSan runtimes with Scudo, in order to be able to have a -fsanitize=scudo,undefined in Clang (see work in D39334). The changes in this patch: - split the cxx specific code in the scudo cmake file into a new library; (remove the spurious foreach loop, that was not necessary) - add the UBSan runtimes (both C and C++); - change the test cmake file to allow for specific C & C++ tests; - make C tests pure C, rename their extension accordingly. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: srhines, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D39461 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317097 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/scudo/CMakeLists.txt | 57 +++++++++++-------- test/scudo/alignment.c | 23 ++++++++ test/scudo/alignment.cpp | 23 -------- test/scudo/double-free.cpp | 2 +- test/scudo/interface.cpp | 2 +- test/scudo/lit.cfg | 10 +++- test/scudo/malloc.cpp | 2 +- test/scudo/memalign.c | 81 +++++++++++++++++++++++++++ test/scudo/memalign.cpp | 81 --------------------------- test/scudo/mismatch.cpp | 2 +- test/scudo/options.cpp | 2 +- test/scudo/overflow.c | 39 +++++++++++++ test/scudo/overflow.cpp | 39 ------------- test/scudo/preinit.c | 40 +++++++++++++ test/scudo/preinit.cpp | 40 ------------- test/scudo/preload.cpp | 10 ++-- test/scudo/quarantine.c | 124 +++++++++++++++++++++++++++++++++++++++++ test/scudo/quarantine.cpp | 124 ----------------------------------------- test/scudo/random_shuffle.cpp | 2 +- test/scudo/realloc.cpp | 2 +- test/scudo/secondary.c | 53 ++++++++++++++++++ test/scudo/secondary.cpp | 53 ------------------ test/scudo/sized-delete.cpp | 2 +- test/scudo/sizes.cpp | 2 +- test/scudo/threads.c | 65 +++++++++++++++++++++ test/scudo/threads.cpp | 65 --------------------- test/scudo/tsd_destruction.c | 42 ++++++++++++++ test/scudo/tsd_destruction.cpp | 42 -------------- test/scudo/valloc.c | 65 +++++++++++++++++++++ test/scudo/valloc.cpp | 65 --------------------- 30 files changed, 587 insertions(+), 572 deletions(-) create mode 100644 test/scudo/alignment.c delete mode 100644 test/scudo/alignment.cpp create mode 100644 test/scudo/memalign.c delete mode 100644 test/scudo/memalign.cpp create mode 100644 test/scudo/overflow.c delete mode 100644 test/scudo/overflow.cpp create mode 100644 test/scudo/preinit.c delete mode 100644 test/scudo/preinit.cpp create mode 100644 test/scudo/quarantine.c delete mode 100644 test/scudo/quarantine.cpp create mode 100644 test/scudo/secondary.c delete mode 100644 test/scudo/secondary.cpp create mode 100644 test/scudo/threads.c delete mode 100644 test/scudo/threads.cpp create mode 100644 test/scudo/tsd_destruction.c delete mode 100644 test/scudo/tsd_destruction.cpp create mode 100644 test/scudo/valloc.c delete mode 100644 test/scudo/valloc.cpp diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 0d6314680..4d26a3477 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -12,12 +12,14 @@ set(SCUDO_SOURCES scudo_flags.cpp scudo_crc32.cpp scudo_interceptors.cpp - scudo_new_delete.cpp scudo_termination.cpp scudo_tsd_exclusive.cpp scudo_tsd_shared.cpp scudo_utils.cpp) +set(SCUDO_CXX_SOURCES + scudo_new_delete.cpp) + # Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available. if (COMPILER_RT_HAS_MSSE4_2_FLAG) set_source_files_properties(scudo_crc32.cpp PROPERTIES COMPILE_FLAGS -msse4.2) @@ -36,26 +38,35 @@ if(COMPILER_RT_HAS_SCUDO) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_DYNAMIC_LIBS) - foreach(arch ${SCUDO_SUPPORTED_ARCH}) - add_compiler_rt_runtime(clang_rt.scudo - STATIC - ARCHS ${arch} - SOURCES ${SCUDO_SOURCES} - OBJECT_LIBS RTSanitizerCommonNoTermination - RTSanitizerCommonLibc - RTInterception - CFLAGS ${SCUDO_CFLAGS} - PARENT_TARGET scudo) - - add_compiler_rt_runtime(clang_rt.scudo - SHARED - ARCHS ${arch} - SOURCES ${SCUDO_SOURCES} - OBJECT_LIBS RTSanitizerCommonNoTermination - RTSanitizerCommonLibc - RTInterception - CFLAGS ${SCUDO_CFLAGS} - LINK_LIBS ${SCUDO_DYNAMIC_LIBS} - PARENT_TARGET scudo) - endforeach() + add_compiler_rt_runtime(clang_rt.scudo + STATIC + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_SOURCES} + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception + RTUbsan + CFLAGS ${SCUDO_CFLAGS} + PARENT_TARGET scudo) + + add_compiler_rt_runtime(clang_rt.scudo_cxx + STATIC + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_CXX_SOURCES} + OBJECT_LIBS RTUbsan_cxx + CFLAGS ${SCUDO_CFLAGS} + PARENT_TARGET scudo) + + add_compiler_rt_runtime(clang_rt.scudo + SHARED + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_SOURCES} ${SCUDO_CXX_SOURCES} + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception + RTUbsan + RTUbsan_cxx + CFLAGS ${SCUDO_CFLAGS} + LINK_LIBS ${SCUDO_DYNAMIC_LIBS} + PARENT_TARGET scudo) endif() diff --git a/test/scudo/alignment.c b/test/scudo/alignment.c new file mode 100644 index 000000000..6235d5060 --- /dev/null +++ b/test/scudo/alignment.c @@ -0,0 +1,23 @@ +// RUN: %clang_scudo %s -o %t +// RUN: not %run %t pointers 2>&1 | FileCheck %s + +// Tests that a non MinAlignment aligned pointer will trigger the associated +// error on deallocation. + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + assert(argc == 2); + if (!strcmp(argv[1], "pointers")) { + void *p = malloc(1U << 16); + assert(p); + free((void *)((uintptr_t)p | 1)); + } + return 0; +} + +// CHECK: ERROR: attempted to deallocate a chunk not properly aligned diff --git a/test/scudo/alignment.cpp b/test/scudo/alignment.cpp deleted file mode 100644 index 125ad8cbe..000000000 --- a/test/scudo/alignment.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: not %run %t pointers 2>&1 | FileCheck %s - -// Tests that a non MinAlignment aligned pointer will trigger the associated -// error on deallocation. - -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - assert(argc == 2); - if (!strcmp(argv[1], "pointers")) { - void *p = malloc(1U << 16); - assert(p); - free(reinterpret_cast(reinterpret_cast(p) | 1)); - } - return 0; -} - -// CHECK: ERROR: attempted to deallocate a chunk not properly aligned diff --git a/test/scudo/double-free.cpp b/test/scudo/double-free.cpp index ddc520505..56118038c 100644 --- a/test/scudo/double-free.cpp +++ b/test/scudo/double-free.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: not %run %t malloc 2>&1 | FileCheck %s // RUN: not %run %t new 2>&1 | FileCheck %s // RUN: not %run %t newarray 2>&1 | FileCheck %s diff --git a/test/scudo/interface.cpp b/test/scudo/interface.cpp index e9575adf3..16523bfe3 100644 --- a/test/scudo/interface.cpp +++ b/test/scudo/interface.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t ownership 2>&1 // RUN: %run %t ownership-and-size 2>&1 // RUN: %run %t heap-size 2>&1 diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index f4b864777..0113bf0e7 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -11,21 +11,24 @@ config.test_source_root = os.path.dirname(__file__) # Path to the shared & static libraries shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.so" % config.target_arch) static_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.a" % config.target_arch) +static_libscudo_cxx = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo_cxx-%s.a" % config.target_arch) + whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo +whole_archive_cxx = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo_cxx # Test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -# C flags. +# C & CXX flags. c_flags = ([config.target_cflags] + - ["-std=c++11", - "-pthread", + ["-pthread", "-fPIE", "-pie", "-O0", "-UNDEBUG", "-ldl", "-Wl,--gc-sections"]) +cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) # Android doesn't want -lrt. if not config.android: @@ -37,6 +40,7 @@ def build_invocation(compile_flags): # Add clang substitutions. config.substitutions.append(("%clang ", build_invocation(c_flags))) config.substitutions.append(("%clang_scudo ", build_invocation(c_flags) + whole_archive)) +config.substitutions.append(("%clangxx_scudo ", build_invocation(cxx_flags) + whole_archive + whole_archive_cxx)) config.substitutions.append(("%shared_libscudo", shared_libscudo)) # Platform-specific default SCUDO_OPTIONS for lit tests. diff --git a/test/scudo/malloc.cpp b/test/scudo/malloc.cpp index 50e52590f..6c6a6c464 100644 --- a/test/scudo/malloc.cpp +++ b/test/scudo/malloc.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t 2>&1 // Tests that a regular workflow of allocation, memory fill and free works as diff --git a/test/scudo/memalign.c b/test/scudo/memalign.c new file mode 100644 index 000000000..1fe6e3ec7 --- /dev/null +++ b/test/scudo/memalign.c @@ -0,0 +1,81 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 + +// Tests that the various aligned allocation functions work as intended. Also +// tests for the condition where the alignment is not a power of 2. + +#include +#include +#include +#include +#include +#include +#include + +// Sometimes the headers may not have this... +void *aligned_alloc(size_t alignment, size_t size); + +int main(int argc, char **argv) +{ + void *p = NULL; + size_t alignment = 1U << 12; + size_t size = 1U << 12; + int err; + + assert(argc == 2); + + if (!strcmp(argv[1], "valid")) { + posix_memalign(&p, alignment, size); + assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); + free(p); + p = aligned_alloc(alignment, size); + assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); + free(p); + // Tests various combinations of alignment and sizes + for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { + alignment = 1U << i; + for (int j = 1; j < 33; j++) { + size = 0x800 * j; + for (int k = 0; k < 3; k++) { + p = memalign(alignment, size - (2 * sizeof(void *) * k)); + assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); + free(p); + } + } + } + // For larger alignment, reduce the number of allocations to avoid running + // out of potential addresses (on 32-bit). + for (int i = 19; i <= 24; i++) { + for (int k = 0; k < 3; k++) { + p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); + assert(p); + assert(((uintptr_t)p & (alignment - 1)) == 0); + free(p); + } + } + } + if (!strcmp(argv[1], "invalid")) { + // Alignment is not a power of 2. + p = memalign(alignment - 1, size); + assert(!p); + // Size is not a multiple of alignment. + p = aligned_alloc(alignment, size >> 1); + assert(!p); + void *p_unchanged = (void *)0x42UL; + p = p_unchanged; + // Alignment is not a power of 2. + err = posix_memalign(&p, 3, size); + assert(p == p_unchanged); + assert(err == EINVAL); + // Alignment is a power of 2, but not a multiple of size(void *). + err = posix_memalign(&p, 2, size); + assert(p == p_unchanged); + assert(err == EINVAL); + } + return 0; +} diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp deleted file mode 100644 index fece04dfc..000000000 --- a/test/scudo/memalign.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 -// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 - -// Tests that the various aligned allocation functions work as intended. Also -// tests for the condition where the alignment is not a power of 2. - -#include -#include -#include -#include -#include -#include -#include - -// Sometimes the headers may not have this... -extern "C" void *aligned_alloc(size_t alignment, size_t size); - -int main(int argc, char **argv) -{ - void *p = nullptr; - size_t alignment = 1U << 12; - size_t size = 1U << 12; - int err; - - assert(argc == 2); - - if (!strcmp(argv[1], "valid")) { - posix_memalign(&p, alignment, size); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - p = aligned_alloc(alignment, size); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - // Tests various combinations of alignment and sizes - for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { - alignment = 1U << i; - for (int j = 1; j < 33; j++) { - size = 0x800 * j; - for (int k = 0; k < 3; k++) { - p = memalign(alignment, size - (2 * sizeof(void *) * k)); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - } - } - } - // For larger alignment, reduce the number of allocations to avoid running - // out of potential addresses (on 32-bit). - for (int i = 19; i <= 24; i++) { - for (int k = 0; k < 3; k++) { - p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - } - } - } - if (!strcmp(argv[1], "invalid")) { - // Alignment is not a power of 2. - p = memalign(alignment - 1, size); - assert(!p); - // Size is not a multiple of alignment. - p = aligned_alloc(alignment, size >> 1); - assert(!p); - void *p_unchanged = (void *)0x42UL; - p = p_unchanged; - // Alignment is not a power of 2. - err = posix_memalign(&p, 3, size); - assert(p == p_unchanged); - assert(err == EINVAL); - // Alignment is a power of 2, but not a multiple of size(void *). - err = posix_memalign(&p, 2, size); - assert(p == p_unchanged); - assert(err == EINVAL); - } - return 0; -} diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index 538c8e6de..b49e0ea46 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s diff --git a/test/scudo/options.cpp b/test/scudo/options.cpp index 6464bc65b..605b63241 100644 --- a/test/scudo/options.cpp +++ b/test/scudo/options.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: %run %t 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s diff --git a/test/scudo/overflow.c b/test/scudo/overflow.c new file mode 100644 index 000000000..c5a58f87f --- /dev/null +++ b/test/scudo/overflow.c @@ -0,0 +1,39 @@ +// RUN: %clang_scudo %s -o %t +// RUN: not %run %t malloc 2>&1 | FileCheck %s +// RUN: %env_scudo_opts=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s + +// Tests that header corruption of an allocated or quarantined chunk is caught. + +#include +#include +#include + +int main(int argc, char **argv) +{ + ssize_t offset = sizeof(void *) == 8 ? 8 : 0; + + assert(argc == 2); + + if (!strcmp(argv[1], "malloc")) { + // Simulate a header corruption of an allocated chunk (1-bit) + void *p = malloc(1U << 4); + assert(p); + ((char *)p)[-(offset + 1)] ^= 1; + free(p); + } + if (!strcmp(argv[1], "quarantine")) { + void *p = malloc(1U << 4); + assert(p); + free(p); + // Simulate a header corruption of a quarantined chunk + ((char *)p)[-(offset + 2)] ^= 1; + // Trigger the quarantine recycle + for (int i = 0; i < 0x100; i++) { + p = malloc(1U << 8); + free(p); + } + } + return 0; +} + +// CHECK: ERROR: corrupted chunk header at address diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp deleted file mode 100644 index c5a58f87f..000000000 --- a/test/scudo/overflow.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s -// RUN: %env_scudo_opts=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s - -// Tests that header corruption of an allocated or quarantined chunk is caught. - -#include -#include -#include - -int main(int argc, char **argv) -{ - ssize_t offset = sizeof(void *) == 8 ? 8 : 0; - - assert(argc == 2); - - if (!strcmp(argv[1], "malloc")) { - // Simulate a header corruption of an allocated chunk (1-bit) - void *p = malloc(1U << 4); - assert(p); - ((char *)p)[-(offset + 1)] ^= 1; - free(p); - } - if (!strcmp(argv[1], "quarantine")) { - void *p = malloc(1U << 4); - assert(p); - free(p); - // Simulate a header corruption of a quarantined chunk - ((char *)p)[-(offset + 2)] ^= 1; - // Trigger the quarantine recycle - for (int i = 0; i < 0x100; i++) { - p = malloc(1U << 8); - free(p); - } - } - return 0; -} - -// CHECK: ERROR: corrupted chunk header at address diff --git a/test/scudo/preinit.c b/test/scudo/preinit.c new file mode 100644 index 000000000..792b2368e --- /dev/null +++ b/test/scudo/preinit.c @@ -0,0 +1,40 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 + +// Verifies that calling malloc in a preinit_array function succeeds, and that +// the resulting pointer can be freed at program termination. + +// On some Android versions, calling mmap() from a preinit function segfaults. +// It looks like __mmap2.S ends up calling a NULL function pointer. +// UNSUPPORTED: android + +#include +#include +#include + +static void *global_p = NULL; + +void __init(void) { + global_p = malloc(1); + if (!global_p) + exit(1); +} + +void __fini(void) { + if (global_p) + free(global_p); +} + +int main(int argc, char **argv) +{ + void *p = malloc(1); + assert(p); + free(p); + + return 0; +} + +__attribute__((section(".preinit_array"), used)) + void (*__local_preinit)(void) = __init; +__attribute__((section(".fini_array"), used)) + void (*__local_fini)(void) = __fini; diff --git a/test/scudo/preinit.cpp b/test/scudo/preinit.cpp deleted file mode 100644 index f904c6c2d..000000000 --- a/test/scudo/preinit.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t 2>&1 - -// Verifies that calling malloc in a preinit_array function succeeds, and that -// the resulting pointer can be freed at program termination. - -// On some Android versions, calling mmap() from a preinit function segfaults. -// It looks like __mmap2.S ends up calling a NULL function pointer. -// UNSUPPORTED: android - -#include -#include -#include - -static void *global_p = nullptr; - -void __init(void) { - global_p = malloc(1); - if (!global_p) - exit(1); -} - -void __fini(void) { - if (global_p) - free(global_p); -} - -int main(int argc, char **argv) -{ - void *p = malloc(1); - assert(p); - free(p); - - return 0; -} - -__attribute__((section(".preinit_array"), used)) - void (*__local_preinit)(void) = __init; -__attribute__((section(".fini_array"), used)) - void (*__local_fini)(void) = __fini; diff --git a/test/scudo/preload.cpp b/test/scudo/preload.cpp index 0da507b3c..b41a70e47 100644 --- a/test/scudo/preload.cpp +++ b/test/scudo/preload.cpp @@ -1,19 +1,19 @@ // Test that the preloaded runtime works without linking the static library. -// RUN: %clang %s -o %t +// RUN: %clang %s -lstdc++ -o %t // RUN: env LD_PRELOAD=%shared_libscudo not %run %t 2>&1 | FileCheck %s // This way of setting LD_PRELOAD does not work with Android test runner. // REQUIRES: !android #include -#include int main(int argc, char *argv[]) { - void *p = malloc(sizeof(int)); + int *p = new int; assert(p); - free(p); - free(p); + *p = 0; + delete p; + delete p; return 0; } diff --git a/test/scudo/quarantine.c b/test/scudo/quarantine.c new file mode 100644 index 000000000..ddbb92005 --- /dev/null +++ b/test/scudo/quarantine.c @@ -0,0 +1,124 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 +// RUN: %env_scudo_opts=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 +// RUN: %env_scudo_opts=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 + +// Tests that the quarantine prevents a chunk from being reused right away. +// Also tests that a chunk will eventually become available again for +// allocation when the recycling criteria has been met. Finally, tests the +// threshold up to which a chunk is quarantine, and the old quarantine behavior. + +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + void *p, *old_p; + size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8; + + assert(argc == 2); + // First, warm up the allocator for the classes used. + p = malloc(size); + assert(p); + free(p); + p = malloc(size + 1); + assert(p); + free(p); + assert(posix_memalign(&p, alignment, size) == 0); + assert(p); + free(p); + assert(posix_memalign(&p, alignment, size + 1) == 0); + assert(p); + free(p); + + if (!strcmp(argv[1], "zeroquarantine")) { + // Verifies that a chunk is deallocated right away when the local and + // global quarantine sizes are 0. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(size); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); + } + if (!strcmp(argv[1], "smallquarantine")) { + // The delayed freelist will prevent a chunk from being available right + // away. + p = malloc(size); + assert(p); + old_p = p; + free(p); + p = malloc(size); + assert(p); + assert(old_p != p); + free(p); + + // Eventually the chunk should become available again. + char found = 0; + for (int i = 0; i < 0x200 && !found; i++) { + p = malloc(size); + assert(p); + found = (p == old_p); + free(p); + } + assert(found); + } + if (!strcmp(argv[1], "threshold")) { + // Verifies that a chunk of size greater than the threshold will be freed + // right away. Alignment has no impact on the threshold. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(size + 1); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); + assert(posix_memalign(&p, alignment, size + 1) == 0); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); + // Verifies that a chunk of size lower or equal to the threshold will be + // quarantined. + p = malloc(size); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + assert(posix_memalign(&p, alignment, size) == 0); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + } + if (!strcmp(argv[1], "oldquarantine")) { + // Verifies that we quarantine everything if the deprecated quarantine + // option is specified. Alignment has no impact on the threshold. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(size); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + assert(posix_memalign(&p, alignment, size) == 0); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + // Secondary backed allocation. + allocated_bytes = __sanitizer_get_current_allocated_bytes(); + p = malloc(1U << 19); + assert(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + free(p); + assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); + } + + return 0; +} diff --git a/test/scudo/quarantine.cpp b/test/scudo/quarantine.cpp deleted file mode 100644 index 8872fe688..000000000 --- a/test/scudo/quarantine.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 -// RUN: %env_scudo_opts=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 -// RUN: %env_scudo_opts=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 - -// Tests that the quarantine prevents a chunk from being reused right away. -// Also tests that a chunk will eventually become available again for -// allocation when the recycling criteria has been met. Finally, tests the -// threshold up to which a chunk is quarantine, and the old quarantine behavior. - -#include -#include -#include -#include - -#include - -int main(int argc, char **argv) -{ - void *p, *old_p; - size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8; - - assert(argc == 2); - // First, warm up the allocator for the classes used. - p = malloc(size); - assert(p); - free(p); - p = malloc(size + 1); - assert(p); - free(p); - assert(posix_memalign(&p, alignment, size) == 0); - assert(p); - free(p); - assert(posix_memalign(&p, alignment, size + 1) == 0); - assert(p); - free(p); - - if (!strcmp(argv[1], "zeroquarantine")) { - // Verifies that a chunk is deallocated right away when the local and - // global quarantine sizes are 0. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - } - if (!strcmp(argv[1], "smallquarantine")) { - // The delayed freelist will prevent a chunk from being available right - // away. - p = malloc(size); - assert(p); - old_p = p; - free(p); - p = malloc(size); - assert(p); - assert(old_p != p); - free(p); - - // Eventually the chunk should become available again. - bool found = false; - for (int i = 0; i < 0x200 && !found; i++) { - p = malloc(size); - assert(p); - found = (p == old_p); - free(p); - } - assert(found); - } - if (!strcmp(argv[1], "threshold")) { - // Verifies that a chunk of size greater than the threshold will be freed - // right away. Alignment has no impact on the threshold. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size + 1); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - assert(posix_memalign(&p, alignment, size + 1) == 0); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - // Verifies that a chunk of size lower or equal to the threshold will be - // quarantined. - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - assert(posix_memalign(&p, alignment, size) == 0); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - } - if (!strcmp(argv[1], "oldquarantine")) { - // Verifies that we quarantine everything if the deprecated quarantine - // option is specified. Alignment has no impact on the threshold. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - assert(posix_memalign(&p, alignment, size) == 0); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - // Secondary backed allocation. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(1U << 19); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - } - - return 0; -} diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp index 54768a578..f886cb150 100644 --- a/test/scudo/random_shuffle.cpp +++ b/test/scudo/random_shuffle.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: rm -rf %T/random_shuffle_tmp_dir // RUN: mkdir %T/random_shuffle_tmp_dir // RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out1 diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp index 01149670e..254c67a2c 100644 --- a/test/scudo/realloc.cpp +++ b/test/scudo/realloc.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t pointers 2>&1 // RUN: %run %t contents 2>&1 // RUN: %run %t usablesize 2>&1 diff --git a/test/scudo/secondary.c b/test/scudo/secondary.c new file mode 100644 index 000000000..b770ca076 --- /dev/null +++ b/test/scudo/secondary.c @@ -0,0 +1,53 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t after 2>&1 | FileCheck %s +// RUN: %run %t before 2>&1 | FileCheck %s + +// Test that we hit a guard page when writing past the end of a chunk +// allocated by the Secondary allocator, or writing too far in front of it. + +#include +#include +#include +#include +#include +#include + +void handler(int signo, siginfo_t *info, void *uctx) { + if (info->si_code == SEGV_ACCERR) { + fprintf(stderr, "SCUDO SIGSEGV\n"); + exit(0); + } + exit(1); +} + +int main(int argc, char **argv) +{ + // The size must be large enough to be serviced by the secondary allocator. + long page_size = sysconf(_SC_PAGESIZE); + size_t size = (1U << 17) + page_size; + struct sigaction a; + + assert(argc == 2); + memset(&a, 0, sizeof(a)); + a.sa_sigaction = handler; + a.sa_flags = SA_SIGINFO; + + char *p = (char *)malloc(size); + assert(p); + memset(p, 'A', size); // This should not trigger anything. + // Set up the SIGSEGV handler now, as the rest should trigger an AV. + sigaction(SIGSEGV, &a, NULL); + if (!strcmp(argv[1], "after")) { + for (int i = 0; i < page_size; i++) + p[size + i] = 'A'; + } + if (!strcmp(argv[1], "before")) { + for (int i = 1; i < page_size; i++) + p[-i] = 'A'; + } + free(p); + + return 1; // A successful test means we shouldn't reach this. +} + +// CHECK: SCUDO SIGSEGV diff --git a/test/scudo/secondary.cpp b/test/scudo/secondary.cpp deleted file mode 100644 index dc14f8ca8..000000000 --- a/test/scudo/secondary.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t after 2>&1 | FileCheck %s -// RUN: %run %t before 2>&1 | FileCheck %s - -// Test that we hit a guard page when writing past the end of a chunk -// allocated by the Secondary allocator, or writing too far in front of it. - -#include -#include -#include -#include -#include -#include - -void handler(int signo, siginfo_t *info, void *uctx) { - if (info->si_code == SEGV_ACCERR) { - fprintf(stderr, "SCUDO SIGSEGV\n"); - exit(0); - } - exit(1); -} - -int main(int argc, char **argv) -{ - // The size must be large enough to be serviced by the secondary allocator. - long page_size = sysconf(_SC_PAGESIZE); - size_t size = (1U << 17) + page_size; - struct sigaction a; - - assert(argc == 2); - memset(&a, 0, sizeof(a)); - a.sa_sigaction = handler; - a.sa_flags = SA_SIGINFO; - - char *p = (char *)malloc(size); - assert(p); - memset(p, 'A', size); // This should not trigger anything. - // Set up the SIGSEGV handler now, as the rest should trigger an AV. - sigaction(SIGSEGV, &a, nullptr); - if (!strcmp(argv[1], "after")) { - for (int i = 0; i < page_size; i++) - p[size + i] = 'A'; - } - if (!strcmp(argv[1], "before")) { - for (int i = 1; i < page_size; i++) - p[-i] = 'A'; - } - free(p); - - return 1; // A successful test means we shouldn't reach this. -} - -// CHECK: SCUDO SIGSEGV diff --git a/test/scudo/sized-delete.cpp b/test/scudo/sized-delete.cpp index 9c3a2c596..85df05e2f 100644 --- a/test/scudo/sized-delete.cpp +++ b/test/scudo/sized-delete.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo -fsized-deallocation %s -o %t +// RUN: %clangxx_scudo -fsized-deallocation %s -o %t // RUN: %env_scudo_opts=DeleteSizeMismatch=1 %run %t gooddel 2>&1 // RUN: %env_scudo_opts=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s // RUN: %env_scudo_opts=DeleteSizeMismatch=0 %run %t baddel 2>&1 diff --git a/test/scudo/sizes.cpp b/test/scudo/sizes.cpp index 8f147b708..73fc71f25 100644 --- a/test/scudo/sizes.cpp +++ b/test/scudo/sizes.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s // RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t malloc 2>&1 // RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s diff --git a/test/scudo/threads.c b/test/scudo/threads.c new file mode 100644 index 000000000..b34e6f0f7 --- /dev/null +++ b/test/scudo/threads.c @@ -0,0 +1,65 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=1024:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 + +// Tests parallel allocations and deallocations of memory chunks from a number +// of concurrent threads, with and without quarantine. +// This test passes if everything executes properly without crashing. + +#include +#include +#include +#include + +#include + +int num_threads; +int total_num_alloc; +const int kMaxNumThreads = 500; +pthread_t tid[kMaxNumThreads]; + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +char go = 0; + +void *thread_fun(void *arg) { + pthread_mutex_lock(&mutex); + while (!go) pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < total_num_alloc / num_threads; i++) { + void *p = malloc(10); + __asm__ __volatile__("" : : "r"(p) : "memory"); + free(p); + } + return 0; +} + +int main(int argc, char** argv) { + assert(argc == 3); + num_threads = atoi(argv[1]); + assert(num_threads > 0); + assert(num_threads <= kMaxNumThreads); + total_num_alloc = atoi(argv[2]); + assert(total_num_alloc > 0); + + printf("%d threads, %d allocations in each\n", num_threads, + total_num_alloc / num_threads); + fprintf(stderr, "Heap size before: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes before: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + for (int i = 0; i < num_threads; i++) + pthread_create(&tid[i], 0, thread_fun, 0); + pthread_mutex_lock(&mutex); + go = 1; + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < num_threads; i++) + pthread_join(tid[i], 0); + + fprintf(stderr, "Heap size after: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes after: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + return 0; +} diff --git a/test/scudo/threads.cpp b/test/scudo/threads.cpp deleted file mode 100644 index 643eda77d..000000000 --- a/test/scudo/threads.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeKb=1024:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 - -// Tests parallel allocations and deallocations of memory chunks from a number -// of concurrent threads, with and without quarantine. -// This test passes if everything executes properly without crashing. - -#include -#include -#include -#include - -#include - -int num_threads; -int total_num_alloc; -const int kMaxNumThreads = 500; -pthread_t tid[kMaxNumThreads]; - -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -bool go = false; - -void *thread_fun(void *arg) { - pthread_mutex_lock(&mutex); - while (!go) pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - for (int i = 0; i < total_num_alloc / num_threads; i++) { - void *p = malloc(10); - __asm__ __volatile__("" : : "r"(p) : "memory"); - free(p); - } - return 0; -} - -int main(int argc, char** argv) { - assert(argc == 3); - num_threads = atoi(argv[1]); - assert(num_threads > 0); - assert(num_threads <= kMaxNumThreads); - total_num_alloc = atoi(argv[2]); - assert(total_num_alloc > 0); - - printf("%d threads, %d allocations in each\n", num_threads, - total_num_alloc / num_threads); - fprintf(stderr, "Heap size before: %zd\n", __sanitizer_get_heap_size()); - fprintf(stderr, "Allocated bytes before: %zd\n", - __sanitizer_get_current_allocated_bytes()); - - for (int i = 0; i < num_threads; i++) - pthread_create(&tid[i], 0, thread_fun, 0); - pthread_mutex_lock(&mutex); - go = true; - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - for (int i = 0; i < num_threads; i++) - pthread_join(tid[i], 0); - - fprintf(stderr, "Heap size after: %zd\n", __sanitizer_get_heap_size()); - fprintf(stderr, "Allocated bytes after: %zd\n", - __sanitizer_get_current_allocated_bytes()); - - return 0; -} diff --git a/test/scudo/tsd_destruction.c b/test/scudo/tsd_destruction.c new file mode 100644 index 000000000..1b0d0eff9 --- /dev/null +++ b/test/scudo/tsd_destruction.c @@ -0,0 +1,42 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 + +#include +#include +#include +#include +#include + +// Some of glibc's own thread local data is destroyed after a user's thread +// local destructors are called, via __libc_thread_freeres. This might involve +// calling free, as is the case for strerror_thread_freeres. +// If there is no prior heap operation in the thread, this free would end up +// initializing some thread specific data that would never be destroyed +// properly, while still being deallocated when the TLS goes away. As a result, +// a program could SEGV, usually in +// __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly +// linked list links would refer to a now unmapped memory area. + +// This test reproduces those circumstances. Success means executing without +// a segmentation fault. + +const int kNumThreads = 16; +pthread_t tid[kNumThreads]; + +void *thread_func(void *arg) { + uintptr_t i = (uintptr_t)arg; + if ((i & 1) == 0) free(malloc(16)); + // Calling strerror_l allows for strerror_thread_freeres to be called. + strerror_l(0, LC_GLOBAL_LOCALE); + return 0; +} + +int main(int argc, char** argv) { + for (uintptr_t j = 0; j < 8; j++) { + for (uintptr_t i = 0; i < kNumThreads; i++) + pthread_create(&tid[i], 0, thread_func, (void *)i); + for (uintptr_t i = 0; i < kNumThreads; i++) + pthread_join(tid[i], 0); + } + return 0; +} diff --git a/test/scudo/tsd_destruction.cpp b/test/scudo/tsd_destruction.cpp deleted file mode 100644 index 1b0d0eff9..000000000 --- a/test/scudo/tsd_destruction.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t 2>&1 - -#include -#include -#include -#include -#include - -// Some of glibc's own thread local data is destroyed after a user's thread -// local destructors are called, via __libc_thread_freeres. This might involve -// calling free, as is the case for strerror_thread_freeres. -// If there is no prior heap operation in the thread, this free would end up -// initializing some thread specific data that would never be destroyed -// properly, while still being deallocated when the TLS goes away. As a result, -// a program could SEGV, usually in -// __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly -// linked list links would refer to a now unmapped memory area. - -// This test reproduces those circumstances. Success means executing without -// a segmentation fault. - -const int kNumThreads = 16; -pthread_t tid[kNumThreads]; - -void *thread_func(void *arg) { - uintptr_t i = (uintptr_t)arg; - if ((i & 1) == 0) free(malloc(16)); - // Calling strerror_l allows for strerror_thread_freeres to be called. - strerror_l(0, LC_GLOBAL_LOCALE); - return 0; -} - -int main(int argc, char** argv) { - for (uintptr_t j = 0; j < 8; j++) { - for (uintptr_t i = 0; i < kNumThreads; i++) - pthread_create(&tid[i], 0, thread_func, (void *)i); - for (uintptr_t i = 0; i < kNumThreads; i++) - pthread_join(tid[i], 0); - } - return 0; -} diff --git a/test/scudo/valloc.c b/test/scudo/valloc.c new file mode 100644 index 000000000..132c4f280 --- /dev/null +++ b/test/scudo/valloc.c @@ -0,0 +1,65 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t valid 2>&1 +// RUN: not %run %t invalid 2>&1 +// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 +// UNSUPPORTED: android, armhf-linux + +// Tests that valloc and pvalloc work as intended. + +#include +#include +#include +#include +#include +#include + +size_t round_up_to(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +int main(int argc, char **argv) +{ + void *p = NULL; + size_t size, page_size; + + assert(argc == 2); + + page_size = sysconf(_SC_PAGESIZE); + // Check that the page size is a power of two. + assert((page_size & (page_size - 1)) == 0); + + if (!strcmp(argv[1], "valid")) { + for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 21; i++) { + size = 1U << i; + p = valloc(size - (2 * sizeof(void *))); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + free(p); + p = pvalloc(size - (2 * sizeof(void *))); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + assert(malloc_usable_size(p) >= round_up_to(size, page_size)); + free(p); + p = valloc(size); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + free(p); + p = pvalloc(size); + assert(p); + assert(((uintptr_t)p & (page_size - 1)) == 0); + assert(malloc_usable_size(p) >= round_up_to(size, page_size)); + free(p); + } + } + if (!strcmp(argv[1], "invalid")) { + // Size passed to pvalloc overflows when rounded up. + p = pvalloc((size_t)-1); + assert(!p); + assert(errno == ENOMEM); + errno = 0; + p = pvalloc((size_t)-page_size); + assert(!p); + assert(errno == ENOMEM); + } + return 0; +} diff --git a/test/scudo/valloc.cpp b/test/scudo/valloc.cpp deleted file mode 100644 index 514a88449..000000000 --- a/test/scudo/valloc.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t valid 2>&1 -// RUN: not %run %t invalid 2>&1 -// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 -// UNSUPPORTED: android, armhf-linux - -// Tests that valloc and pvalloc work as intended. - -#include -#include -#include -#include -#include -#include - -size_t round_up_to(size_t size, size_t alignment) { - return (size + alignment - 1) & ~(alignment - 1); -} - -int main(int argc, char **argv) -{ - void *p = nullptr; - size_t size, page_size; - - assert(argc == 2); - - page_size = sysconf(_SC_PAGESIZE); - // Check that the page size is a power of two. - assert((page_size & (page_size - 1)) == 0); - - if (!strcmp(argv[1], "valid")) { - for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 21; i++) { - size = 1U << i; - p = valloc(size - (2 * sizeof(void *))); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - free(p); - p = pvalloc(size - (2 * sizeof(void *))); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - assert(malloc_usable_size(p) >= round_up_to(size, page_size)); - free(p); - p = valloc(size); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - free(p); - p = pvalloc(size); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - assert(malloc_usable_size(p) >= round_up_to(size, page_size)); - free(p); - } - } - if (!strcmp(argv[1], "invalid")) { - // Size passed to pvalloc overflows when rounded up. - p = pvalloc((size_t)-1); - assert(!p); - assert(errno == ENOMEM); - errno = 0; - p = pvalloc((size_t)-page_size); - assert(!p); - assert(errno == ENOMEM); - } - return 0; -} -- cgit v1.2.1 From 4f6767844a54e52043f3a8e237b3075b0507fd0a Mon Sep 17 00:00:00 2001 From: Kostya Kortchinsky Date: Wed, 1 Nov 2017 17:00:26 +0000 Subject: [scudo] Fix standlone build -lrt requirement Summary: The split in D39461 introduced separate C++ flags, but `cxx_flags` needs `-lrt` as well for the standalone build. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39497 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317103 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/scudo/lit.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index 0113bf0e7..2f6469d25 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -28,12 +28,13 @@ c_flags = ([config.target_cflags] + "-UNDEBUG", "-ldl", "-Wl,--gc-sections"]) -cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) # Android doesn't want -lrt. if not config.android: c_flags += ["-lrt"] +cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) + def build_invocation(compile_flags): return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " " -- cgit v1.2.1 From a638156d40e40dd33b5363204b33e3a9c5a026d6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 1 Nov 2017 20:27:06 +0000 Subject: [fuzzer] Script to detect unbalanced allocation in -trace_malloc output Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39466 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317119 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/scripts/unbalanced_allocs.py | 93 ++++++++++++++++++++++++++++++++ test/fuzzer/trace-malloc-unbalanced.test | 27 ++++++++++ 2 files changed, 120 insertions(+) create mode 100755 lib/fuzzer/scripts/unbalanced_allocs.py create mode 100644 test/fuzzer/trace-malloc-unbalanced.test diff --git a/lib/fuzzer/scripts/unbalanced_allocs.py b/lib/fuzzer/scripts/unbalanced_allocs.py new file mode 100755 index 000000000..a4ce18767 --- /dev/null +++ b/lib/fuzzer/scripts/unbalanced_allocs.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +#===- lib/fuzzer/scripts/unbalanced_allocs.py ------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# Post-process -trace_malloc=2 output and printout only allocations and frees +# unbalanced inside of fuzzer runs. +# Usage: +# my_fuzzer -trace_malloc=2 -runs=10 2>&1 | unbalanced_allocs.py -skip=5 +# +#===------------------------------------------------------------------------===# + +import argparse +import sys + +_skip = 0 + +def PrintStack(line, stack): + global _skip + if _skip > 0: + return + print 'Unbalanced ' + line.rstrip(); + for l in stack: + print l.rstrip() + +def ProcessStack(line, f): + stack = [] + while line and line.startswith(' #'): + stack += [line] + line = f.readline() + return line, stack + +def ProcessFree(line, f, allocs): + if not line.startswith('FREE['): + return f.readline() + + addr = int(line.split()[1], 16) + next_line, stack = ProcessStack(f.readline(), f) + if addr in allocs: + del allocs[addr] + else: + PrintStack(line, stack) + return next_line + +def ProcessMalloc(line, f, allocs): + if not line.startswith('MALLOC['): + return ProcessFree(line, f, allocs) + + addr = int(line.split()[1], 16) + assert not addr in allocs + + next_line, stack = ProcessStack(f.readline(), f) + allocs[addr] = (line, stack) + return next_line + +def ProcessRun(line, f): + if not line.startswith('MallocFreeTracer: START'): + return ProcessMalloc(line, f, {}) + + allocs = {} + print line.rstrip() + line = f.readline() + while line: + if line.startswith('MallocFreeTracer: STOP'): + global _skip + _skip = _skip - 1 + for _, (l, s) in allocs.iteritems(): + PrintStack(l, s) + print line.rstrip() + return f.readline() + line = ProcessMalloc(line, f, allocs) + return line + +def ProcessFile(f): + line = f.readline() + while line: + line = ProcessRun(line, f); + +def main(argv): + parser = argparse.ArgumentParser() + parser.add_argument('--skip', default=0, help='number of runs to ignore') + args = parser.parse_args() + global _skip + _skip = int(args.skip) + 1 + ProcessFile(sys.stdin) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/fuzzer/trace-malloc-unbalanced.test b/test/fuzzer/trace-malloc-unbalanced.test new file mode 100644 index 000000000..53b83fb68 --- /dev/null +++ b/test/fuzzer/trace-malloc-unbalanced.test @@ -0,0 +1,27 @@ +// FIXME: This test infinite loops on darwin because it crashes +// printing a stack trace repeatedly +UNSUPPORTED: darwin + +// Verifies lib/fuzzer/scripts/unbalanced_allocs.py script + +RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=100 2>&1 | \ +RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s + +RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=100 2>&1 | \ +RUN: %libfuzzer_src/scripts/unbalanced_allocs.py --skip=5 | FileCheck %s --check-prefixes=CHECK,CHECK2 + +CHECK: MallocFreeTracer: START +CHECK: Unbalanced MALLOC[{{[0-9]+}}] [[PTR:0x[0-9a-f]+]] 4 +CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} +CHECK: MallocFreeTracer: STOP + +CHECK: MallocFreeTracer: START +CHECK: Unbalanced FREE[{{[0-9]+}}] [[PTR]] +CHECK2-NEXT: {{ #0 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #1 0x[0-9a-f]+ in }} +CHECK2-NEXT: {{ #2 0x[0-9a-f]+ in }} +CHECK: MallocFreeTracer: STOP -- cgit v1.2.1 From bcc227ee4af1ef3e63033b35dcb1d5627a3b2941 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 2 Nov 2017 04:12:10 +0000 Subject: [fuzzer] Fix nested mallocs Summary: Nested mallocs are possible with internal symbolizer. Reviewers: kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D39397 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317186 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/FuzzerLoop.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp index 9bea05f18..f4771e1df 100644 --- a/lib/fuzzer/FuzzerLoop.cpp +++ b/lib/fuzzer/FuzzerLoop.cpp @@ -70,18 +70,39 @@ struct MallocFreeTracer { std::atomic Mallocs; std::atomic Frees; int TraceLevel = 0; + + std::recursive_mutex TraceMutex; + bool TraceDisabled = false; }; static MallocFreeTracer AllocTracer; -static std::mutex MallocFreeStackMutex; +// Locks printing and avoids nested hooks triggered from mallocs/frees in +// sanitizer. +class TraceLock { +public: + TraceLock() : Lock(AllocTracer.TraceMutex) { + AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; + } + ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; } + + bool IsDisabled() const { + // This is already inverted value. + return !AllocTracer.TraceDisabled; + } + +private: + std::lock_guard Lock; +}; ATTRIBUTE_NO_SANITIZE_MEMORY void MallocHook(const volatile void *ptr, size_t size) { size_t N = AllocTracer.Mallocs++; F->HandleMalloc(size); if (int TraceLevel = AllocTracer.TraceLevel) { - std::lock_guard Lock(MallocFreeStackMutex); + TraceLock Lock; + if (Lock.IsDisabled()) + return; Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); @@ -92,7 +113,9 @@ ATTRIBUTE_NO_SANITIZE_MEMORY void FreeHook(const volatile void *ptr) { size_t N = AllocTracer.Frees++; if (int TraceLevel = AllocTracer.TraceLevel) { - std::lock_guard Lock(MallocFreeStackMutex); + TraceLock Lock; + if (Lock.IsDisabled()) + return; Printf("FREE[%zd] %p\n", N, ptr); if (TraceLevel >= 2 && EF) EF->__sanitizer_print_stack_trace(); -- cgit v1.2.1