Vendor import of compiler-rt trunk r306956:

https://llvm.org/svn/llvm-project/compiler-rt/trunk@306956
This commit is contained in:
Dimitry Andric 2017-07-01 13:24:15 +00:00
parent 10fcf738d7
commit 50aa32eff7
60 changed files with 1197 additions and 581 deletions

View File

@ -21,18 +21,9 @@ 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(TOUPPER ${sanitizer} sanitizer_uppercase)
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})
if(${runtime} STREQUAL tsan)
add_subdirectory(tsan/dd)
endif()
endif()
endfunction()
@ -45,14 +36,9 @@ 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})
endforeach()
compiler_rt_build_runtime(profile)
endif()

View File

@ -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) {
@ -632,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

View File

@ -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);
@ -722,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);

View File

@ -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
@ -63,12 +67,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 +88,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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
@ -199,24 +198,38 @@ 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);
INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
// 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;
#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*/); }
INTERCEPTOR_ATTRIBUTE
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; }
INTERCEPTOR_ATTRIBUTE
@ -224,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. /////

View File

@ -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);
}

View File

@ -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) {

View File

@ -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; \

View File

@ -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; \

View File

@ -48,6 +48,7 @@ set(PROFILE_SOURCES
InstrProfilingFile.c
InstrProfilingMerge.c
InstrProfilingMergeFile.c
InstrProfilingNameVar.c
InstrProfilingWriter.c
InstrProfilingPlatformDarwin.c
InstrProfilingPlatformLinux.c

View File

@ -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);

View File

@ -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, 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, 0);
}

View File

@ -91,24 +91,39 @@ 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)
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;
}
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() {
@ -122,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;
@ -169,6 +185,8 @@ static int doProfileMerging(FILE *ProfileFile) {
__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
*MergeDone = 1;
return 0;
}
@ -190,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;
@ -199,15 +217,14 @@ 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));
fclose(ProfileFile);
return NULL;
}
fseek(ProfileFile, 0L, SEEK_SET);
return ProfileFile;
}
@ -216,17 +233,20 @@ 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;
FreeHook = &free;
setupIOBuffer();
RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader());
ProfDataWriter fileWriter;
initFileWriter(&fileWriter, OutputFile);
RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
fclose(OutputFile);
return RetVal;

View File

@ -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,9 @@ 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,15 +138,17 @@ typedef struct VPDataReaderType {
uint32_t N);
} VPDataReaderType;
int lprofWriteData(WriterCallback Writer, void *WriterCtx,
VPDataReaderType *VPDataReader);
int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
/* 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. */

View File

@ -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};

View File

@ -31,41 +31,44 @@ 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);
if (IOVecs[I].Data)
memcpy(*Buffer, IOVecs[I].Data, Length);
*Buffer += Length;
}
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 +86,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 +104,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 +207,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 +217,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,9 +231,9 @@ static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
return 0;
}
COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer,
void *WriterCtx,
VPDataReaderType *VPDataReader) {
COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,
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();
@ -235,18 +241,17 @@ 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,
SkipNameDataWrite);
}
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,
const char *NamesEnd) {
const char *NamesEnd, int SkipNameDataWrite) {
/* Calculate size of sections. */
const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
@ -268,14 +273,14 @@ lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
#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}};
if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx))
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;
return writeValueProfData(Writer, WriterCtx, VPDataReader, DataBegin,
DataEnd);
return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
}

View File

@ -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;
@ -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();
}

View File

@ -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
@ -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"

View File

@ -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,

View File

@ -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<u8>(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;
}

View File

@ -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<uptr>(MmapFixedOrDie(beg, size)));
MapUnmapCallback().OnMap(beg, size);
}
void UnmapWithCallback(uptr beg, uptr size) {
MapUnmapCallback().OnUnmap(beg, size);
UnmapOrDie(reinterpret_cast<void *>(beg), size);
}
static bool CanAllocate(uptr size, uptr alignment) {
return size <= SizeClassMap::kMaxSize &&
alignment <= SizeClassMap::kMaxSize;
@ -116,16 +106,20 @@ class SizeClassAllocator64 {
BlockingMutexLock l(&region->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(&region->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<uptr>(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<uptr>(MmapFixedOrDieOnFatalError(beg, size));
if (UNLIKELY(!mapped))
return false;
CHECK_EQ(beg, mapped);
MapUnmapCallback().OnMap(beg, size);
return true;
}
void MapWithCallbackOrDie(uptr beg, uptr size) {
CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
MapUnmapCallback().OnMap(beg, size);
}
void UnmapWithCallbackOrDie(uptr beg, uptr size) {
MapUnmapCallback().OnUnmap(beg, size);
UnmapOrDie(reinterpret_cast<void *>(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<uptr>(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<u32>(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);
}
if (kRandomShuffleChunks)
RandomShuffle(&free_array[num_freed_chunks], total_count,
&region->rand_state);
region->num_freed_chunks += total_count;
region->allocated_user += total_count * size;
CHECK_LE(region->allocated_user, region->mapped_user);
const uptr new_chunks_count = (region->mapped_user - new_space_beg) / size;
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;
}
CHECK_LE(region->allocated_meta, region->mapped_meta);
if (region->mapped_user + region->mapped_meta >
// 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) {
Printf("%s: Out of memory. Dying. ", SanitizerToolName);
Printf("The process has exhausted %zuMB for size class %zu.\n",
kRegionSize / 1024 / 1024, size);
Die();
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[region->num_freed_chunks], new_chunks_count,
&region->rand_state);
// 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);
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 {
}
}
};

View File

@ -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.

View File

@ -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,57 @@ INTERCEPTOR(int, mprobe, void *ptr) {
}
#endif
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);
#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 +6454,6 @@ static void InitializeCommonInterceptors() {
INIT_UTMP;
INIT_UTMPX;
INIT_GETLOADAVG;
INIT_WCSLEN;
INIT_WCSCAT;
}

View File

@ -354,5 +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_WCSCAT SI_NOT_WINDOWS
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H

View File

@ -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,13 +192,13 @@ 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;
}
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),
@ -206,8 +206,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-1, 0);
int reserrno;
if (internal_iserror(p, &reserrno)) {
char mem_type[30];
if (UNLIKELY(internal_iserror(p, &reserrno))) {
if (tolerate_enomem && reserrno == ENOMEM)
return nullptr;
char mem_type[40];
internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
fixed_addr);
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
@ -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);
}

View File

@ -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);

View File

@ -436,29 +436,30 @@ TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) {
EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
}
template<class Allocator>
void FailInAssertionOnOOM() {
Allocator a;
a.Init(kReleaseToOSIntervalNever);
SizeClassAllocatorLocalCache<Allocator> cache;
memset(&cache, 0, sizeof(cache));
cache.Init(0);
AllocatorStats stats;
stats.Init();
const size_t kNumChunks = 128;
uint32_t chunks[kNumChunks];
for (int i = 0; i < 1000000; i++) {
a.GetFromAllocator(&stats, 52, chunks, kNumChunks);
}
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<Allocator64>(), "Out of memory");
Allocator64 a;
a.Init(kReleaseToOSIntervalNever);
SizeClassAllocatorLocalCache<Allocator64> 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++) {
if (!a.GetFromAllocator(&stats, 52, chunks, kNumChunks)) {
allocation_failed = true;
break;
}
}
EXPECT_EQ(allocation_failed, true);
a.TestOnlyUnmap();
}
#endif
@ -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);

View File

@ -22,8 +22,7 @@
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_quarantine.h"
#include <limits.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
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<uptr>(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<uptr>(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<uptr>(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<uptr>(Ptr);
ScudoChunk *Chunk = getScudoChunk(UserBeg);
@ -584,10 +580,9 @@ struct ScudoAllocator {
void *calloc(uptr NMemB, uptr Size) {
initThreadMaybe();
uptr Total = NMemB * Size;
if (Size != 0 && Total / Size != NMemB) // Overflow check
if (CheckForCallocOverflow(NMemB, Size))
return FailureHandler::OnBadRequest();
return allocate(Total, MinAlignment, FromMalloc, true);
return allocate(NMemB * Size, MinAlignment, FromMalloc, true);
}
void commitBack(ScudoThreadContext *ThreadContext) {
@ -655,10 +650,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 +660,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);
}

View File

@ -116,6 +116,11 @@ struct AP32 {
typedef SizeClassAllocator32<AP32> 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"

View File

@ -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);
}

View File

@ -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&) {

View File

@ -45,7 +45,7 @@ static void initOnce() {
NumberOfContexts = getNumberOfCPUs();
ThreadContexts = reinterpret_cast<ScudoThreadContext *>(
MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__));
for (int i = 0; i < NumberOfContexts; i++)
for (uptr i = 0; i < NumberOfContexts; i++)
ThreadContexts[i].init();
}

View File

@ -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)

View File

@ -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) \

View File

@ -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)

View File

@ -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=<path> along with your project-specific lists.
# Always instrument the main function.
fun:main

View File

@ -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=<path> along with your project-specific lists.
# Never instrument any function whose symbol starts with __xray.
fun:__xray*

View File

@ -35,6 +35,16 @@ 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()
# Run sanitizer tests only if we're sure that clang would produce
# working binaries.
if(COMPILER_RT_CAN_EXECUTE_TESTS)
@ -42,49 +52,24 @@ 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)
foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD})
# cfi testing is gated on ubsan
if(NOT ${sanitizer} STREQUAL cfi)
compiler_rt_test_runtime(${sanitizer})
endif()
endforeach()
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()

View File

@ -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

View File

@ -0,0 +1,31 @@
// RUN: %clang_asan %s -o %t -framework Foundation
// RUN: %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
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

View File

@ -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 <stdlib.h>
#include <string.h>

View File

@ -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 <stdlib.h>
#include <stdio.h>

View File

@ -2,11 +2,18 @@
#include <stdio.h>
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

View File

@ -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 <stdlib.h>
#include <libintl.h>

View File

@ -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 <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string>
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);

View File

@ -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 <limits.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <limits>
#include <new>
int main(int argc, char **argv) {
// Disable stderr buffering. Needed on Windows.
setvbuf(stderr, NULL, _IONBF, 0);
volatile size_t size = std::numeric_limits<size_t>::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<size_t>::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

View File

@ -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 <stdlib.h>
// For glibc, cause link failures by referencing a nonexistent function.

View File

@ -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 <stdio.h>
static volatile int zero = 0;

View File

@ -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)

View File

@ -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)){

View File

@ -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 <stdio.h>

View File

@ -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 <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits>
#include <new>
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<size_t>::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

View File

@ -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 <limits.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <limits>
int main(int argc, char **argv) {
volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
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);
}
#include <new>
if (!strcmp(argv[1], "calloc-overflow")) {
fprintf(stderr, "calloc-overflow:\n");
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);
static const size_t kMaxAllowedMallocSizePlusOne =
#if __LP64__ || defined(_WIN64)
(8UL << 30) + 1;
#else
(2UL << 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<size_t>::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

View File

@ -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}

View File

@ -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 <assert.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
@ -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

View File

@ -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 <string.h>
#include <limits>
#include <new>
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<size_t>::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<size_t>::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;
}

View File

@ -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 <limits.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <limits>
int main(int argc, char **argv) {
volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
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);
}
#include <new>
if (!strcmp(argv[1], "calloc-overflow")) {
fprintf(stderr, "calloc-overflow:\n");
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);
static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1;
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<size_t>::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

View File

@ -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();
}