Merge "Update aosp/master compiler-rt for rebase to r235153"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d65b396..0d8a880 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -238,12 +238,13 @@
endif()
# Determine if we should restrict stack frame sizes.
-# Stack frames on PowerPC and in debug biuld can be much larger than
+# Stack frames on PowerPC and Mips and in debug biuld can be much larger than
# anticipated.
# FIXME: Fix all sanitizers and add -Wframe-larger-than to
# SANITIZER_COMMON_FLAGS
if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG AND NOT COMPILER_RT_DEBUG
- AND NOT ${LLVM_NATIVE_ARCH} STREQUAL "PowerPC")
+ AND NOT ${LLVM_NATIVE_ARCH} STREQUAL "PowerPC"
+ AND NOT ${LLVM_NATIVE_ARCH} STREQUAL "Mips")
set(SANITIZER_LIMIT_FRAME_SIZE TRUE)
else()
set(SANITIZER_LIMIT_FRAME_SIZE FALSE)
@@ -305,9 +306,9 @@
-stdlib=libc++
-mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})
set(DARWIN_osx_LINKFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION}
- -stdlib=libc++ -lc++)
+ -stdlib=libc++ -lc++ -lc++abi)
set(DARWIN_iossim_LINKFLAGS
- -stdlib=libc++ -lc++
+ -stdlib=libc++ -lc++ -lc++abi
-Wl,-ios_simulator_version_min,7.0.0
-mios-simulator-version-min=7.0
-isysroot ${IOSSIM_SDK_DIR})
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index ae59732..0fdb784 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -49,3 +49,11 @@
append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
endmacro()
+
+macro(append_have_file_definition filename varname list)
+ check_include_file("${filename}" "${varname}")
+ if (NOT "${varname}")
+ set("${varname}" 0)
+ endif()
+ list(APPEND ${list} "${varname}=${${varname}}")
+endmacro()
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index f52639b..28f2761 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -221,10 +221,12 @@
# Architectures supported by compiler-rt libraries.
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mips64 mipsel mips64el)
-# LSan common files should be available on all architectures supported
+# LSan and UBSan common files should be available on all architectures supported
# by other sanitizers (even if they build into dummy object files).
filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
${SANITIZER_COMMON_SUPPORTED_ARCH})
+filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH
+ ${SANITIZER_COMMON_SUPPORTED_ARCH})
filter_available_targets(ASAN_SUPPORTED_ARCH
x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el)
filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
@@ -233,7 +235,8 @@
filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64
mipsel mips64el aarch64 powerpc64 powerpc64le)
filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
-filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel mips64 mips64el)
+filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips
+ mipsel mips64 mips64el powerpc64 powerpc64le)
if(ANDROID)
set(OS_NAME "Android")
@@ -305,3 +308,10 @@
set(COMPILER_RT_HAS_UBSAN FALSE)
endif()
+# -msse3 flag is not valid for Mips therefore clang gives a warning
+# message with -msse3. But check_c_compiler_flags() checks only for
+# compiler error messages. Therefore COMPILER_RT_HAS_MSSE3_FLAG turns out to be
+# true on Mips. So we make it false here.
+if("${LLVM_NATIVE_ARCH}" STREQUAL "Mips")
+ set(COMPILER_RT_HAS_MSSE3_FLAG FALSE)
+endif()
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 91a7037..2b6ae54 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -8,6 +8,7 @@
add_subdirectory(interception)
add_subdirectory(sanitizer_common)
add_subdirectory(lsan)
+ add_subdirectory(ubsan)
endif()
if(COMPILER_RT_HAS_ASAN)
@@ -33,7 +34,3 @@
add_subdirectory(tsan/dd)
endif()
-if(COMPILER_RT_HAS_UBSAN)
- add_subdirectory(ubsan)
-endif()
-
diff --git a/lib/asan/Android.mk b/lib/asan/Android.mk
index dc9218b..e98bd84 100644
--- a/lib/asan/Android.mk
+++ b/lib/asan/Android.mk
@@ -156,7 +156,7 @@
LOCAL_SRC_FILES := $(asan_rtl_files) $(asan_rtl_cxx_files)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SHARED_LIBRARIES := liblog libc libdl
-LOCAL_STATIC_LIBRARIES := libcompiler_rt
+LOCAL_STATIC_LIBRARIES := libcompiler_rt libubsan
# MacOS toolchain is out-of-date and does not support -z global.
# TODO: re-enable once the toolchain issue is fixed.
ifneq ($(HOST_OS),darwin)
@@ -256,6 +256,7 @@
LOCAL_MULTILIB := both
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_ADDRESS_SANITIZER := false
+LOCAL_WHOLE_STATIC_LIBRARIES := libubsan
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 8b771fb..e09c94d 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -96,6 +96,7 @@
$<TARGET_OBJECTS:RTInterception.${os}>
$<TARGET_OBJECTS:RTSanitizerCommon.${os}>
$<TARGET_OBJECTS:RTLSanCommon.${os}>
+ $<TARGET_OBJECTS:RTUbsan.${os}>
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
add_dependencies(asan clang_rt.asan_${os}_dynamic)
@@ -107,7 +108,8 @@
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>)
add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
@@ -119,6 +121,7 @@
add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
add_dependencies(asan clang_rt.asan_cxx-${arch})
@@ -137,6 +140,7 @@
add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
OUTPUT_NAME ${SHARED_ASAN_NAME}
SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
${ASAN_COMMON_RUNTIME_OBJECTS}
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index efb7767..e8ea549 100644
--- a/lib/asan/asan_flags.cc
+++ b/lib/asan/asan_flags.cc
@@ -20,6 +20,8 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "ubsan/ubsan_flags.h"
+#include "ubsan/ubsan_platform.h"
namespace __asan {
@@ -72,8 +74,8 @@
RegisterAsanFlags(&asan_parser, f);
RegisterCommonFlags(&asan_parser);
- // Set the default values and prepare for parsing LSan flags (which can also
- // overwrite common flags).
+ // Set the default values and prepare for parsing LSan and UBSan flags
+ // (which can also overwrite common flags).
#if CAN_SANITIZE_LEAKS
__lsan::Flags *lf = __lsan::flags();
lf->SetDefaults();
@@ -83,6 +85,15 @@
RegisterCommonFlags(&lsan_parser);
#endif
+#if CAN_SANITIZE_UB
+ __ubsan::Flags *uf = __ubsan::flags();
+ uf->SetDefaults();
+
+ FlagParser ubsan_parser;
+ __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+ RegisterCommonFlags(&ubsan_parser);
+#endif
+
// Override from ASan compile definition.
const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
asan_parser.ParseString(asan_compile_def);
@@ -90,12 +101,19 @@
// Override from user-specified string.
const char *asan_default_options = MaybeCallAsanDefaultOptions();
asan_parser.ParseString(asan_default_options);
+#if CAN_SANITIZE_UB
+ const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+ ubsan_parser.ParseString(ubsan_default_options);
+#endif
// Override from command line.
asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
#if CAN_SANITIZE_LEAKS
lsan_parser.ParseString(GetEnv("LSAN_OPTIONS"));
#endif
+#if CAN_SANITIZE_UB
+ ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
// Let activation flags override current settings. On Android they come
// from a system property. On other platforms this is no-op.
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 585181c..1318785 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -23,6 +23,10 @@
#include "asan_suppressions.h"
#include "sanitizer_common/sanitizer_libc.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common/sanitizer_posix.h"
+#endif
+
namespace __asan {
// Return true if we can quickly decide that the region is unpoisoned.
@@ -75,6 +79,13 @@
#define ASAN_WRITE_RANGE(ctx, offset, size) \
ACCESS_MEMORY_RANGE(ctx, offset, size, true)
+#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
+ ASAN_READ_RANGE((ctx), (s), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n))
+
+#define ASAN_READ_STRING(ctx, s, n) \
+ ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
// Behavior of functions like "memcpy" or "strcpy" is undefined
// if memory intervals overlap. We report error in this case.
// Macro is used to avoid creation of new frames.
@@ -290,7 +301,7 @@
ssize += stack - bottom;
ssize = RoundUpTo(ssize, PageSize);
static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb
- if (ssize && ssize <= kMaxSaneContextStackSize) {
+ if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) {
PoisonShadow(bottom, ssize, 0);
}
}
@@ -475,8 +486,9 @@
ENSURE_ASAN_INITED();
char *result = REAL(strchr)(str, c);
if (flags()->replace_str) {
- uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
- ASAN_READ_RANGE(ctx, str, bytes_read);
+ uptr len = REAL(strlen)(str);
+ uptr bytes_read = (result ? result - str : len) + 1;
+ ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
}
return result;
}
@@ -505,7 +517,7 @@
uptr from_length = REAL(strlen)(from);
ASAN_READ_RANGE(ctx, from, from_length + 1);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
// If the copying actually happens, the |from| string should not overlap
// with the resulting string starting at |to|, which has a length of
@@ -527,7 +539,7 @@
uptr copy_length = Min(size, from_length + 1);
ASAN_READ_RANGE(ctx, from, copy_length);
uptr to_length = REAL(strlen)(to);
- ASAN_READ_RANGE(ctx, to, to_length);
+ ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
if (from_length > 0) {
CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
@@ -629,23 +641,6 @@
}
#endif // ASAN_INTERCEPT_STRNLEN
-static inline bool IsValidStrtolBase(int base) {
- return (base == 0) || (2 <= base && base <= 36);
-}
-
-static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
- CHECK(endptr);
- if (nptr == *endptr) {
- // No digits were found at strtol call, we need to find out the last
- // symbol accessed by strtoll on our own.
- // We get this symbol by skipping leading blanks and optional +/- sign.
- while (IsSpace(*nptr)) nptr++;
- if (*nptr == '+' || *nptr == '-') nptr++;
- *endptr = const_cast<char *>(nptr);
- }
- CHECK(*endptr >= nptr);
-}
-
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
char **endptr, int base) {
void *ctx;
@@ -656,13 +651,7 @@
}
char *real_endptr;
long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
- if (endptr != 0) {
- *endptr = real_endptr;
- }
- if (IsValidStrtolBase(base)) {
- FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
- }
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
return result;
}
@@ -683,7 +672,7 @@
// different from int). So, we just imitate this behavior.
int result = REAL(strtol)(nptr, &real_endptr, 10);
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
@@ -700,7 +689,7 @@
char *real_endptr;
long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
@@ -715,16 +704,7 @@
}
char *real_endptr;
long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
- if (endptr != 0) {
- *endptr = real_endptr;
- }
- // If base has unsupported value, strtoll can exit with EINVAL
- // without reading any characters. So do additional checks only
- // if base is valid.
- if (IsValidStrtolBase(base)) {
- FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
- }
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
return result;
}
@@ -738,7 +718,7 @@
char *real_endptr;
long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
FixRealStrtolEndptr(nptr, &real_endptr);
- ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
+ ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
return result;
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 4652dde..2e857f6 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -21,6 +21,7 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include <pthread.h>
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index c1c340c..62c814e 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -578,6 +578,11 @@
InternalScopedString str(1024);
str.append("Thread T%d%s", context->tid,
ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ if (context->parent_tid == kInvalidTid) {
+ str.append(" created by unknown thread\n");
+ Printf("%s", str.data());
+ return;
+ }
str.append(
" created by T%d%s here:\n", context->parent_tid,
ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index f346615..ce86506 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -28,6 +28,8 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "lsan/lsan_common.h"
+#include "ubsan/ubsan_init.h"
+#include "ubsan/ubsan_platform.h"
int __asan_option_detect_stack_use_after_return; // Global interface symbol.
uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
@@ -295,9 +297,9 @@
CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
}
-static void ProtectGap(uptr a, uptr size) {
- void *res = Mprotect(a, size);
- if (a == (uptr)res)
+static void ProtectGap(uptr addr, uptr size) {
+ void *res = MmapNoAccess(addr, size);
+ if (addr == (uptr)res)
return;
Report("ERROR: Failed to protect the shadow gap. "
"ASan cannot proceed correctly. ABORTING.\n");
@@ -495,6 +497,10 @@
}
#endif // CAN_SANITIZE_LEAKS
+#if CAN_SANITIZE_UB
+ __ubsan::InitAsPlugin();
+#endif
+
InitializeSuppressions();
VReport(1, "AddressSanitizer Init done\n");
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 9da136c..a84c855 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -45,8 +45,8 @@
u32 stack_id;
AsanThread *thread;
- void OnCreated(void *arg);
- void OnFinished();
+ void OnCreated(void *arg) override;
+ void OnFinished() override;
};
// AsanThreadContext objects are never freed, so we need many of them.
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index 513d128..16baf45 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -214,18 +214,18 @@
$<TARGET_OBJECTS:RTAsan.osx>
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
- $<TARGET_OBJECTS:RTLSanCommon.osx>)
+ $<TARGET_OBJECTS:RTLSanCommon.osx>
+ $<TARGET_OBJECTS:RTUbsan.osx>)
else()
set(ASAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTAsan.${arch}>
$<TARGET_OBJECTS:RTAsan_cxx.${arch}>
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
- if(NOT WIN32)
- list(APPEND ASAN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
- endif()
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
endif()
add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 1cd2a08b..89b0d3d 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -290,9 +290,6 @@
Ident(StrCmp(s1, s2));
Ident(StrCmp(s1, s2 + size - 1));
Ident(StrCmp(s1 + size - 1, s2 + size - 1));
- s1[size - 1] = 'z';
- s2[size - 1] = 'x';
- Ident(StrCmp(s1, s2));
// One of arguments points to not allocated memory.
EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
@@ -371,17 +368,14 @@
// One of arguments points to not allocated memory.
EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(strcat(to + to_size, from), RightOOBWriteMessage(0));
EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
// "from" is not zero-terminated.
from[from_size - 1] = 'z';
EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
from[from_size - 1] = '\0';
- // "to" is not zero-terminated.
- memset(to, 'z', to_size);
- EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
// "to" is too short to fit "from".
+ memset(to, 'z', to_size);
to[to_size - from_size + 1] = '\0';
EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
// length of "to" is just enough.
@@ -409,7 +403,6 @@
// One of arguments points to not allocated memory.
EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
- EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBWriteMessage(0));
EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
memset(from, 'z', from_size);
@@ -417,8 +410,6 @@
to[0] = '\0';
// "from" is too short.
EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
- // "to" is not zero-terminated.
- EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBWriteMessage(0));
// "to" is too short to fit "from".
to[0] = 'z';
to[to_size - from_size + 1] = '\0';
@@ -508,20 +499,15 @@
EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
// Die if a buffer doesn't have terminating NULL.
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- // Make last symbol a terminating NULL or other non-digit.
+ // Make last symbol a terminating NULL
array[9] = '\0';
Atoi(array);
- array[9] = 'a';
- Atoi(array);
- Atoi(array + 9);
// Sometimes we need to detect overflow if no digits are found.
memset(array, ' ', 10);
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
array[9] = '-';
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
- array[8] = '-';
- Atoi(array);
free(array);
}
@@ -546,7 +532,6 @@
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
char *array = MallocAndMemsetString(3);
- char *endptr = NULL;
array[0] = '1';
array[1] = '2';
array[2] = '3';
@@ -554,19 +539,12 @@
EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
// Buffer overflow if there is no terminating null (depends on base).
- Strtol(array, &endptr, 3);
- EXPECT_EQ(array + 2, endptr);
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
array[2] = 'z';
- Strtol(array, &endptr, 35);
- EXPECT_EQ(array + 2, endptr);
EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
// Add terminating zero to get rid of overflow.
array[2] = '\0';
Strtol(array, NULL, 36);
- // Don't check for overflow if base is invalid.
- Strtol(array - 1, NULL, -1);
- Strtol(array + 3, NULL, 1);
// Sometimes we need to detect overflow if no digits are found.
array[0] = array[1] = array[2] = ' ';
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
@@ -574,13 +552,6 @@
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
array[2] = '-';
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[1] = '+';
- Strtol(array, NULL, 0);
- array[1] = array[2] = 'z';
- Strtol(array, &endptr, 0);
- EXPECT_EQ(array, endptr);
- Strtol(array + 2, NULL, 0);
- EXPECT_EQ(array, endptr);
free(array);
}
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index aa08080..07d59e0 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -593,7 +593,8 @@
#if !defined(__ANDROID__) && !defined(__arm__) && \
!defined(__powerpc64__) && !defined(__powerpc__) && \
- !defined(__aarch64__)
+ !defined(__aarch64__) && !defined(__mips__) && \
+ !defined(__mips64)
NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
// create three red zones for these two stack objects.
int a;
@@ -616,7 +617,8 @@
}
}
#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
- // !defined(__powerpc__) && !defined(__arm__)
+ // !defined(__powerpc__) && !defined(__arm__) &&
+ // !defined(__mips__) && !defined(__mips64)
TEST(AddressSanitizer, UnderscopeLongJmpTest) {
static jmp_buf buf;
diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c
index 67b124a..14283ef 100644
--- a/lib/builtins/fixdfdi.c
+++ b/lib/builtins/fixdfdi.c
@@ -12,6 +12,28 @@
#include "fp_lib.h"
ARM_EABI_FNALIAS(d2lz, fixdfdi)
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int __fixunsdfdi(double a);
+
+COMPILER_RT_ABI di_int
+__fixdfdi(double a)
+{
+ if (a < 0.0) {
+ return -__fixunsdfdi(-a);
+ }
+ return __fixunsdfdi(a);
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
typedef di_int fixint_t;
typedef du_int fixuint_t;
#include "fp_fixint_impl.inc"
@@ -20,3 +42,5 @@
__fixdfdi(fp_t a) {
return __fixint(a);
}
+
+#endif
diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c
index 835ff85..fab47e2 100644
--- a/lib/builtins/fixsfdi.c
+++ b/lib/builtins/fixsfdi.c
@@ -13,6 +13,28 @@
ARM_EABI_FNALIAS(f2lz, fixsfdi)
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int __fixunssfdi(float a);
+
+COMPILER_RT_ABI di_int
+__fixsfdi(float a)
+{
+ if (a < 0.0f) {
+ return -__fixunssfdi(-a);
+ }
+ return __fixunssfdi(a);
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
typedef di_int fixint_t;
typedef du_int fixuint_t;
#include "fp_fixint_impl.inc"
@@ -21,3 +43,5 @@
__fixsfdi(fp_t a) {
return __fixint(a);
}
+
+#endif
diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c
index f4f689e..b93d1c1 100644
--- a/lib/builtins/fixunsdfdi.c
+++ b/lib/builtins/fixunsdfdi.c
@@ -10,12 +10,34 @@
#define DOUBLE_PRECISION
#include "fp_lib.h"
-typedef du_int fixuint_t;
-#include "fp_fixuint_impl.inc"
ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int
+__fixunsdfdi(double a)
+{
+ su_int high = a/0x1p32f;
+ su_int low = a - (double)high*0x1p32f;
+ return ((du_int)high << 32) | low;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
COMPILER_RT_ABI du_int
__fixunsdfdi(fp_t a) {
return __fixuint(a);
}
+
+#endif
diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c
index cd21cfd..374ebbe 100644
--- a/lib/builtins/fixunssfdi.c
+++ b/lib/builtins/fixunssfdi.c
@@ -10,12 +10,35 @@
#define SINGLE_PRECISION
#include "fp_lib.h"
-typedef du_int fixuint_t;
-#include "fp_fixuint_impl.inc"
ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
+#ifndef __SOFT_FP__
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+COMPILER_RT_ABI du_int
+__fixunssfdi(float a)
+{
+ double da = a;
+ su_int high = da/0x1p32f;
+ su_int low = da - (double)high*0x1p32f;
+ return ((du_int)high << 32) | low;
+}
+
+#else
+/* Support for systems that don't have hardware floating-point; there are no
+ * flags to set, and we don't want to code-gen to an unknown soft-float
+ * implementation.
+ */
+
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
COMPILER_RT_ABI du_int
__fixunssfdi(fp_t a) {
return __fixuint(a);
}
+
+#endif
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index 5a8da38..d2e137e 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -302,12 +302,12 @@
char buf[64];
internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
__dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
- internal_write(fd, buf, internal_strlen(buf));
+ WriteToFile(fd, buf, internal_strlen(buf));
if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
- internal_write(fd, __dfsan_label_info[l].desc,
- internal_strlen(__dfsan_label_info[l].desc));
+ WriteToFile(fd, __dfsan_label_info[l].desc,
+ internal_strlen(__dfsan_label_info[l].desc));
}
- internal_write(fd, "\n", 1);
+ WriteToFile(fd, "\n", 1);
}
}
@@ -343,7 +343,7 @@
Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
flags().dump_labels_at_exit);
dfsan_dump_labels(fd);
- internal_close(fd);
+ CloseFile(fd);
}
}
@@ -361,7 +361,7 @@
// case by disabling memory protection when ASLR is disabled.
uptr init_addr = (uptr)&dfsan_init;
if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr))
- Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr);
+ MmapNoAccess(kUnusedAddr, kAppAddr - kUnusedAddr);
InitializeFlags();
InitializeInterceptors();
diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc
index 318ecd6..35f6fb4 100644
--- a/lib/dfsan/dfsan_custom.cc
+++ b/lib/dfsan/dfsan_custom.cc
@@ -847,266 +847,247 @@
*ret_label = 0;
return write(fd, buf, count);
}
+}
// Type used to extract a dfsan_label with va_arg()
typedef int dfsan_label_va;
-// A chunk of data representing the output of formatting either a constant
-// string or a single format directive.
-struct Chunk {
- // Address of the beginning of the formatted string
- const char *ptr;
- // Size of the formatted string
+// Formats a chunk either a constant string or a single format directive (e.g.,
+// '%.3f').
+struct Formatter {
+ Formatter(char *str_, const char *fmt_, size_t size_)
+ : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
+ width(-1) {}
+
+ int format() {
+ char *tmp_fmt = build_format_string();
+ int retval =
+ snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
+ 0 /* used only to avoid warnings */);
+ free(tmp_fmt);
+ return retval;
+ }
+
+ template <typename T> int format(T arg) {
+ char *tmp_fmt = build_format_string();
+ int retval;
+ if (width >= 0) {
+ retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
+ tmp_fmt, width, arg);
+ } else {
+ retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
+ tmp_fmt, arg);
+ }
+ free(tmp_fmt);
+ return retval;
+ }
+
+ char *build_format_string() {
+ size_t fmt_size = fmt_cur - fmt_start + 1;
+ char *new_fmt = (char *)malloc(fmt_size + 1);
+ assert(new_fmt);
+ internal_memcpy(new_fmt, fmt_start, fmt_size);
+ new_fmt[fmt_size] = '\0';
+ return new_fmt;
+ }
+
+ char *str_cur() { return str + str_off; }
+
+ size_t num_written_bytes(int retval) {
+ if (retval < 0) {
+ return 0;
+ }
+
+ size_t num_avail = str_off < size ? size - str_off : 0;
+ if (num_avail == 0) {
+ return 0;
+ }
+
+ size_t num_written = retval;
+ // A return value of {v,}snprintf of size or more means that the output was
+ // truncated.
+ if (num_written >= num_avail) {
+ num_written -= num_avail;
+ }
+
+ return num_written;
+ }
+
+ char *str;
+ size_t str_off;
size_t size;
-
- // Type of DFSan label (depends on the format directive)
- enum {
- // Constant string, no argument and thus no label
- NONE = 0,
- // Label for an argument of '%n'
- IGNORED,
- // Label for a '%s' argument
- STRING,
- // Label for any other type of argument
- NUMERIC,
- } label_type;
-
- // Value of the argument (if label_type == STRING)
- const char *arg;
+ const char *fmt_start;
+ const char *fmt_cur;
+ int width;
};
-// Formats the input. The output is stored in 'str' starting from offset
-// 'off'. The format directive is represented by the first 'format_size' bytes
-// of 'format'. If 'has_size' is true, 'size' bounds the number of output
-// bytes. Returns the return value of the vsnprintf call used to format the
-// input.
-static int format_chunk(char *str, size_t off, bool has_size, size_t size,
- const char *format, size_t format_size, ...) {
- char *chunk_format = (char *) malloc(format_size + 1);
- assert(chunk_format);
- internal_memcpy(chunk_format, format, format_size);
- chunk_format[format_size] = '\0';
-
- va_list ap;
- va_start(ap, format_size);
- int r = 0;
- if (has_size) {
- r = vsnprintf(str + off, off < size ? size - off : 0, chunk_format, ap);
- } else {
- r = vsprintf(str + off, chunk_format, ap);
- }
- va_end(ap);
-
- free(chunk_format);
- return r;
-}
-
// Formats the input and propagates the input labels to the output. The output
-// is stored in 'str'. If 'has_size' is true, 'size' bounds the number of
-// output bytes. 'format' and 'ap' are the format string and the list of
-// arguments for formatting. Returns the return value vsnprintf would return.
+// is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
+// 'ap' are the format string and the list of arguments for formatting. Returns
+// the return value vsnprintf would return.
//
// The function tokenizes the format string in chunks representing either a
// constant string or a single format directive (e.g., '%.3f') and formats each
// chunk independently into the output string. This approach allows to figure
// out which bytes of the output string depends on which argument and thus to
// propagate labels more precisely.
-static int format_buffer(char *str, bool has_size, size_t size,
- const char *format, dfsan_label *va_labels,
- dfsan_label *ret_label, va_list ap) {
- InternalMmapVector<Chunk> chunks(8);
- size_t off = 0;
+//
+// WARNING: This implementation does not support conversion specifiers with
+// positional arguments.
+static int format_buffer(char *str, size_t size, const char *fmt,
+ dfsan_label *va_labels, dfsan_label *ret_label,
+ va_list ap) {
+ Formatter formatter(str, fmt, size);
- while (*format) {
- chunks.push_back(Chunk());
- Chunk& chunk = chunks.back();
- chunk.ptr = str + off;
- chunk.arg = nullptr;
+ while (*formatter.fmt_cur) {
+ formatter.fmt_start = formatter.fmt_cur;
+ formatter.width = -1;
+ int retval = 0;
- int status = 0;
-
- if (*format != '%') {
+ if (*formatter.fmt_cur != '%') {
// Ordinary character. Consume all the characters until a '%' or the end
// of the string.
- size_t format_size = 0;
- for (; *format && *format != '%'; ++format, ++format_size) {}
- status = format_chunk(str, off, has_size, size, format - format_size,
- format_size);
- chunk.label_type = Chunk::NONE;
+ for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
+ ++formatter.fmt_cur) {}
+ retval = formatter.format();
+ dfsan_set_label(0, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
} else {
// Conversion directive. Consume all the characters until a conversion
// specifier or the end of the string.
- bool end_format = false;
-#define FORMAT_CHUNK(t) \
- format_chunk(str, off, has_size, size, format - format_size, \
- format_size + 1, va_arg(ap, t))
-
- for (size_t format_size = 1; *++format && !end_format; ++format_size) {
- switch (*format) {
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- switch (*(format - 1)) {
- case 'h':
- // Also covers the 'hh' case (since the size of the arg is still
- // an int).
- status = FORMAT_CHUNK(int);
- break;
- case 'l':
- if (format_size >= 2 && *(format - 2) == 'l') {
- status = FORMAT_CHUNK(long long int);
- } else {
- status = FORMAT_CHUNK(long int);
- }
- break;
- case 'q':
- status = FORMAT_CHUNK(long long int);
- break;
- case 'j':
- status = FORMAT_CHUNK(intmax_t);
- break;
- case 'z':
- status = FORMAT_CHUNK(size_t);
- break;
- case 't':
- status = FORMAT_CHUNK(size_t);
- break;
- default:
- status = FORMAT_CHUNK(int);
- }
- chunk.label_type = Chunk::NUMERIC;
- end_format = true;
+ bool end_fmt = false;
+ for (; *formatter.fmt_cur && !end_fmt; ) {
+ switch (*++formatter.fmt_cur) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ switch (*(formatter.fmt_cur - 1)) {
+ case 'h':
+ // Also covers the 'hh' case (since the size of the arg is still
+ // an int).
+ retval = formatter.format(va_arg(ap, int));
break;
-
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- if (*(format - 1) == 'L') {
- status = FORMAT_CHUNK(long double);
+ case 'l':
+ if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
+ *(formatter.fmt_cur - 2) == 'l') {
+ retval = formatter.format(va_arg(ap, long long int));
} else {
- status = FORMAT_CHUNK(double);
+ retval = formatter.format(va_arg(ap, long int));
}
- chunk.label_type = Chunk::NUMERIC;
- end_format = true;
break;
-
- case 'c':
- status = FORMAT_CHUNK(int);
- chunk.label_type = Chunk::NUMERIC;
- end_format = true;
+ case 'q':
+ retval = formatter.format(va_arg(ap, long long int));
break;
-
- case 's':
- chunk.arg = va_arg(ap, char *);
- status =
- format_chunk(str, off, has_size, size,
- format - format_size, format_size + 1,
- chunk.arg);
- chunk.label_type = Chunk::STRING;
- end_format = true;
+ case 'j':
+ retval = formatter.format(va_arg(ap, intmax_t));
break;
-
- case 'p':
- status = FORMAT_CHUNK(void *);
- chunk.label_type = Chunk::NUMERIC;
- end_format = true;
+ case 'z':
+ case 't':
+ retval = formatter.format(va_arg(ap, size_t));
break;
-
- case 'n':
- *(va_arg(ap, int *)) = (int)off;
- chunk.label_type = Chunk::IGNORED;
- end_format = true;
- break;
-
- case '%':
- status = format_chunk(str, off, has_size, size,
- format - format_size, format_size + 1);
- chunk.label_type = Chunk::NONE;
- end_format = true;
- break;
-
default:
- break;
+ retval = formatter.format(va_arg(ap, int));
+ }
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ if (*(formatter.fmt_cur - 1) == 'L') {
+ retval = formatter.format(va_arg(ap, long double));
+ } else {
+ retval = formatter.format(va_arg(ap, double));
+ }
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'c':
+ retval = formatter.format(va_arg(ap, int));
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 's': {
+ char *arg = va_arg(ap, char *);
+ retval = formatter.format(arg);
+ va_labels++;
+ internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
+ sizeof(dfsan_label) *
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+ }
+
+ case 'p':
+ retval = formatter.format(va_arg(ap, void *));
+ dfsan_set_label(*va_labels++, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case 'n': {
+ int *ptr = va_arg(ap, int *);
+ *ptr = (int)formatter.str_off;
+ va_labels++;
+ dfsan_set_label(0, ptr, sizeof(ptr));
+ end_fmt = true;
+ break;
+ }
+
+ case '%':
+ retval = formatter.format();
+ dfsan_set_label(0, formatter.str_cur(),
+ formatter.num_written_bytes(retval));
+ end_fmt = true;
+ break;
+
+ case '*':
+ formatter.width = va_arg(ap, int);
+ va_labels++;
+ break;
+
+ default:
+ break;
}
}
-#undef FORMAT_CHUNK
}
- if (status < 0) {
- return status;
+ if (retval < 0) {
+ return retval;
}
- // A return value of {v,}snprintf of size or more means that the output was
- // truncated.
- if (has_size) {
- if (off < size) {
- size_t ustatus = (size_t) status;
- chunk.size = ustatus >= (size - off) ?
- ustatus - (size - off) : ustatus;
- } else {
- chunk.size = 0;
- }
- } else {
- chunk.size = status;
- }
- off += status;
- }
-
- // TODO(martignlo): Decide how to combine labels (e.g., whether to ignore or
- // not the label of the format string).
-
- // Label each output chunk according to the label supplied as argument to the
- // function. We need to go through all the chunks and arguments even if the
- // string was only partially printed ({v,}snprintf case).
- for (size_t i = 0; i < chunks.size(); ++i) {
- const Chunk& chunk = chunks[i];
- void *chunk_ptr = const_cast<char *>(chunk.ptr);
-
- switch (chunk.label_type) {
- case Chunk::NONE:
- dfsan_set_label(0, chunk_ptr, chunk.size);
- break;
- case Chunk::IGNORED:
- va_labels++;
- dfsan_set_label(0, chunk_ptr, chunk.size);
- break;
- case Chunk::NUMERIC: {
- dfsan_label label = *va_labels++;
- dfsan_set_label(label, chunk_ptr, chunk.size);
- break;
- }
- case Chunk::STRING: {
- // Consume the label of the pointer to the string
- va_labels++;
- internal_memcpy(shadow_for(chunk_ptr),
- shadow_for(chunk.arg),
- sizeof(dfsan_label) * (strlen(chunk.arg)));
- break;
- }
- }
+ formatter.fmt_cur++;
+ formatter.str_off += retval;
}
*ret_label = 0;
// Number of bytes written in total.
- return off;
+ return formatter.str_off;
}
+extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
dfsan_label format_label, dfsan_label *va_labels,
dfsan_label *ret_label, ...) {
va_list ap;
va_start(ap, ret_label);
- int ret = format_buffer(str, false, 0, format, va_labels, ret_label, ap);
+ int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
va_end(ap);
return ret;
}
@@ -1118,7 +1099,7 @@
dfsan_label *ret_label, ...) {
va_list ap;
va_start(ap, ret_label);
- int ret = format_buffer(str, true, size, format, va_labels, ret_label, ap);
+ int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
va_end(ap);
return ret;
}
diff --git a/lib/dfsan/scripts/check_custom_wrappers.sh b/lib/dfsan/scripts/check_custom_wrappers.sh
index 50bc85d..1880882 100755
--- a/lib/dfsan/scripts/check_custom_wrappers.sh
+++ b/lib/dfsan/scripts/check_custom_wrappers.sh
@@ -32,7 +32,7 @@
grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
| sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
-grep -E "^\\s*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
+grep -E "^[[:space:]]*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
| sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
if [ $? -ne 0 ]
diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h
index 4641b32..99e2c1d 100644
--- a/lib/lsan/lsan_thread.h
+++ b/lib/lsan/lsan_thread.h
@@ -22,8 +22,8 @@
class ThreadContext : public ThreadContextBase {
public:
explicit ThreadContext(int tid);
- void OnStarted(void *arg);
- void OnFinished();
+ void OnStarted(void *arg) override;
+ void OnFinished() override;
uptr stack_begin() { return stack_begin_; }
uptr stack_end() { return stack_end_; }
uptr tls_begin() { return tls_begin_; }
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 4a24394..a1e8193 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -94,6 +94,13 @@
if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
} while (0);
+#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \
+ CHECK_UNPOISONED((x), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define CHECK_UNPOISONED_STRING(x, n) \
+ CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
+
INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
ENSURE_MSAN_INITED();
SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -118,6 +125,7 @@
INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED_STRING(path, 0)
SSIZE_T res = REAL(readlink)(path, buf, bufsiz);
if (res > 0)
__msan_unpoison(buf, res);
@@ -283,13 +291,11 @@
return res;
}
-// FIXME: Add stricter shadow checks in str* interceptors (ex.: strcpy should
-// check the shadow of the terminating \0 byte).
-
INTERCEPTOR(char *, strcpy, char *dest, const char *src) { // NOLINT
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
char *res = REAL(strcpy)(dest, src); // NOLINT
CopyShadowAndOrigin(dest, src, n + 1, &stack);
return res;
@@ -311,6 +317,7 @@
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
char *res = REAL(stpcpy)(dest, src); // NOLINT
CopyShadowAndOrigin(dest, src, n + 1, &stack);
return res;
@@ -322,6 +329,7 @@
// On FreeBSD strdup() leverages strlen().
InterceptorScope interceptor_scope;
SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
char *res = REAL(strdup)(src);
CopyShadowAndOrigin(res, src, n + 1, &stack);
return res;
@@ -332,6 +340,7 @@
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
SIZE_T n = REAL(strlen)(src);
+ CHECK_UNPOISONED_STRING(src + n, 0);
char *res = REAL(__strdup)(src);
CopyShadowAndOrigin(res, src, n + 1, &stack);
return res;
@@ -381,6 +390,8 @@
GET_STORE_STACK_TRACE;
SIZE_T src_size = REAL(strlen)(src);
SIZE_T dest_size = REAL(strlen)(dest);
+ CHECK_UNPOISONED_STRING(src + src_size, 0);
+ CHECK_UNPOISONED_STRING(dest + dest_size, 0);
char *res = REAL(strcat)(dest, src); // NOLINT
CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack);
return res;
@@ -391,6 +402,7 @@
GET_STORE_STACK_TRACE;
SIZE_T dest_size = REAL(strlen)(dest);
SIZE_T copy_size = REAL(strnlen)(src, n);
+ CHECK_UNPOISONED_STRING(dest + dest_size, 0);
char *res = REAL(strncat)(dest, src, n); // NOLINT
CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack);
__msan_unpoison(dest + dest_size + copy_size, 1); // \0
@@ -667,6 +679,7 @@
INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
ENSURE_MSAN_INITED();
+ CHECK_UNPOISONED_STRING(name, 0)
int res = REAL(setenv)(name, value, overwrite);
if (!res) UnpoisonEnviron();
return res;
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 6c18516..26ba82b 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -56,7 +56,7 @@
static bool ProtectMemoryRange(uptr beg, uptr size) {
if (size > 0) {
uptr end = beg + size - 1;
- if (!Mprotect(beg, size)) {
+ if (!MmapNoAccess(beg, size)) {
Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end);
return false;
}
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index 33c28b2..ddb8070 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -103,7 +103,7 @@
Decorator d;
Printf("%s", d.Warning());
- Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
+ Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
Printf("%s", d.End());
stack->Print();
if (origin) {
@@ -115,7 +115,7 @@
void ReportExpectedUMRNotFound(StackTrace *stack) {
SpinMutexLock l(&CommonSanitizerReportMutex);
- Printf(" WARNING: Expected use of uninitialized value not found\n");
+ Printf("WARNING: Expected use of uninitialized value not found\n");
stack->Print();
}
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 45fbd07..e32e97f 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/file.h>
#ifdef _WIN32
#include <direct.h>
#endif
@@ -294,6 +295,11 @@
}
}
+ /* Try to flock the file to serialize concurrent processes writing out to the
+ * same GCDA. This can fail if the filesystem doesn't support it, but in that
+ * case we'll just carry on with the old racy behaviour and hope for the best.
+ */
+ flock(fd, LOCK_EX);
output_file = fdopen(fd, mode);
/* Initialize the write buffer. */
@@ -493,6 +499,7 @@
}
fclose(output_file);
+ flock(fd, LOCK_UN);
output_file = NULL;
write_buffer = NULL;
}
diff --git a/lib/sanitizer_common/Android.mk b/lib/sanitizer_common/Android.mk
index 1af2324..9436a43 100644
--- a/lib/sanitizer_common/Android.mk
+++ b/lib/sanitizer_common/Android.mk
@@ -72,6 +72,9 @@
san_rtl_c_includes := \
external/compiler-rt/lib \
+################################################################################
+# Host modules
+
ifneq ($(HOST_OS),darwin)
include $(CLEAR_VARS)
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 5b32b6a..d213953 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -83,6 +83,7 @@
sanitizer_platform.h
sanitizer_platform_interceptors.h
sanitizer_platform_limits_posix.h
+ sanitizer_posix.h
sanitizer_procmaps.h
sanitizer_quarantine.h
sanitizer_report_decorator.h
@@ -111,6 +112,10 @@
SANITIZER_NEEDS_SEGV=1)
endif()
+include(CheckIncludeFile)
+append_have_file_definition(rpc/xdr.h HAVE_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+append_have_file_definition(tirpc/rpc/xdr.h HAVE_TIRPC_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+
set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_no_rtti_flag(SANITIZER_CFLAGS)
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index b5105f8..deaffef 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -323,7 +323,7 @@
void Init() {
CHECK_EQ(kSpaceBeg,
- reinterpret_cast<uptr>(Mprotect(kSpaceBeg, kSpaceSize)));
+ reinterpret_cast<uptr>(MmapNoAccess(kSpaceBeg, kSpaceSize)));
MapWithCallback(kSpaceEnd, AdditionalSize());
}
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 956fc99..8185c81 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -54,18 +54,17 @@
if (fd_pid == pid)
return;
else
- internal_close(fd);
+ CloseFile(fd);
}
internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
- uptr openrv = OpenFile(full_path, WrOnly);
- if (internal_iserror(openrv)) {
+ fd = OpenFile(full_path, WrOnly);
+ if (fd == kInvalidFd) {
const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
- internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
- internal_write(kStderrFd, full_path, internal_strlen(full_path));
+ WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+ WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
Die();
}
- fd = openrv;
fd_pid = pid;
}
@@ -82,7 +81,7 @@
SpinMutexLock l(mu);
if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
- internal_close(fd);
+ CloseFile(fd);
fd = kInvalidFd;
if (internal_strcmp(path, "stdout") == 0) {
fd = kStdoutFd;
@@ -136,7 +135,7 @@
}
uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
- uptr max_len, int *errno_p) {
+ uptr max_len, error_t *errno_p) {
uptr PageSize = GetPageSizeCached();
uptr kMinFileLen = PageSize;
uptr read_len = 0;
@@ -144,9 +143,8 @@
*buff_size = 0;
// The files we usually open are not seekable, so try different buffer sizes.
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
- uptr openrv = OpenFile(file_name, RdOnly);
- if (internal_iserror(openrv, errno_p)) return 0;
- fd_t fd = openrv;
+ fd_t fd = OpenFile(file_name, RdOnly, errno_p);
+ if (fd == kInvalidFd) return 0;
UnmapOrDie(*buff, *buff_size);
*buff = (char*)MmapOrDie(size, __func__);
*buff_size = size;
@@ -154,8 +152,8 @@
read_len = 0;
bool reached_eof = false;
while (read_len + PageSize <= size) {
- uptr just_read = internal_read(fd, *buff + read_len, PageSize);
- if (internal_iserror(just_read, errno_p)) {
+ uptr just_read;
+ if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
UnmapOrDie(*buff, *buff_size);
return 0;
}
@@ -165,7 +163,7 @@
}
read_len += just_read;
}
- internal_close(fd);
+ CloseFile(fd);
if (reached_eof) // We've read the whole file.
break;
}
@@ -219,8 +217,15 @@
const char *StripModuleName(const char *module) {
if (module == 0)
return 0;
- if (const char *slash_pos = internal_strrchr(module, '/'))
+ if (SANITIZER_WINDOWS) {
+ // On Windows, both slash and backslash are possible.
+ // Pick the one that goes last.
+ if (const char *bslash_pos = internal_strrchr(module, '\\'))
+ return StripModuleName(bslash_pos + 1);
+ }
+ if (const char *slash_pos = internal_strrchr(module, '/')) {
return slash_pos + 1;
+ }
return module;
}
@@ -243,14 +248,15 @@
}
#endif
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+void LoadedModule::set(const char *module_name, uptr base_address) {
+ clear();
full_name_ = internal_strdup(module_name);
base_address_ = base_address;
- ranges_.clear();
}
void LoadedModule::clear() {
InternalFree(full_name_);
+ full_name_ = nullptr;
while (!ranges_.empty()) {
AddressRange *r = ranges_.front();
ranges_.pop_front();
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 0dfa815..2e920c8 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -39,6 +39,9 @@
const uptr kMaxPathLength = 4096;
+// 16K loaded modules should be enough for everyone.
+static const uptr kMaxNumberOfModules = 1 << 14;
+
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
extern const char *SanitizerToolName; // Can be changed by the tool.
@@ -69,9 +72,13 @@
void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
void *MmapNoReserveOrDie(uptr size, const char *mem_type);
void *MmapFixedOrDie(uptr fixed_addr, uptr size);
-void *Mprotect(uptr fixed_addr, uptr size);
+void *MmapNoAccess(uptr fixed_addr, uptr size);
// Map aligned chunk of address space; size and alignment are powers of two.
void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
+// Disallow access to a memory range. Use MmapNoAccess to allocate an
+// unaccessible memory.
+bool MprotectNoAccess(uptr addr, uptr size);
+
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
void FlushUnneededShadowMemory(uptr addr, uptr size);
@@ -160,7 +167,7 @@
struct ReportFile {
void Write(const char *buffer, uptr length);
- bool PrintsToTty();
+ bool SupportsColors();
void SetReportPath(const char *path);
// Don't use fields directly. They are only declared public to allow
@@ -193,18 +200,33 @@
RdWr
};
-uptr OpenFile(const char *filename, FileAccessMode mode);
+// Returns kInvalidFd on error.
+fd_t OpenFile(const char *filename, FileAccessMode mode,
+ error_t *errno_p = nullptr);
+void CloseFile(fd_t);
+
+// Return true on success, false on error.
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size,
+ uptr *bytes_read = nullptr, error_t *error_p = nullptr);
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
+ uptr *bytes_written = nullptr, error_t *error_p = nullptr);
+
+bool RenameFile(const char *oldpath, const char *newpath,
+ error_t *error_p = nullptr);
+
+bool SupportsColoredOutput(fd_t fd);
+
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// The size of the mmaped region is stored in '*buff_size',
// Returns the number of read bytes or 0 if file can not be opened.
uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
- uptr max_len, int *errno_p = nullptr);
+ uptr max_len, error_t *errno_p = nullptr);
// Maps given file to virtual memory, and returns pointer to it
-// (or NULL if the mapping failes). Stores the size of mmaped region
+// (or NULL if mapping fails). Stores the size of mmaped region
// in '*buff_size'.
void *MapFileToMemory(const char *file_name, uptr *buff_size);
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset);
bool IsAccessibleMemoryRange(uptr beg, uptr size);
@@ -548,8 +570,8 @@
// executable or a shared object).
class LoadedModule {
public:
- LoadedModule() : full_name_(nullptr), base_address_(0) {}
- LoadedModule(const char *module_name, uptr base_address);
+ LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); }
+ void set(const char *module_name, uptr base_address);
void clear();
void addAddressRange(uptr beg, uptr end, bool executable);
bool containsAddress(uptr address) const;
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index f724115..69c1cf8 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -102,6 +102,13 @@
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
#endif
+#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \
+ COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
#ifndef COMMON_INTERCEPTOR_ON_DLOPEN
#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {}
#endif
@@ -159,7 +166,8 @@
INTERCEPTOR(char*, textdomain, const char *domainname) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
- char* domain = REAL(textdomain)(domainname);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+ char *domain = REAL(textdomain)(domainname);
if (domain) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
}
@@ -185,8 +193,8 @@
c2 = (unsigned char)s2[i];
if (c1 != c2 || c1 == '\0') break;
}
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
return CharCmpX(c1, c2);
}
@@ -231,8 +239,8 @@
c2 = (unsigned char)s2[i];
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
return CharCaseCmp(c1, c2);
}
@@ -727,12 +735,12 @@
// its metadata. See
// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
char *res = REAL(strptime)(s, format, tm);
- if (res) {
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
+ if (res && tm) {
// Do not call unpoison_tm here, because strptime does not, in fact,
// initialize the entire struct tm. For example, tm_zone pointer is left
// uninitialized.
- if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
}
return res;
}
@@ -1513,6 +1521,7 @@
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
__sanitizer_glob_t glob_copy = {
0, 0, 0,
0, wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1543,6 +1552,7 @@
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
__sanitizer_glob_t glob_copy = {
0, 0, 0,
0, wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1689,6 +1699,7 @@
INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0);
// FIXME: figure out read size based on the address family.
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
@@ -2359,6 +2370,37 @@
#define INIT_GET_CURRENT_DIR_NAME
#endif
+UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
+ CHECK(endptr);
+ if (nptr == *endptr) {
+ // No digits were found at strtol call, we need to find out the last
+ // symbol accessed by strtoll on our own.
+ // We get this symbol by skipping leading blanks and optional +/- sign.
+ while (IsSpace(*nptr)) nptr++;
+ if (*nptr == '+' || *nptr == '-') nptr++;
+ *endptr = const_cast<char *>(nptr);
+ }
+ CHECK(*endptr >= nptr);
+}
+
+UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr,
+ char **endptr, char *real_endptr, int base) {
+ if (endptr != 0) {
+ *endptr = real_endptr;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ }
+ // If base has unsupported value, strtol can exit with EINVAL
+ // without reading any characters. So do additional checks only
+ // if base is valid.
+ bool is_valid_base = (base == 0) || (2 <= base && base <= 36);
+ if (is_valid_base) {
+ FixRealStrtolEndptr(nptr, &real_endptr);
+ }
+ COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ?
+ (real_endptr - nptr) + 1 : 0);
+}
+
+
#if SANITIZER_INTERCEPT_STRTOIMAX
INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
void *ctx;
@@ -2366,8 +2408,9 @@
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
- INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
- if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ char *real_endptr;
+ INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
return res;
}
@@ -2377,8 +2420,9 @@
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
- INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
- if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+ char *real_endptr;
+ INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
return res;
}
@@ -3642,6 +3686,7 @@
INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
return REAL(pthread_setname_np)(thread, name);
}
@@ -4699,6 +4744,7 @@
INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
void *ctx;
COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+ if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag);
void *res = REAL(dlopen)(filename, flag);
COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 9622e60..1b65bce 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -17,12 +17,16 @@
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
+#if SANITIZER_POSIX
+#include "sanitizer_posix.h"
+#endif
+
namespace __sanitizer {
-bool ReportFile::PrintsToTty() {
+bool ReportFile::SupportsColors() {
SpinMutexLock l(mu);
ReopenIfNecessary();
- return internal_isatty(fd) != 0;
+ return SupportsColoredOutput(fd);
}
bool ColorizeReports() {
@@ -33,7 +37,7 @@
const char *flag = common_flags()->color;
return internal_strcmp(flag, "always") == 0 ||
- (internal_strcmp(flag, "auto") == 0 && report_file.PrintsToTty());
+ (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
}
static void (*sandboxing_callback)();
@@ -113,12 +117,13 @@
}
void MaybeStartBackgroudThread() {
- if (!SANITIZER_LINUX) return; // Need to implement/test on other platforms.
+#if SANITIZER_LINUX // Need to implement/test on other platforms.
// Start the background thread if one of the rss limits is given.
if (!common_flags()->hard_rss_limit_mb &&
!common_flags()->soft_rss_limit_mb) return;
if (!&real_pthread_create) return; // Can't spawn the thread anyway.
internal_start_thread(BackgroundThread, nullptr);
+#endif
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index 94863c6..2c7c7e0 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -63,7 +63,7 @@
// dump current memory layout to another file.
static bool cov_sandboxed = false;
-static int cov_fd = kInvalidFd;
+static fd_t cov_fd = kInvalidFd;
static unsigned int cov_max_block_size = 0;
static bool coverage_enabled = false;
static const char *coverage_dir;
@@ -109,7 +109,8 @@
// Maximal size pc array may ever grow.
// We MmapNoReserve this space to ensure that the array is contiguous.
- static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27);
+ static const uptr kPcArrayMaxSize =
+ FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
// The amount file mapping for the pc array is grown by.
static const uptr kPcArrayMmapSize = 64 * 1024;
@@ -123,7 +124,7 @@
// Current file mapped size of the pc array.
uptr pc_array_mapped_size;
// Descriptor of the file mapped pc array.
- int pc_fd;
+ fd_t pc_fd;
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
@@ -176,8 +177,8 @@
internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
coverage_dir, internal_getpid());
pc_fd = OpenFile(path.data(), RdWr);
- if (internal_iserror(pc_fd)) {
- Report(" Coverage: failed to open %s for reading/writing\n", path.data());
+ if (pc_fd == kInvalidFd) {
+ Report("Coverage: failed to open %s for reading/writing\n", path.data());
Die();
}
@@ -210,8 +211,9 @@
tr_event_array = reinterpret_cast<u32 *>(MmapNoReserveOrDie(
sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(),
"CovInit::tr_event_array"));
- Mprotect(reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
- GetMmapGranularity());
+ MprotectNoAccess(
+ reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
+ GetMmapGranularity());
tr_event_array_size = kTrEventArrayMaxSize;
tr_event_pointer = tr_event_array;
@@ -229,22 +231,22 @@
void CoverageData::Disable() {
if (pc_array) {
- internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize);
+ UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize);
pc_array = nullptr;
}
if (cc_array) {
- internal_munmap(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
+ UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
cc_array = nullptr;
}
if (tr_event_array) {
- internal_munmap(tr_event_array,
- sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
- GetMmapGranularity());
+ UnmapOrDie(tr_event_array,
+ sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
+ GetMmapGranularity());
tr_event_array = nullptr;
tr_event_pointer = nullptr;
}
if (pc_fd != kInvalidFd) {
- internal_close(pc_fd);
+ CloseFile(pc_fd);
pc_fd = kInvalidFd;
}
}
@@ -338,9 +340,8 @@
const char *module_name = sym->GetModuleNameForPc(caller_pc);
if (!module_name) return;
if (module_name_vec.empty() ||
- internal_strcmp(module_name_vec.back().copied_module_name, module_name))
- module_name_vec.push_back(
- {internal_strdup(module_name), range_beg, range_end});
+ module_name_vec.back().copied_module_name != module_name)
+ module_name_vec.push_back({module_name, range_beg, range_end});
else
module_name_vec.back().end = range_end;
}
@@ -516,15 +517,15 @@
static void CovWritePacked(int pid, const char *module, const void *blob,
unsigned int blob_size) {
- if (cov_fd < 0) return;
+ if (cov_fd == kInvalidFd) return;
unsigned module_name_length = internal_strlen(module);
CovHeader header = {pid, module_name_length, blob_size};
if (cov_max_block_size == 0) {
// Writing to a file. Just go ahead.
- internal_write(cov_fd, &header, sizeof(header));
- internal_write(cov_fd, module, module_name_length);
- internal_write(cov_fd, blob, blob_size);
+ WriteToFile(cov_fd, &header, sizeof(header));
+ WriteToFile(cov_fd, module, module_name_length);
+ WriteToFile(cov_fd, blob, blob_size);
} else {
// Writing to a socket. We want to split the data into appropriately sized
// blocks.
@@ -547,8 +548,7 @@
internal_memcpy(block_data_begin, blob_pos, payload_size);
blob_pos += payload_size;
((CovHeader *)block.data())->data_length = payload_size;
- internal_write(cov_fd, block.data(),
- header_size_with_module + payload_size);
+ WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size);
}
}
}
@@ -557,7 +557,7 @@
// If packed = true and name == 0: <pid>.<sancov>.<packed>.
// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
// user-supplied).
-static int CovOpenFile(InternalScopedString *path, bool packed,
+static fd_t CovOpenFile(InternalScopedString *path, bool packed,
const char *name, const char *extension = "sancov") {
path->clear();
if (!packed) {
@@ -571,11 +571,9 @@
else
path->append("%s/%s.%s.packed", coverage_dir, name, extension);
}
- uptr fd = OpenFile(path->data(), WrOnly);
- if (internal_iserror(fd)) {
- Report(" SanitizerCoverage: failed to open %s for writing\n", path->data());
- return -1;
- }
+ fd_t fd = OpenFile(path->data(), WrOnly);
+ if (fd == kInvalidFd)
+ Report("SanitizerCoverage: failed to open %s for writing\n", path->data());
return fd;
}
@@ -595,34 +593,35 @@
out.append("%s 0x%zx\n", module_name, module_address);
}
InternalScopedString path(kMaxPathLength);
- int fd = CovOpenFile(&path, false, "trace-points");
- if (fd < 0) return;
- internal_write(fd, out.data(), out.length());
- internal_close(fd);
+ fd_t fd = CovOpenFile(&path, false, "trace-points");
+ if (fd == kInvalidFd) return;
+ WriteToFile(fd, out.data(), out.length());
+ CloseFile(fd);
fd = CovOpenFile(&path, false, "trace-compunits");
- if (fd < 0) return;
+ if (fd == kInvalidFd) return;
out.clear();
for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
out.append("%s\n", comp_unit_name_vec[i].copied_module_name);
- internal_write(fd, out.data(), out.length());
- internal_close(fd);
+ WriteToFile(fd, out.data(), out.length());
+ CloseFile(fd);
fd = CovOpenFile(&path, false, "trace-events");
- if (fd < 0) return;
+ if (fd == kInvalidFd) return;
uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array);
// The trace file could be huge, and may not be written with a single syscall.
while (bytes_to_write) {
- uptr actually_written = internal_write(fd, event_bytes, bytes_to_write);
- if (actually_written <= bytes_to_write) {
+ uptr actually_written;
+ if (WriteToFile(fd, event_bytes, bytes_to_write, &actually_written) &&
+ actually_written <= bytes_to_write) {
bytes_to_write -= actually_written;
event_bytes += actually_written;
} else {
break;
}
}
- internal_close(fd);
+ CloseFile(fd);
VReport(1, " CovDump: Trace: %zd PCs written\n", size());
VReport(1, " CovDump: Trace: %zd Events written\n", max_idx);
}
@@ -660,10 +659,10 @@
}
}
InternalScopedString path(kMaxPathLength);
- int fd = CovOpenFile(&path, false, "caller-callee");
- if (fd < 0) return;
- internal_write(fd, out.data(), out.length());
- internal_close(fd);
+ fd_t fd = CovOpenFile(&path, false, "caller-callee");
+ if (fd == kInvalidFd) return;
+ WriteToFile(fd, out.data(), out.length());
+ CloseFile(fd);
VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
}
@@ -694,11 +693,11 @@
CHECK_LE(r.beg, r.end);
CHECK_LE(r.end, size());
const char *base_name = StripModuleName(r.copied_module_name);
- int fd =
+ fd_t fd =
CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov");
- if (fd < 0) return;
- internal_write(fd, bitset.data() + r.beg, r.end - r.beg);
- internal_close(fd);
+ if (fd == kInvalidFd) return;
+ WriteToFile(fd, bitset.data() + r.beg, r.end - r.beg);
+ CloseFile(fd);
VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg,
base_name);
}
@@ -722,10 +721,10 @@
n_set_bits++;
}
const char *base_name = StripModuleName(r.copied_module_name);
- int fd = CovOpenFile(&path, /* packed */ false, base_name, "bitset-sancov");
- if (fd < 0) return;
- internal_write(fd, out.data() + r.beg, r.end - r.beg);
- internal_close(fd);
+ fd_t fd = CovOpenFile(&path, /* packed */false, base_name, "bitset-sancov");
+ if (fd == kInvalidFd) return;
+ WriteToFile(fd, out.data() + r.beg, r.end - r.beg);
+ CloseFile(fd);
VReport(1,
" CovDump: bitset of %zd bits written for '%s', %zd bits are set\n",
r.end - r.beg, base_name, n_set_bits);
@@ -751,9 +750,8 @@
uptr pc = UnbundlePc(pc_array[i]);
uptr counter = UnbundleCounter(pc_array[i]);
if (!pc) continue; // Not visited.
- const char *unused;
uptr offset = 0;
- sym->GetModuleNameAndOffsetForPC(pc, &unused, &offset);
+ sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
offsets.push_back(BundlePcAndCounter(offset, counter));
}
@@ -771,22 +769,22 @@
const char *module_name = StripModuleName(r.copied_module_name);
if (cov_sandboxed) {
- if (cov_fd >= 0) {
+ if (cov_fd != kInvalidFd) {
CovWritePacked(internal_getpid(), module_name, offsets.data(),
offsets.size() * sizeof(offsets[0]));
VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
}
} else {
// One file per module per process.
- int fd = CovOpenFile(&path, false /* packed */, module_name);
- if (fd < 0) continue;
- internal_write(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
- internal_close(fd);
+ fd_t fd = CovOpenFile(&path, false /* packed */, module_name);
+ if (fd == kInvalidFd) continue;
+ WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
+ CloseFile(fd);
VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
}
}
- if (cov_fd >= 0)
- internal_close(cov_fd);
+ if (cov_fd != kInvalidFd)
+ CloseFile(cov_fd);
}
void CoverageData::DumpAll() {
@@ -805,18 +803,19 @@
if (!coverage_enabled) return;
cov_sandboxed = args->coverage_sandboxed;
if (!cov_sandboxed) return;
- cov_fd = args->coverage_fd;
cov_max_block_size = args->coverage_max_block_size;
- if (cov_fd < 0) {
+ if (args->coverage_fd >= 0) {
+ cov_fd = (fd_t)args->coverage_fd;
+ } else {
InternalScopedString path(kMaxPathLength);
// Pre-open the file now. The sandbox won't allow us to do it later.
cov_fd = CovOpenFile(&path, true /* packed */, 0);
}
}
-int MaybeOpenCovFile(const char *name) {
+fd_t MaybeOpenCovFile(const char *name) {
CHECK(name);
- if (!coverage_enabled) return -1;
+ if (!coverage_enabled) return kInvalidFd;
InternalScopedString path(kMaxPathLength);
return CovOpenFile(&path, true /* packed */, name);
}
@@ -836,9 +835,7 @@
coverage_dir = dir;
coverage_data.Init();
if (enabled) coverage_data.Enable();
-#if !SANITIZER_WINDOWS
if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
-#endif
}
void ReInitializeCoverage(bool enabled, const char *dir) {
@@ -893,7 +890,7 @@
}
SANITIZER_INTERFACE_ATTRIBUTE
sptr __sanitizer_maybe_open_cov_file(const char *name) {
- return MaybeOpenCovFile(name);
+ return (sptr)MaybeOpenCovFile(name);
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_total_unique_coverage() {
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index d3bde4b..a3d75ab 100644
--- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -35,7 +35,6 @@
namespace __sanitizer {
-static const uptr kMaxNumberOfModules = 1 << 14;
static const uptr kMaxTextSize = 64 * 1024;
struct CachedMapping {
@@ -96,32 +95,30 @@
}
}
- int err;
+ error_t err;
InternalScopedString tmp_path(64 + internal_strlen(coverage_dir));
uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
"%s/%zd.sancov.map.tmp", coverage_dir,
internal_getpid());
CHECK_LE(res, tmp_path.size());
- uptr map_fd = OpenFile(tmp_path.data(), WrOnly);
- if (internal_iserror(map_fd, &err)) {
- Report(" Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
+ fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err);
+ if (map_fd == kInvalidFd) {
+ Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
err);
Die();
}
- res = internal_write(map_fd, text.data(), text.length());
- if (internal_iserror(res, &err)) {
+ if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) {
Printf("sancov.map write failed: %d\n", err);
Die();
}
- internal_close(map_fd);
+ CloseFile(map_fd);
InternalScopedString path(64 + internal_strlen(coverage_dir));
res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
coverage_dir, internal_getpid());
CHECK_LE(res, path.size());
- res = internal_rename(tmp_path.data(), path.data());
- if (internal_iserror(res, &err)) {
+ if (!RenameFile(tmp_path.data(), path.data(), &err)) {
Printf("sancov.map rename failed: %d\n", err);
Die();
}
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
index b931edc..5890b54 100644
--- a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -40,19 +40,20 @@
explicit DD(const DDFlags *flags);
- DDPhysicalThread* CreatePhysicalThread();
- void DestroyPhysicalThread(DDPhysicalThread *pt);
+ DDPhysicalThread *CreatePhysicalThread() override;
+ void DestroyPhysicalThread(DDPhysicalThread *pt) override;
- DDLogicalThread* CreateLogicalThread(u64 ctx);
- void DestroyLogicalThread(DDLogicalThread *lt);
+ DDLogicalThread *CreateLogicalThread(u64 ctx) override;
+ void DestroyLogicalThread(DDLogicalThread *lt) override;
- void MutexInit(DDCallback *cb, DDMutex *m);
- void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
- void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
- void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
- void MutexDestroy(DDCallback *cb, DDMutex *m);
+ void MutexInit(DDCallback *cb, DDMutex *m) override;
+ void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override;
+ void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+ bool trylock) override;
+ void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override;
+ void MutexDestroy(DDCallback *cb, DDMutex *m) override;
- DDReport *GetReport(DDCallback *cb);
+ DDReport *GetReport(DDCallback *cb) override;
void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
void ReportDeadlock(DDCallback *cb, DDMutex *m);
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index e835b46..01098a3 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -54,7 +54,7 @@
bool Parse(const char *value) final {
char *data;
uptr data_mapped_size;
- int err;
+ error_t err;
uptr len =
ReadFileToBuffer(value, &data, &data_mapped_size,
Max(kMaxIncludeSize, GetPageSizeCached()), &err);
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index 884602f..80c30ac 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -151,3 +151,5 @@
"Use DEFAULT to get default format.")
COMMON_FLAG(bool, no_huge_pages_for_shadow, true,
"If true, the shadow is not allowed to use huge pages. ")
+COMMON_FLAG(bool, strict_string_checks, false,
+ "If set check that string arguments are properly null-terminated")
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index e7737bd..b76c602 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -80,7 +80,15 @@
typedef signed short s16; // NOLINT
typedef signed int s32;
typedef signed long long s64; // NOLINT
+#if SANITIZER_WINDOWS
+// On Windows, files are HANDLE, which is a synonim of void*.
+// Use void* to avoid including <windows.h> everywhere.
+typedef void* fd_t;
+typedef unsigned error_t;
+#else
typedef int fd_t;
+typedef int error_t;
+#endif
// WARNING: OFF_T may be different from OS type off_t, depending on the value of
// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index c086b8a..ae4e938 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -11,6 +11,7 @@
// run-time libraries.
// These tools can not use some of the libc functions directly because those
// functions are intercepted. Instead, we implement a tiny subset of libc here.
+// FIXME: Some of functions declared in this file are in fact POSIX, not libc.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LIBC_H
#define SANITIZER_LIBC_H
@@ -56,74 +57,26 @@
// Optimized for the case when the result is true.
bool mem_is_zero(const char *mem, uptr size);
-
-// Memory
-uptr internal_mmap(void *addr, uptr length, int prot, int flags,
- int fd, u64 offset);
-uptr internal_munmap(void *addr, uptr length);
-
// I/O
-const fd_t kInvalidFd = -1;
+const fd_t kInvalidFd = (fd_t)-1;
const fd_t kStdinFd = 0;
-const fd_t kStdoutFd = 1;
-const fd_t kStderrFd = 2;
-uptr internal_close(fd_t fd);
-int internal_isatty(fd_t fd);
+const fd_t kStdoutFd = (fd_t)1;
+const fd_t kStderrFd = (fd_t)2;
-// Use __sanitizer::OpenFile() instead.
-uptr internal_open(const char *filename, int flags);
-uptr internal_open(const char *filename, int flags, u32 mode);
-
-uptr internal_read(fd_t fd, void *buf, uptr count);
-uptr internal_write(fd_t fd, const void *buf, uptr count);
uptr internal_ftruncate(fd_t fd, uptr size);
// OS
-uptr internal_filesize(fd_t fd); // -1 on error.
-uptr internal_stat(const char *path, void *buf);
-uptr internal_lstat(const char *path, void *buf);
-uptr internal_fstat(fd_t fd, void *buf);
-uptr internal_dup2(int oldfd, int newfd);
-uptr internal_readlink(const char *path, char *buf, uptr bufsize);
-uptr internal_unlink(const char *path);
-uptr internal_rename(const char *oldpath, const char *newpath);
void NORETURN internal__exit(int exitcode);
-uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
-uptr internal_ptrace(int request, int pid, void *addr, void *data);
-uptr internal_waitpid(int pid, int *status, int options);
uptr internal_getpid();
uptr internal_getppid();
-int internal_fork();
-
// Threading
uptr internal_sched_yield();
-// These functions call appropriate pthread_ functions directly, bypassing
-// the interceptor. They are weak and may not be present in some tools.
-SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
- void *param);
-SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_join(void *th, void **ret);
-
-#define DEFINE_REAL_PTHREAD_FUNCTIONS \
- namespace __sanitizer { \
- int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \
- void *param) { \
- return REAL(pthread_create)(th, attr, callback, param); \
- } \
- int real_pthread_join(void *th, void **ret) { \
- return REAL(pthread_join(th, ret)); \
- } \
- } // namespace __sanitizer
-
// Error handling
bool internal_iserror(uptr retval, int *rverrno = 0);
-int internal_sigaction(int signum, const void *act, void *oldact);
-
} // namespace __sanitizer
#endif // SANITIZER_LIBC_H
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index cefb1dc..8c4aeff 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -12,6 +12,7 @@
#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
+#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"
namespace __sanitizer {
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 8d2ea48..11a6fe6 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -127,6 +127,10 @@
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}
+int internal_mprotect(void *addr, uptr length, int prot) {
+ return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
+}
+
uptr internal_close(fd_t fd) {
return internal_syscall(SYSCALL(close), fd);
}
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 2ce2025..fd3c134 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -17,6 +17,7 @@
#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_posix.h"
#include "sanitizer_platform_limits_posix.h"
struct link_map; // Opaque type returned by dlopen().
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 1c099d8..ab9f0ab 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -15,6 +15,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_freebsd.h"
@@ -22,8 +23,6 @@
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
-#include "sanitizer_atomic.h"
-#include "sanitizer_symbolizer.h"
#if SANITIZER_ANDROID || SANITIZER_FREEBSD
#include <dlfcn.h> // for dlsym()
@@ -437,9 +436,8 @@
return 0;
if (data->filter && !data->filter(module_name.data()))
return 0;
- void *mem = &data->modules[data->current_n];
- LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
- info->dlpi_addr);
+ LoadedModule *cur_module = &data->modules[data->current_n];
+ cur_module->set(module_name.data(), info->dlpi_addr);
data->current_n++;
for (int i = 0; i < info->dlpi_phnum; i++) {
const Elf_Phdr *phdr = &info->dlpi_phdr[i];
@@ -462,19 +460,6 @@
}
#endif // SANITIZER_ANDROID
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
- // Some kinds of sandboxes may forbid filesystem access, so we won't be able
- // to read the file mappings from /proc/self/maps. Luckily, neither the
- // process will be able to load additional libraries, so it's fine to use the
- // cached mappings.
- MemoryMappingLayout::CacheMemoryMappings();
- // Same for /proc/self/exe in the symbolizer.
-#if !SANITIZER_GO
- Symbolizer::GetOrInit()->PrepareForSandboxing();
- CovPrepareForSandboxing(args);
-#endif
-}
-
// getrusage does not give us the current RSS, only the max RSS.
// Still, this is better than nothing if /proc/self/statm is not available
// for some reason, e.g. due to a sandbox.
@@ -488,8 +473,8 @@
uptr GetRSS() {
if (!common_flags()->can_use_proc_maps_statm)
return GetRSSFromGetrusage();
- uptr fd = OpenFile("/proc/self/statm", RdOnly);
- if ((sptr)fd < 0)
+ fd_t fd = OpenFile("/proc/self/statm", RdOnly);
+ if (fd == kInvalidFd)
return GetRSSFromGetrusage();
char buf[64];
uptr len = internal_read(fd, buf, sizeof(buf) - 1);
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 91a5b7d..4c5b409 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -59,6 +59,10 @@
return munmap(addr, length);
}
+int internal_mprotect(void *addr, uptr length, int prot) {
+ return mprotect(addr, length, prot);
+}
+
uptr internal_close(fd_t fd) {
return close(fd);
}
@@ -220,11 +224,6 @@
UNIMPLEMENTED();
}
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
- (void)args;
- // Nothing here for now.
-}
-
uptr GetPageSize() {
return sysconf(_SC_PAGESIZE);
}
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
index 9eed905..f5d3fe8 100644
--- a/lib/sanitizer_common/sanitizer_mac.h
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -15,6 +15,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_MAC
+#include "sanitizer_posix.h"
namespace __sanitizer {
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index fef5a5b..92f7848 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -130,4 +130,10 @@
# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
#endif
+// Assume obsolete RPC headers are available by default
+#if !defined(HAVE_RPC_XDR_H) && !defined(HAVE_TIRPC_RPC_XDR_H)
+# define HAVE_RPC_XDR_H (SANITIZER_LINUX && !SANITIZER_ANDROID)
+# define HAVE_TIRPC_RPC_XDR_H 0
+#endif
+
#endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 2839e92..e8117f3 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -135,7 +135,11 @@
#include <netax25/ax25.h>
#include <netipx/ipx.h>
#include <netrom/netrom.h>
-#include <rpc/xdr.h>
+#if HAVE_RPC_XDR_H
+# include <rpc/xdr.h>
+#elif HAVE_TIRPC_RPC_XDR_H
+# include <tirpc/rpc/xdr.h>
+#endif
#include <scsi/scsi.h>
#include <sys/mtio.h>
#include <sys/kd.h>
@@ -1159,7 +1163,7 @@
CHECK_SIZE_AND_OFFSET(group, gr_gid);
CHECK_SIZE_AND_OFFSET(group, gr_mem);
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if HAVE_RPC_XDR_H || HAVE_TIRPC_RPC_XDR_H
CHECK_TYPE_SIZE(XDR);
CHECK_SIZE_AND_OFFSET(XDR, x_op);
CHECK_SIZE_AND_OFFSET(XDR, x_ops);
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 5e01212..0b6d35e 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -9,7 +9,7 @@
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements POSIX-specific functions from
-// sanitizer_libc.h.
+// sanitizer_posix.h.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
@@ -17,6 +17,7 @@
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
+#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
@@ -198,27 +199,62 @@
return (void *)p;
}
-void *Mprotect(uptr fixed_addr, uptr size) {
+void *MmapNoAccess(uptr fixed_addr, uptr size) {
return (void *)internal_mmap((void*)fixed_addr, size,
PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED |
MAP_NORESERVE, -1, 0);
}
-uptr OpenFile(const char *filename, FileAccessMode mode) {
+bool MprotectNoAccess(uptr addr, uptr size) {
+ return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
+}
+
+fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
int flags;
switch (mode) {
case RdOnly: flags = O_RDONLY; break;
case WrOnly: flags = O_WRONLY | O_CREAT; break;
case RdWr: flags = O_RDWR | O_CREAT; break;
}
- return internal_open(filename, flags, 0660);
+ fd_t res = internal_open(filename, flags, 0660);
+ if (internal_iserror(res, errno_p))
+ return kInvalidFd;
+ return res;
+}
+
+void CloseFile(fd_t fd) {
+ internal_close(fd);
+}
+
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
+ error_t *error_p) {
+ uptr res = internal_read(fd, buff, buff_size);
+ if (internal_iserror(res, error_p))
+ return false;
+ if (bytes_read)
+ *bytes_read = res;
+ return true;
+}
+
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
+ error_t *error_p) {
+ uptr res = internal_write(fd, buff, buff_size);
+ if (internal_iserror(res, error_p))
+ return false;
+ if (bytes_written)
+ *bytes_written = res;
+ return true;
+}
+
+bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
+ uptr res = internal_rename(oldpath, newpath);
+ return !internal_iserror(res, error_p);
}
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
- uptr openrv = OpenFile(file_name, RdOnly);
- CHECK(!internal_iserror(openrv));
- fd_t fd = openrv;
+ fd_t fd = OpenFile(file_name, RdOnly);
+ CHECK(fd != kInvalidFd);
uptr fsize = internal_filesize(fd);
CHECK_NE(fsize, (uptr)-1);
CHECK_GT(fsize, 0);
@@ -227,13 +263,13 @@
return internal_iserror(map) ? 0 : (void *)map;
}
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
uptr flags = MAP_SHARED;
if (addr) flags |= MAP_FIXED;
uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
int mmap_errno = 0;
if (internal_iserror(p, &mmap_errno)) {
- Printf("could not map writable file (%zd, %zu, %zu): %zd, errno: %d\n",
+ Printf("could not map writable file (%d, %zu, %zu): %zd, errno: %d\n",
fd, offset, size, p, mmap_errno);
return 0;
}
diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h
new file mode 100644
index 0000000..a3377a8
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_posix.h
@@ -0,0 +1,81 @@
+//===-- sanitizer_posix.h -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and declares some useful POSIX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_POSIX_H
+#define SANITIZER_POSIX_H
+
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers from sanitizer runtime.
+#include "sanitizer_internal_defs.h"
+
+#if !SANITIZER_POSIX
+// Make it hard to accidentally use any of functions declared in this file:
+#error This file should only be included on POSIX
+#endif
+
+namespace __sanitizer {
+
+// I/O
+// Don't use directly, use __sanitizer::OpenFile() instead.
+uptr internal_open(const char *filename, int flags);
+uptr internal_open(const char *filename, int flags, u32 mode);
+uptr internal_close(fd_t fd);
+
+uptr internal_read(fd_t fd, void *buf, uptr count);
+uptr internal_write(fd_t fd, const void *buf, uptr count);
+
+// Memory
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset);
+uptr internal_munmap(void *addr, uptr length);
+int internal_mprotect(void *addr, uptr length, int prot);
+
+// OS
+uptr internal_filesize(fd_t fd); // -1 on error.
+uptr internal_stat(const char *path, void *buf);
+uptr internal_lstat(const char *path, void *buf);
+uptr internal_fstat(fd_t fd, void *buf);
+uptr internal_dup2(int oldfd, int newfd);
+uptr internal_readlink(const char *path, char *buf, uptr bufsize);
+uptr internal_unlink(const char *path);
+uptr internal_rename(const char *oldpath, const char *newpath);
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
+
+uptr internal_ptrace(int request, int pid, void *addr, void *data);
+uptr internal_waitpid(int pid, int *status, int options);
+
+int internal_fork();
+
+// These functions call appropriate pthread_ functions directly, bypassing
+// the interceptor. They are weak and may not be present in some tools.
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
+ void *param);
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_join(void *th, void **ret);
+
+#define DEFINE_REAL_PTHREAD_FUNCTIONS \
+ namespace __sanitizer { \
+ int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \
+ void *param) { \
+ return REAL(pthread_create)(th, attr, callback, param); \
+ } \
+ int real_pthread_join(void *th, void **ret) { \
+ return REAL(pthread_join(th, ret)); \
+ } \
+ } // namespace __sanitizer
+
+int internal_sigaction(int signum, const void *act, void *oldact);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_POSIX_H
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 11828e6..9eb28c6 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -18,7 +18,10 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_posix.h"
+#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
#include <errno.h>
#include <pthread.h>
@@ -119,8 +122,8 @@
#endif
}
-int internal_isatty(fd_t fd) {
- return isatty(fd);
+bool SupportsColoredOutput(fd_t fd) {
+ return isatty(fd) != 0;
}
#ifndef SANITIZER_GO
@@ -200,6 +203,19 @@
return result;
}
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+ // Some kinds of sandboxes may forbid filesystem access, so we won't be able
+ // to read the file mappings from /proc/self/maps. Luckily, neither the
+ // process will be able to load additional libraries, so it's fine to use the
+ // cached mappings.
+ MemoryMappingLayout::CacheMemoryMappings();
+ // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+ Symbolizer::GetOrInit()->PrepareForSandboxing();
+ CovPrepareForSandboxing(args);
+#endif
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc
index 2ec08d7..2c6ce8e 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -130,7 +130,6 @@
continue;
if (filter && !filter(cur_name))
continue;
- void *mem = &modules[n_modules];
// Don't subtract 'cur_beg' from the first entry:
// * If a binary is compiled w/o -pie, then the first entry in
// process maps is likely the binary itself (all dynamic libs
@@ -143,7 +142,8 @@
// shadow memory of the tool), so the module can't be the
// first entry.
uptr base_address = (i ? cur_beg : 0) - cur_offset;
- LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
+ LoadedModule *cur_module = &modules[n_modules];
+ cur_module->set(cur_name, base_address);
cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
n_modules++;
}
diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
index c0a8614..29d6996 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -171,13 +171,13 @@
continue;
if (filter && !filter(cur_name))
continue;
- LoadedModule *cur_module = 0;
+ LoadedModule *cur_module = nullptr;
if (n_modules > 0 &&
0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
cur_module = &modules[n_modules - 1];
} else {
- void *mem = &modules[n_modules];
- cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+ cur_module = &modules[n_modules];
+ cur_module->set(cur_name, cur_beg);
n_modules++;
}
cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 64e1c79..47b27e7 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -310,7 +310,7 @@
// in the future.
guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_,
"ScopedStackWithGuard");
- CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_));
+ CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_));
}
~ScopedStackSpaceWithGuard() {
UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_);
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
index df7661a..8b2496a 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -75,8 +75,29 @@
end_hook_ = end_hook;
}
+const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) {
+ mu_->CheckLocked();
+
+ // 'str' will be the same string multiple times in a row, optimize this case.
+ if (last_match_ && !internal_strcmp(last_match_, str))
+ return last_match_;
+
+ // FIXME: this is linear search.
+ // We should optimize this further if this turns out to be a bottleneck later.
+ for (uptr i = 0; i < storage_.size(); ++i) {
+ if (!internal_strcmp(storage_[i], str)) {
+ last_match_ = storage_[i];
+ return last_match_;
+ }
+ }
+ last_match_ = internal_strdup(str);
+ storage_.push_back(last_match_);
+ return last_match_;
+}
+
Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
- : tools_(tools), start_hook_(0), end_hook_(0) {}
+ : module_names_(&mu_), n_modules_(0), modules_fresh_(false), tools_(tools),
+ start_hook_(0), end_hook_(0) {}
Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
: sym_(sym) {
@@ -89,76 +110,4 @@
sym_->end_hook_();
}
-SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
- BlockingMutexLock l(&mu_);
- const char *module_name;
- uptr module_offset;
- SymbolizedStack *res = SymbolizedStack::New(addr);
- if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
- &module_offset))
- return res;
- // Always fill data about module name and offset.
- res->info.FillModuleInfo(module_name, module_offset);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
- SymbolizerScope sym_scope(this);
- if (tool->SymbolizePC(addr, res)) {
- return res;
- }
- }
- return res;
-}
-
-bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
- BlockingMutexLock l(&mu_);
- const char *module_name;
- uptr module_offset;
- if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
- &module_offset))
- return false;
- info->Clear();
- info->module = internal_strdup(module_name);
- info->module_offset = module_offset;
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
- SymbolizerScope sym_scope(this);
- if (tool->SymbolizeData(addr, info)) {
- return true;
- }
- }
- return true;
-}
-
-bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
- uptr *module_address) {
- BlockingMutexLock l(&mu_);
- return PlatformFindModuleNameAndOffsetForAddress(pc, module_name,
- module_address);
-}
-
-void Symbolizer::Flush() {
- BlockingMutexLock l(&mu_);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
- SymbolizerScope sym_scope(this);
- tool->Flush();
- }
-}
-
-const char *Symbolizer::Demangle(const char *name) {
- BlockingMutexLock l(&mu_);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
- SymbolizerScope sym_scope(this);
- if (const char *demangled = tool->Demangle(name))
- return demangled;
- }
- return PlatformDemangle(name);
-}
-
-void Symbolizer::PrepareForSandboxing() {
- BlockingMutexLock l(&mu_);
- PlatformPrepareForSandboxing();
-}
-
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 225da70..9233223 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -75,7 +75,7 @@
class SymbolizerTool;
-class Symbolizer {
+class Symbolizer final {
public:
/// Initialize and return platform-specific implementation of symbolizer
/// (if it wasn't already initialized).
@@ -84,15 +84,19 @@
// all inlined functions, if necessary).
SymbolizedStack *SymbolizePC(uptr address);
bool SymbolizeData(uptr address, DataInfo *info);
+
+ // The module names Symbolizer returns are stable and unique for every given
+ // module. It is safe to store and compare them as pointers.
bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
uptr *module_address);
const char *GetModuleNameForPc(uptr pc) {
- const char *module_name = 0;
+ const char *module_name = nullptr;
uptr unused;
if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused))
return module_name;
return nullptr;
}
+
// Release internal caches (if any).
void Flush();
// Attempts to demangle the provided C++ mangled name.
@@ -110,16 +114,40 @@
EndSymbolizationHook end_hook);
private:
+ // GetModuleNameAndOffsetForPC has to return a string to the caller.
+ // Since the corresponding module might get unloaded later, we should create
+ // our owned copies of the strings that we can safely return.
+ // ModuleNameOwner does not provide any synchronization, thus calls to
+ // its method should be protected by |mu_|.
+ class ModuleNameOwner {
+ public:
+ explicit ModuleNameOwner(BlockingMutex *synchronized_by)
+ : storage_(kInitialCapacity), last_match_(nullptr),
+ mu_(synchronized_by) {}
+ const char *GetOwnedCopy(const char *str);
+
+ private:
+ static const uptr kInitialCapacity = 1000;
+ InternalMmapVector<const char*> storage_;
+ const char *last_match_;
+
+ BlockingMutex *mu_;
+ } module_names_;
+
/// Platform-specific function for creating a Symbolizer object.
static Symbolizer *PlatformInit();
- virtual bool PlatformFindModuleNameAndOffsetForAddress(
- uptr address, const char **module_name, uptr *module_offset) {
- UNIMPLEMENTED();
- }
+ bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+ uptr *module_offset);
+ LoadedModule *FindModuleForAddress(uptr address);
+ LoadedModule modules_[kMaxNumberOfModules];
+ uptr n_modules_;
+ // If stale, need to reload the modules before looking up addresses.
+ bool modules_fresh_;
+
// Platform-specific default demangler, must not return nullptr.
- virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); }
- virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); }
+ const char *PlatformDemangle(const char *name);
+ void PlatformPrepareForSandboxing();
static Symbolizer *symbolizer_;
static StaticSpinMutex init_mu_;
@@ -132,7 +160,6 @@
typedef IntrusiveList<SymbolizerTool>::Iterator Iterator;
IntrusiveList<SymbolizerTool> tools_;
- protected:
explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);
static LowLevelAllocator symbolizer_allocator_;
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index f1e2289..160f55d 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -60,6 +60,121 @@
return prefix_end;
}
+SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
+ BlockingMutexLock l(&mu_);
+ const char *module_name;
+ uptr module_offset;
+ SymbolizedStack *res = SymbolizedStack::New(addr);
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ return res;
+ // Always fill data about module name and offset.
+ res->info.FillModuleInfo(module_name, module_offset);
+ for (auto iter = Iterator(&tools_); iter.hasNext();) {
+ auto *tool = iter.next();
+ SymbolizerScope sym_scope(this);
+ if (tool->SymbolizePC(addr, res)) {
+ return res;
+ }
+ }
+ return res;
+}
+
+bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ BlockingMutexLock l(&mu_);
+ const char *module_name;
+ uptr module_offset;
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ return false;
+ info->Clear();
+ info->module = internal_strdup(module_name);
+ info->module_offset = module_offset;
+ for (auto iter = Iterator(&tools_); iter.hasNext();) {
+ auto *tool = iter.next();
+ SymbolizerScope sym_scope(this);
+ if (tool->SymbolizeData(addr, info)) {
+ return true;
+ }
+ }
+ return true;
+}
+
+bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) {
+ BlockingMutexLock l(&mu_);
+ const char *internal_module_name = nullptr;
+ if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name,
+ module_address))
+ return false;
+
+ if (module_name)
+ *module_name = module_names_.GetOwnedCopy(internal_module_name);
+ return true;
+}
+
+void Symbolizer::Flush() {
+ BlockingMutexLock l(&mu_);
+ for (auto iter = Iterator(&tools_); iter.hasNext();) {
+ auto *tool = iter.next();
+ SymbolizerScope sym_scope(this);
+ tool->Flush();
+ }
+}
+
+const char *Symbolizer::Demangle(const char *name) {
+ BlockingMutexLock l(&mu_);
+ for (auto iter = Iterator(&tools_); iter.hasNext();) {
+ auto *tool = iter.next();
+ SymbolizerScope sym_scope(this);
+ if (const char *demangled = tool->Demangle(name))
+ return demangled;
+ }
+ return PlatformDemangle(name);
+}
+
+void Symbolizer::PrepareForSandboxing() {
+ BlockingMutexLock l(&mu_);
+ PlatformPrepareForSandboxing();
+}
+
+bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
+ const char **module_name,
+ uptr *module_offset) {
+ LoadedModule *module = FindModuleForAddress(address);
+ if (module == 0)
+ return false;
+ *module_name = module->full_name();
+ *module_offset = address - module->base_address();
+ return true;
+}
+
+LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
+ bool modules_were_reloaded = false;
+ if (!modules_fresh_) {
+ for (uptr i = 0; i < n_modules_; i++)
+ modules_[i].clear();
+ n_modules_ =
+ GetListOfModules(modules_, kMaxNumberOfModules, /* filter */ nullptr);
+ CHECK_GT(n_modules_, 0);
+ CHECK_LT(n_modules_, kMaxNumberOfModules);
+ modules_fresh_ = true;
+ modules_were_reloaded = true;
+ }
+ for (uptr i = 0; i < n_modules_; i++) {
+ if (modules_[i].containsAddress(address)) {
+ return &modules_[i];
+ }
+ }
+ // Reload the modules and look up again, if we haven't tried it yet.
+ if (!modules_were_reloaded) {
+ // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+ // It's too aggressive to reload the list of modules each time we fail
+ // to find a module for a given address.
+ modules_fresh_ = false;
+ return FindModuleForAddress(address);
+ }
+ return 0;
+}
+
Symbolizer *Symbolizer::GetOrInit() {
SpinMutexLock l(&init_mu_);
if (symbolizer_)
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index 189b0ab..6e714c7 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -129,13 +129,13 @@
explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
private:
- bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
// Empty line marks the end of llvm-symbolizer output.
return length >= 2 && buffer[length - 1] == '\n' &&
buffer[length - 2] == '\n';
}
- void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
#if defined(__x86_64__)
const char* const kSymbolizerArch = "--default-arch=x86_64";
#elif defined(__i386__)
@@ -202,7 +202,7 @@
const char *module_name() const { return module_name_; }
private:
- bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+ bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
// Output should consist of two lines.
int num_lines = 0;
for (uptr i = 0; i < length; ++i) {
@@ -214,7 +214,7 @@
return false;
}
- void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+ void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
}
@@ -349,69 +349,16 @@
#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
-class POSIXSymbolizer : public Symbolizer {
- public:
- explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> tools)
- : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {}
+const char *Symbolizer::PlatformDemangle(const char *name) {
+ return DemangleCXXABI(name);
+}
- private:
- const char *PlatformDemangle(const char *name) override {
- return DemangleCXXABI(name);
- }
-
- void PlatformPrepareForSandboxing() override {
+void Symbolizer::PlatformPrepareForSandboxing() {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
- // Cache /proc/self/exe on Linux.
- CacheBinaryName();
+ // Cache /proc/self/exe on Linux.
+ CacheBinaryName();
#endif
- }
-
- LoadedModule *FindModuleForAddress(uptr address) {
- bool modules_were_reloaded = false;
- if (!modules_fresh_) {
- for (uptr i = 0; i < n_modules_; i++)
- modules_[i].clear();
- n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
- /* filter */ 0);
- CHECK_GT(n_modules_, 0);
- CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
- modules_fresh_ = true;
- modules_were_reloaded = true;
- }
- for (uptr i = 0; i < n_modules_; i++) {
- if (modules_[i].containsAddress(address)) {
- return &modules_[i];
- }
- }
- // Reload the modules and look up again, if we haven't tried it yet.
- if (!modules_were_reloaded) {
- // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
- // It's too aggressive to reload the list of modules each time we fail
- // to find a module for a given address.
- modules_fresh_ = false;
- return FindModuleForAddress(address);
- }
- return 0;
- }
-
- bool PlatformFindModuleNameAndOffsetForAddress(uptr address,
- const char **module_name,
- uptr *module_offset) override {
- LoadedModule *module = FindModuleForAddress(address);
- if (module == 0)
- return false;
- *module_name = module->full_name();
- *module_offset = address - module->base_address();
- return true;
- }
-
- // 16K loaded modules should be enough for everyone.
- static const uptr kMaxNumberOfModuleContexts = 1 << 14;
- LoadedModule modules_[kMaxNumberOfModuleContexts];
- uptr n_modules_;
- // If stale, need to reload the modules before looking up addresses.
- bool modules_fresh_;
-};
+}
static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
const char *path = common_flags()->external_symbolizer_path;
@@ -494,7 +441,7 @@
IntrusiveList<SymbolizerTool> list;
list.clear();
ChooseSymbolizerTools(&list, &symbolizer_allocator_);
- return new(symbolizer_allocator_) POSIXSymbolizer(list);
+ return new(symbolizer_allocator_) Symbolizer(list);
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
index 98d16e0..f1c01a3 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
@@ -13,6 +13,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_POSIX
+#include "sanitizer_posix.h"
#include "sanitizer_symbolizer_internal.h"
#include <errno.h>
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 67ed4b3..31f3746 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -129,42 +129,19 @@
return name;
}
-bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name,
- uptr *module_offset) {
- InitializeDbgHelpIfNeeded();
-
- IMAGEHLP_MODULE64 mod_info;
- internal_memset(&mod_info, 0, sizeof(mod_info));
- mod_info.SizeOfStruct = sizeof(mod_info);
- if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) {
- *module_name = mod_info.ImageName;
- *module_offset = addr - (uptr)mod_info.BaseOfImage;
- return true;
- }
- return false;
+const char *Symbolizer::PlatformDemangle(const char *name) {
+ return name;
}
-// TODO(kuba.brecka): To be merged with POSIXSymbolizer.
-class WinSymbolizer : public Symbolizer {
- public:
- explicit WinSymbolizer(IntrusiveList<SymbolizerTool> tools)
- : Symbolizer(tools) {}
-
- private:
- bool PlatformFindModuleNameAndOffsetForAddress(
- uptr addr, const char **module_name, uptr *module_offset) override {
- return ::FindModuleNameAndOffsetForAddress(addr, module_name,
- module_offset);
- }
- const char *PlatformDemangle(const char *name) override { return name; }
- void PlatformPrepareForSandboxing() override { }
-};
+void Symbolizer::PlatformPrepareForSandboxing() {
+ // Do nothing.
+}
Symbolizer *Symbolizer::PlatformInit() {
IntrusiveList<SymbolizerTool> list;
list.clear();
list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
- return new(symbolizer_allocator_) WinSymbolizer(list);
+ return new(symbolizer_allocator_) Symbolizer(list);
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 3ec9084..e5e2f64 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -93,6 +93,9 @@
}
void UnmapOrDie(void *addr, uptr size) {
+ if (!size || !addr)
+ return;
+
if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
Report("ERROR: %s failed to "
"deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
@@ -122,7 +125,7 @@
return MmapOrDie(size, mem_type);
}
-void *Mprotect(uptr fixed_addr, uptr size) {
+void *MmapNoAccess(uptr fixed_addr, uptr size) {
void *res = VirtualAlloc((LPVOID)fixed_addr, size,
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
if (res == 0)
@@ -132,6 +135,12 @@
return res;
}
+bool MprotectNoAccess(uptr addr, uptr size) {
+ DWORD old_protection;
+ return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
+}
+
+
void FlushUnneededShadowMemory(uptr addr, uptr size) {
// This is almost useless on 32-bits.
// FIXME: add madvise-analog when we move to 64-bits.
@@ -157,7 +166,7 @@
UNIMPLEMENTED();
}
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
UNIMPLEMENTED();
}
@@ -206,76 +215,46 @@
namespace {
struct ModuleInfo {
- HMODULE handle;
+ const char *filepath;
uptr base_address;
uptr end_address;
};
int CompareModulesBase(const void *pl, const void *pr) {
- const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr;
- if (l.base_address < r.base_address)
+ const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
+ if (l->base_address < r->base_address)
return -1;
- return l.base_address > r.base_address;
+ return l->base_address > r->base_address;
}
} // namespace
#ifndef SANITIZER_GO
void DumpProcessMap() {
Report("Dumping process modules:\n");
- HANDLE cur_process = GetCurrentProcess();
+ InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
+ uptr num_modules =
+ GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
- // Query the list of modules. Start by assuming there are no more than 256
- // modules and retry if that's not sufficient.
- ModuleInfo *modules;
- size_t num_modules;
- {
- HMODULE *hmodules = 0;
- uptr modules_buffer_size = sizeof(HMODULE) * 256;
- DWORD bytes_required;
- while (!hmodules) {
- hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
- CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
- &bytes_required));
- if (bytes_required > modules_buffer_size) {
- // Either there turned out to be more than 256 hmodules, or new hmodules
- // could have loaded since the last try. Retry.
- UnmapOrDie(hmodules, modules_buffer_size);
- hmodules = 0;
- modules_buffer_size = bytes_required;
- }
- }
-
- num_modules = bytes_required / sizeof(HMODULE);
- modules =
- (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__);
- for (size_t i = 0; i < num_modules; ++i) {
- modules[i].handle = hmodules[i];
- MODULEINFO mi;
- if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi)))
- continue;
- modules[i].base_address = (uptr)mi.lpBaseOfDll;
- modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
- }
- UnmapOrDie(hmodules, modules_buffer_size);
+ InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
+ for (size_t i = 0; i < num_modules; ++i) {
+ module_infos[i].filepath = modules[i].full_name();
+ module_infos[i].base_address = modules[i].base_address();
+ module_infos[i].end_address = modules[i].ranges().next()->end;
}
-
- qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase);
+ qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
+ CompareModulesBase);
for (size_t i = 0; i < num_modules; ++i) {
- const ModuleInfo &mi = modules[i];
- char module_name[MAX_PATH];
- bool got_module_name = GetModuleFileNameA(
- mi.handle, module_name, sizeof(module_name));
+ const ModuleInfo &mi = module_infos[i];
if (mi.end_address != 0) {
Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
- got_module_name ? module_name : "[no name]");
- } else if (got_module_name) {
- Printf("\t??\?-??? %s\n", module_name);
+ mi.filepath[0] ? mi.filepath : "[no name]");
+ } else if (mi.filepath[0]) {
+ Printf("\t??\?-??? %s\n", mi.filepath);
} else {
Printf("\t???\n");
}
}
- UnmapOrDie(modules, num_modules * sizeof(ModuleInfo));
}
#endif
@@ -346,117 +325,130 @@
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
- UNIMPLEMENTED();
-};
+ HANDLE cur_process = GetCurrentProcess();
-#ifndef SANITIZER_GO
-int Atexit(void (*function)(void)) {
- return atexit(function);
-}
-#endif
-
-// ------------------ sanitizer_libc.h
-uptr internal_mmap(void *addr, uptr length, int prot, int flags,
- int fd, u64 offset) {
- UNIMPLEMENTED();
-}
-
-uptr internal_munmap(void *addr, uptr length) {
- UNIMPLEMENTED();
-}
-
-uptr internal_close(fd_t fd) {
- UNIMPLEMENTED();
-}
-
-int internal_isatty(fd_t fd) {
- return _isatty(fd);
-}
-
-uptr internal_open(const char *filename, int flags) {
- UNIMPLEMENTED();
-}
-
-uptr internal_open(const char *filename, int flags, u32 mode) {
- UNIMPLEMENTED();
-}
-
-uptr OpenFile(const char *filename, FileAccessMode mode) {
- UNIMPLEMENTED();
-}
-
-uptr internal_read(fd_t fd, void *buf, uptr count) {
- UNIMPLEMENTED();
-}
-
-uptr internal_write(fd_t fd, const void *buf, uptr count) {
- if (fd != kStderrFd)
- UNIMPLEMENTED();
-
- static HANDLE output_stream = 0;
- // Abort immediately if we know printing is not possible.
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
-
- // If called for the first time, try to use stderr to output stuff,
- // falling back to stdout if anything goes wrong.
- bool fallback_to_stdout = false;
- if (output_stream == 0) {
- output_stream = GetStdHandle(STD_ERROR_HANDLE);
- // We don't distinguish "no such handle" from error.
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
-
- if (output_stream == INVALID_HANDLE_VALUE) {
- // Retry with stdout?
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
- } else {
- // Successfully got an stderr handle. However, if WriteFile() fails,
- // we can still try to fallback to stdout.
- fallback_to_stdout = true;
+ // Query the list of modules. Start by assuming there are no more than 256
+ // modules and retry if that's not sufficient.
+ HMODULE *hmodules = 0;
+ uptr modules_buffer_size = sizeof(HMODULE) * 256;
+ DWORD bytes_required;
+ while (!hmodules) {
+ hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
+ CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
+ &bytes_required));
+ if (bytes_required > modules_buffer_size) {
+ // Either there turned out to be more than 256 hmodules, or new hmodules
+ // could have loaded since the last try. Retry.
+ UnmapOrDie(hmodules, modules_buffer_size);
+ hmodules = 0;
+ modules_buffer_size = bytes_required;
}
}
- DWORD ret;
- if (WriteFile(output_stream, buf, count, &ret, 0))
- return ret;
+ // |num_modules| is the number of modules actually present,
+ // |count| is the number of modules we return.
+ size_t nun_modules = bytes_required / sizeof(HMODULE),
+ count = 0;
+ for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
+ HMODULE handle = hmodules[i];
+ MODULEINFO mi;
+ if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
+ continue;
- // Re-try with stdout if using a valid stderr handle fails.
- if (fallback_to_stdout) {
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream != INVALID_HANDLE_VALUE)
- return internal_write(fd, buf, count);
+ char module_name[MAX_PATH];
+ bool got_module_name =
+ GetModuleFileNameA(handle, module_name, sizeof(module_name));
+ if (!got_module_name)
+ module_name[0] = '\0';
+
+ if (filter && !filter(module_name))
+ continue;
+
+ uptr base_address = (uptr)mi.lpBaseOfDll;
+ uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+ LoadedModule *cur_module = &modules[count];
+ cur_module->set(module_name, base_address);
+ // We add the whole module as one single address range.
+ cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
+ count++;
}
+ UnmapOrDie(hmodules, modules_buffer_size);
+
+ return count;
+};
+
+#ifndef SANITIZER_GO
+// We can't use atexit() directly at __asan_init time as the CRT is not fully
+// initialized at this point. Place the functions into a vector and use
+// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
+InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
+
+int Atexit(void (*function)(void)) {
+ atexit_functions.push_back(function);
return 0;
}
-uptr internal_stat(const char *path, void *buf) {
+static int RunAtexit() {
+ int ret = 0;
+ for (uptr i = 0; i < atexit_functions.size(); ++i) {
+ ret |= atexit(atexit_functions[i]);
+ }
+ return ret;
+}
+
+#pragma section(".CRT$XID", long, read) // NOLINT
+static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
+#endif
+
+// ------------------ sanitizer_libc.h
+fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
+ if (mode != WrOnly)
+ UNIMPLEMENTED();
+ fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, nullptr);
+ CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
+ CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
+ return res;
+}
+
+void CloseFile(fd_t fd) {
+ CloseHandle(fd);
+}
+
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
+ error_t *error_p) {
UNIMPLEMENTED();
}
-uptr internal_lstat(const char *path, void *buf) {
- UNIMPLEMENTED();
+bool SupportsColoredOutput(fd_t fd) {
+ // FIXME: support colored output.
+ return false;
}
-uptr internal_fstat(fd_t fd, void *buf) {
- UNIMPLEMENTED();
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
+ error_t *error_p) {
+ CHECK(fd != kInvalidFd);
+
+ if (fd == kStdoutFd) {
+ fd = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (fd == 0) fd = kInvalidFd;
+ } else if (fd == kStderrFd) {
+ fd = GetStdHandle(STD_ERROR_HANDLE);
+ if (fd == 0) fd = kInvalidFd;
+ }
+
+ DWORD internal_bytes_written;
+ if (fd == kInvalidFd ||
+ WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
+ if (error_p) *error_p = GetLastError();
+ return false;
+ } else {
+ if (bytes_written) *bytes_written = internal_bytes_written;
+ return true;
+ }
}
-uptr internal_filesize(fd_t fd) {
- UNIMPLEMENTED();
-}
-
-uptr internal_dup2(int oldfd, int newfd) {
- UNIMPLEMENTED();
-}
-
-uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
UNIMPLEMENTED();
}
@@ -473,10 +465,6 @@
UNIMPLEMENTED();
}
-uptr internal_rename(const char *oldpath, const char *newpath) {
- UNIMPLEMENTED();
-}
-
uptr GetRSS() {
return 0;
}
@@ -600,7 +588,7 @@
void ReportFile::Write(const char *buffer, uptr length) {
SpinMutexLock l(mu);
ReopenIfNecessary();
- if (length != internal_write(fd, buffer, length)) {
+ if (!WriteToFile(fd, buffer, length)) {
// stderr may be closed, but we may be able to print to the debugger
// instead. This is the case when launching a program from Visual Studio,
// and the following routine should write to its console.
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index 53180d0..776b8d9 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -4,10 +4,11 @@
# We need to merge these integers into a set and then
# either print them (as hex) or dump them into another file.
import array
+import bisect
+import glob
+import os.path
import struct
import sys
-import bisect
-import os.path
prog_name = ""
@@ -181,13 +182,19 @@
if len(sys.argv) <= 2:
Usage();
+ file_list = []
+ for f in sys.argv[2:]:
+ file_list += glob.glob(f)
+ if not file_list:
+ Usage()
+
if sys.argv[1] == "print":
- PrintFiles(sys.argv[2:])
+ PrintFiles(file_list)
elif sys.argv[1] == "merge":
- MergeAndPrint(sys.argv[2:])
+ MergeAndPrint(file_list)
elif sys.argv[1] == "unpack":
- Unpack(sys.argv[2:])
+ Unpack(file_list)
elif sys.argv[1] == "rawunpack":
- RawUnpack(sys.argv[2:])
+ RawUnpack(file_list)
else:
Usage()
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index 279f6fe..3252db7 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -17,6 +17,7 @@
#if SANITIZER_LINUX || SANITIZER_MAC
# define SANITIZER_TEST_HAS_STAT_H 1
# include <sys/stat.h>
+# include "sanitizer_common/sanitizer_posix.h"
#else
# define SANITIZER_TEST_HAS_STAT_H 0
#endif
@@ -78,16 +79,14 @@
char tmpfile[128];
temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
- uptr openrv = OpenFile(tmpfile, WrOnly);
- EXPECT_FALSE(internal_iserror(openrv));
- fd_t fd = openrv;
+ fd_t fd = OpenFile(tmpfile, WrOnly);
+ ASSERT_NE(fd, kInvalidFd);
EXPECT_EQ(len1, internal_write(fd, str1, len1));
EXPECT_EQ(len2, internal_write(fd, str2, len2));
- internal_close(fd);
+ CloseFile(fd);
- openrv = OpenFile(tmpfile, RdOnly);
- EXPECT_FALSE(internal_iserror(openrv));
- fd = openrv;
+ fd = OpenFile(tmpfile, RdOnly);
+ ASSERT_NE(fd, kInvalidFd);
uptr fsize = internal_filesize(fd);
EXPECT_EQ(len1 + len2, fsize);
@@ -115,7 +114,7 @@
internal_memset(buf, 0, len1);
EXPECT_EQ(len2, internal_read(fd, buf, len2));
EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
- internal_close(fd);
+ CloseFile(fd);
internal_unlink(tmpfile);
}
#endif
@@ -134,12 +133,11 @@
char tmpfile[128];
temp_file_name(tmpfile, sizeof(tmpfile),
"sanitizer_common.internalmmapwithoffset.tmp.");
- uptr res = OpenFile(tmpfile, RdWr);
- ASSERT_FALSE(internal_iserror(res));
- fd_t fd = res;
+ fd_t fd = OpenFile(tmpfile, RdWr);
+ ASSERT_NE(fd, kInvalidFd);
uptr page_size = GetPageSizeCached();
- res = internal_ftruncate(fd, page_size * 2);
+ uptr res = internal_ftruncate(fd, page_size * 2);
ASSERT_FALSE(internal_iserror(res));
res = internal_lseek(fd, page_size, SEEK_SET);
@@ -154,8 +152,8 @@
ASSERT_EQ('A', p[0]);
ASSERT_EQ('B', p[1]);
- internal_close(fd);
- internal_munmap(p, page_size);
+ CloseFile(fd);
+ UnmapOrDie(p, page_size);
internal_unlink(tmpfile);
}
#endif
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
index abe4ef4..12bc9e1 100644
--- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -37,8 +37,7 @@
const char *binary_name = last_slash ? last_slash + 1 : argv0;
MemoryMappingLayout memory_mapping(false);
const uptr kMaxModules = 100;
- LoadedModule *modules =
- (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+ LoadedModule modules[kMaxModules];
uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
EXPECT_GT(n_modules, 0U);
bool found = false;
@@ -51,7 +50,6 @@
modules[i].clear();
}
EXPECT_TRUE(found);
- free(modules);
}
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index a8bd726..654ea1d 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -45,7 +45,7 @@
void FastUnwindTest::SetUp() {
size_t ps = GetPageSize();
mapping = MmapOrDie(2 * ps, "FastUnwindTest");
- Mprotect((uptr)mapping, ps);
+ MprotectNoAccess((uptr)mapping, ps);
// Unwinder may peek 1 word down from the starting FP.
fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr));
diff --git a/lib/tsan/dd/dd_rtl.h b/lib/tsan/dd/dd_rtl.h
index bb1b202..9abf17d 100644
--- a/lib/tsan/dd/dd_rtl.h
+++ b/lib/tsan/dd/dd_rtl.h
@@ -35,7 +35,7 @@
Thread *thr;
Callback(Thread *thr);
- virtual u32 Unwind();
+ u32 Unwind() override;
};
typedef AddrHashMap<Mutex, 31051> MutexHashMap;
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 1e81ef3..4c06600 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -47,6 +47,10 @@
RegisterFlag(parser, #Name, Description, &f->Name);
#include "tsan_flags.inc"
#undef TSAN_FLAG
+ // DDFlags
+ RegisterFlag(parser, "second_deadlock_stack",
+ "Report where each mutex is locked in deadlock reports",
+ &f->second_deadlock_stack);
}
void InitializeFlags(Flags *f, const char *env) {
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index c45bcdc..df4d5fd 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -156,6 +156,9 @@
const int SIG_SETMASK = 2;
#endif
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
+ (!cur_thread()->is_inited)
+
namespace std {
struct nothrow_t {};
} // namespace std
@@ -274,6 +277,13 @@
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
#endif
+#define READ_STRING_OF_LEN(thr, pc, s, len, n) \
+ MemoryAccessRange((thr), (pc), (uptr)(s), \
+ common_flags()->strict_string_checks ? (len) + 1 : (n), false)
+
+#define READ_STRING(thr, pc, s, n) \
+ READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n))
+
#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
struct BlockingCall {
@@ -663,14 +673,17 @@
}
TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
- SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size);
- MemoryAccessRange(thr, pc, (uptr)dst, size, true);
+ // On FreeBSD we get here from libthr internals on thread initialization.
+ if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
+ SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size);
+ MemoryAccessRange(thr, pc, (uptr)dst, size, true);
+ }
return internal_memset(dst, v, size);
}
TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
// On FreeBSD we get here from libthr internals on thread initialization.
- if (cur_thread()->is_inited) {
+ if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size);
MemoryAccessRange(thr, pc, (uptr)dst, size, true);
MemoryAccessRange(thr, pc, (uptr)src, size, false);
@@ -702,8 +715,9 @@
TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
SCOPED_TSAN_INTERCEPTOR(strchr, s, c);
char *res = REAL(strchr)(s, c);
- uptr len = res ? (char*)res - (char*)s + 1 : internal_strlen(s) + 1;
- MemoryAccessRange(thr, pc, (uptr)s, len, false);
+ uptr len = internal_strlen(s);
+ uptr n = res ? (char*)res - (char*)s + 1 : len + 1;
+ READ_STRING_OF_LEN(thr, pc, s, len, n);
return res;
}
@@ -711,7 +725,7 @@
SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
char *res = REAL(strchrnul)(s, c);
uptr len = (char*)res - (char*)s + 1;
- MemoryAccessRange(thr, pc, (uptr)s, len, false);
+ READ_STRING(thr, pc, s, len);
return res;
}
@@ -802,8 +816,11 @@
TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
- DontNeedShadowFor((uptr)addr, sz);
- ctx->metamap.ResetRange(thr, pc, (uptr)addr, (uptr)sz);
+ if (sz != 0) {
+ // If sz == 0, munmap will return EINVAL and don't unmap any memory.
+ DontNeedShadowFor((uptr)addr, sz);
+ ctx->metamap.ResetRange(thr, pc, (uptr)addr, (uptr)sz);
+ }
int res = REAL(munmap)(addr, sz);
return res;
}
@@ -1039,13 +1056,25 @@
}
struct CondMutexUnlockCtx {
+ ScopedInterceptor *si;
ThreadState *thr;
uptr pc;
void *m;
};
static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
+ // pthread_cond_wait interceptor has enabled async signal delivery
+ // (see BlockingCall below). Disable async signals since we are running
+ // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
+ // since the thread is cancelled, so we have to manually execute them
+ // (the thread still can run some user code due to pthread_cleanup_push).
+ ThreadSignalContext *ctx = SigCtx(arg->thr);
+ CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
+ atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
MutexLock(arg->thr, arg->pc, (uptr)arg->m);
+ // Undo BlockingCall ctor effects.
+ arg->thr->ignore_interceptors--;
+ arg->si->~ScopedInterceptor();
}
INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
@@ -1060,12 +1089,17 @@
SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
MutexUnlock(thr, pc, (uptr)m);
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
- CondMutexUnlockCtx arg = {thr, pc, m};
+ CondMutexUnlockCtx arg = {&si, thr, pc, m};
+ int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
// See test/tsan/cond_cancel.cc.
- int res = call_pthread_cancel_with_cleanup(
- (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
- cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+ {
+ // Enable signal delivery while the thread is blocked.
+ BlockingCall bc(thr);
+ res = call_pthread_cancel_with_cleanup(
+ (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
+ cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+ }
if (res == errno_EOWNERDEAD)
MutexRepair(thr, pc, (uptr)m);
MutexLock(thr, pc, (uptr)m);
@@ -1077,12 +1111,16 @@
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
MutexUnlock(thr, pc, (uptr)m);
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
- CondMutexUnlockCtx arg = {thr, pc, m};
+ CondMutexUnlockCtx arg = {&si, thr, pc, m};
+ int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
// See test/tsan/cond_cancel.cc.
- int res = call_pthread_cancel_with_cleanup(
- REAL(pthread_cond_timedwait), cond, m, abstime,
- (void(*)(void *arg))cond_mutex_unlock, &arg);
+ {
+ BlockingCall bc(thr);
+ res = call_pthread_cancel_with_cleanup(
+ REAL(pthread_cond_timedwait), cond, m, abstime,
+ (void(*)(void *arg))cond_mutex_unlock, &arg);
+ }
if (res == errno_EOWNERDEAD)
MutexRepair(thr, pc, (uptr)m);
MutexLock(thr, pc, (uptr)m);
@@ -1389,6 +1427,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__xstat)(version, path, buf);
}
#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
@@ -1399,9 +1438,11 @@
TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
#if SANITIZER_FREEBSD
SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(stat)(path, buf);
#else
SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__xstat)(0, path, buf);
#endif
}
@@ -1409,6 +1450,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__xstat64)(version, path, buf);
}
#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
@@ -1419,6 +1461,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__xstat64)(0, path, buf);
}
#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
@@ -1429,6 +1472,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__lxstat)(version, path, buf);
}
#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
@@ -1439,9 +1483,11 @@
TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
#if SANITIZER_FREEBSD
SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(lstat)(path, buf);
#else
SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__lxstat)(0, path, buf);
#endif
}
@@ -1449,6 +1495,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__lxstat64)(version, path, buf);
}
#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
@@ -1459,6 +1506,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+ READ_STRING(thr, pc, path, 0);
return REAL(__lxstat64)(0, path, buf);
}
#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
@@ -1518,6 +1566,7 @@
TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
+ READ_STRING(thr, pc, name, 0);
int fd = REAL(open)(name, flags, mode);
if (fd >= 0)
FdFileCreate(thr, pc, fd);
@@ -1527,6 +1576,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
+ READ_STRING(thr, pc, name, 0);
int fd = REAL(open64)(name, flags, mode);
if (fd >= 0)
FdFileCreate(thr, pc, fd);
@@ -1539,6 +1589,7 @@
TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
+ READ_STRING(thr, pc, name, 0);
int fd = REAL(creat)(name, mode);
if (fd >= 0)
FdFileCreate(thr, pc, fd);
@@ -1548,6 +1599,7 @@
#if !SANITIZER_FREEBSD
TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
+ READ_STRING(thr, pc, name, 0);
int fd = REAL(creat64)(name, mode);
if (fd >= 0)
FdFileCreate(thr, pc, fd);
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 659e8d8..e408ba1 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -18,6 +18,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -135,7 +136,7 @@
CHECK_LE(beg, end);
if (beg == end)
return;
- if (beg != (uptr)Mprotect(beg, end - beg)) {
+ if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
Printf("FATAL: Make sure you are not using unlimited stack\n");
Die();
@@ -394,6 +395,8 @@
return res;
}
+// Note: this function runs with async signals enabled,
+// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
void *abstime), void *c, void *m, void *abstime,
void(*cleanup)(void *arg), void *arg) {
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index 63f1748..b72d9b0 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -76,6 +76,8 @@
}
#ifndef SANITIZER_GO
+// Note: this function runs with async signals enabled,
+// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
void *abstime), void *c, void *m, void *abstime,
void(*cleanup)(void *arg), void *arg) {
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 1c64caf..ee279a3 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -133,7 +133,7 @@
ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
InternalScopedBuffer<char> buf(4096);
WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads);
- internal_write(fd, buf.data(), internal_strlen(buf.data()));
+ WriteToFile(fd, buf.data(), internal_strlen(buf.data()));
}
static void BackgroundThread(void *arg) {
@@ -153,12 +153,12 @@
} else {
InternalScopedString filename(kMaxPathLength);
filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
- uptr openrv = OpenFile(filename.data(), WrOnly);
- if (internal_iserror(openrv)) {
+ fd_t fd = OpenFile(filename.data(), WrOnly);
+ if (fd == kInvalidFd) {
Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
&filename[0]);
} else {
- mprof_fd = openrv;
+ mprof_fd = fd;
}
}
}
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index d32688e..dde908a 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -431,13 +431,13 @@
u64 epoch1;
// Override superclass callbacks.
- void OnDead();
- void OnJoined(void *arg);
- void OnFinished();
- void OnStarted(void *arg);
- void OnCreated(void *arg);
- void OnReset();
- void OnDetached(void *arg);
+ void OnDead() override;
+ void OnJoined(void *arg) override;
+ void OnFinished() override;
+ void OnStarted(void *arg) override;
+ void OnCreated(void *arg) override;
+ void OnReset() override;
+ void OnDetached(void *arg) override;
};
struct RacyStacks {
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index ddf2b69..09180d8 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -36,12 +36,8 @@
DDCallback::lt = thr->dd_lt;
}
- virtual u32 Unwind() {
- return CurrentStackId(thr, pc);
- }
- virtual int UniqueTid() {
- return thr->unique_id;
- }
+ u32 Unwind() override { return CurrentStackId(thr, pc); }
+ int UniqueTid() override { return thr->unique_id; }
};
void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 49c4d15..4202d30 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -88,11 +88,13 @@
end++;
for (; meta < end; meta++) {
u32 idx = *meta;
+ if (idx == 0) {
+ // Note: don't write to meta in this case -- the block can be huge.
+ continue;
+ }
*meta = 0;
- for (;;) {
- if (idx == 0)
- break;
- has_something = true;
+ has_something = true;
+ while (idx != 0) {
if (idx & kFlagBlock) {
block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
break;
diff --git a/lib/ubsan/Android.mk b/lib/ubsan/Android.mk
index eed81cc..2df7fdd 100644
--- a/lib/ubsan/Android.mk
+++ b/lib/ubsan/Android.mk
@@ -40,9 +40,41 @@
ubsan_rtl_c_includes := \
external/compiler-rt/lib \
+################################################################################
+# Target modules
+
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libubsan
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(ubsan_rtl_c_includes)
+LOCAL_CPPFLAGS := $(ubsan_rtl_cppflags)
+LOCAL_SRC_FILES := $(ubsan_rtl_files)
+LOCAL_CXX_STL := none
+LOCAL_ADDRESS_SANITIZER := false
+LOCAL_MULTILIB := both
+include $(BUILD_STATIC_LIBRARY)
+
+endif # ($(TARGET_ARCH),arm)
+
+################################################################################
+# Host modules
+
ifneq ($(HOST_OS),darwin)
include $(CLEAR_VARS)
+LOCAL_MODULE := libubsan
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(ubsan_rtl_c_includes)
+LOCAL_CPPFLAGS := $(ubsan_rtl_cppflags) -fno-rtti
+LOCAL_SRC_FILES := $(ubsan_rtl_files)
+LOCAL_CXX_STL := none
+LOCAL_ADDRESS_SANITIZER := false
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
LOCAL_MODULE := libubsan_standalone
LOCAL_CPP_EXTENSION := .cc
LOCAL_C_INCLUDES := $(ubsan_rtl_c_includes)
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index a8b3f61..08bb739 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -8,6 +8,10 @@
ubsan_value.cc
)
+set(UBSAN_STANDALONE_SOURCES
+ ubsan_init_standalone.cc
+ )
+
set(UBSAN_CXX_SOURCES
ubsan_handlers_cxx.cc
ubsan_type_hash.cc
@@ -17,68 +21,75 @@
set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_no_rtti_flag(UBSAN_CFLAGS)
+set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(UBSAN_STANDALONE_CFLAGS)
set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS})
add_custom_target(ubsan)
if(APPLE)
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+ # Common parts of UBSan runtime.
add_compiler_rt_darwin_object_library(RTUbsan ${os}
- ARCH ${UBSAN_SUPPORTED_ARCH}
+ ARCH ${UBSAN_COMMON_SUPPORTED_ARCH}
SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
CFLAGS ${UBSAN_CXXFLAGS})
- add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os}
- ARCH ${UBSAN_SUPPORTED_ARCH}
- SOURCES $<TARGET_OBJECTS:RTUbsan.${os}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${os}>
- LINKFLAGS -lc++abi)
+ if(COMPILER_RT_HAS_UBSAN)
+ # Initializer of standalone UBSan runtime.
+ add_compiler_rt_darwin_object_library(RTUbsan_standalone ${os}
+ ARCH ${UBSAN_SUPPORTED_ARCH}
+ SOURCES ${UBSAN_STANDALONE_SOURCES}
+ CFLAGS ${UBSAN_STANDALONE_CFLAGS})
- add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+ add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os}
+ ARCH ${UBSAN_SUPPORTED_ARCH}
+ SOURCES $<TARGET_OBJECTS:RTUbsan.${os}>
+ $<TARGET_OBJECTS:RTUbsan_standalone.${os}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${os}>)
+
+ add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+ endif()
endforeach()
else()
- # Build separate libraries for each target.
- foreach(arch ${UBSAN_SUPPORTED_ARCH})
+ # Common parts of UBSan runtime.
+ foreach(arch ${UBSAN_COMMON_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTUbsan ${arch}
SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS})
# C++-specific parts of UBSan runtime. Requires a C++ ABI library.
add_compiler_rt_object_library(RTUbsan_cxx ${arch}
SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS})
-
- # Standalone UBSan runtimes.
- add_compiler_rt_runtime(clang_rt.ubsan_standalone-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTUbsan.${arch}>
- CFLAGS ${UBSAN_CFLAGS})
- add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
- CFLAGS ${UBSAN_CXXFLAGS})
- # UBSan runtimes used when another sanitizer is available.
- add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTUbsan.${arch}>
- CFLAGS ${UBSAN_CFLAGS})
- add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
- CFLAGS ${UBSAN_CXXFLAGS})
-
- add_dependencies(ubsan
- clang_rt.ubsan-${arch}
- clang_rt.ubsan_cxx-${arch}
- clang_rt.ubsan_standalone-${arch}
- clang_rt.ubsan_standalone_cxx-${arch})
- if (UNIX AND NOT ${arch} MATCHES "i386|i686")
- add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra)
- add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra)
- add_sanitizer_rt_symbols(clang_rt.ubsan_standalone-${arch} ubsan.syms.extra)
- add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx-${arch} ubsan.syms.extra)
- add_dependencies(ubsan
- clang_rt.ubsan-${arch}-symbols
- clang_rt.ubsan_cxx-${arch}-symbols
- clang_rt.ubsan_standalone-${arch}-symbols
- clang_rt.ubsan_standalone_cxx-${arch}-symbols)
- endif()
endforeach()
+
+ if(COMPILER_RT_HAS_UBSAN)
+ foreach(arch ${UBSAN_SUPPORTED_ARCH})
+ # Initializer of standalone UBSan runtime.
+ add_compiler_rt_object_library(RTUbsan_standalone ${arch}
+ SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS})
+
+ # Standalone UBSan runtimes.
+ add_compiler_rt_runtime(clang_rt.ubsan_standalone-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_standalone.${arch}>
+ CFLAGS ${UBSAN_CFLAGS})
+ add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
+ CFLAGS ${UBSAN_CXXFLAGS})
+
+ add_dependencies(ubsan
+ clang_rt.ubsan_standalone-${arch}
+ clang_rt.ubsan_standalone_cxx-${arch})
+ if (UNIX AND NOT ${arch} MATCHES "i386|i686")
+ add_sanitizer_rt_symbols(clang_rt.ubsan_standalone-${arch} ubsan.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx-${arch} ubsan.syms.extra)
+ add_dependencies(ubsan
+ clang_rt.ubsan_standalone-${arch}-symbols
+ clang_rt.ubsan_standalone_cxx-${arch}-symbols)
+ endif()
+ endforeach()
+ endif()
endif()
add_dependencies(compiler-rt ubsan)
diff --git a/lib/ubsan/Makefile.mk b/lib/ubsan/Makefile.mk
index d5561f4..ec3f5c5 100644
--- a/lib/ubsan/Makefile.mk
+++ b/lib/ubsan/Makefile.mk
@@ -11,8 +11,9 @@
SubDirs :=
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+StandaloneSources := ubsan_init_standalone.cc
CXXSources := ubsan_type_hash.cc ubsan_handlers_cxx.cc
-CSources := $(filter-out $(CXXSources),$(Sources))
+CSources := $(filter-out $(StandaloneSources),$(filter-out $(CXXSources),$(Sources)))
ObjNames := $(Sources:%.cc=%.o)
Implementation := Generic
@@ -24,3 +25,4 @@
# Define a convenience variable for all the ubsan functions.
UbsanFunctions := $(CSources:%.cc=%)
UbsanCXXFunctions := $(CXXSources:%.cc=%)
+UbsanStandaloneFunctions := $(StandaloneSources:%.cc=%)
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 2314fb6..6f76c6a 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -27,7 +27,7 @@
using namespace __ubsan;
static void MaybePrintStackTrace(uptr pc, uptr bp) {
- // We assume that flags are already parsed: InitIfNecessary
+ // We assume that flags are already parsed, as UBSan runtime
// will definitely be called when we print the first diagnostics message.
if (!flags()->print_stacktrace)
return;
@@ -76,7 +76,7 @@
}
SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
return Symbolizer::GetOrInit()->SymbolizePC(PC);
}
@@ -330,7 +330,7 @@
ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
: Opts(Opts), SummaryLoc(SummaryLoc) {
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
CommonSanitizerReportMutex.Lock();
}
@@ -355,10 +355,7 @@
}
bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
- // If .preinit_array is not used, it is possible that the UBSan runtime is not
- // initialized.
- if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
CHECK(suppression_ctx);
Suppression *s;
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
index 49ada8a..eda7557 100644
--- a/lib/ubsan/ubsan_flags.cc
+++ b/lib/ubsan/ubsan_flags.cc
@@ -20,7 +20,7 @@
namespace __ubsan {
-static const char *MaybeCallUbsanDefaultOptions() {
+const char *MaybeCallUbsanDefaultOptions() {
return (&__ubsan_default_options) ? __ubsan_default_options() : "";
}
@@ -39,31 +39,22 @@
#undef UBSAN_FLAG
}
-void InitializeFlags(bool standalone) {
- Flags *f = flags();
- FlagParser parser;
- RegisterUbsanFlags(&parser, f);
-
- if (standalone) {
- RegisterCommonFlags(&parser);
-
- SetCommonFlagsDefaults();
+void InitializeFlags() {
+ SetCommonFlagsDefaults();
+ {
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.print_summary = false;
OverrideCommonFlags(cf);
- } else {
- // Ignore common flags if not standalone.
- // This is inconsistent with LSan, which allows common flags in LSAN_FLAGS.
- // This is caused by undefined initialization order between ASan and UBsan,
- // which makes it impossible to make sure that common flags from ASAN_OPTIONS
- // have not been used (in __asan_init) before they are overwritten with flags
- // from UBSAN_OPTIONS.
- CommonFlags cf_ignored;
- RegisterCommonFlags(&parser, &cf_ignored);
}
+ Flags *f = flags();
f->SetDefaults();
+
+ FlagParser parser;
+ RegisterCommonFlags(&parser);
+ RegisterUbsanFlags(&parser, f);
+
// Override from user-specified string.
parser.ParseString(MaybeCallUbsanDefaultOptions());
// Override from environment variable.
diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h
index b47f14e..18aed9b 100644
--- a/lib/ubsan/ubsan_flags.h
+++ b/lib/ubsan/ubsan_flags.h
@@ -15,6 +15,10 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
+namespace __sanitizer {
+class FlagParser;
+}
+
namespace __ubsan {
struct Flags {
@@ -28,7 +32,10 @@
extern Flags ubsan_flags;
inline Flags *flags() { return &ubsan_flags; }
-void InitializeFlags(bool standalone);
+void InitializeFlags();
+void RegisterUbsanFlags(FlagParser *parser, Flags *f);
+
+const char *MaybeCallUbsanDefaultOptions();
} // namespace __ubsan
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
index 9527269..c3b8b6c 100644
--- a/lib/ubsan/ubsan_init.cc
+++ b/lib/ubsan/ubsan_init.cc
@@ -23,45 +23,54 @@
using namespace __ubsan;
-static bool ubsan_inited;
+static enum {
+ UBSAN_MODE_UNKNOWN = 0,
+ UBSAN_MODE_STANDALONE,
+ UBSAN_MODE_PLUGIN
+} ubsan_mode;
+static StaticSpinMutex ubsan_init_mu;
-void __ubsan::InitIfNecessary() {
-#if !SANITIZER_CAN_USE_PREINIT_ARRAY
- // No need to lock mutex if we're initializing from preinit array.
- static StaticSpinMutex init_mu;
- SpinMutexLock l(&init_mu);
-#endif
- if (LIKELY(ubsan_inited))
- return;
- bool standalone = false;
- if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
- // WARNING: If this condition holds, then either UBSan runs in a standalone
- // mode, or initializer for another sanitizer hasn't run yet. In a latter
- // case, another sanitizer will overwrite "SanitizerToolName" and reparse
- // common flags. It means, that we are not allowed to *use* common flags
- // in this function.
- SanitizerToolName = "UndefinedBehaviorSanitizer";
- standalone = true;
- }
- // Initialize UBSan-specific flags.
- InitializeFlags(standalone);
+static void CommonInit() {
InitializeSuppressions();
- InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
- ubsan_inited = true;
}
-#if SANITIZER_CAN_USE_PREINIT_ARRAY
-__attribute__((section(".preinit_array"), used))
-void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
-#else
-// Use a dynamic initializer.
-class UbsanInitializer {
- public:
- UbsanInitializer() {
- InitIfNecessary();
+static void CommonStandaloneInit() {
+ SanitizerToolName = "UndefinedBehaviorSanitizer";
+ InitializeFlags();
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_STANDALONE;
+}
+
+void __ubsan::InitAsStandalone() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonStandaloneInit();
+ return;
}
-};
-static UbsanInitializer ubsan_initializer;
-#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+ CHECK_NE(UBSAN_MODE_PLUGIN, ubsan_mode);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsStandaloneIfNecessary() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_NE(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ return;
+ }
+ SpinMutexLock l(&ubsan_init_mu);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsPlugin() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+#endif
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_PLUGIN;
+}
#endif // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h
index 18356cf..103ae24 100644
--- a/lib/ubsan/ubsan_init.h
+++ b/lib/ubsan/ubsan_init.h
@@ -15,9 +15,16 @@
namespace __ubsan {
-// NOTE: This function might take a lock (if .preinit_array initialization is
-// not used). It's generally a bad idea to call it on a fast path.
-void InitIfNecessary();
+// Initialize UBSan as a standalone tool. Typically should be called early
+// during initialization.
+void InitAsStandalone();
+
+// Initialize UBSan as a standalone tool, if it hasn't been initialized before.
+void InitAsStandaloneIfNecessary();
+
+// Initializes UBSan as a plugin tool. This function should be called once
+// from "parent tool" (e.g. ASan) initialization.
+void InitAsPlugin();
} // namespace __ubsan
diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc
new file mode 100644
index 0000000..47899a5
--- /dev/null
+++ b/lib/ubsan/ubsan_init_standalone.cc
@@ -0,0 +1,34 @@
+//===-- ubsan_init_standalone.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization of standalone UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_platform.h"
+#if !CAN_SANITIZE_UB
+# error "UBSan is not supported on this platform!"
+#endif
+
+#include "ubsan_init.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone;
+#else
+// Use a dynamic initializer.
+class UbsanStandaloneInitializer {
+ public:
+ UbsanStandaloneInitializer() {
+ __ubsan::InitAsStandalone();
+ }
+};
+static UbsanStandaloneInitializer ubsan_standalone_initializer;
+#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+
diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h
index efb7974..8ba253b 100644
--- a/lib/ubsan/ubsan_platform.h
+++ b/lib/ubsan/ubsan_platform.h
@@ -16,11 +16,10 @@
// Other platforms should be easy to add, and probably work as-is.
#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \
(defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
- defined(__aarch64__) || defined(__mips__))
+ defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__))
# define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0
-# error "UBSan not supported for this platform!"
#endif
#endif
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index c85d68d..441f713 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -37,13 +37,13 @@
/// Type info for classes with no bases, and base class for type info for
/// classes with bases.
class __class_type_info : public std::type_info {
- virtual ~__class_type_info();
+ ~__class_type_info() override;
};
/// Type info for classes with simple single public inheritance.
class __si_class_type_info : public __class_type_info {
public:
- virtual ~__si_class_type_info();
+ ~__si_class_type_info() override;
const __class_type_info *__base_type;
};
@@ -63,7 +63,7 @@
/// Type info for classes with multiple, virtual, or non-public inheritance.
class __vmi_class_type_info : public __class_type_info {
public:
- virtual ~__vmi_class_type_info();
+ ~__vmi_class_type_info() override;
unsigned int flags;
unsigned int base_count;
diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc
index ea91d63..215c195 100644
--- a/lib/ubsan/ubsan_value.cc
+++ b/lib/ubsan/ubsan_value.cc
@@ -83,7 +83,13 @@
#endif
case 32: {
float Value;
- internal_memcpy(&Value, &Val, 4);
+#if defined(__BIG_ENDIAN__)
+ // For big endian the float value is in the second 4 bytes
+ // instead of the first 4 bytes.
+ internal_memcpy(&Value, ((const char*)&Val)+4, 4);
+#else
+ internal_memcpy(&Value, &Val, 4);
+#endif
return Value;
}
case 64: {
diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk
index b0e8802..61250c7 100644
--- a/make/platform/clang_darwin.mk
+++ b/make/platform/clang_darwin.mk
@@ -230,7 +230,7 @@
CFLAGS.profile_ios.armv7s := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
CFLAGS.profile_ios.arm64 := $(CFLAGS) $(IOS6_DEPLOYMENT_ARGS)
-SANITIZER_LDFLAGS := -stdlib=libc++ -lc++
+SANITIZER_LDFLAGS := -stdlib=libc++ -lc++ -lc++abi
SHARED_LIBRARY.asan_osx_dynamic := 1
LDFLAGS.asan_osx_dynamic := $(SANITIZER_LDFLAGS) -install_name @rpath/libclang_rt.asan_osx_dynamic.dylib \
@@ -241,11 +241,11 @@
-Wl,-ios_simulator_version_min,7.0.0 $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS)
SHARED_LIBRARY.ubsan_osx_dynamic := 1
-LDFLAGS.ubsan_osx_dynamic := $(SANITIZER_LDFLAGS) -lc++abi -install_name @rpath/libclang_rt.ubsan_osx_dynamic.dylib \
+LDFLAGS.ubsan_osx_dynamic := $(SANITIZER_LDFLAGS) -install_name @rpath/libclang_rt.ubsan_osx_dynamic.dylib \
$(SANITIZER_MACOSX_DEPLOYMENT_ARGS)
SHARED_LIBRARY.ubsan_iossim_dynamic := 1
-LDFLAGS.ubsan_iossim_dynamic := $(SANITIZER_LDFLAGS) -lc++abi -install_name @rpath/libclang_rt.ubsan_iossim_dynamic.dylib \
+LDFLAGS.ubsan_iossim_dynamic := $(SANITIZER_LDFLAGS) -install_name @rpath/libclang_rt.ubsan_iossim_dynamic.dylib \
-Wl,-ios_simulator_version_min,7.0.0 $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS)
ifneq ($(OSX_SDK),)
@@ -275,18 +275,22 @@
FUNCTIONS.asan_osx_dynamic := $(AsanFunctions) $(AsanCXXFunctions) \
$(InterceptionFunctions) \
$(SanitizerCommonFunctions) \
- $(AsanDynamicFunctions)
+ $(AsanDynamicFunctions) \
+ $(UbsanFunctions) $(UbsanCXXFunctions)
FUNCTIONS.asan_iossim_dynamic := $(AsanFunctions) $(AsanCXXFunctions) \
$(InterceptionFunctions) \
$(SanitizerCommonFunctions) \
- $(AsanDynamicFunctions)
+ $(AsanDynamicFunctions) \
+ $(UbsanFunctions) $(UbsanCXXFunctions)
FUNCTIONS.ubsan_osx_dynamic := $(UbsanFunctions) $(UbsanCXXFunctions) \
- $(SanitizerCommonFunctions)
+ $(SanitizerCommonFunctions) \
+ $(UbsanStandaloneFunctions)
FUNCTIONS.ubsan_iossim_dynamic := $(UbsanFunctions) $(UbsanCXXFunctions) \
- $(SanitizerCommonFunctions)
+ $(SanitizerCommonFunctions) \
+ $(UbsanStandaloneFunctions)
CCKEXT_PROFILE_FUNCTIONS := \
InstrProfiling \
diff --git a/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc b/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc
deleted file mode 100644
index 028683d..0000000
--- a/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that memset() call from a shared library gets intercepted.
-// Please always keep this file in sync with
-// ../Linux/interception-in-shared-lib-test.cc.
-
-// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \
-// RUN: -shared -o %t-so.so \
-// RUN: -fPIC -install_name @rpath/interception-in-shared-lib-test.cc.tmp-so.so
-// TODO(glider): figure out how to set rpath in a more portable way and unite
-// this test with ../Linux/interception-in-shared-lib-test.cc.
-// RUN: %clangxx_asan -O0 %s -o %t -Wl,-rpath,@executable_path %t-so.so && \
-// RUN: not %run %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-
-#if defined(SHARED_LIB)
-extern "C"
-void my_memset(void *p, size_t sz) {
- memset(p, 0, sz);
-}
-#else
-extern "C" void my_memset(void *p, size_t sz);
-
-int main(int argc, char *argv[]) {
- char buf[10];
- my_memset(buf, 11);
- // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}}
- // CHECK: {{WRITE of size 11 at 0x.* thread T0}}
- // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:19}}
- return 0;
-}
-#endif
diff --git a/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc b/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc
deleted file mode 100644
index b828d55..0000000
--- a/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that memset() call from a shared library gets intercepted.
-// Please always keep this file in sync with
-// ../Darwin/interception-in-shared-lib-test.cc.
-
-// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \
-// RUN: -shared -o %T/libinterception-in-shared-lib-test.so \
-// RUN: -fPIC
-// TODO(glider): figure out how to set rpath in a more portable way and unite
-// this test with ../Darwin/interception-in-shared-lib-test.cc.
-// RUN: %clangxx_asan -O0 %s -o %t -Wl,-R,\$ORIGIN -L%T -linterception-in-shared-lib-test && \
-// RUN: not %run %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <string.h>
-
-#if defined(SHARED_LIB)
-extern "C"
-void my_memset(void *p, size_t sz) {
- memset(p, 0, sz);
-}
-#else
-extern "C" void my_memset(void *p, size_t sz);
-
-int main(int argc, char *argv[]) {
- char buf[10];
- my_memset(buf, 11);
- // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}}
- // CHECK: {{WRITE of size 11 at 0x.* thread T0}}
- // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:19}}
- return 0;
-}
-#endif
diff --git a/test/asan/TestCases/Linux/coverage-direct-activation.cc b/test/asan/TestCases/Posix/coverage-direct-activation.cc
similarity index 86%
rename from test/asan/TestCases/Linux/coverage-direct-activation.cc
rename to test/asan/TestCases/Posix/coverage-direct-activation.cc
index 9b2a0d8..05dc557 100644
--- a/test/asan/TestCases/Linux/coverage-direct-activation.cc
+++ b/test/asan/TestCases/Posix/coverage-direct-activation.cc
@@ -1,18 +1,18 @@
// Test for direct coverage writing enabled at activation time.
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_activation_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %dynamiclib -fPIC
// RUN: %clangxx -c -DSO_DIR=\"%T\" %s -o %t.o
// RUN: %clangxx_asan -fsanitize-coverage=1 %t.o %libdl -o %t
// RUN: rm -rf %T/coverage-direct-activation
// RUN: mkdir -p %T/coverage-direct-activation/normal
-// RUN: ASAN_OPTIONS=coverage=1,coverage_direct=0,coverage_dir=%T/coverage-direct-activation/normal:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1,coverage_direct=0,coverage_dir=%T/coverage-direct-activation/normal:verbosity=1 %run %t %dynamiclib
// RUN: %sancov print %T/coverage-direct-activation/normal/*.sancov >%T/coverage-direct-activation/normal/out.txt
// RUN: mkdir -p %T/coverage-direct-activation/direct
// RUN: ASAN_OPTIONS=start_deactivated=1,coverage_direct=1,verbosity=1 \
-// RUN: ASAN_ACTIVATION_OPTIONS=coverage=1,coverage_dir=%T/coverage-direct-activation/direct %run %t
+// RUN: ASAN_ACTIVATION_OPTIONS=coverage=1,coverage_dir=%T/coverage-direct-activation/direct %run %t %dynamiclib
// RUN: cd %T/coverage-direct-activation/direct
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
@@ -24,7 +24,7 @@
// RUN: mkdir -p %T/coverage-direct-activation/direct2
// RUN: ASAN_OPTIONS=start_deactivated=1,coverage=1,coverage_direct=1,verbosity=1 \
-// RUN: ASAN_ACTIVATION_OPTIONS=coverage_dir=%T/coverage-direct-activation/direct2 %run %t
+// RUN: ASAN_ACTIVATION_OPTIONS=coverage_dir=%T/coverage-direct-activation/direct2 %run %t %dynamiclib
// RUN: cd %T/coverage-direct-activation/direct2
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
@@ -47,8 +47,8 @@
int main(int argc, char **argv) {
fprintf(stderr, "PID: %d\n", getpid());
- void *handle1 =
- dlopen(SO_DIR "/libcoverage_direct_activation_test_1.so", RTLD_LAZY);
+ assert(argc > 1);
+ void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib
assert(handle1);
void (*bar1)() = (void (*)())dlsym(handle1, "bar");
assert(bar1);
diff --git a/test/asan/TestCases/Linux/coverage-direct-large.cc b/test/asan/TestCases/Posix/coverage-direct-large.cc
similarity index 88%
rename from test/asan/TestCases/Linux/coverage-direct-large.cc
rename to test/asan/TestCases/Posix/coverage-direct-large.cc
index 25c950e..cf7351d 100644
--- a/test/asan/TestCases/Linux/coverage-direct-large.cc
+++ b/test/asan/TestCases/Posix/coverage-direct-large.cc
@@ -2,18 +2,18 @@
// Current implementation maps output file in chunks of 64K. This test overflows
// 1 chunk.
-// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 -DSHARED %s -shared -o %T/libcoverage_direct_large_test_1.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 -DSO_DIR=\"%T\" %s %libdl -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 -DSHARED %s -shared -o %dynamiclib -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 %s %libdl -o %t
// RUN: rm -rf %T/coverage-direct-large
// RUN: mkdir -p %T/coverage-direct-large/normal && cd %T/coverage-direct-large/normal
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1 %run %t %dynamiclib
// RUN: %sancov print *.sancov >out.txt
// RUN: cd ../..
// RUN: mkdir -p %T/coverage-direct-large/direct && cd %T/coverage-direct-large/direct
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t %dynamiclib
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
// RUN: cd ../..
@@ -49,11 +49,11 @@
#include <assert.h>
#include <dlfcn.h>
-int main(void) {
+#include <stdio.h>
+int main(int argc, char **argv) {
F4(CALL, f)
-
- void *handle1 =
- dlopen(SO_DIR "/libcoverage_direct_large_test_1.so", RTLD_LAZY);
+ assert(argc > 1);
+ void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib
assert(handle1);
void (*so_entry)() = (void (*)())dlsym(handle1, "so_entry");
assert(so_entry);
diff --git a/test/asan/TestCases/Posix/coverage-direct.cc b/test/asan/TestCases/Posix/coverage-direct.cc
index 45222fa..60acbb7 100644
--- a/test/asan/TestCases/Posix/coverage-direct.cc
+++ b/test/asan/TestCases/Posix/coverage-direct.cc
@@ -1,16 +1,16 @@
// Test for direct coverage writing with dlopen at coverage level 1 to 3.
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s %libdl -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %dynamiclib -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s %libdl -o %t
// RUN: rm -rf %T/coverage-direct
// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
// RUN: cd %T/coverage-direct/direct
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
@@ -19,17 +19,17 @@
// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
-// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %dynamiclib -fPIC
// RUN: %clangxx_asan -fsanitize-coverage=2 -DSO_DIR=\"%T\" %s %libdl -o %t
// RUN: rm -rf %T/coverage-direct
// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
// RUN: cd %T/coverage-direct/direct
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
@@ -38,17 +38,17 @@
// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
-// RUN: %clangxx_asan -fsanitize-coverage=3 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=3 -DSHARED %s -shared -o %dynamiclib -fPIC
// RUN: %clangxx_asan -fsanitize-coverage=3 -DSO_DIR=\"%T\" %s %libdl -o %t
// RUN: rm -rf %T/coverage-direct
// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
// RUN: cd %T/coverage-direct/direct
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >out.txt
@@ -71,8 +71,8 @@
int main(int argc, char **argv) {
fprintf(stderr, "PID: %d\n", getpid());
- void *handle1 =
- dlopen(SO_DIR "/libcoverage_direct_test_1.so", RTLD_LAZY);
+ assert(argc > 1);
+ void *handle1 = dlopen(argv[1], RTLD_LAZY);
assert(handle1);
void (*bar1)() = (void (*)())dlsym(handle1, "bar");
assert(bar1);
diff --git a/test/asan/TestCases/Linux/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc
similarity index 100%
rename from test/asan/TestCases/Linux/coverage-fork-direct.cc
rename to test/asan/TestCases/Posix/coverage-fork-direct.cc
diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Posix/coverage-module-unloaded.cc
similarity index 67%
rename from test/asan/TestCases/Linux/coverage-module-unloaded.cc
rename to test/asan/TestCases/Posix/coverage-module-unloaded.cc
index 573fc46..26ef479 100644
--- a/test/asan/TestCases/Linux/coverage-module-unloaded.cc
+++ b/test/asan/TestCases/Posix/coverage-module-unloaded.cc
@@ -1,13 +1,13 @@
// Check that unloading a module doesn't break coverage dumping for remaining
// modules.
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s %libdl -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %dynamiclib1 -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %dynamiclib2 -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s %libdl -o %t
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
// RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded
-// RUN: %run %t 2>&1 | FileCheck %s
-// RUN: %run %t foo 2>&1 | FileCheck %s
-// RUN: cd .. && rm coverage-module-unloaded -r
+// RUN: %run %t %dynamiclib1 %dynamiclib2 2>&1 | FileCheck %s
+// RUN: %run %t %dynamiclib1 %dynamiclib2 foo 2>&1 | FileCheck %s
+// RUN: rm -r %T/coverage-module-unloaded
//
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android
@@ -25,14 +25,13 @@
int main(int argc, char **argv) {
fprintf(stderr, "PID: %d\n", getpid());
- void *handle1 =
- dlopen(SO_DIR "/libcoverage_module_unloaded_test_1.so", RTLD_LAZY);
+ assert(argc > 2);
+ void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib1
assert(handle1);
void (*bar1)() = (void (*)())dlsym(handle1, "bar");
assert(bar1);
bar1();
- void *handle2 =
- dlopen(SO_DIR "/libcoverage_module_unloaded_test_2.so", RTLD_LAZY);
+ void *handle2 = dlopen(argv[2], RTLD_LAZY); // %dynamiclib2
assert(handle2);
void (*bar2)() = (void (*)())dlsym(handle2, "bar");
assert(bar2);
@@ -50,7 +49,7 @@
// CHECK: PID: [[PID:[0-9]+]]
// CHECK: [[PID]].sancov: 1 PCs written
-// CHECK: test_1.so.[[PID]]
-// CHECK: test_2.so.[[PID]]
+// CHECK: coverage-module-unloaded{{.*}}1.[[PID]]
+// CHECK: coverage-module-unloaded{{.*}}2.[[PID]]
// Even though we've unloaded one of the libs we still dump the coverage file
-// for that lib (although the data will be inaccurate, it at all useful)
+// for that lib (although the data will be inaccurate, if at all useful)
diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Posix/coverage-sandboxing.cc
similarity index 84%
rename from test/asan/TestCases/Linux/coverage-sandboxing.cc
rename to test/asan/TestCases/Posix/coverage-sandboxing.cc
index 15bada8..8f1c1ee 100644
--- a/test/asan/TestCases/Linux/coverage-sandboxing.cc
+++ b/test/asan/TestCases/Posix/coverage-sandboxing.cc
@@ -1,5 +1,5 @@
-// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_sandboxing_test.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_sandboxing_test
+// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t %ld_flags_rpath_exe
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
// RUN: rm -rf %T/coverage_sandboxing_test
// RUN: mkdir %T/coverage_sandboxing_test && cd %T/coverage_sandboxing_test
@@ -12,12 +12,12 @@
// RUN: %run %t a b 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox
// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed
// RUN: cd ..
-// RUN: %sancov print vanilla/libcoverage_sandboxing_test.so.*.sancov > vanilla.txt
-// RUN: %sancov print sandbox1/libcoverage_sandboxing_test.so.*.sancov > sandbox1.txt
-// RUN: %sancov print sandbox2/libcoverage_sandboxing_test.so.*.sancov > sandbox2.txt
+// RUN: %sancov print vanilla/`basename %dynamiclib`*.sancov > vanilla.txt
+// RUN: %sancov print sandbox1/`basename %dynamiclib`*.sancov > sandbox1.txt
+// RUN: %sancov print sandbox2/`basename %dynamiclib`*.sancov > sandbox2.txt
// RUN: diff vanilla.txt sandbox1.txt
// RUN: diff vanilla.txt sandbox2.txt
-// RUN: cd ../ && rm coverage_sandboxing_test -r
+// RUN: rm -r %T/coverage_sandboxing_test
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android
diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Posix/coverage.cc
similarity index 75%
rename from test/asan/TestCases/Linux/coverage.cc
rename to test/asan/TestCases/Posix/coverage.cc
index 1ad19e6..7b59015 100644
--- a/test/asan/TestCases/Linux/coverage.cc
+++ b/test/asan/TestCases/Posix/coverage.cc
@@ -1,21 +1,21 @@
-// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %dynamiclib -fPIC %ld_flags_rpath_so
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s %ld_flags_rpath_exe -o %t
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
// RUN: rm -rf %T/coverage && mkdir -p %T/coverage && cd %T/coverage
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
-// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1
+// RUN: %sancov print `ls coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1
// RUN: %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
-// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
+// RUN: %sancov print `ls coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
// RUN: %run %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
-// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
+// RUN: %sancov print `ls *coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
// RUN: %run %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
-// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
-// RUN: %sancov print libcoverage_test.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1
-// RUN: %sancov merge coverage.*sancov > merged-cov
+// RUN: %sancov print `ls *coverage.*sancov | grep -v '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
+// RUN: %sancov print `ls *coverage.*sancov | grep '.so'` 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1
+// RUN: %sancov merge `ls *coverage.*sancov | grep -v '.so'` > merged-cov
// RUN: %sancov print merged-cov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2
// RUN: not %run %t foo bar 4 2>&1 | FileCheck %s --check-prefix=CHECK-report
// RUN: not %run %t foo bar 4 5 2>&1 | FileCheck %s --check-prefix=CHECK-segv
-// RUN: cd .. && rm coverage -r
+// RUN: rm -r %T/coverage
//
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android
diff --git a/test/asan/TestCases/Posix/interception-in-shared-lib-test.cc b/test/asan/TestCases/Posix/interception-in-shared-lib-test.cc
new file mode 100644
index 0000000..a7d2bfb
--- /dev/null
+++ b/test/asan/TestCases/Posix/interception-in-shared-lib-test.cc
@@ -0,0 +1,27 @@
+// Check that memset() call from a shared library gets intercepted.
+
+// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \
+// RUN: -shared -o %dynamiclib -fPIC %ld_flags_rpath_so
+// RUN: %clangxx_asan -O0 %s -o %t %ld_flags_rpath_exe && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(SHARED_LIB)
+extern "C"
+void my_memset(void *p, size_t sz) {
+ memset(p, 0, sz);
+}
+#else
+extern "C" void my_memset(void *p, size_t sz);
+
+int main(int argc, char *argv[]) {
+ char buf[10];
+ my_memset(buf, 11);
+ // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}}
+ // CHECK: {{WRITE of size 11 at 0x.* thread T0}}
+ // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:}}[[@LINE-10]]
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Windows/coverage-basic.cc b/test/asan/TestCases/Windows/coverage-basic.cc
new file mode 100644
index 0000000..3081d7c
--- /dev/null
+++ b/test/asan/TestCases/Windows/coverage-basic.cc
@@ -0,0 +1,25 @@
+// RUN: rm -rf %T/coverage-basic
+// RUN: mkdir %T/coverage-basic && cd %T/coverage-basic
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o test.exe
+// RUN: env ASAN_OPTIONS=coverage=1 %run test.exe
+//
+// RUN: %sancov print *.sancov | FileCheck %s
+#include <stdio.h>
+
+void foo() { fprintf(stderr, "FOO\n"); }
+void bar() { fprintf(stderr, "BAR\n"); }
+
+int main(int argc, char **argv) {
+ if (argc == 2) {
+ foo();
+ bar();
+ } else {
+ bar();
+ foo();
+ }
+}
+
+// CHECK: 0x{{[0-9a-f]*}}
+// CHECK: 0x{{[0-9a-f]*}}
+// CHECK: 0x{{[0-9a-f]*}}
+// CHECK-NOT: 0x{{[0-9a-f]*}}
diff --git a/test/asan/TestCases/atoi_strict.c b/test/asan/TestCases/atoi_strict.c
new file mode 100644
index 0000000..d60af6f
--- /dev/null
+++ b/test/asan/TestCases/atoi_strict.c
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atoi function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+ // Last symbol is non-digit
+ memset(array, '1', 10);
+ array[9] = 'a';
+ int r = atoi(array);
+ assert(r == 111111111);
+}
+
+void test2(char *array) {
+ // Single non-digit symbol
+ array[9] = 'a';
+ int r = atoi(array + 9);
+ assert(r == 0);
+}
+
+void test3(char *array) {
+ // Incorrect number format
+ memset(array, ' ', 10);
+ array[9] = '-';
+ array[8] = '-';
+ int r = atoi(array);
+ assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+ char *array = (char*)malloc(10);
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(array);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1: READ of size 11
+ if (!strcmp(argv[1], "test2")) test2(array);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2: READ of size 2
+ if (!strcmp(argv[1], "test3")) test3(array);
+ // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK3: READ of size 11
+ free(array);
+ return 0;
+}
diff --git a/test/asan/TestCases/atol_strict.c b/test/asan/TestCases/atol_strict.c
new file mode 100644
index 0000000..97ec5ba
--- /dev/null
+++ b/test/asan/TestCases/atol_strict.c
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atol function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+ // Last symbol is non-digit
+ memset(array, '1', 10);
+ array[9] = 'a';
+ long r = atol(array);
+ assert(r == 111111111);
+}
+
+void test2(char *array) {
+ // Single non-digit symbol
+ array[9] = 'a';
+ long r = atol(array + 9);
+ assert(r == 0);
+}
+
+void test3(char *array) {
+ // Incorrect number format
+ memset(array, ' ', 10);
+ array[9] = '-';
+ array[8] = '-';
+ long r = atol(array);
+ assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+ char *array = (char*)malloc(10);
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(array);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1: READ of size 11
+ if (!strcmp(argv[1], "test2")) test2(array);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2: READ of size 2
+ if (!strcmp(argv[1], "test3")) test3(array);
+ // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK3: READ of size 11
+ free(array);
+ return 0;
+}
diff --git a/test/asan/TestCases/atoll_strict.c b/test/asan/TestCases/atoll_strict.c
new file mode 100644
index 0000000..cd0ef69
--- /dev/null
+++ b/test/asan/TestCases/atoll_strict.c
@@ -0,0 +1,55 @@
+// Test strict_string_checks option in atoll function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array) {
+ // Last symbol is non-digit
+ memset(array, '1', 10);
+ array[9] = 'a';
+ long long r = atoll(array);
+ assert(r == 111111111);
+}
+
+void test2(char *array) {
+ // Single non-digit symbol
+ array[9] = 'a';
+ long long r = atoll(array + 9);
+ assert(r == 0);
+}
+
+void test3(char *array) {
+ // Incorrect number format
+ memset(array, ' ', 10);
+ array[9] = '-';
+ array[8] = '-';
+ long long r = atoll(array);
+ assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+ char *array = (char*)malloc(10);
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(array);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1: READ of size 11
+ if (!strcmp(argv[1], "test2")) test2(array);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2: READ of size 2
+ if (!strcmp(argv[1], "test3")) test3(array);
+ // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK3: READ of size 11
+ free(array);
+ return 0;
+}
diff --git a/test/asan/TestCases/strcat_strict.c b/test/asan/TestCases/strcat_strict.c
new file mode 100644
index 0000000..806b682
--- /dev/null
+++ b/test/asan/TestCases/strcat_strict.c
@@ -0,0 +1,44 @@
+// Test strict_string_checks option in strcat function
+// RUN: %clang_asan %s -o %t
+// RUN: not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=false not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-STRICT --check-prefix=CHECK1
+// RUN: not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=false not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-STRICT --check-prefix=CHECK2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *to, int to_size, char *from) {
+ // One of arguments points to not allocated memory.
+ char* r = strcat(to + to_size, from);
+}
+
+void test2(char *to, int to_size, char *from) {
+ // "to" is not zero-terminated.
+ memset(to, 'z', to_size);
+ char* r = strcat(to, from);
+}
+
+int main(int argc, char **argv) {
+ size_t to_size = 100;
+ char *to = (char*)malloc(to_size);
+ size_t from_size = 20;
+ char *from = (char*)malloc(from_size);
+ memset(from, 'z', from_size);
+ from[from_size - 1] = '\0';
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(to, to_size, from);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1-STRICT: READ of size 1
+ // CHECK1-NONSTRICT: WRITE of size 20
+ if (!strcmp(argv[1], "test2")) test2(to, to_size, from);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2-STRICT: READ of size 101
+ // CHECK2-NONSTRICT: WRITE of size 20
+ free(to);
+ free(from);
+ return 0;
+}
diff --git a/test/asan/TestCases/strchr_strict.c b/test/asan/TestCases/strchr_strict.c
new file mode 100644
index 0000000..d0c32f7
--- /dev/null
+++ b/test/asan/TestCases/strchr_strict.c
@@ -0,0 +1,22 @@
+// Test strict_string_checks option in strchr function
+// RUN: %clang_asan %s -o %t && %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ size_t size = 100;
+ char fill = 'o';
+ char *s = (char*)malloc(size);
+ memset(s, fill, size);
+ char c = 'o';
+ char* r = strchr(s, c);
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK: READ of size 101
+ assert(r == s);
+ free(s);
+ return 0;
+}
diff --git a/test/asan/TestCases/strcmp_strict.c b/test/asan/TestCases/strcmp_strict.c
new file mode 100644
index 0000000..6514ab9
--- /dev/null
+++ b/test/asan/TestCases/strcmp_strict.c
@@ -0,0 +1,26 @@
+// Test strict_string_checks option in strcmp function
+// RUN: %clang_asan %s -o %t && %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ size_t size = 100;
+ char fill = 'o';
+ char *s1 = (char*)malloc(size);
+ memset(s1, fill, size);
+ char *s2 = (char*)malloc(size);
+ memset(s2, fill, size);
+ s1[size - 1] = 'z';
+ s2[size - 1] = 'x';
+ int r = strcmp(s1, s2);
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK: READ of size 101
+ assert(r == 1);
+ free(s1);
+ free(s2);
+ return 0;
+}
diff --git a/test/asan/TestCases/strncat_strict.c b/test/asan/TestCases/strncat_strict.c
new file mode 100644
index 0000000..377af96
--- /dev/null
+++ b/test/asan/TestCases/strncat_strict.c
@@ -0,0 +1,44 @@
+// Test strict_string_checks option in strncat function
+// RUN: %clang_asan %s -o %t
+// RUN: not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=false not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-NONSTRICT --check-prefix=CHECK1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1-STRICT --check-prefix=CHECK1
+// RUN: not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=false not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-NONSTRICT --check-prefix=CHECK2
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2-STRICT --check-prefix=CHECK2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *to, int to_size, char *from) {
+ // One of arguments points to not allocated memory.
+ char* r = strncat(to + to_size, from, 2);
+}
+
+void test2(char *to, int to_size, char *from) {
+ // "to" is not zero-terminated.
+ memset(to, 'z', to_size);
+ char* r = strncat(to, from, 1);
+}
+
+int main(int argc, char **argv) {
+ size_t to_size = 100;
+ char *to = (char*)malloc(to_size);
+ size_t from_size = 20;
+ char *from = (char*)malloc(from_size);
+ memset(from, 'z', from_size);
+ from[from_size - 1] = '\0';
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(to, to_size, from);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1-STRICT: READ of size 1
+ // CHECK1-NONSTRICT: WRITE of size 3
+ if (!strcmp(argv[1], "test2")) test2(to, to_size, from);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2-STRICT: READ of size 101
+ // CHECK2-NONSTRICT: WRITE of size 2
+ free(to);
+ free(from);
+ return 0;
+}
diff --git a/test/asan/TestCases/strtol_strict.c b/test/asan/TestCases/strtol_strict.c
new file mode 100644
index 0000000..2ff5028
--- /dev/null
+++ b/test/asan/TestCases/strtol_strict.c
@@ -0,0 +1,111 @@
+// Test strict_string_checks option in strtol function
+// RUN: %clang_asan -DTEST1 %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test7 2>&1 | FileCheck %s --check-prefix=CHECK7
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array, char *endptr) {
+ // Buffer overflow if there is no terminating null (depends on base)
+ long r = strtol(array, &endptr, 3);
+ assert(array + 2 == endptr);
+ assert(r == 5);
+}
+
+void test2(char *array, char *endptr) {
+ // Buffer overflow if there is no terminating null (depends on base)
+ array[2] = 'z';
+ long r = strtol(array, &endptr, 35);
+ assert(array + 2 == endptr);
+ assert(r == 37);
+}
+
+void test3(char *array, char *endptr) {
+ // Buffer overflow if base is invalid.
+ long r = strtol(array - 1, NULL, -1);
+ assert(r == 0);
+}
+
+void test4(char *array, char *endptr) {
+ // Buffer overflow if base is invalid.
+ long r = strtol(array + 3, NULL, 1);
+ assert(r == 0);
+}
+
+void test5(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[0] = ' ';
+ array[1] = '+';
+ array[2] = '-';
+ long r = strtol(array, NULL, 0);
+ assert(r == 0);
+}
+
+void test6(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[0] = ' ';
+ array[1] = array[2] = 'z';
+ long r = strtol(array, &endptr, 0);
+ assert(array == endptr);
+ assert(r == 0);
+}
+
+void test7(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[2] = 'z';
+ long r = strtol(array + 2, NULL, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+ char *array = (char*)malloc(3);
+ char *endptr = NULL;
+ array[0] = '1';
+ array[1] = '2';
+ array[2] = '3';
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(array, endptr);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1: READ of size 4
+ if (!strcmp(argv[1], "test2")) test2(array, endptr);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2: READ of size 4
+ if (!strcmp(argv[1], "test3")) test3(array, endptr);
+ // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK3: READ of size 5
+ if (!strcmp(argv[1], "test4")) test4(array, endptr);
+ // CHECK4: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK4: READ of size 1
+ if (!strcmp(argv[1], "test5")) test5(array, endptr);
+ // CHECK5: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK5: READ of size 4
+ if (!strcmp(argv[1], "test6")) test6(array, endptr);
+ // CHECK6: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK6: READ of size 4
+ if (!strcmp(argv[1], "test7")) test7(array, endptr);
+ // CHECK7: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK7: READ of size 2
+ free(array);
+ return 0;
+}
diff --git a/test/asan/TestCases/strtoll_strict.c b/test/asan/TestCases/strtoll_strict.c
new file mode 100644
index 0000000..1f0e54f
--- /dev/null
+++ b/test/asan/TestCases/strtoll_strict.c
@@ -0,0 +1,111 @@
+// Test strict_string_checks option in strtoll function
+// RUN: %clang_asan -DTEST1 %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test1 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test2 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test3 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test4 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test5 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test6 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=false %run %t test7 2>&1
+// RUN: ASAN_OPTIONS=strict_string_checks=true not %run %t test7 2>&1 | FileCheck %s --check-prefix=CHECK7
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1(char *array, char *endptr) {
+ // Buffer overflow if there is no terminating null (depends on base)
+ long long r = strtoll(array, &endptr, 3);
+ assert(array + 2 == endptr);
+ assert(r == 5);
+}
+
+void test2(char *array, char *endptr) {
+ // Buffer overflow if there is no terminating null (depends on base)
+ array[2] = 'z';
+ long long r = strtoll(array, &endptr, 35);
+ assert(array + 2 == endptr);
+ assert(r == 37);
+}
+
+void test3(char *array, char *endptr) {
+ // Buffer overflow if base is invalid.
+ long long r = strtoll(array - 1, NULL, -1);
+ assert(r == 0);
+}
+
+void test4(char *array, char *endptr) {
+ // Buffer overflow if base is invalid.
+ long long r = strtoll(array + 3, NULL, 1);
+ assert(r == 0);
+}
+
+void test5(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[0] = ' ';
+ array[1] = '+';
+ array[2] = '-';
+ long long r = strtoll(array, NULL, 0);
+ assert(r == 0);
+}
+
+void test6(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[0] = ' ';
+ array[1] = array[2] = 'z';
+ long long r = strtoll(array, &endptr, 0);
+ assert(array == endptr);
+ assert(r == 0);
+}
+
+void test7(char *array, char *endptr) {
+ // Overflow if no digits are found.
+ array[2] = 'z';
+ long long r = strtoll(array + 2, NULL, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+ char *array = (char*)malloc(3);
+ char *endptr = NULL;
+ array[0] = '1';
+ array[1] = '2';
+ array[2] = '3';
+ if (argc != 2) return 1;
+ if (!strcmp(argv[1], "test1")) test1(array, endptr);
+ // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK1: READ of size 4
+ if (!strcmp(argv[1], "test2")) test2(array, endptr);
+ // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK2: READ of size 4
+ if (!strcmp(argv[1], "test3")) test3(array, endptr);
+ // CHECK3: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK3: READ of size 5
+ if (!strcmp(argv[1], "test4")) test4(array, endptr);
+ // CHECK4: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK4: READ of size 1
+ if (!strcmp(argv[1], "test5")) test5(array, endptr);
+ // CHECK5: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK5: READ of size 4
+ if (!strcmp(argv[1], "test6")) test6(array, endptr);
+ // CHECK6: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK6: READ of size 4
+ if (!strcmp(argv[1], "test7")) test7(array, endptr);
+ // CHECK7: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK7: READ of size 2
+ free(array);
+ return 0;
+}
diff --git a/test/asan/TestCases/suppressions-library.cc b/test/asan/TestCases/suppressions-library.cc
index 28f19f5..b7fee23 100644
--- a/test/asan/TestCases/suppressions-library.cc
+++ b/test/asan/TestCases/suppressions-library.cc
@@ -1,10 +1,10 @@
-// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -install_name @rpath/suppressions-library.cc.tmp-so.so
-// RUN: %clangxx_asan -O0 %s %t-so.so -o %t -rpath @executable_path
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so
+// RUN: %clangxx_asan -O0 %s -o %t %ld_flags_rpath_exe
// Check that without suppressions, we catch the issue.
// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
-// RUN: echo "interceptor_via_lib:suppressions-library.cc.tmp-so.so" > %t.supp
+// RUN: echo "interceptor_via_lib:"`basename %dynamiclib` > %t.supp
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
// XFAIL: android
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index a6f443c..05a5715 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -135,6 +135,17 @@
config.available_features.add("asan-" + config.bits + "-bits")
+if config.host_os == 'Darwin':
+ config.substitutions.append( ("%ld_flags_rpath_exe", '-Wl,-rpath,@executable_path/ %dynamiclib') )
+ config.substitutions.append( ("%ld_flags_rpath_so", '-install_name @rpath/`basename %dynamiclib`') )
+elif config.host_os in ['Linux', 'FreeBSD']:
+ config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") )
+ config.substitutions.append( ("%ld_flags_rpath_so", '') )
+
+# Must be defined after the substitutions that use %dynamiclib.
+config.substitutions.append( ("%dynamiclib", '%T/lib%xdynamiclib_namespec.so') )
+config.substitutions.append( ("%xdynamiclib_namespec", '$(basename %t).dynamic') )
+
# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL
# because the test hangs.
if config.target_arch != 'arm':
diff --git a/test/cfi/README.txt b/test/cfi/README.txt
new file mode 100644
index 0000000..6b82f5e
--- /dev/null
+++ b/test/cfi/README.txt
@@ -0,0 +1,8 @@
+The tests in this directory use a common convention for exercising the
+functionality associated with bit sets of different sizes. When certain
+macros are defined the tests instantiate classes that force the bit sets
+to be of certain sizes.
+
+- B32 forces 32-bit bit sets.
+- B64 forces 64-bit bit sets.
+- BM forces memory bit sets.
diff --git a/test/cfi/nvcall.cpp b/test/cfi/nvcall.cpp
new file mode 100644
index 0000000..e4385ee
--- /dev/null
+++ b/test/cfi/nvcall.cpp
@@ -0,0 +1,65 @@
+// RUN: %clangxx_cfi -o %t %s
+// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi -DB32 -o %t %s
+// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi -DB64 -o %t %s
+// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx_cfi -DBM -o %t %s
+// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s
+
+// RUN: %clangxx -o %t %s
+// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s
+
+// Tests that the CFI mechanism crashes the program when making a non-virtual
+// call to an object of the wrong class, by casting a pointer to such an object
+// and attempting to make a call through it.
+
+#include <stdio.h>
+#include "utils.h"
+
+struct A {
+ virtual void f();
+};
+
+void A::f() {}
+
+struct B {
+ void f();
+ virtual void g();
+};
+
+void B::f() {}
+void B::g() {}
+
+int main() {
+#ifdef B32
+ break_optimization(new Deriver<B, 0>);
+#endif
+
+#ifdef B64
+ break_optimization(new Deriver<B, 0>);
+ break_optimization(new Deriver<B, 1>);
+#endif
+
+#ifdef BM
+ break_optimization(new Deriver<B, 0>);
+ break_optimization(new Deriver<B, 1>);
+ break_optimization(new Deriver<B, 2>);
+#endif
+
+ A *a = new A;
+ break_optimization(a);
+
+ // CFI: 1
+ // NCFI: 1
+ fprintf(stderr, "1\n");
+
+ ((B *)a)->f(); // UB here
+
+ // CFI-NOT: 2
+ // NCFI: 2
+ fprintf(stderr, "2\n");
+}
diff --git a/test/cfi/simple-pass.cpp b/test/cfi/simple-pass.cpp
index 50e7d92..4d856eb 100644
--- a/test/cfi/simple-pass.cpp
+++ b/test/cfi/simple-pass.cpp
@@ -3,95 +3,119 @@
// Tests that the CFI mechanism does not crash the program when making various
// kinds of valid calls involving classes with various different linkages and
-// types of inheritance.
+// types of inheritance, and both virtual and non-virtual member functions.
#include "utils.h"
struct A {
virtual void f();
+ void g();
};
void A::f() {}
+void A::g() {}
struct A2 : A {
virtual void f();
+ void g();
};
void A2::f() {}
+void A2::g() {}
struct B {
virtual void f() {}
+ void g() {}
};
struct B2 : B {
virtual void f() {}
+ void g() {}
};
namespace {
struct C {
virtual void f();
+ void g();
};
void C::f() {}
+void C::g() {}
struct C2 : C {
virtual void f();
+ void g();
};
void C2::f() {}
+void C2::g() {}
struct D {
virtual void f() {}
+ void g() {}
};
struct D2 : D {
virtual void f() {}
+ void g() {}
};
}
struct E {
virtual void f() {}
+ void g() {}
};
struct E2 : virtual E {
virtual void f() {}
+ void g() {}
};
int main() {
A *a = new A;
break_optimization(a);
a->f();
+ a->g();
a = new A2;
break_optimization(a);
a->f();
+ a->g();
B *b = new B;
break_optimization(b);
b->f();
+ b->g();
b = new B2;
break_optimization(b);
b->f();
+ b->g();
C *c = new C;
break_optimization(c);
c->f();
+ c->g();
c = new C2;
break_optimization(c);
c->f();
+ c->g();
D *d = new D;
break_optimization(d);
d->f();
+ d->g();
d = new D2;
break_optimization(d);
d->f();
+ d->g();
E *e = new E;
break_optimization(e);
e->f();
+ e->g();
e = new E2;
break_optimization(e);
e->f();
+ e->g();
}
diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc
index bdd7cf5..057b060 100644
--- a/test/dfsan/custom.cc
+++ b/test/dfsan/custom.cc
@@ -870,6 +870,11 @@
test_sprintf_chunk("z", "%c", 'z');
// %n, %s, %d, %f, and %% already tested
+
+ // Test formatting with width passed as an argument.
+ r = sprintf(buf, "hi %*d my %*s friend %.*f", 3, 1, 6, "dear", 4, 3.14159265359);
+ assert(r == 30);
+ assert(strcmp(buf, "hi 1 my dear friend 3.1416") == 0);
}
void test_snprintf() {
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index 5a9542f..2996c1d 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -1,5 +1,7 @@
set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
-list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck)
+if(NOT ${LLVM_NATIVE_ARCH} STREQUAL "Mips")
+ list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck)
+endif()
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND TSAN_TEST_DEPS tsan)
endif()
diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c
index e744570..ddfb745 100644
--- a/test/tsan/cond_cancel.c
+++ b/test/tsan/cond_cancel.c
@@ -8,9 +8,14 @@
pthread_cond_t c;
int x;
+static void my_cleanup(void *arg) {
+ printf("my_cleanup\n");
+ pthread_mutex_unlock((pthread_mutex_t*)arg);
+}
+
void *thr1(void *p) {
pthread_mutex_lock(&m);
- pthread_cleanup_push((void(*)(void *arg))pthread_mutex_unlock, &m);
+ pthread_cleanup_push(my_cleanup, &m);
barrier_wait(&barrier);
while (x == 0)
pthread_cond_wait(&c, &m);
diff --git a/test/tsan/deadlock_detector_stress_test.cc b/test/tsan/deadlock_detector_stress_test.cc
index e02a912..c77ffe5 100644
--- a/test/tsan/deadlock_detector_stress_test.cc
+++ b/test/tsan/deadlock_detector_stress_test.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadMutex
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND
-// TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
+// RUN: TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s
// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock
diff --git a/test/tsan/signal_cond.cc b/test/tsan/signal_cond.cc
new file mode 100644
index 0000000..f5eae74
--- /dev/null
+++ b/test/tsan/signal_cond.cc
@@ -0,0 +1,51 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <semaphore.h>
+
+// Test that signals can be delivered to blocked pthread_cond_wait.
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=91
+
+int g_thread_run = 1;
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+sem_t sem;
+
+void sig_handler(int sig) {
+ (void)sig;
+ write(1, "SIGNAL\n", sizeof("SIGNAL\n") - 1);
+ sem_post(&sem);
+}
+
+void* my_thread(void* arg) {
+ pthread_mutex_lock(&mutex);
+ while (g_thread_run)
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+
+int main() {
+ sem_init(&sem, 0, 0);
+ signal(SIGUSR1, &sig_handler);
+ pthread_t thr;
+ pthread_create(&thr, 0, &my_thread, 0);
+ // wait for thread to get inside pthread_cond_wait
+ // (can't use barrier_wait for that)
+ sleep(1);
+ pthread_kill(thr, SIGUSR1);
+ while (sem_wait(&sem) == -1 && errno == EINTR) {
+ }
+ pthread_mutex_lock(&mutex);
+ g_thread_run = 0;
+ pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ pthread_join(thr, 0);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK: SIGNAL
+// CHECK: DONE
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
index 5268171..82c6e0d 100644
--- a/test/ubsan/TestCases/Float/cast-overflow.cpp
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -13,8 +13,6 @@
// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
// This test assumes float and double are IEEE-754 single- and double-precision.
-// XFAIL: armv7l-unknown-linux-gnueabihf
-// XFAIL: aarch64
#if defined(__APPLE__)
# include <machine/endian.h>
@@ -82,11 +80,13 @@
// FIXME: Produce a source location for these checks and test for it here.
// Floating point -> integer overflow.
- case '0':
+ case '0': {
// Note that values between 0x7ffffe00 and 0x80000000 may or may not
// successfully round-trip, depending on the rounding mode.
// CHECK-0: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
- return MaxFloatRepresentableAsInt + 0x80;
+ static int test_int = MaxFloatRepresentableAsInt + 0x80;
+ return 0;
+ }
case '1':
// CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
return MinFloatRepresentableAsInt - 0x100;
@@ -96,26 +96,32 @@
volatile unsigned u = (unsigned)f;
return 0;
}
- case '3':
+ case '3': {
// CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
- return (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
+ static int test_int = (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
+ return 0;
+ }
- case '4':
+ case '4': {
// CHECK-4: runtime error: value {{.*}} is outside the range of representable values of type 'int'
- return Inf;
+ static int test_int = Inf;
+ return 0;
+ }
case '5':
// CHECK-5: runtime error: value {{.*}} is outside the range of representable values of type 'int'
return NaN;
// Integer -> floating point overflow.
- case '6':
+ case '6': {
// CHECK-6: {{runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'|__int128 not supported}}
#ifdef __SIZEOF_INT128__
- return (float)(FloatMaxAsUInt128 + 1);
+ static int test_int = (float)(FloatMaxAsUInt128 + 1);
+ return 0;
#else
puts("__int128 not supported");
return 0;
#endif
+ }
// FIXME: The backend cannot lower __fp16 operations on x86 yet.
//case '7':
// (__fp16)65504; // ok
diff --git a/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc b/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc
index 0252172..d00b3e0 100644
--- a/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc
+++ b/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc
@@ -3,16 +3,16 @@
// RUN: mkdir -p %T/coverage-levels
// RUN: OPT=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels
// RUN: %clangxx -fsanitize=shift -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=1 %s -o %t
-// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
+// RUN: UBSAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
// RUN: %clangxx -fsanitize=undefined -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=1 %s -o %t
-// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
+// RUN: UBSAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=1 %s -o %t
-// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN
+// RUN: UBSAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN
// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=2 %s -o %t
-// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN
+// RUN: UBSAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN
// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=3 %s -o %t
-// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN
+// RUN: UBSAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN
volatile int sink;
int main(int argc, char **argv) {
diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
index 2609c6a..5a2fda4 100644
--- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp
+++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -1,7 +1,7 @@
// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
-// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
+// RUN: UBSAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
// -fsanitize=function is unsupported on Darwin yet.
// XFAIL: darwin