Index: cmake/Modules/AddCompilerRT.cmake =================================================================== --- cmake/Modules/AddCompilerRT.cmake +++ cmake/Modules/AddCompilerRT.cmake @@ -477,56 +477,97 @@ foreach(flag ${LIBCXX_CFLAGS}) set(flagstr "${flagstr} ${flag}") endforeach() - set(LIBCXX_CFLAGS ${flagstr}) + set(LIBCXX_C_FLAGS ${flagstr}) + set(LIBCXX_CXX_FLAGS ${flagstr}) if(LIBCXX_USE_TOOLCHAIN) set(compiler_args -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER}) if(NOT COMPILER_RT_STANDALONE_BUILD) - set(force_deps DEPENDS clang) + set(toolchain_deps $) + set(force_deps DEPENDS $) endif() else() set(compiler_args -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) endif() + set(STAMP_DIR ${prefix}-stamps/) + set(BINARY_DIR ${prefix}-bins/) + + add_custom_target(${name}-clear + COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR} + COMMENT "Clobbering ${name} build and stamp directories" + USES_TERMINAL + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp + DEPENDS ${LIBCXX_DEPS} ${toolchain_deps} + COMMAND ${CMAKE_COMMAND} -E touch ${BINARY_DIR}/CMakeCache.txt + COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_DIR}/${name}-mkdir + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp + COMMENT "Clobbering bootstrap build and stamp directories" + ) + + add_custom_target(${name}-clobber + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) + if(CMAKE_SYSROOT) set(sysroot_arg -DCMAKE_SYSROOT=${CMAKE_SYSROOT}) endif() ExternalProject_Add(${name} - DEPENDS ${LIBCXX_DEPS} + DEPENDS ${name}-clobber ${LIBCXX_DEPS} PREFIX ${prefix} SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH} + STAMP_DIR ${STAMP_DIR} + BINARY_DIR ${BINARY_DIR} CMAKE_ARGS -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} ${compiler_args} ${sysroot_arg} - -DCMAKE_C_FLAGS=${LIBCXX_CFLAGS} - -DCMAKE_CXX_FLAGS=${LIBCXX_CFLAGS} + -DCMAKE_C_FLAGS=${LIBCXX_C_FLAGS} + -DCMAKE_CXX_FLAGS=${LIBCXX_CXX_FLAGS} -DCMAKE_BUILD_TYPE=Release - -DCMAKE_INSTALL_PREFIX= + -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DLLVM_PATH=${LLVM_MAIN_SRC_DIR} - -DLIBCXX_STANDALONE_BUILD=On + -DLLVM_BINARY_DIR=${prefix} + -DLLVM_LIBRARY_OUTPUT_INTDIR=${prefix}/lib + -DLIBCXX_STANDALONE_BUILD=ON ${LIBCXX_CMAKE_ARGS} - STEP_TARGETS configure build install - LOG_BUILD 1 - LOG_CONFIGURE 1 - LOG_INSTALL 1 + INSTALL_COMMAND "" + STEP_TARGETS configure build + BUILD_ALWAYS 1 + USES_TERMINAL_CONFIGURE 1 + USES_TERMINAL_BUILD 1 + USES_TERMINAL_INSTALL 1 EXCLUDE_FROM_ALL TRUE ) - ExternalProject_Add_Step(${name} force-reconfigure - DEPENDERS configure - ALWAYS 1 - ) + if (CMAKE_GENERATOR MATCHES "Make") + set(run_clean "$(MAKE)" "-C" "${BINARY_DIR}" "clean") + else() + set(run_clean ${CMAKE_COMMAND} --build ${BINARY_DIR} --target clean + --config "$") + endif() - ExternalProject_Add_Step(${name} clobber - COMMAND ${CMAKE_COMMAND} -E remove_directory - COMMAND ${CMAKE_COMMAND} -E make_directory - COMMENT "Clobberring ${name} build directory..." - DEPENDERS configure + ExternalProject_Add_Step(${name} clean + COMMAND ${run_clean} + COMMENT "Cleaning ${name}..." + DEPENDEES configure ${force_deps} + WORKING_DIRECTORY ${BINARY_DIR} + EXCLUDE_FROM_MAIN 1 + USES_TERMINAL 1 ) + ExternalProject_Add_StepTargets(${name} clean) + + if(LIBCXX_USE_TOOLCHAIN) + add_dependencies(${name}-clean ${name}-clobber) + set_target_properties(${name}-clean PROPERTIES + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) + endif() endmacro() function(rt_externalize_debuginfo name) Index: cmake/base-config-ix.cmake =================================================================== --- cmake/base-config-ix.cmake +++ cmake/base-config-ix.cmake @@ -139,8 +139,16 @@ add_default_target_arch(${COMPILER_RT_DEFAULT_TARGET_ARCH}) elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64") if(NOT MSVC) - test_target_arch(x86_64 "" "-m64") - test_target_arch(i386 __i386__ "-m32") + if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + if (CMAKE_SIZEOF_VOID_P EQUAL 4) + test_target_arch(i386 __i386__ "-m32") + else() + test_target_arch(x86_64 "" "-m64") + endif() + else() + test_target_arch(x86_64 "" "-m64") + test_target_arch(i386 __i386__ "-m32") + endif() else() if (CMAKE_SIZEOF_VOID_P EQUAL 4) test_target_arch(i386 "" "") Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -488,7 +488,7 @@ list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND - (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia|SunOS" OR + (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia|SunOS" OR (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN)))) set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE) else() @@ -501,7 +501,8 @@ set(COMPILER_RT_HAS_INTERCEPTION FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH) +if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND + NOT OS_NAME MATCHES "OpenBSD") set(COMPILER_RT_HAS_ASAN TRUE) else() set(COMPILER_RT_HAS_ASAN FALSE) @@ -530,7 +531,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|NetBSD") + OS_NAME MATCHES "Linux|FreeBSD|NetBSD") set(COMPILER_RT_HAS_MSAN TRUE) else() set(COMPILER_RT_HAS_MSAN FALSE) @@ -558,14 +559,14 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia|SunOS") + OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Windows|Android|Fuchsia|SunOS") set(COMPILER_RT_HAS_UBSAN TRUE) else() set(COMPILER_RT_HAS_UBSAN FALSE) endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android|Darwin") + OS_NAME MATCHES "Linux|FreeBSD|NetBSD|OpenBSD|Android|Darwin") set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE) else() set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) Index: include/sanitizer/netbsd_syscall_hooks.h =================================================================== --- include/sanitizer/netbsd_syscall_hooks.h +++ include/sanitizer/netbsd_syscall_hooks.h @@ -21,7 +21,7 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2018-02-15 +// Generated date: 2018-03-03 // Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp // //===----------------------------------------------------------------------===// Index: include/xray/xray_log_interface.h =================================================================== --- include/xray/xray_log_interface.h +++ include/xray/xray_log_interface.h @@ -72,6 +72,17 @@ /// // deal with the error here, if it is an error. /// } /// +/// // Alternatively, we can go through the buffers ourselves without +/// // relying on the implementations' flushing semantics (if the +/// // implementation supports exporting this data directly). +/// auto MyBufferProcessor = +[](const char* mode, XRayBuffer buffer) { +/// // Check the "mode" to see if it's something we know how to handle... +/// // and/or do something with an XRayBuffer instance. +/// }; +/// auto process_status = __xray_log_process_buffers(MyBufferProcessor); +/// if (process_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) { +/// // deal with the error here, if it is an error. +/// } /// /// NOTE: Before calling __xray_patch() again, consider re-initializing the /// implementation first. Some implementations might stay in an "off" state when @@ -227,6 +238,11 @@ /// does not update the currently installed implementation. XRayLogRegisterStatus __xray_log_select_mode(const char *Mode); +/// Returns an identifier for the currently selected XRay mode chosen through +/// the __xray_log_select_mode(...) function call. Returns nullptr if there is +/// no currently installed mode. +const char *__xray_log_get_current_mode(); + /// This function removes the currently installed implementation. It will also /// uninstall any handlers that have been previously installed. It does NOT /// unpatch the instrumentation sleds. @@ -257,6 +273,54 @@ /// XRayLogFlushStatus for what the return values mean. XRayLogFlushStatus __xray_log_flushLog(); +/// An XRayBuffer represents a section of memory which can be treated by log +/// processing functions as bytes stored in the logging implementation's +/// buffers. +struct XRayBuffer { + const void *Data; + size_t Size; +}; + +/// Registers an iterator function which takes an XRayBuffer argument, then +/// returns another XRayBuffer function representing the next buffer. When the +/// Iterator function returns an empty XRayBuffer (Data = nullptr, Size = 0), +/// this signifies the end of the buffers. +/// +/// The first invocation of this Iterator function will always take an empty +/// XRayBuffer (Data = nullptr, Size = 0). +void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer)); + +/// Removes the currently registered buffer iterator function. +void __xray_log_remove_buffer_iterator(); + +/// Invokes the provided handler to process data maintained by the logging +/// handler. This API will be provided raw access to the data available in +/// memory from the logging implementation. The callback function must: +/// +/// 1) Not modify the data, to avoid running into undefined behaviour. +/// +/// 2) Either know the data layout, or treat the data as raw bytes for later +/// interpretation. +/// +/// This API is best used in place of the `__xray_log_flushLog()` implementation +/// above to enable the caller to provide an alternative means of extracting the +/// data from the XRay implementation. +/// +/// Implementations MUST then provide: +/// +/// 1) A function that will return an XRayBuffer. Functions that return an +/// "empty" XRayBuffer signifies that there are no more buffers to be +/// processed. This function should be registered through the +/// `__xray_log_set_buffer_iterator(...)` function. +/// +/// 2) Its own means of converting data it holds in memory into an XRayBuffer +/// structure. +/// +/// See XRayLogFlushStatus for what the return values mean. +/// +XRayLogFlushStatus __xray_log_process_buffers(void (*Processor)(const char *, + XRayBuffer)); + } // extern "C" namespace __xray { Index: lib/asan/asan_interceptors_memintrinsics.h =================================================================== --- lib/asan/asan_interceptors_memintrinsics.h +++ lib/asan/asan_interceptors_memintrinsics.h @@ -133,15 +133,22 @@ const char *offset2, uptr length2) { return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1)); } -#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ - const char *offset1 = (const char*)_offset1; \ - const char *offset2 = (const char*)_offset2; \ - if (RangesOverlap(offset1, length1, offset2, length2)) { \ - GET_STACK_TRACE_FATAL_HERE; \ - ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ - offset2, length2, &stack); \ - } \ -} while (0) +#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) \ + do { \ + const char *offset1 = (const char *)_offset1; \ + const char *offset2 = (const char *)_offset2; \ + if (RangesOverlap(offset1, length1, offset2, length2)) { \ + GET_STACK_TRACE_FATAL_HERE; \ + bool suppressed = IsInterceptorSuppressed(name); \ + if (!suppressed && HaveStackTraceBasedSuppressions()) { \ + suppressed = IsStackTraceSuppressed(&stack); \ + } \ + if (!suppressed) { \ + ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ + offset2, length2, &stack); \ + } \ + } \ + } while (0) } // namespace __asan Index: lib/asan/asan_malloc_mac.cc =================================================================== --- lib/asan/asan_malloc_mac.cc +++ lib/asan/asan_malloc_mac.cc @@ -38,6 +38,9 @@ #define COMMON_MALLOC_CALLOC(count, size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_calloc(count, size, &stack); +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ + GET_STACK_TRACE_MALLOC; \ + int res = asan_posix_memalign(memptr, alignment, size, &stack); #define COMMON_MALLOC_VALLOC(size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); Index: lib/asan/asan_poisoning.h =================================================================== --- lib/asan/asan_poisoning.h +++ lib/asan/asan_poisoning.h @@ -38,7 +38,7 @@ // performance-critical code with care. ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, u8 value) { - DCHECK(CanPoisonMemory()); + DCHECK(!value || CanPoisonMemory()); uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); uptr shadow_end = MEM_TO_SHADOW( aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; Index: lib/asan/asan_poisoning.cc =================================================================== --- lib/asan/asan_poisoning.cc +++ lib/asan/asan_poisoning.cc @@ -32,7 +32,7 @@ } void PoisonShadow(uptr addr, uptr size, u8 value) { - if (!CanPoisonMemory()) return; + if (value && !CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); CHECK(AddrIsInMem(addr)); CHECK(AddrIsAlignedByGranularity(addr + size)); Index: lib/esan/esan_interceptors.cpp =================================================================== --- lib/esan/esan_interceptors.cpp +++ lib/esan/esan_interceptors.cpp @@ -175,6 +175,15 @@ do { \ } while (false) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + do { \ + if (!fixMmapAddr(&addr, sz, flags)) \ + return (void *)-1; \ + void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); \ + return (void *)checkMmapResult((uptr)result, sz); \ + } while (false) + #include "sanitizer_common/sanitizer_common_interceptors.inc" //===----------------------------------------------------------------------===// @@ -321,44 +330,6 @@ return REAL(rmdir)(path); } -//===----------------------------------------------------------------------===// -// Shadow-related interceptors -//===----------------------------------------------------------------------===// - -// These are candidates for sharing with all sanitizers if shadow memory -// support is also standardized. - -INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF_T off) { - if (UNLIKELY(REAL(mmap) == nullptr)) { - // With esan init during interceptor init and a static libc preventing - // our early-calloc from triggering, we can end up here before our - // REAL pointer is set up. - return (void *)internal_mmap(addr, sz, prot, flags, fd, off); - } - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); - if (!fixMmapAddr(&addr, sz, flags)) - return (void *)-1; - void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); - return (void *)checkMmapResult((uptr)result, sz); -} - -#if SANITIZER_LINUX -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF64_T off) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); - if (!fixMmapAddr(&addr, sz, flags)) - return (void *)-1; - void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); - return (void *)checkMmapResult((uptr)result, sz); -} -#define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define ESAN_MAYBE_INTERCEPT_MMAP64 -#endif - //===----------------------------------------------------------------------===// // Signal-related interceptors //===----------------------------------------------------------------------===// @@ -527,9 +498,6 @@ INTERCEPT_FUNCTION(puts); INTERCEPT_FUNCTION(rmdir); - INTERCEPT_FUNCTION(mmap); - ESAN_MAYBE_INTERCEPT_MMAP64; - ESAN_MAYBE_INTERCEPT_SIGNAL; ESAN_MAYBE_INTERCEPT_SIGACTION; ESAN_MAYBE_INTERCEPT_SIGPROCMASK; Index: lib/fuzzer/CMakeLists.txt =================================================================== --- lib/fuzzer/CMakeLists.txt +++ lib/fuzzer/CMakeLists.txt @@ -86,7 +86,7 @@ set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir") file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir}) add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD - COMMAND ${CMAKE_LINKER} --whole-archive "$" --no-whole-archive ${dir}/src/libcxx_fuzzer_${arch}-build/lib/libc++.a -r -o ${name}.o + COMMAND ${CMAKE_LINKER} --whole-archive "$" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o COMMAND ${CMAKE_COMMAND} -E remove "$" COMMAND ${CMAKE_AR} qcs "$" ${name}.o @@ -104,13 +104,18 @@ -fvisibility=hidden CMAKE_ARGS -DLIBCXX_ENABLE_EXCEPTIONS=OFF -DLIBCXX_CXX_ABI=none) - target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${COMPILER_RT_LIBCXX_PATH}/include) + target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build) - target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${COMPILER_RT_LIBCXX_PATH}/include) + target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build) partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX} ${arch}) partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch}) endforeach() +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia" AND HAVE_LIBCXX) + foreach(arch ${FUZZER_SUPPORTED_ARCH}) + add_dependencies(RTfuzzer.${arch} cxx) + add_dependencies(RTfuzzer_main.${arch} cxx) + endforeach() endif() if(COMPILER_RT_INCLUDE_TESTS) Index: lib/fuzzer/FuzzerDictionary.h =================================================================== --- lib/fuzzer/FuzzerDictionary.h +++ lib/fuzzer/FuzzerDictionary.h @@ -115,11 +115,11 @@ }; // Parses one dictionary entry. -// If successfull, write the enty to Unit and returns true, +// If successful, write the enty to Unit and returns true, // otherwise returns false. bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // Parses the dictionary file, fills Units, returns true iff all lines -// were parsed succesfully. +// were parsed successfully. bool ParseDictionaryFile(const std::string &Text, Vector *Units); } // namespace fuzzer Index: lib/fuzzer/FuzzerDriver.cpp =================================================================== --- lib/fuzzer/FuzzerDriver.cpp +++ lib/fuzzer/FuzzerDriver.cpp @@ -747,7 +747,7 @@ Printf("Dictionary analysis failed\n"); exit(1); } - Printf("Dictionary analysis suceeded\n"); + Printf("Dictionary analysis succeeded\n"); exit(0); } Index: lib/fuzzer/FuzzerFlags.def =================================================================== --- lib/fuzzer/FuzzerFlags.def +++ lib/fuzzer/FuzzerFlags.def @@ -45,7 +45,7 @@ "This flag can be used to minimize a corpus.") FUZZER_FLAG_STRING(merge_inner, "internal flag") FUZZER_FLAG_STRING(merge_control_file, - "Specify a control file used for the merge proccess. " + "Specify a control file used for the merge process. " "If a merge process gets killed it tries to leave this file " "in a state suitable for resuming the merge. " "By default a temporary file will be used.") Index: lib/fuzzer/FuzzerMutate.h =================================================================== --- lib/fuzzer/FuzzerMutate.h +++ lib/fuzzer/FuzzerMutate.h @@ -27,7 +27,7 @@ void StartMutationSequence(); /// Print the current sequence of mutations. void PrintMutationSequence(); - /// Indicate that the current sequence of mutations was successfull. + /// Indicate that the current sequence of mutations was successful. void RecordSuccessfulMutationSequence(); /// Mutates data by invoking user-provided mutator. size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); @@ -125,7 +125,7 @@ // recreated periodically. Dictionary TempAutoDictionary; // Persistent dictionary modified by the fuzzer, consists of - // entries that led to successfull discoveries in the past mutations. + // entries that led to successful discoveries in the past mutations. Dictionary PersistentAutoDictionary; Vector CurrentMutatorSequence; Index: lib/fuzzer/afl/afl_driver.cpp =================================================================== --- lib/fuzzer/afl/afl_driver.cpp +++ lib/fuzzer/afl/afl_driver.cpp @@ -90,7 +90,7 @@ #endif // Used to avoid repeating error checking boilerplate. If cond is false, a -// fatal error has occured in the program. In this event print error_message +// fatal error has occurred in the program. In this event print error_message // to stderr and abort(). Otherwise do nothing. Note that setting // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended // to the file as well, if the error occurs after the duplication is performed. @@ -278,7 +278,7 @@ assert(in); LLVMFuzzerTestOneInput(reinterpret_cast(bytes.data()), bytes.size()); - std::cout << "Execution successfull" << std::endl; + std::cout << "Execution successful" << std::endl; } return 0; } Index: lib/fuzzer/tests/CMakeLists.txt =================================================================== --- lib/fuzzer/tests/CMakeLists.txt +++ lib/fuzzer/tests/CMakeLists.txt @@ -40,7 +40,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH) set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build) set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${COMPILER_RT_LIBCXX_PATH}/include) - set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/src/libcxx_fuzzer_${arch}-build/lib/libc++.a) + set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a) endif() set(FuzzerTestObjects) Index: lib/hwasan/hwasan_interceptors.cc =================================================================== --- lib/hwasan/hwasan_interceptors.cc +++ lib/hwasan/hwasan_interceptors.cc @@ -264,28 +264,9 @@ return hwasan_malloc(size, &stack); } - -INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, - int fd, OFF_T offset) { - if (hwasan_init_is_running) - return REAL(mmap)(addr, length, prot, flags, fd, offset); - ENSURE_HWASAN_INITED(); - if (addr && !MEM_IS_APP(addr)) { - if (flags & map_fixed) { - errno = errno_EINVAL; - return (void *)-1; - } else { - addr = nullptr; - } - } - void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); - return res; -} - -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, - int fd, OFF64_T offset) { - ENSURE_HWASAN_INITED(); +template +static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T sz, int prot, + int flags, int fd, OFF64_T off) { if (addr && !MEM_IS_APP(addr)) { if (flags & map_fixed) { errno = errno_EINVAL; @@ -294,13 +275,8 @@ addr = nullptr; } } - void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); - return res; + return real_mmap(addr, sz, prot, flags, fd, off); } -#define HWASAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define HWASAN_MAYBE_INTERCEPT_MMAP64 -#endif extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); @@ -436,6 +412,13 @@ return REAL(memset)(dst, v, size); \ } +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \ + offset) \ + do { \ + return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd, \ + offset); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" #include "sanitizer_common/sanitizer_signal_interceptors.inc" @@ -469,8 +452,6 @@ InitializeCommonInterceptors(); InitializeSignalInterceptors(); - INTERCEPT_FUNCTION(mmap); - HWASAN_MAYBE_INTERCEPT_MMAP64; INTERCEPT_FUNCTION(posix_memalign); HWASAN_MAYBE_INTERCEPT_MEMALIGN; INTERCEPT_FUNCTION(__libc_memalign); Index: lib/lsan/lsan_allocator.h =================================================================== --- lib/lsan/lsan_allocator.h +++ lib/lsan/lsan_allocator.h @@ -90,6 +90,8 @@ AllocatorCache *GetAllocatorCache(); +int lsan_posix_memalign(void **memptr, uptr alignment, uptr size, + const StackTrace &stack); void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack); void *lsan_malloc(uptr size, const StackTrace &stack); void lsan_free(void *p); Index: lib/lsan/lsan_allocator.cc =================================================================== --- lib/lsan/lsan_allocator.cc +++ lib/lsan/lsan_allocator.cc @@ -128,6 +128,21 @@ return m->requested_size; } +int lsan_posix_memalign(void **memptr, uptr alignment, uptr size, + const StackTrace &stack) { + if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { + ReturnNullOrDieOnFailure::OnBadRequest(); + return errno_EINVAL; + } + void *ptr = Allocate(stack, size, alignment, kAlwaysClearMemory); + if (UNLIKELY(!ptr)) + // OOM error is already taken care of by Allocate. + return errno_ENOMEM; + CHECK(IsAligned((uptr)ptr, alignment)); + *memptr = ptr; + return 0; +} + void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; Index: lib/lsan/lsan_interceptors.cc =================================================================== --- lib/lsan/lsan_interceptors.cc +++ lib/lsan/lsan_interceptors.cc @@ -86,9 +86,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; - *memptr = lsan_memalign(alignment, size, stack); - // FIXME: Return ENOMEM if user requested more than max alloc size. - return 0; + return lsan_posix_memalign(memptr, alignment, size, stack); } INTERCEPTOR(void*, valloc, uptr size) { Index: lib/lsan/lsan_malloc_mac.cc =================================================================== --- lib/lsan/lsan_malloc_mac.cc +++ lib/lsan/lsan_malloc_mac.cc @@ -37,6 +37,9 @@ #define COMMON_MALLOC_CALLOC(count, size) \ GET_STACK_TRACE_MALLOC; \ void *p = lsan_calloc(count, size, stack) +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ + GET_STACK_TRACE_MALLOC; \ + int res = lsan_posix_memalign(memptr, alignment, size, stack) #define COMMON_MALLOC_VALLOC(size) \ GET_STACK_TRACE_MALLOC; \ void *p = lsan_valloc(size, stack) Index: lib/msan/CMakeLists.txt =================================================================== --- lib/msan/CMakeLists.txt +++ lib/msan/CMakeLists.txt @@ -17,8 +17,13 @@ set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec MSAN_RTL_CFLAGS) +endif() append_rtti_flag(OFF MSAN_RTL_CFLAGS) -append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS) +if(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS) +endif() # Prevent clang from generating libc calls. append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS) Index: lib/msan/msan_interceptors.cc =================================================================== --- lib/msan/msan_interceptors.cc +++ lib/msan/msan_interceptors.cc @@ -481,37 +481,6 @@ return res; } -INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); - SIZE_T res = REAL(strxfrm)(dest, src, n); - if (res < n) __msan_unpoison(dest, res + 1); - return res; -} - -INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T n, - void *loc) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); - SIZE_T res = REAL(strxfrm_l)(dest, src, n, loc); - if (res < n) __msan_unpoison(dest, res + 1); - return res; -} - -#if SANITIZER_LINUX -INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T n, - void *loc) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED(src, REAL(strlen)(src) + 1); - SIZE_T res = REAL(__strxfrm_l)(dest, src, n, loc); - if (res < n) __msan_unpoison(dest, res + 1); - return res; -} -#define MSAN_MAYBE_INTERCEPT___STRXFRM_L INTERCEPT_FUNCTION(__strxfrm_l) -#else -#define MSAN_MAYBE_INTERCEPT___STRXFRM_L -#endif - #define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \ ENSURE_MSAN_INITED(); \ InterceptorScope interceptor_scope; \ @@ -681,7 +650,7 @@ return res; } -#if SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD INTERCEPTOR(int, fstat, int fd, void *buf) { ENSURE_MSAN_INITED(); int res = REAL(fstat)(fd, buf); @@ -971,11 +940,9 @@ } } -INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, - int fd, OFF_T offset) { - if (msan_init_is_running) - return REAL(mmap)(addr, length, prot, flags, fd, offset); - ENSURE_MSAN_INITED(); +template +static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, + int prot, int flags, int fd, OFF64_T offset) { if (addr && !MEM_IS_APP(addr)) { if (flags & map_fixed) { errno = errno_EINVAL; @@ -984,34 +951,11 @@ addr = nullptr; } } - void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); - if (res != (void*)-1) - __msan_unpoison(res, RoundUpTo(length, GetPageSize())); + void *res = real_mmap(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) __msan_unpoison(res, RoundUpTo(length, GetPageSize())); return res; } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD -INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, - int fd, OFF64_T offset) { - ENSURE_MSAN_INITED(); - if (addr && !MEM_IS_APP(addr)) { - if (flags & map_fixed) { - errno = errno_EINVAL; - return (void *)-1; - } else { - addr = nullptr; - } - } - void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); - if (res != (void*)-1) - __msan_unpoison(res, RoundUpTo(length, GetPageSize())); - return res; -} -#define MSAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) -#else -#define MSAN_MAYBE_INTERCEPT_MMAP64 -#endif - INTERCEPTOR(int, getrusage, int who, void *usage) { ENSURE_MSAN_INITED(); int res = REAL(getrusage)(who, usage); @@ -1329,6 +1273,12 @@ __msan_unpoison(to + size, 1); \ } while (false) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \ + offset) \ + do { \ + return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1577,8 +1527,6 @@ InitializeCommonInterceptors(); InitializeSignalInterceptors(); - INTERCEPT_FUNCTION(mmap); - MSAN_MAYBE_INTERCEPT_MMAP64; INTERCEPT_FUNCTION(posix_memalign); MSAN_MAYBE_INTERCEPT_MEMALIGN; MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; @@ -1632,9 +1580,6 @@ INTERCEPT_FUNCTION(vswprintf); INTERCEPT_FUNCTION(swprintf); #endif - INTERCEPT_FUNCTION(strxfrm); - INTERCEPT_FUNCTION(strxfrm_l); - MSAN_MAYBE_INTERCEPT___STRXFRM_L; INTERCEPT_FUNCTION(strftime); INTERCEPT_FUNCTION(strftime_l); MSAN_MAYBE_INTERCEPT___STRFTIME_L; Index: lib/msan/tests/CMakeLists.txt =================================================================== --- lib/msan/tests/CMakeLists.txt +++ lib/msan/tests/CMakeLists.txt @@ -109,7 +109,7 @@ DEPS ${MSAN_INST_LOADABLE_OBJECTS}) set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST}) - set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}-install + set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}-build ${MSAN_LOADABLE_SO}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND MSAN_TEST_DEPS msan) Index: lib/sanitizer_common/CMakeLists.txt =================================================================== --- lib/sanitizer_common/CMakeLists.txt +++ lib/sanitizer_common/CMakeLists.txt @@ -16,9 +16,11 @@ sanitizer_linux.cc sanitizer_linux_s390.cc sanitizer_mac.cc + sanitizer_openbsd.cc sanitizer_persistent_allocator.cc sanitizer_platform_limits_linux.cc sanitizer_platform_limits_netbsd.cc + sanitizer_platform_limits_openbsd.cc sanitizer_platform_limits_posix.cc sanitizer_platform_limits_solaris.cc sanitizer_posix.cc Index: lib/sanitizer_common/sanitizer_allocator_primary32.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_primary32.h +++ lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -266,14 +266,12 @@ static const uptr kRegionSize = 1 << kRegionSizeLog; static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize; - struct SizeClassInfo { + struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo { SpinMutex mutex; IntrusiveList free_list; u32 rand_state; - char padding[kCacheLineSize - 2 * sizeof(uptr) - - sizeof(IntrusiveList)]; }; - COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize); + COMPILER_CHECK(sizeof(SizeClassInfo) % kCacheLineSize == 0); uptr ComputeRegionId(uptr mem) { const uptr res = mem >> kRegionSizeLog; @@ -299,7 +297,7 @@ } SizeClassInfo *GetSizeClassInfo(uptr class_id) { - CHECK_LT(class_id, kNumClasses); + DCHECK_LT(class_id, kNumClasses); return &size_class_info_array[class_id]; } Index: lib/sanitizer_common/sanitizer_allocator_primary64.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_primary64.h +++ lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -80,6 +80,8 @@ } SetReleaseToOSIntervalMs(release_to_os_interval_ms); MapWithCallbackOrDie(SpaceEnd(), AdditionalSize()); + // Check that the RegionInfo array is aligned on the CacheLine size. + DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0); } s32 ReleaseToOSIntervalMs() const { @@ -584,7 +586,7 @@ u64 last_released_bytes; }; - struct RegionInfo { + struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) RegionInfo { BlockingMutex mutex; uptr num_freed_chunks; // Number of elements in the freearray. uptr mapped_free_array; // Bytes mapped for freearray. @@ -597,12 +599,11 @@ Stats stats; ReleaseToOsInfo rtoi; }; - COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); + COMPILER_CHECK(sizeof(RegionInfo) % kCacheLineSize == 0); RegionInfo *GetRegionInfo(uptr class_id) const { - CHECK_LT(class_id, kNumClasses); - RegionInfo *regions = - reinterpret_cast(SpaceBeg() + kSpaceSize); + DCHECK_LT(class_id, kNumClasses); + RegionInfo *regions = reinterpret_cast(SpaceEnd()); return ®ions[class_id]; } Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -39,11 +39,7 @@ const uptr kWordSize = SANITIZER_WORDSIZE / 8; const uptr kWordSizeInBits = 8 * kWordSize; -#if defined(__powerpc__) || defined(__powerpc64__) - const uptr kCacheLineSize = 128; -#else - const uptr kCacheLineSize = 64; -#endif +const uptr kCacheLineSize = SANITIZER_CACHE_LINE_SIZE; const uptr kMaxPathLength = 4096; Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,7 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_MMAP_IMPL // COMMON_INTERCEPTOR_COPY_STRING // COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// @@ -267,6 +268,12 @@ } #endif +#ifndef COMMON_INTERCEPTOR_MMAP_IMPL +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + { return REAL(mmap)(addr, sz, prot, flags, fd, off); } +#endif + #ifndef COMMON_INTERCEPTOR_COPY_STRING #define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} #endif @@ -3590,7 +3597,7 @@ // * GNU version returns message pointer, which points to either buf or some // static storage. #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ - SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD + SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_FREEBSD // POSIX version. Spec is not clear on whether buf is NULL-terminated. // At least on OSX, buf contents are valid even when the call fails. INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { @@ -6522,6 +6529,78 @@ #define INIT_WCSCAT #endif +static SIZE_T RealStrLen(const char *str) { return REAL(strlen)(str); } + +static SIZE_T RealStrLen(const wchar_t *str) { return REAL(wcslen)(str); } + +#define STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, strxfrm, dest, src, len, ##__VA_ARGS__); \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, \ + sizeof(*src) * (RealStrLen(src) + 1)); \ + SIZE_T res = REAL(strxfrm)(dest, src, len, ##__VA_ARGS__); \ + if (res < len) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(*src) * (res + 1)); \ + return res; \ + } + +#if SANITIZER_INTERCEPT_STRXFRM +INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T len) { + STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(strxfrm_l, dest, src, len, locale); +} + +#define INIT_STRXFRM \ + COMMON_INTERCEPT_FUNCTION(strxfrm); \ + COMMON_INTERCEPT_FUNCTION(strxfrm_l); +#else +#define INIT_STRXFRM +#endif + +#if SANITIZER_INTERCEPT___STRXFRM_L +INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(__strxfrm_l, dest, src, len, locale); +} + +#define INIT___STRXFRM_L COMMON_INTERCEPT_FUNCTION(__strxfrm_l); +#else +#define INIT___STRXFRM_L +#endif + +#if SANITIZER_INTERCEPT_WCSXFRM +INTERCEPTOR(SIZE_T, wcsxfrm, wchar_t *dest, const wchar_t *src, SIZE_T len) { + STRXFRM_INTERCEPTOR_IMPL(wcsxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(wcsxfrm_l, dest, src, len, locale); +} + +#define INIT_WCSXFRM \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm); \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm_l); +#else +#define INIT_WCSXFRM +#endif + +#if SANITIZER_INTERCEPT___WCSXFRM_L +INTERCEPTOR(SIZE_T, __wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(__wcsxfrm_l, dest, src, len, locale); +} + +#define INIT___WCSXFRM_L COMMON_INTERCEPT_FUNCTION(__wcsxfrm_l); +#else +#define INIT___WCSXFRM_L +#endif + #if SANITIZER_INTERCEPT_ACCT INTERCEPTOR(int, acct, const char *file) { void *ctx; @@ -6792,6 +6871,34 @@ #define INIT_STRLCPY #endif +#if SANITIZER_INTERCEPT_MMAP +INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, int fd, + OFF_T off) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return (void *)internal_mmap(addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, off); +} +#define INIT_MMAP COMMON_INTERCEPT_FUNCTION(mmap); +#else +#define INIT_MMAP +#endif + +#if SANITIZER_INTERCEPT_MMAP64 +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, int fd, + OFF64_T off) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return (void *)internal_mmap(addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap64, addr, sz, prot, flags, fd, off); +} +#define INIT_MMAP64 COMMON_INTERCEPT_FUNCTION(mmap64); +#else +#define INIT_MMAP64 +#endif + #if SANITIZER_INTERCEPT_DEVNAME INTERCEPTOR(char *, devname, u64 dev, u32 type) { void *ctx; @@ -7029,6 +7136,8 @@ static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); + INIT_MMAP; + INIT_MMAP64; INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; @@ -7046,6 +7155,8 @@ INIT_STRSPN; INIT_STRTOK; INIT_STRPBRK; + INIT_STRXFRM; + INIT___STRXFRM_L; INIT_MEMSET; INIT_MEMMOVE; INIT_MEMCPY; @@ -7238,6 +7349,8 @@ INIT_GETLOADAVG; INIT_WCSLEN; INIT_WCSCAT; + INIT_WCSXFRM; + INIT___WCSXFRM_L; INIT_ACCT; INIT_USER_FROM_UID; INIT_UID_FROM_USER; Index: lib/sanitizer_common/sanitizer_errno.h =================================================================== --- lib/sanitizer_common/sanitizer_errno.h +++ lib/sanitizer_common/sanitizer_errno.h @@ -24,7 +24,7 @@ #if SANITIZER_FREEBSD || SANITIZER_MAC # define __errno_location __error -#elif SANITIZER_ANDROID || SANITIZER_NETBSD +#elif SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_OPENBSD # define __errno_location __errno #elif SANITIZER_SOLARIS # define __errno_location ___errno Index: lib/sanitizer_common/sanitizer_fuchsia.cc =================================================================== --- lib/sanitizer_common/sanitizer_fuchsia.cc +++ lib/sanitizer_common/sanitizer_fuchsia.cc @@ -66,7 +66,7 @@ uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } -uptr GetTid() { return GetThreadSelf(); } +tid_t GetTid() { return GetThreadSelf(); } void Abort() { abort(); } Index: lib/sanitizer_common/sanitizer_internal_defs.h =================================================================== --- lib/sanitizer_common/sanitizer_internal_defs.h +++ lib/sanitizer_common/sanitizer_internal_defs.h @@ -39,7 +39,8 @@ #endif // TLS is handled differently on different platforms -#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FREEBSD +#if SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_FREEBSD || SANITIZER_OPENBSD # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ __attribute__((tls_model("initial-exec"))) thread_local #else @@ -100,7 +101,7 @@ // FIXME: do we have anything like this on Mac? #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY #if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || \ - SANITIZER_FREEBSD) && !defined(PIC) + SANITIZER_FREEBSD || SANITIZER_OPENBSD) && !defined(PIC) # define SANITIZER_CAN_USE_PREINIT_ARRAY 1 // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. // FIXME: Check for those conditions. @@ -159,7 +160,8 @@ typedef int pid_t; #endif -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \ +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_MAC || \ (SANITIZER_LINUX && defined(__x86_64__)) typedef u64 OFF_T; #else @@ -170,7 +172,7 @@ #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else -# if defined(__s390__) && !defined(__s390x__) +# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) // Special case: 31-bit s390 has unsigned long as size_t. typedef unsigned long operator_new_size_type; # else @@ -178,12 +180,7 @@ # endif #endif -#if SANITIZER_MAC -// On Darwin, thread IDs are 64-bit even on 32-bit systems. typedef u64 tid_t; -#else -typedef uptr tid_t; -#endif // ----------- ATTENTION ------------- // This header should NOT include any other headers to avoid portability issues. Index: lib/sanitizer_common/sanitizer_libignore.cc =================================================================== --- lib/sanitizer_common/sanitizer_libignore.cc +++ lib/sanitizer_common/sanitizer_libignore.cc @@ -9,7 +9,8 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ + SANITIZER_NETBSD || SANITIZER_OPENBSD #include "sanitizer_libignore.h" #include "sanitizer_flags.h" Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -84,6 +84,7 @@ // FreeBSD 9.2 and 10.0. #include } +#include extern char **environ; // provided by crt1 #endif // SANITIZER_FREEBSD @@ -453,11 +454,13 @@ tid_t GetTid() { #if SANITIZER_FREEBSD - return (uptr)pthread_self(); + long Tid; + thr_self(&Tid); + return Tid; #elif SANITIZER_NETBSD return _lwp_self(); #elif SANITIZER_SOLARIS - return (uptr)thr_self(); + return thr_self(); #else return internal_syscall(SYSCALL(gettid)); #endif Index: lib/sanitizer_common/sanitizer_malloc_mac.inc =================================================================== --- lib/sanitizer_common/sanitizer_malloc_mac.inc +++ lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -170,12 +170,8 @@ INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { COMMON_MALLOC_ENTER(); CHECK(memptr); - COMMON_MALLOC_MEMALIGN(alignment, size); - if (p) { - *memptr = p; - return 0; - } - return -1; + COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size); + return res; } namespace { Index: lib/sanitizer_common/sanitizer_openbsd.cc =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_openbsd.cc @@ -0,0 +1,101 @@ +//===-- sanitizer_openbsd.cc ----------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements Solaris-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_OPENBSD + +#include + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char **environ; + +namespace __sanitizer { + +uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, + u64 offset) { + return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + +uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } + +int internal_mprotect(void *addr, uptr length, int prot) { + return mprotect(addr, length, prot); +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // On OpenBSD we cannot get the full path + struct kinfo_proc kp; + size_t kl; + const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; + if (sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) + return internal_snprintf(buf, + (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), + "%s", kp.p_comm); + return (uptr)0; +} + +static void GetArgsAndEnv(char ***argv, char ***envp) { + size_t nargv; + size_t nenv; + int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; + int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; + if (sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_NARGV failed\n"); + Die(); + } + if (sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_NENV failed\n"); + Die(); + } + if (sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_ARGV failed\n"); + Die(); + } + if (sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_ENV failed\n"); + Die(); + } +} + +char **GetArgv() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return argv; +} + +void ReExec() { + UNIMPLEMENTED(); +} + +} // namespace __sanitizer + +#endif // SANITIZER_OPENBSD Index: lib/sanitizer_common/sanitizer_platform.h =================================================================== --- lib/sanitizer_common/sanitizer_platform.h +++ lib/sanitizer_common/sanitizer_platform.h @@ -14,8 +14,8 @@ #define SANITIZER_PLATFORM_H #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ - !(defined(__sun__) && defined(__svr4__)) + !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \ + !defined(__Fuchsia__) && !(defined(__sun__) && defined(__srv4__)) # error "This operating system is not supported" #endif @@ -37,6 +37,12 @@ # define SANITIZER_NETBSD 0 #endif +#if defined(__OpenBSD__) +# define SANITIZER_OPENBSD 1 +#else +# define SANITIZER_OPENBSD 0 +#endif + #if defined(__sun__) && defined(__svr4__) # define SANITIZER_SOLARIS 1 #else @@ -100,7 +106,7 @@ #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS) + SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 @@ -296,10 +302,19 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS # define SANITIZER_MADVISE_DONTNEED MADV_FREE #else # define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED #endif +// Older gcc have issues aligning to a constexpr, and require an integer. +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56859 among others. +#if defined(__powerpc__) || defined(__powerpc64__) +# define SANITIZER_CACHE_LINE_SIZE 128 +#else +# define SANITIZER_CACHE_LINE_SIZE 64 +#endif + #endif // SANITIZER_PLATFORM_H Index: lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_interceptors.h +++ lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -246,6 +246,10 @@ #define SANITIZER_INTERCEPT_MBSNRTOWCS \ (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX +#define SANITIZER_INTERCEPT_STRXFRM SI_POSIX +#define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX +#define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX +#define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX #define SANITIZER_INTERCEPT_WCSNRTOMBS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_WCRTOMB \ @@ -420,6 +424,8 @@ #define SANITIZER_INTERCEPT_GETLOADAVG \ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_MMAP SI_POSIX +#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) Index: lib/sanitizer_common/sanitizer_platform_limits_netbsd.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -384,8 +384,6 @@ extern int ptrace_pt_get_process_state; extern int ptrace_pt_set_siginfo; extern int ptrace_pt_get_siginfo; -extern int ptrace_pt_set_sigmask; -extern int ptrace_pt_get_sigmask; extern int ptrace_piod_read_d; extern int ptrace_piod_write_d; extern int ptrace_piod_read_i; Index: lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -258,8 +258,6 @@ int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; int ptrace_pt_set_siginfo = PT_SET_SIGINFO; int ptrace_pt_get_siginfo = PT_GET_SIGINFO; -int ptrace_pt_set_sigmask = PT_SET_SIGMASK; -int ptrace_pt_get_sigmask = PT_GET_SIGMASK; int ptrace_piod_read_d = PIOD_READ_D; int ptrace_piod_write_d = PIOD_WRITE_D; int ptrace_piod_read_i = PIOD_READ_I; Index: lib/sanitizer_common/sanitizer_platform_limits_openbsd.h =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_platform_limits_openbsd.h @@ -0,0 +1,382 @@ +//===-- sanitizer_platform_limits_openbsd.h -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific OpenBSD data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_OPENBSD_H +#define SANITIZER_PLATFORM_LIMITS_OPENBSD_H + +#if SANITIZER_OPENBSD + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ + ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) + +#if defined(__x86_64__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312) +#elif defined(__i386__) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164) +#endif + +#define RLIMIT_AS RLIMIT_DATA + +namespace __sanitizer { +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; + +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { + u64 aio_offset; + uptr aio_buf; + long aio_nbytes; + u32 aio_fildes; + u32 aio_lio_opcode; + long aio_reqprio; +#if SANITIZER_WORDSIZE == 64 + u8 aio_sigevent[32]; +#else + u8 aio_sigevent[20]; +#endif + u32 _state; + u32 _errno; + long _retval; +}; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; +}; + +struct __sanitizer_sem_t { + uptr data[5]; +}; + +struct __sanitizer_ipc_perm { + u32 cuid; + u32 cgid; + u32 uid; + u32 gid; + u32 mode; + unsigned short seq; + long key; +}; + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + int shm_segsz; + u32 shm_lpid; + u32 shm_cpid; + short shm_nattch; + u64 shm_atime; + long __shm_atimensec; + u64 shm_dtime; + long __shm_dtimensec; + u64 shm_ctime; + long __shm_ctimensec; + void *_shm_internal; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct __sanitizer_sockaddr *ifa_addr; // (struct sockaddr *) + struct __sanitizer_sockaddr *ifa_netmask; // (struct sockaddr *) + struct __sanitizer_sockaddr *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +typedef long long __sanitizer_time_t; +typedef int __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { + u64 d_fileno; + u64 d_off; + u16 d_reclen; +}; + +typedef u64 __sanitizer_clock_t; +typedef u32 __sanitizer_clockid_t; + +typedef u32 __sanitizer___kernel_uid_t; +typedef u32 __sanitizer___kernel_gid_t; +typedef u64 __sanitizer___kernel_off_t; +typedef struct { + u32 fds_bits[8]; +} __sanitizer___kernel_fd_set; + +typedef struct { + unsigned int pta_magic; + int pta_flags; + void *pta_private; +} __sanitizer_pthread_attr_t; + +typedef unsigned int __sanitizer_sigset_t; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +struct __sanitizer_sigaction { + union { + __sanitizer_sighandler_ptr handler; + __sanitizer_sigactionhandler_ptr sigaction; + }; + __sanitizer_sigset_t sa_mask; + int sa_flags; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, void *info, void *ctx); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { +#if SANITIZER_WORDSIZE == 64 + u64 dlpi_addr; +#else + u32 dlpi_addr; +#endif + const char *dlpi_name; + const void *dlpi_phdr; +#if SANITIZER_WORDSIZE == 64 + u32 dlpi_phnum; +#else + u16 dlpi_phnum; +#endif +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + unsigned ai_addrlen; + struct __sanitizer_sockaddr *ai_addr; + char *ai_canonname; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + int gl_pathc; + int gl_matchc; + int gl_offs; + int gl_flags; + char **gl_pathv; + void **gl_statv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; + +extern unsigned path_max; + +typedef char __sanitizer_FILE; +#define SANITIZER_HAS_STRUCT_FILE 0 + +extern int shmctl_ipc_stat; + +// This simplifies generic code +#define struct_shminfo_sz -1 +#define struct_shm_info_sz -1 +#define shmctl_shm_stat -1 +#define shmctl_ipc_info -1 +#define shmctl_shm_info -1 + +extern unsigned struct_utmp_sz; +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; +} // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +#define SIGACTION_SYMNAME __sigaction14 + +#endif // SANITIZER_OPENBSD + +#endif Index: lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc @@ -0,0 +1,279 @@ +//===-- sanitizer_platform_limits_openbsd.cc ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_OPENBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_openbsd.h" + +namespace __sanitizer { +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_statvfs_sz = sizeof(struct statvfs); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +CHECK_TYPE_SIZE(dl_phdr_info); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_off); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#endif // SANITIZER_OPENBSD Index: lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -24,7 +24,7 @@ // FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that // incorporates the map structure. # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544))) + ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560))) // Get sys/_types.h, because that tells us whether 64-bit inodes are // used in struct dirent below. #include Index: lib/sanitizer_common/sanitizer_posix.h =================================================================== --- lib/sanitizer_common/sanitizer_posix.h +++ lib/sanitizer_common/sanitizer_posix.h @@ -17,6 +17,7 @@ // This header should NOT include any other headers from sanitizer runtime. #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_platform_limits_solaris.h" Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -19,6 +19,7 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_platform_limits_solaris.h" #include "sanitizer_posix.h" @@ -42,7 +43,7 @@ #if SANITIZER_FREEBSD // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before // that, it was never implemented. So just define it to zero. -#undef MAP_NORESERVE +#undef MAP_NORESERVE #define MAP_NORESERVE 0 #endif Index: lib/sanitizer_common/sanitizer_stacktrace.h =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace.h +++ lib/sanitizer_common/sanitizer_stacktrace.h @@ -23,6 +23,8 @@ # define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS # define SANITIZER_CAN_FAST_UNWIND 0 +#elif SANITIZER_OPENBSD +# define SANITIZER_CAN_FAST_UNWIND 0 #else # define SANITIZER_CAN_FAST_UNWIND 1 #endif @@ -30,7 +32,7 @@ // Fast unwind is the only option on Mac for now; we will need to // revisit this macro when slow unwind works on Mac, see // https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC +#if SANITIZER_MAC || SANITIZER_OPENBSD # define SANITIZER_CAN_SLOW_UNWIND 0 #else # define SANITIZER_CAN_SLOW_UNWIND 1 Index: lib/sanitizer_common/sanitizer_syscall_generic.inc =================================================================== --- lib/sanitizer_common/sanitizer_syscall_generic.inc +++ lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -11,7 +11,8 @@ // //===----------------------------------------------------------------------===// -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name Index: lib/sanitizer_common/sanitizer_syscalls_netbsd.inc =================================================================== --- lib/sanitizer_common/sanitizer_syscalls_netbsd.inc +++ lib/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -43,7 +43,7 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2018-02-15 +// Generated date: 2018-03-03 // Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp // //===----------------------------------------------------------------------===// @@ -324,10 +324,6 @@ PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); } else if (req_ == ptrace_pt_get_siginfo) { PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); - } else if (req_ == ptrace_pt_set_sigmask) { - PRE_READ(addr_, sizeof(__sanitizer_sigset_t)); - } else if (req_ == ptrace_pt_get_sigmask) { - PRE_WRITE(addr_, sizeof(__sanitizer_sigset_t)); } else if (req_ == ptrace_pt_setregs) { PRE_READ(addr_, struct_ptrace_reg_struct_sz); } else if (req_ == ptrace_pt_getregs) { @@ -371,10 +367,6 @@ POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); } else if (req_ == ptrace_pt_get_siginfo) { POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); - } else if (req_ == ptrace_pt_set_sigmask) { - POST_READ(addr_, sizeof(__sanitizer_sigset_t)); - } else if (req_ == ptrace_pt_get_sigmask) { - POST_WRITE(addr_, sizeof(__sanitizer_sigset_t)); } else if (req_ == ptrace_pt_setregs) { POST_READ(addr_, struct_ptrace_reg_struct_sz); } else if (req_ == ptrace_pt_getregs) { Index: lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh =================================================================== --- lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +++ lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh @@ -129,7 +129,7 @@ $LLVM_SRC fi cd ${LLVM_BUILD} -ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC +ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC LLVMDemangle cd ${BUILD_DIR} rm -rf ${SYMBOLIZER_BUILD} @@ -152,6 +152,7 @@ $LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \ $LLVM_BUILD/lib/libLLVMSupport.a \ $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ + $LLVM_BUILD/lib/libLLVMDemangle.a \ $LLVM_BUILD/lib/libLLVMMC.a \ $ZLIB_BUILD/libz.a \ symbolizer.a \ Index: lib/sanitizer_common/symbolizer/scripts/global_symbols.txt =================================================================== --- lib/sanitizer_common/symbolizer/scripts/global_symbols.txt +++ lib/sanitizer_common/symbolizer/scripts/global_symbols.txt @@ -61,6 +61,7 @@ ioctl U isalpha U isatty U +islower U isprint U isupper U isxdigit U Index: lib/scudo/CMakeLists.txt =================================================================== --- lib/scudo/CMakeLists.txt +++ lib/scudo/CMakeLists.txt @@ -9,6 +9,10 @@ set(SCUDO_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) +# Use gc-sections by default to avoid unused code being pulled in. +list(APPEND SCUDO_CFLAGS -ffunction-sections -fdata-sections) +list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -Wl,--gc-sections) + set(SCUDO_SOURCES scudo_allocator.cpp scudo_crc32.cpp Index: lib/scudo/scudo_allocator.cpp =================================================================== --- lib/scudo/scudo_allocator.cpp +++ lib/scudo/scudo_allocator.cpp @@ -64,14 +64,6 @@ static ScudoBackendAllocator &getBackendAllocator(); namespace Chunk { - // We can't use the offset member of the chunk itself, as we would double - // fetch it without any warranty that it wouldn't have been tampered. To - // prevent this, we work with a local copy of the header. - static INLINE void *getBackendPtr(const void *Ptr, UnpackedHeader *Header) { - return reinterpret_cast(reinterpret_cast(Ptr) - - getHeaderSize() - (Header->Offset << MinAlignmentLog)); - } - static INLINE AtomicPackedHeader *getAtomicHeader(void *Ptr) { return reinterpret_cast(reinterpret_cast(Ptr) - getHeaderSize()); @@ -86,13 +78,32 @@ return IsAligned(reinterpret_cast(Ptr), MinAlignment); } + // We can't use the offset member of the chunk itself, as we would double + // fetch it without any warranty that it wouldn't have been tampered. To + // prevent this, we work with a local copy of the header. + static INLINE void *getBackendPtr(const void *Ptr, UnpackedHeader *Header) { + return reinterpret_cast(reinterpret_cast(Ptr) - + getHeaderSize() - (Header->Offset << MinAlignmentLog)); + } + // Returns the usable size for a chunk, meaning the amount of bytes from the // beginning of the user data to the end of the backend allocated chunk. static INLINE uptr getUsableSize(const void *Ptr, UnpackedHeader *Header) { - const uptr Size = getBackendAllocator().getActuallyAllocatedSize( - getBackendPtr(Ptr, Header), Header->ClassId); - DCHECK_NE(Size, 0); - return Size - getHeaderSize() - (Header->Offset << MinAlignmentLog); + const uptr ClassId = Header->ClassId; + if (ClassId) + return PrimaryAllocator::ClassIdToSize(ClassId) - getHeaderSize() - + (Header->Offset << MinAlignmentLog); + return SecondaryAllocator::GetActuallyAllocatedSize( + getBackendPtr(Ptr, Header)) - getHeaderSize(); + } + + // Returns the size the user requested when allocating the chunk. + static INLINE uptr getSize(const void *Ptr, UnpackedHeader *Header) { + const uptr SizeOrUnusedBytes = Header->SizeOrUnusedBytes; + if (Header->ClassId) + return SizeOrUnusedBytes; + return SecondaryAllocator::GetActuallyAllocatedSize( + getBackendPtr(Ptr, Header)) - getHeaderSize() - SizeOrUnusedBytes; } // Compute the checksum of the chunk pointer and its header. @@ -135,9 +146,8 @@ atomic_load_relaxed(getConstAtomicHeader(Ptr)); *NewUnpackedHeader = bit_cast(NewPackedHeader); if (UNLIKELY(NewUnpackedHeader->Checksum != - computeChecksum(Ptr, NewUnpackedHeader))) { - dieWithMessage("ERROR: corrupted chunk header at address %p\n", Ptr); - } + computeChecksum(Ptr, NewUnpackedHeader))) + dieWithMessage("corrupted chunk header at address %p\n", Ptr); } // Packs and stores the header, computing the checksum in the process. @@ -158,9 +168,8 @@ PackedHeader OldPackedHeader = bit_cast(*OldUnpackedHeader); if (UNLIKELY(!atomic_compare_exchange_strong( getAtomicHeader(Ptr), &OldPackedHeader, NewPackedHeader, - memory_order_relaxed))) { - dieWithMessage("ERROR: race on chunk header at address %p\n", Ptr); - } + memory_order_relaxed))) + dieWithMessage("race on chunk header at address %p\n", Ptr); } } // namespace Chunk @@ -173,10 +182,8 @@ void Recycle(void *Ptr) { UnpackedHeader Header; Chunk::loadHeader(Ptr, &Header); - if (UNLIKELY(Header.State != ChunkQuarantine)) { - dieWithMessage("ERROR: invalid chunk state when recycling address %p\n", - Ptr); - } + if (UNLIKELY(Header.State != ChunkQuarantine)) + dieWithMessage("invalid chunk state when recycling address %p\n", Ptr); Chunk::eraseHeader(Ptr); void *BackendPtr = Chunk::getBackendPtr(Ptr, &Header); if (Header.ClassId) @@ -236,7 +243,7 @@ explicit ScudoAllocator(LinkerInitialized) : AllocatorQuarantine(LINKER_INITIALIZED) {} - void performSanityChecks() { + NOINLINE void performSanityChecks() { // Verify that the header offset field can hold the maximum offset. In the // case of the Secondary allocator, it takes care of alignment and the // offset will always be 0. In the case of the Primary, the worst case @@ -251,10 +258,8 @@ const uptr MaxOffset = (MaxPrimaryAlignment - Chunk::getHeaderSize()) >> MinAlignmentLog; Header.Offset = MaxOffset; - if (Header.Offset != MaxOffset) { - dieWithMessage("ERROR: the maximum possible offset doesn't fit in the " - "header\n"); - } + if (Header.Offset != MaxOffset) + dieWithMessage("maximum possible offset doesn't fit in header\n"); // Verify that we can fit the maximum size or amount of unused bytes in the // header. Given that the Secondary fits the allocation to a page, the worst // case scenario happens in the Primary. It will depend on the second to @@ -262,16 +267,13 @@ // The following is an over-approximation that works for our needs. const uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1; Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes; - if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) { - dieWithMessage("ERROR: the maximum possible unused bytes doesn't fit in " - "the header\n"); - } + if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) + dieWithMessage("maximum possible unused bytes doesn't fit in header\n"); const uptr LargestClassId = SizeClassMap::kLargestClassID; Header.ClassId = LargestClassId; - if (Header.ClassId != LargestClassId) { - dieWithMessage("ERROR: the largest class ID doesn't fit in the header\n"); - } + if (Header.ClassId != LargestClassId) + dieWithMessage("largest class ID doesn't fit in header\n"); } void init() { @@ -332,12 +334,9 @@ // RSS from /proc/self/statm by default. We might want to // call getrusage directly, even if it's less accurate. const uptr CurrentRssMb = GetRSS() >> 20; - if (HardRssLimitMb && HardRssLimitMb < CurrentRssMb) { - Report("%s: hard RSS limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, HardRssLimitMb, CurrentRssMb); - DumpProcessMap(); - Die(); - } + if (HardRssLimitMb && UNLIKELY(HardRssLimitMb < CurrentRssMb)) + dieWithMessage("hard RSS limit exhausted (%zdMb vs %zdMb)\n", + HardRssLimitMb, CurrentRssMb); if (SoftRssLimitMb) { if (atomic_load_relaxed(&RssLimitExceeded)) { if (CurrentRssMb <= SoftRssLimitMb) @@ -345,8 +344,8 @@ } else { if (CurrentRssMb > SoftRssLimitMb) { atomic_store_relaxed(&RssLimitExceeded, true); - Report("%s: soft RSS limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, SoftRssLimitMb, CurrentRssMb); + Printf("Scudo INFO: soft RSS limit exhausted (%zdMb vs %zdMb)\n", + SoftRssLimitMb, CurrentRssMb); } } } @@ -398,8 +397,7 @@ // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && ClassId) - memset(BackendPtr, 0, - BackendAllocator.getActuallyAllocatedSize(BackendPtr, ClassId)); + memset(BackendPtr, 0, PrimaryAllocator::ClassIdToSize(ClassId)); UnpackedHeader Header = {}; uptr UserPtr = reinterpret_cast(BackendPtr) + Chunk::getHeaderSize(); @@ -412,7 +410,7 @@ Header.Offset = (AlignedUserPtr - UserPtr) >> MinAlignmentLog; UserPtr = AlignedUserPtr; } - CHECK_LE(UserPtr + Size, reinterpret_cast(BackendPtr) + BackendSize); + DCHECK_LE(UserPtr + Size, reinterpret_cast(BackendPtr) + BackendSize); Header.State = ChunkAllocated; Header.AllocType = Type; if (ClassId) { @@ -458,7 +456,7 @@ // with tiny chunks, taking a lot of VA memory. This is an approximation // of the usable size, that allows us to not call // GetActuallyAllocatedSize. - uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog); + const uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog); UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk::compareExchangeHeader(Ptr, &NewHeader, Header); @@ -484,33 +482,26 @@ __sanitizer_free_hook(Ptr); if (UNLIKELY(!Ptr)) return; - if (UNLIKELY(!Chunk::isAligned(Ptr))) { - dieWithMessage("ERROR: attempted to deallocate a chunk not properly " - "aligned at address %p\n", Ptr); - } + if (UNLIKELY(!Chunk::isAligned(Ptr))) + dieWithMessage("misaligned pointer when deallocating address %p\n", Ptr); UnpackedHeader Header; Chunk::loadHeader(Ptr, &Header); - if (UNLIKELY(Header.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when deallocating address " - "%p\n", Ptr); - } + if (UNLIKELY(Header.State != ChunkAllocated)) + dieWithMessage("invalid chunk state when deallocating address %p\n", Ptr); if (DeallocationTypeMismatch) { // The deallocation type has to match the allocation one. if (Header.AllocType != Type) { // With the exception of memalign'd Chunks, that can be still be free'd. - if (Header.AllocType != FromMemalign || Type != FromMalloc) { - dieWithMessage("ERROR: allocation type mismatch when deallocating " - "address %p\n", Ptr); - } + if (Header.AllocType != FromMemalign || Type != FromMalloc) + dieWithMessage("allocation type mismatch when deallocating address " + "%p\n", Ptr); } } - const uptr Size = Header.ClassId ? Header.SizeOrUnusedBytes : - Chunk::getUsableSize(Ptr, &Header) - Header.SizeOrUnusedBytes; + const uptr Size = Chunk::getSize(Ptr, &Header); if (DeleteSizeMismatch) { - if (DeleteSize && DeleteSize != Size) { - dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", + if (DeleteSize && DeleteSize != Size) + dieWithMessage("invalid sized delete when deallocating address %p\n", Ptr); - } } quarantineOrDeallocateChunk(Ptr, &Header, Size); } @@ -519,21 +510,18 @@ // size still fits in the chunk. void *reallocate(void *OldPtr, uptr NewSize) { initThreadMaybe(); - if (UNLIKELY(!Chunk::isAligned(OldPtr))) { - dieWithMessage("ERROR: attempted to reallocate a chunk not properly " - "aligned at address %p\n", OldPtr); - } + if (UNLIKELY(!Chunk::isAligned(OldPtr))) + dieWithMessage("misaligned address when reallocating address %p\n", + OldPtr); UnpackedHeader OldHeader; Chunk::loadHeader(OldPtr, &OldHeader); - if (UNLIKELY(OldHeader.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when reallocating address " - "%p\n", OldPtr); - } + if (UNLIKELY(OldHeader.State != ChunkAllocated)) + dieWithMessage("invalid chunk state when reallocating address %p\n", + OldPtr); if (DeallocationTypeMismatch) { - if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { - dieWithMessage("ERROR: allocation type mismatch when reallocating " - "address %p\n", OldPtr); - } + if (UNLIKELY(OldHeader.AllocType != FromMalloc)) + dieWithMessage("allocation type mismatch when reallocating address " + "%p\n", OldPtr); } const uptr UsableSize = Chunk::getUsableSize(OldPtr, &OldHeader); // The new size still fits in the current chunk, and the size difference @@ -550,7 +538,7 @@ // old one. void *NewPtr = allocate(NewSize, MinAlignment, FromMalloc); if (NewPtr) { - uptr OldSize = OldHeader.ClassId ? OldHeader.SizeOrUnusedBytes : + const uptr OldSize = OldHeader.ClassId ? OldHeader.SizeOrUnusedBytes : UsableSize - OldHeader.SizeOrUnusedBytes; memcpy(NewPtr, OldPtr, Min(NewSize, UsableSize)); quarantineOrDeallocateChunk(OldPtr, &OldHeader, OldSize); @@ -566,10 +554,8 @@ UnpackedHeader Header; Chunk::loadHeader(Ptr, &Header); // Getting the usable size of a chunk only makes sense if it's allocated. - if (UNLIKELY(Header.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when sizing address %p\n", - Ptr); - } + if (UNLIKELY(Header.State != ChunkAllocated)) + dieWithMessage("invalid chunk state when sizing address %p\n", Ptr); return Chunk::getUsableSize(Ptr, &Header); } Index: lib/scudo/scudo_allocator_combined.h =================================================================== --- lib/scudo/scudo_allocator_combined.h +++ lib/scudo/scudo_allocator_combined.h @@ -49,12 +49,6 @@ Secondary.Deallocate(&Stats, Ptr); } - uptr getActuallyAllocatedSize(void *Ptr, uptr ClassId) { - if (ClassId) - return PrimaryAllocator::ClassIdToSize(ClassId); - return Secondary.GetActuallyAllocatedSize(Ptr); - } - void initCache(AllocatorCache *Cache) { Cache->Init(&Stats); } Index: lib/scudo/scudo_allocator_secondary.h =================================================================== --- lib/scudo/scudo_allocator_secondary.h +++ lib/scudo/scudo_allocator_secondary.h @@ -21,120 +21,177 @@ # error "This file must be included inside scudo_allocator.h." #endif +// Secondary backed allocations are standalone chunks that contain extra +// information stored in a LargeChunk::Header prior to the frontend's header. +// +// The secondary takes care of alignment requirements (so that it can release +// unnecessary pages in the rare event of larger alignments), and as such must +// know about the frontend's header size. +// +// Since Windows doesn't support partial releasing of a reserved memory region, +// we have to keep track of both the reserved and the committed memory. +// +// The resulting chunk resembles the following: +// +// +--------------------+ +// | Guard page(s) | +// +--------------------+ +// | Unused space* | +// +--------------------+ +// | LargeChunk::Header | +// +--------------------+ +// | {Unp,P}ackedHeader | +// +--------------------+ +// | Data (aligned) | +// +--------------------+ +// | Unused space** | +// +--------------------+ +// | Guard page(s) | +// +--------------------+ + +namespace LargeChunk { + struct Header { + ReservedAddressRange StoredRange; + uptr CommittedSize; + uptr Size; + }; + constexpr uptr getHeaderSize() { + return RoundUpTo(sizeof(Header), MinAlignment); + } + static Header *getHeader(uptr Ptr) { + return reinterpret_cast
(Ptr - getHeaderSize()); + } + static Header *getHeader(const void *Ptr) { + return getHeader(reinterpret_cast(Ptr)); + } +} // namespace LargeChunk + class ScudoLargeMmapAllocator { public: void Init() { - PageSizeCached = GetPageSizeCached(); + NumberOfAllocs = 0; + NumberOfFrees = 0; + AllocatedBytes = 0; + FreedBytes = 0; + LargestSize = 0; } void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) { const uptr UserSize = Size - Chunk::getHeaderSize(); // The Scudo frontend prevents us from allocating more than // MaxAllowedMallocSize, so integer overflow checks would be superfluous. - uptr MapSize = Size + AlignedReservedAddressRangeSize; - if (Alignment > MinAlignment) - MapSize += Alignment; - const uptr PageSize = PageSizeCached; - MapSize = RoundUpTo(MapSize, PageSize); + uptr ReservedSize = Size + LargeChunk::getHeaderSize(); + if (UNLIKELY(Alignment > MinAlignment)) + ReservedSize += Alignment; + const uptr PageSize = GetPageSizeCached(); + ReservedSize = RoundUpTo(ReservedSize, PageSize); // Account for 2 guard pages, one before and one after the chunk. - MapSize += 2 * PageSize; + ReservedSize += 2 * PageSize; ReservedAddressRange AddressRange; - uptr MapBeg = AddressRange.Init(MapSize); - if (UNLIKELY(MapBeg == ~static_cast(0))) + uptr ReservedBeg = AddressRange.Init(ReservedSize); + if (UNLIKELY(ReservedBeg == ~static_cast(0))) return ReturnNullOrDieOnFailure::OnOOM(); // A page-aligned pointer is assumed after that, so check it now. - CHECK(IsAligned(MapBeg, PageSize)); - uptr MapEnd = MapBeg + MapSize; + DCHECK(IsAligned(ReservedBeg, PageSize)); + uptr ReservedEnd = ReservedBeg + ReservedSize; // The beginning of the user area for that allocation comes after the // initial guard page, and both headers. This is the pointer that has to // abide by alignment requirements. - uptr UserBeg = MapBeg + PageSize + HeadersSize; + uptr CommittedBeg = ReservedBeg + PageSize; + uptr UserBeg = CommittedBeg + HeadersSize; uptr UserEnd = UserBeg + UserSize; + uptr CommittedEnd = RoundUpTo(UserEnd, PageSize); // In the rare event of larger alignments, we will attempt to fit the mmap // area better and unmap extraneous memory. This will also ensure that the // offset and unused bytes field of the header stay small. - if (Alignment > MinAlignment) { + if (UNLIKELY(Alignment > MinAlignment)) { if (!IsAligned(UserBeg, Alignment)) { UserBeg = RoundUpTo(UserBeg, Alignment); - DCHECK_GE(UserBeg, MapBeg); - const uptr NewMapBeg = RoundDownTo(UserBeg - HeadersSize, PageSize) - - PageSize; - DCHECK_GE(NewMapBeg, MapBeg); - if (NewMapBeg != MapBeg) { - AddressRange.Unmap(MapBeg, NewMapBeg - MapBeg); - MapBeg = NewMapBeg; + CommittedBeg = RoundDownTo(UserBeg - HeadersSize, PageSize); + const uptr NewReservedBeg = CommittedBeg - PageSize; + DCHECK_GE(NewReservedBeg, ReservedBeg); + if (!SANITIZER_WINDOWS && NewReservedBeg != ReservedBeg) { + AddressRange.Unmap(ReservedBeg, NewReservedBeg - ReservedBeg); + ReservedBeg = NewReservedBeg; } UserEnd = UserBeg + UserSize; + CommittedEnd = RoundUpTo(UserEnd, PageSize); } - const uptr NewMapEnd = RoundUpTo(UserEnd, PageSize) + PageSize; - if (NewMapEnd != MapEnd) { - AddressRange.Unmap(NewMapEnd, MapEnd - NewMapEnd); - MapEnd = NewMapEnd; + const uptr NewReservedEnd = CommittedEnd + PageSize; + DCHECK_LE(NewReservedEnd, ReservedEnd); + if (!SANITIZER_WINDOWS && NewReservedEnd != ReservedEnd) { + AddressRange.Unmap(NewReservedEnd, ReservedEnd - NewReservedEnd); + ReservedEnd = NewReservedEnd; } - MapSize = MapEnd - MapBeg; } - DCHECK_LE(UserEnd, MapEnd - PageSize); - // Actually mmap the memory, preserving the guard pages on either side - CHECK_EQ(MapBeg + PageSize, - AddressRange.Map(MapBeg + PageSize, MapSize - 2 * PageSize)); + DCHECK_LE(UserEnd, CommittedEnd); + const uptr CommittedSize = CommittedEnd - CommittedBeg; + // Actually mmap the memory, preserving the guard pages on either sides. + CHECK_EQ(CommittedBeg, AddressRange.Map(CommittedBeg, CommittedSize)); const uptr Ptr = UserBeg - Chunk::getHeaderSize(); - ReservedAddressRange *StoredRange = getReservedAddressRange(Ptr); - *StoredRange = AddressRange; + LargeChunk::Header *H = LargeChunk::getHeader(Ptr); + H->StoredRange = AddressRange; + H->Size = CommittedEnd - Ptr; + H->CommittedSize = CommittedSize; // The primary adds the whole class size to the stats when allocating a // chunk, so we will do something similar here. But we will not account for // the guard pages. { SpinMutexLock l(&StatsMutex); - Stats->Add(AllocatorStatAllocated, MapSize - 2 * PageSize); - Stats->Add(AllocatorStatMapped, MapSize - 2 * PageSize); + Stats->Add(AllocatorStatAllocated, CommittedSize); + Stats->Add(AllocatorStatMapped, CommittedSize); + AllocatedBytes += CommittedSize; + if (LargestSize < CommittedSize) + LargestSize = CommittedSize; + NumberOfAllocs++; } return reinterpret_cast(Ptr); } void Deallocate(AllocatorStats *Stats, void *Ptr) { + LargeChunk::Header *H = LargeChunk::getHeader(Ptr); // Since we're unmapping the entirety of where the ReservedAddressRange // actually is, copy onto the stack. - const uptr PageSize = PageSizeCached; - ReservedAddressRange AddressRange = *getReservedAddressRange(Ptr); + ReservedAddressRange AddressRange = H->StoredRange; + const uptr Size = H->CommittedSize; { SpinMutexLock l(&StatsMutex); - Stats->Sub(AllocatorStatAllocated, AddressRange.size() - 2 * PageSize); - Stats->Sub(AllocatorStatMapped, AddressRange.size() - 2 * PageSize); + Stats->Sub(AllocatorStatAllocated, Size); + Stats->Sub(AllocatorStatMapped, Size); + FreedBytes += Size; + NumberOfFrees++; } AddressRange.Unmap(reinterpret_cast(AddressRange.base()), AddressRange.size()); } - uptr GetActuallyAllocatedSize(void *Ptr) { - const ReservedAddressRange *StoredRange = getReservedAddressRange(Ptr); - // Deduct PageSize as ReservedAddressRange size includes the trailing guard - // page. - const uptr MapEnd = reinterpret_cast(StoredRange->base()) + - StoredRange->size() - PageSizeCached; - return MapEnd - reinterpret_cast(Ptr); + static uptr GetActuallyAllocatedSize(void *Ptr) { + return LargeChunk::getHeader(Ptr)->Size; } - private: - ReservedAddressRange *getReservedAddressRange(uptr Ptr) { - return reinterpret_cast( - Ptr - sizeof(ReservedAddressRange)); - } - ReservedAddressRange *getReservedAddressRange(const void *Ptr) { - return getReservedAddressRange(reinterpret_cast(Ptr)); + void PrintStats() { + Printf("Stats: LargeMmapAllocator: allocated %zd times (%zd K), " + "freed %zd times (%zd K), remains %zd (%zd K) max %zd M\n", + NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees, + FreedBytes >> 10, NumberOfAllocs - NumberOfFrees, + (AllocatedBytes - FreedBytes) >> 10, LargestSize >> 20); } - static constexpr uptr AlignedReservedAddressRangeSize = - RoundUpTo(sizeof(ReservedAddressRange), MinAlignment); + private: static constexpr uptr HeadersSize = - AlignedReservedAddressRangeSize + Chunk::getHeaderSize(); + LargeChunk::getHeaderSize() + Chunk::getHeaderSize(); - uptr PageSizeCached; SpinMutex StatsMutex; + u32 NumberOfAllocs; + u32 NumberOfFrees; + uptr AllocatedBytes; + uptr FreedBytes; + uptr LargestSize; }; #endif // SCUDO_ALLOCATOR_SECONDARY_H_ Index: lib/scudo/scudo_termination.cpp =================================================================== --- lib/scudo/scudo_termination.cpp +++ lib/scudo/scudo_termination.cpp @@ -35,7 +35,7 @@ void NORETURN CheckFailed(const char *File, int Line, const char *Condition, u64 Value1, u64 Value2) { - __scudo::dieWithMessage("Scudo CHECK failed: %s:%d %s (%lld, %lld)\n", + __scudo::dieWithMessage("CHECK failed at %s:%d %s (%lld, %lld)\n", File, Line, Condition, Value1, Value2); } Index: lib/scudo/scudo_utils.cpp =================================================================== --- lib/scudo/scudo_utils.cpp +++ lib/scudo/scudo_utils.cpp @@ -38,11 +38,14 @@ namespace __scudo { FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) { + static const char ScudoError[] = "Scudo ERROR: "; + static constexpr uptr PrefixSize = sizeof(ScudoError) - 1; // Our messages are tiny, 256 characters is more than enough. char Message[256]; va_list Args; va_start(Args, Format); - VSNPrintf(Message, sizeof(Message), Format, Args); + internal_memcpy(Message, ScudoError, PrefixSize); + VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args); va_end(Args); RawWrite(Message); Die(); Index: lib/tsan/CMakeLists.txt =================================================================== --- lib/tsan/CMakeLists.txt +++ lib/tsan/CMakeLists.txt @@ -214,7 +214,7 @@ DEPS ${TSAN_RUNTIME_LIBRARIES} CFLAGS ${TARGET_CFLAGS} -fsanitize=thread USE_TOOLCHAIN) - list(APPEND libcxx_tsan_deps libcxx_tsan_${arch}-install) + list(APPEND libcxx_tsan_deps libcxx_tsan_${arch}-build) endforeach() add_custom_target(libcxx_tsan DEPENDS ${libcxx_tsan_deps}) Index: lib/tsan/go/test.c =================================================================== --- lib/tsan/go/test.c +++ lib/tsan/go/test.c @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include +#include #include #include @@ -44,7 +46,13 @@ } } -char buf0[100<<10]; +/* + * See lib/tsan/rtl/tsan_platform.h for details of what the memory layout + * of Go programs looks like. To prevent running over existing mappings, + * we pick an address slightly inside the Go heap region. + */ +void *go_heap = (void *)0xC011110000; +char *buf0; void foobar() {} void barfoo() {} @@ -54,6 +62,15 @@ void *proc0 = 0; __tsan_init(&thr0, &proc0, symbolize_cb); current_proc = proc0; + + // Allocate something resembling a heap in Go. + buf0 = mmap(go_heap, 16384, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); + if (buf0 == MAP_FAILED) { + fprintf(stderr, "failed to allocate Go-like heap at %p; errno %d\n", + go_heap, errno); + return 1; + } char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1)); __tsan_map_shadow(buf, 4096); __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -760,35 +760,14 @@ return true; } -TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF_T off) { - SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off); - if (!fix_mmap_addr(&addr, sz, flags)) - return MAP_FAILED; - void *res = REAL(mmap)(addr, sz, prot, flags, fd, off); +template +static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, + void *addr, SIZE_T sz, int prot, int flags, + int fd, OFF64_T off) { + if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; + void *res = real_mmap(addr, sz, prot, flags, fd, off); if (res != MAP_FAILED) { - if (fd > 0) - FdAccess(thr, pc, fd); - - if (thr->ignore_reads_and_writes == 0) - MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); - else - MemoryResetRange(thr, pc, (uptr)res, sz); - } - return res; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF64_T off) { - SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off); - if (!fix_mmap_addr(&addr, sz, flags)) - return MAP_FAILED; - void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off); - if (res != MAP_FAILED) { - if (fd > 0) - FdAccess(thr, pc, fd); - + if (fd > 0) FdAccess(thr, pc, fd); if (thr->ignore_reads_and_writes == 0) MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); else @@ -796,10 +775,6 @@ } return res; } -#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64) -#else -#define TSAN_MAYBE_INTERCEPT_MMAP64 -#endif TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); @@ -2311,6 +2286,13 @@ MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + do { \ + return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ + off); \ + } while (false) + #if !SANITIZER_MAC #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ @@ -2635,8 +2617,6 @@ TSAN_INTERCEPT(realloc); TSAN_INTERCEPT(free); TSAN_INTERCEPT(cfree); - TSAN_INTERCEPT(mmap); - TSAN_MAYBE_INTERCEPT_MMAP64; TSAN_INTERCEPT(munmap); TSAN_MAYBE_INTERCEPT_MEMALIGN; TSAN_INTERCEPT(valloc); Index: lib/tsan/rtl/tsan_malloc_mac.cc =================================================================== --- lib/tsan/rtl/tsan_malloc_mac.cc +++ lib/tsan/rtl/tsan_malloc_mac.cc @@ -15,6 +15,7 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_MAC +#include "sanitizer_common/sanitizer_errno.h" #include "tsan_interceptors.h" #include "tsan_stack_trace.h" @@ -39,6 +40,15 @@ if (cur_thread()->in_symbolizer) return InternalCalloc(count, size); \ SCOPED_INTERCEPTOR_RAW(calloc, size, count); \ void *p = user_calloc(thr, pc, size, count) +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ + if (cur_thread()->in_symbolizer) { \ + void *p = InternalAlloc(size, nullptr, alignment); \ + if (!p) return errno_ENOMEM; \ + *memptr = p; \ + return 0; \ + } \ + SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, alignment, size); \ + int res = user_posix_memalign(thr, pc, memptr, alignment, size); #define COMMON_MALLOC_VALLOC(size) \ if (cur_thread()->in_symbolizer) \ return InternalAlloc(size, nullptr, GetPageSizeCached()); \ Index: lib/xray/tests/CMakeLists.txt =================================================================== --- lib/xray/tests/CMakeLists.txt +++ lib/xray/tests/CMakeLists.txt @@ -3,6 +3,12 @@ add_custom_target(XRayUnitTests) set_target_properties(XRayUnitTests PROPERTIES FOLDER "XRay unittests") +# Create an XRAY_IMPL_FILES variable which will include all the implementation +# files that are in the lib directory. Unfortunately, when new files are added +# to the implementation, CMake must be run so that this variable is +# re-generated. +file(GLOB XRAY_IMPL_FILES "../*.cc" "../*.h") + set(XRAY_UNITTEST_CFLAGS ${XRAY_CFLAGS} ${COMPILER_RT_UNITTEST_CFLAGS} @@ -24,6 +30,11 @@ generate_compiler_rt_tests(TEST_OBJECTS XRayUnitTests "${testname}-${arch}-Test" "${arch}" SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} + # Note that any change in the implementations will cause all the unit + # tests to be re-built. This is by design, but may be cumbersome during + # the build/test cycle. + COMPILE_DEPS ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} + ${XRAY_HEADERS} ${XRAY_IMPL_FILES} DEPS gtest xray llvm-xray CFLAGS ${XRAY_UNITTEST_CFLAGS} LINK_FLAGS -fxray-instrument Index: lib/xray/xray_log_interface.cc =================================================================== --- lib/xray/xray_log_interface.cc +++ lib/xray/xray_log_interface.cc @@ -18,9 +18,20 @@ #include "xray/xray_interface.h" #include "xray_defs.h" -__sanitizer::SpinMutex XRayImplMutex; -XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr}; -XRayLogImpl *GlobalXRayImpl = nullptr; +namespace __xray { +static __sanitizer::SpinMutex XRayImplMutex; +static XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr}; +static XRayLogImpl *GlobalXRayImpl = nullptr; + +// This is the default implementation of a buffer iterator, which always yields +// a null buffer. +XRayBuffer NullBufferIterator(XRayBuffer) XRAY_NEVER_INSTRUMENT { + return {nullptr, 0}; +} + +// This is the global function responsible for iterating through given buffers. +__sanitizer::atomic_uintptr_t XRayBufferIterator{ + reinterpret_cast(&NullBufferIterator)}; // We use a linked list of Mode to XRayLogImpl mappings. This is a linked list // when it should be a map because we're avoiding having to depend on C++ @@ -31,9 +42,25 @@ XRayLogImpl Impl; }; -ModeImpl SentinelModeImpl{ +static ModeImpl SentinelModeImpl{ nullptr, nullptr, {nullptr, nullptr, nullptr, nullptr}}; -ModeImpl *ModeImpls = &SentinelModeImpl; +static ModeImpl *ModeImpls = &SentinelModeImpl; +static const ModeImpl *CurrentMode = nullptr; + +} // namespace __xray + +using namespace __xray; + +void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer)) + XRAY_NEVER_INSTRUMENT { + __sanitizer::atomic_store(&__xray::XRayBufferIterator, + reinterpret_cast(Iterator), + __sanitizer::memory_order_release); +} + +void __xray_log_remove_buffer_iterator() XRAY_NEVER_INSTRUMENT { + __xray_log_set_buffer_iterator(&NullBufferIterator); +} XRayLogRegisterStatus __xray_log_register_mode(const char *Mode, @@ -62,6 +89,7 @@ __sanitizer::SpinMutexLock Guard(&XRayImplMutex); for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) { if (!__sanitizer::internal_strcmp(Mode, it->Mode)) { + CurrentMode = it; CurrentXRayImpl = it->Impl; GlobalXRayImpl = &CurrentXRayImpl; __xray_set_handler(it->Impl.handle_arg0); @@ -71,11 +99,19 @@ return XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND; } +const char *__xray_log_get_current_mode() XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); + if (CurrentMode != nullptr) + return CurrentMode->Mode; + return nullptr; +} + void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT { if (Impl.log_init == nullptr || Impl.log_finalize == nullptr || Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); GlobalXRayImpl = nullptr; + CurrentMode = nullptr; __xray_remove_handler(); __xray_remove_handler_arg1(); return; @@ -116,3 +152,20 @@ return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; return GlobalXRayImpl->flush_log(); } + +XRayLogFlushStatus __xray_log_process_buffers( + void (*Processor)(const char *, XRayBuffer)) XRAY_NEVER_INSTRUMENT { + // We want to make sure that there will be no changes to the global state for + // the log by synchronising on the XRayBufferIteratorMutex. + if (!GlobalXRayImpl) + return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + auto Iterator = reinterpret_cast( + atomic_load(&XRayBufferIterator, __sanitizer::memory_order_acquire)); + auto Buffer = (*Iterator)(XRayBuffer{nullptr, 0}); + auto Mode = CurrentMode ? CurrentMode->Mode : nullptr; + while (Buffer.Data != nullptr) { + (*Processor)(Mode, Buffer); + Buffer = (*Iterator)(Buffer); + } + return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} Index: test/asan/TestCases/Darwin/odr-lto.cc =================================================================== --- test/asan/TestCases/Darwin/odr-lto.cc +++ test/asan/TestCases/Darwin/odr-lto.cc @@ -3,15 +3,10 @@ // REQUIRES: lto -// RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -// RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -// RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ODR - // RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -mllvm -asan-use-private-alias // RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -mllvm -asan-use-private-alias // RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto -// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ODR +// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s #include #include @@ -40,6 +35,5 @@ #endif // PART == 1 -// CHECK-ODR: ERROR: AddressSanitizer: odr-violation -// CHECK-NO-ODR-NOT: ERROR: AddressSanitizer: odr-violation -// CHECK-NO-ODR: Done. +// CHECK-NOT: ERROR: AddressSanitizer: odr-violation +// CHECK: Done. Index: test/asan/TestCases/Posix/lto-constmerge-odr.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Posix/lto-constmerge-odr.cc @@ -0,0 +1,14 @@ +// RUN: %clangxx_asan -O3 -flto %s -o %t +// RUN: %run %t 2>&1 + +// REQUIRES: lto + +int main(int argc, const char * argv[]) { + struct { long width, height; } a = {16, 16}; + struct { long width, height; } b = {16, 16}; + + // Just to make sure 'a' and 'b' don't get optimized out. + asm volatile("" : : "r" (&a), "r" (&b)); + + return 0; +} Index: test/asan/TestCases/handle_noreturn_bug.cc =================================================================== --- /dev/null +++ test/asan/TestCases/handle_noreturn_bug.cc @@ -0,0 +1,13 @@ +// Regression test: __asan_handle_no_return should unpoison stack even with poison_heap=0. +// RUN: %clangxx_asan -O0 %s -o %t && \ +// RUN: %env_asan_opts=poison_heap=1 %run %t && \ +// RUN: %env_asan_opts=poison_heap=0 %run %t + +#include + +int main(int argc, char **argv) { + int x[2]; + int * volatile p = &x[0]; + __asan_handle_no_return(); + int volatile z = p[2]; +} Index: test/asan/TestCases/strcat-overlap.cc =================================================================== --- /dev/null +++ test/asan/TestCases/strcat-overlap.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// This test when run with suppressions invokes undefined +// behavior which can cause all sorts of bad things to happen +// depending on how strcat() is implemented. For now only run +// on platforms where we know the test passes. +// REQUIRES: x86_64h-darwin || x86_64-darwin || i386-darwin || x86_64-linux || i386-linux +// UNSUPPORTED: win32 +// UNSUPPORTED: android + +#include + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { + char buffer[] = "hello\0XXX"; + // CHECK: strcat-param-overlap: memory ranges + // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap + // CHECK: {{#0 0x.* in .*strcat}} + // CHECK: {{#1 0x.* in bad_function.*strcat-overlap.cc:}}[[@LINE+2]] + // CHECK: {{#2 0x.* in main .*strcat-overlap.cc:}}[[@LINE+5]] + strcat(buffer, buffer + 1); // BOOM +} + +int main(int argc, char **argv) { + bad_function(); + return 0; +} Index: test/asan/TestCases/strcpy-overlap.cc =================================================================== --- /dev/null +++ test/asan/TestCases/strcpy-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strcpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { + char buffer[] = "hello"; + // CHECK: strcpy-param-overlap: memory ranges + // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap + // CHECK: {{#0 0x.* in .*strcpy}} + // CHECK: {{#1 0x.* in bad_function.*strcpy-overlap.cc:}}[[@LINE+2]] + // CHECK: {{#2 0x.* in main .*strcpy-overlap.cc:}}[[@LINE+5]] + strcpy(buffer, buffer + 1); // BOOM +} + +int main(int argc, char **argv) { + bad_function(); + return 0; +} Index: test/asan/TestCases/strncat-overlap.cc =================================================================== --- /dev/null +++ test/asan/TestCases/strncat-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncat" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { + char buffer[] = "hello\0XXX"; + // CHECK: strncat-param-overlap: memory ranges + // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap + // CHECK: {{#0 0x.* in .*strncat}} + // CHECK: {{#1 0x.* in bad_function.*strncat-overlap.cc:}}[[@LINE+2]] + // CHECK: {{#2 0x.* in main .*strncat-overlap.cc:}}[[@LINE+5]] + strncat(buffer, buffer + 1, 3); // BOOM +} + +int main(int argc, char **argv) { + bad_function(); + return 0; +} Index: test/asan/TestCases/strncpy-overlap.cc =================================================================== --- /dev/null +++ test/asan/TestCases/strncpy-overlap.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: echo "interceptor_via_fun:bad_function" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t +// RUN: echo "interceptor_name:strncpy" > %t.supp +// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t + +// UNSUPPORTED: android + +#include + + +// Don't inline function otherwise stacktrace changes. +__attribute__((noinline)) void bad_function() { + char buffer[] = "hello"; + // CHECK: strncpy-param-overlap: memory ranges + // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap + // CHECK: {{#0 0x.* in .*strncpy}} + // CHECK: {{#1 0x.* in bad_function.*strncpy-overlap.cc:}}[[@LINE+2]] + // CHECK: {{#2 0x.* in main .*strncpy-overlap.cc:}}[[@LINE+5]] + strncpy(buffer, buffer + 1, 5); // BOOM +} + +int main(int argc, char **argv) { + bad_function(); + return 0; +} Index: test/cfi/simple-pass.cpp =================================================================== --- test/cfi/simple-pass.cpp +++ test/cfi/simple-pass.cpp @@ -1,5 +1,10 @@ +// -mretpoline does not work yet on Darwin. +// XFAIL: darwin + // RUN: %clangxx_cfi -o %t %s // RUN: %run %t +// RUN: %clangxx_cfi -mretpoline -o %t2 %s +// RUN: %run %t2 // Tests that the CFI mechanism does not crash the program when making various // kinds of valid calls involving classes with various different linkages and Index: test/fuzzer/lit.cfg =================================================================== --- test/fuzzer/lit.cfg +++ test/fuzzer/lit.cfg @@ -7,8 +7,6 @@ config.suffixes = ['.test'] config.test_source_root = os.path.dirname(__file__) -config.environment['LD_LIBRARY_PATH'] = config.llvm_library_dir - # Choose between lit's internal shell pipeline runner and a real shell. If # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") @@ -54,9 +52,9 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True): compiler_cmd = config.c_compiler if config.clang and config.stdlib == 'libc++': - link_cmd = '-stdlib=libc++' + link_cmd = '-stdlib=libc++ -Wl,-rpath=%s' % config.llvm_library_dir elif config.clang and config.stdlib == 'static-libc++': - link_cmd = '-stdlib=libc++ -lc++abi -static-libstdc++' + link_cmd = '-stdlib=libc++ -lc++abi -static-libstdc++ -Wl,-rpath=%s' % config.llvm_library_dir else: link_cmd = '-lc++' if any(x in config.target_triple for x in ('darwin', 'freebsd')) else '-lstdc++' std_cmd = '--driver-mode=g++ -std=c++11' if is_cpp else '' Index: test/msan/dtls_test.c =================================================================== --- test/msan/dtls_test.c +++ test/msan/dtls_test.c @@ -5,6 +5,8 @@ Regression test for a bug in msan/glibc integration, see https://sourceware.org/bugzilla/show_bug.cgi?id=16291 and https://github.com/google/sanitizers/issues/547 + + XFAIL: freebsd */ #ifndef BUILD_SO Index: test/msan/getutent.cc =================================================================== --- test/msan/getutent.cc +++ test/msan/getutent.cc @@ -1,14 +1,18 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +#ifndef __FreeBSD__ #include +#endif #include #include int main(void) { +#ifndef __FreeBSD__ setutent(); while (struct utmp *ut = getutent()) __msan_check_mem_is_initialized(ut, sizeof(*ut)); endutent(); +#endif setutxent(); while (struct utmpx *utx = getutxent()) Index: test/msan/iconv.cc =================================================================== --- test/msan/iconv.cc +++ test/msan/iconv.cc @@ -15,7 +15,7 @@ char inbuf_[100]; strcpy(inbuf_, "sample text"); char outbuf_[100]; -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__NetBSD__) // Some OSes expect the 2nd argument of iconv(3) to be of type const char ** const char *inbuf = inbuf_; #else Index: test/msan/lit.cfg =================================================================== --- test/msan/lit.cfg +++ test/msan/lit.cfg @@ -29,7 +29,7 @@ # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -if config.host_os not in ['Linux', 'NetBSD']: +if config.host_os not in ['Linux', 'NetBSD', 'FreeBSD']: config.unsupported = True # For mips64, mips64el we have forced store_context_size to 1 because these Index: test/msan/pthread_getattr_np_deadlock.cc =================================================================== --- test/msan/pthread_getattr_np_deadlock.cc +++ test/msan/pthread_getattr_np_deadlock.cc @@ -1,6 +1,7 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && %run %t // Regression test for a deadlock in pthread_getattr_np +// UNSUPPORTED: freebsd #include #include Index: test/msan/pvalloc.cc =================================================================== --- test/msan/pvalloc.cc +++ test/msan/pvalloc.cc @@ -4,6 +4,7 @@ // RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s // RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t psm1 2>&1 +// pvalloc is Linux only // UNSUPPORTED: win32, freebsd, netbsd // Checks that pvalloc overflows are caught. If the allocator is allowed to Index: test/msan/strlen_of_shadow.cc =================================================================== --- test/msan/strlen_of_shadow.cc +++ test/msan/strlen_of_shadow.cc @@ -2,6 +2,8 @@ // Check that strlen() and similar intercepted functions can be called on shadow // memory. +// The mem_to_shadow's part might need rework +// XFAIL: freebsd #include #include Index: test/msan/textdomain.cc =================================================================== --- test/msan/textdomain.cc +++ test/msan/textdomain.cc @@ -1,4 +1,5 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// textdomain() is not a part of libc on FreeBSD and NetBSD. // UNSUPPORTED: netbsd, freebsd #include Index: test/msan/tls_reuse.cc =================================================================== --- test/msan/tls_reuse.cc +++ test/msan/tls_reuse.cc @@ -1,6 +1,7 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t // Check that when TLS block is reused between threads, its shadow is cleaned. +// XFAIL: freebsd #include #include Index: test/msan/tsearch.cc =================================================================== --- test/msan/tsearch.cc +++ test/msan/tsearch.cc @@ -1,7 +1,7 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t // tdestroy is a GNU extension -// UNSUPPORTED: netbsd +// UNSUPPORTED: netbsd, freebsd #include #include Index: test/msan/tzset.cc =================================================================== --- test/msan/tzset.cc +++ test/msan/tzset.cc @@ -1,4 +1,5 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t +// XFAIL: freebsd #include #include Index: test/msan/wcsxfrm.cc =================================================================== --- /dev/null +++ test/msan/wcsxfrm.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && not %run %t + +#include +#include +#include +#include +#include + +int main(void) { + wchar_t q[10]; + size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + + __msan_poison(&q, sizeof(q)); + n = wcsxfrm_l(q, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + + q[0] = 'A'; + q[1] = '\x00'; + __msan_poison(&q, sizeof(q)); + wcsxfrm(NULL, q, 0); + + // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value + // CHECK: in main {{.*}}wcsxfrm.cc:25 + return 0; +} Index: test/sanitizer_common/TestCases/Linux/mmap64_test.c =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/Linux/mmap64_test.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t + +#define _LARGEFILE64_SOURCE 1 + +#include +#include + +int main() { + char *buf = (char *)mmap64(0, 100000, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(buf); + munmap(buf, 100000); +} Index: test/sanitizer_common/TestCases/Posix/mmap_test.c =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/Posix/mmap_test.c @@ -0,0 +1,11 @@ +// RUN: %clang %s -o %t && %run %t + +#include +#include + +int main() { + char *buf = (char *)mmap(0, 100000, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(buf); + munmap(buf, 100000); +} Index: test/sanitizer_common/TestCases/Posix/strxfrm.c =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/Posix/strxfrm.c @@ -0,0 +1,20 @@ +// RUN: %clang -O0 %s -o %t && %run %t +// UNSUPPORTED: darwin + +#include +#include +#include + +int main(int argc, char **argv) { + char q[10]; + size_t n = strxfrm(q, "abcdef", sizeof(q)); + assert(n < sizeof(q)); + + char q2[10]; + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + n = strxfrm_l(q2, L"qwerty", sizeof(q), loc); + assert(n < sizeof(q2)); + + freelocale(loc); + return 0; +} Index: test/sanitizer_common/TestCases/Posix/wcsxfrm.c =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/Posix/wcsxfrm.c @@ -0,0 +1,20 @@ +// RUN: %clang -O0 %s -o %t && %run %t +// UNSUPPORTED: darwin + +#include +#include +#include + +int main(int argc, char **argv) { + wchar_t q[10]; + size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); + assert(n < sizeof(q)); + + wchar_t q2[10]; + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + n = wcsxfrm_l(q2, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); + assert(n < sizeof(q2)); + + freelocale(loc); + return 0; +} Index: test/scudo/alignment.c =================================================================== --- test/scudo/alignment.c +++ test/scudo/alignment.c @@ -20,4 +20,4 @@ return 0; } -// CHECK: ERROR: attempted to deallocate a chunk not properly aligned +// CHECK: ERROR: misaligned pointer when deallocating address Index: test/scudo/sized-delete.cpp =================================================================== --- test/scudo/sized-delete.cpp +++ test/scudo/sized-delete.cpp @@ -38,4 +38,4 @@ return 0; } -// CHECK: ERROR: invalid sized delete on chunk at address +// CHECK: ERROR: invalid sized delete when deallocating address Index: test/tsan/lit.cfg =================================================================== --- test/tsan/lit.cfg +++ test/tsan/lit.cfg @@ -56,7 +56,7 @@ if config.has_libcxx and config.host_os != 'Darwin': # FIXME: Dehardcode this path somehow. libcxx_path = os.path.join(config.compiler_rt_obj_root, "lib", - "tsan", "libcxx_tsan_" + config.target_arch) + "tsan", "libcxx_tsan_%s" % config.target_arch) libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1") libcxx_libdir = os.path.join(libcxx_path, "lib") libcxx_so = os.path.join(libcxx_libdir, "libc++.so") Index: test/xray/TestCases/Posix/logging-modes.cc =================================================================== --- test/xray/TestCases/Posix/logging-modes.cc +++ test/xray/TestCases/Posix/logging-modes.cc @@ -9,6 +9,7 @@ #include "xray/xray_log_interface.h" #include #include +#include [[clang::xray_never_instrument]] void printing_handler(int32_t fid, XRayEntryType) { @@ -20,8 +21,19 @@ printing = false; } +[[clang::xray_never_instrument]] XRayBuffer next_buffer(XRayBuffer buffer) { + static const char data[10] = {}; + static const XRayBuffer first_and_last{data, 10}; + if (buffer.Data == nullptr) + return first_and_last; + if (buffer.Data == first_and_last.Data) + return XRayBuffer{nullptr, 0}; + assert(false && "Invalid buffer provided."); +} + [[clang::xray_never_instrument]] XRayLogInitStatus printing_init(size_t, size_t, void *, size_t) { + __xray_log_set_buffer_iterator(next_buffer); return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } @@ -30,11 +42,16 @@ } [[clang::xray_never_instrument]] XRayLogFlushStatus printing_flush_log() { + __xray_log_remove_buffer_iterator(); return XRayLogFlushStatus::XRAY_LOG_FLUSHED; } [[clang::xray_always_instrument]] void callme() { std::printf("called me!\n"); } +static auto buffer_counter = 0; + +void process_buffer(const char *, XRayBuffer) { ++buffer_counter; } + static bool unused = [] { assert(__xray_log_register_mode("custom", {printing_init, printing_finalize, @@ -46,6 +63,9 @@ int main(int argc, char **argv) { assert(__xray_log_select_mode("custom") == XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "custom"); assert(__xray_patch() == XRayPatchingStatus::SUCCESS); assert(__xray_log_init(0, 0, nullptr, 0) == XRayLogInitStatus::XRAY_LOG_INITIALIZED); @@ -53,6 +73,9 @@ callme(); // CHECK: called me! // CHECK: printing {{.*}} assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(buffer_counter == 1); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); assert(__xray_log_select_mode("not-found") == XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND); Index: utils/generate_netbsd_syscalls.awk =================================================================== --- utils/generate_netbsd_syscalls.awk +++ utils/generate_netbsd_syscalls.awk @@ -718,10 +718,6 @@ pcmd(" PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") pcmd("} else if (req_ == ptrace_pt_get_siginfo) {") pcmd(" PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") - pcmd("} else if (req_ == ptrace_pt_set_sigmask) {") - pcmd(" PRE_READ(addr_, sizeof(__sanitizer_sigset_t));") - pcmd("} else if (req_ == ptrace_pt_get_sigmask) {") - pcmd(" PRE_WRITE(addr_, sizeof(__sanitizer_sigset_t));") pcmd("} else if (req_ == ptrace_pt_setregs) {") pcmd(" PRE_READ(addr_, struct_ptrace_reg_struct_sz);") pcmd("} else if (req_ == ptrace_pt_getregs) {") @@ -758,10 +754,6 @@ pcmd(" POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") pcmd(" } else if (req_ == ptrace_pt_get_siginfo) {") pcmd(" POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);") - pcmd(" } else if (req_ == ptrace_pt_set_sigmask) {") - pcmd(" POST_READ(addr_, sizeof(__sanitizer_sigset_t));") - pcmd(" } else if (req_ == ptrace_pt_get_sigmask) {") - pcmd(" POST_WRITE(addr_, sizeof(__sanitizer_sigset_t));") pcmd(" } else if (req_ == ptrace_pt_setregs) {") pcmd(" POST_READ(addr_, struct_ptrace_reg_struct_sz);") pcmd(" } else if (req_ == ptrace_pt_getregs) {")