[scudo] Implement stricter separation of C vs C++

Summary:
Initially, Scudo had a monolithic design where both C and C++ functions were
living in the same library. This was not necessarily ideal, and with the work
on -fsanitize=scudo, it became more apparent that this needed to change.

We are splitting the new/delete interceptor in their own C++ library. This
allows more flexibility, notably with regard to std::bad_alloc when the work is
done. This also allows us to not link new & delete when using pure C.

Additionally, we add the UBSan runtimes with Scudo, in order to be able to have
a -fsanitize=scudo,undefined in Clang (see work in D39334).

The changes in this patch:
- split the cxx specific code in the scudo cmake file into a new library;
  (remove the spurious foreach loop, that was not necessary)
- add the UBSan runtimes (both C and C++);
- change the test cmake file to allow for specific C & C++ tests;
- make C tests pure C, rename their extension accordingly.

Reviewers: alekseyshl

Reviewed By: alekseyshl

Subscribers: srhines, mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D39461

llvm-svn: 317097
This commit is contained in:
Kostya Kortchinsky 2017-11-01 15:28:20 +00:00
parent 2b09f39b4d
commit d937b0a10c
21 changed files with 63 additions and 48 deletions

View File

@ -12,12 +12,14 @@ set(SCUDO_SOURCES
scudo_flags.cpp
scudo_crc32.cpp
scudo_interceptors.cpp
scudo_new_delete.cpp
scudo_termination.cpp
scudo_tsd_exclusive.cpp
scudo_tsd_shared.cpp
scudo_utils.cpp)
set(SCUDO_CXX_SOURCES
scudo_new_delete.cpp)
# Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available.
if (COMPILER_RT_HAS_MSSE4_2_FLAG)
set_source_files_properties(scudo_crc32.cpp PROPERTIES COMPILE_FLAGS -msse4.2)
@ -36,26 +38,35 @@ if(COMPILER_RT_HAS_SCUDO)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_DYNAMIC_LIBS)
foreach(arch ${SCUDO_SUPPORTED_ARCH})
add_compiler_rt_runtime(clang_rt.scudo
STATIC
ARCHS ${arch}
SOURCES ${SCUDO_SOURCES}
OBJECT_LIBS RTSanitizerCommonNoTermination
RTSanitizerCommonLibc
RTInterception
CFLAGS ${SCUDO_CFLAGS}
PARENT_TARGET scudo)
add_compiler_rt_runtime(clang_rt.scudo
STATIC
ARCHS ${SCUDO_SUPPORTED_ARCH}
SOURCES ${SCUDO_SOURCES}
OBJECT_LIBS RTSanitizerCommonNoTermination
RTSanitizerCommonLibc
RTInterception
RTUbsan
CFLAGS ${SCUDO_CFLAGS}
PARENT_TARGET scudo)
add_compiler_rt_runtime(clang_rt.scudo
SHARED
ARCHS ${arch}
SOURCES ${SCUDO_SOURCES}
OBJECT_LIBS RTSanitizerCommonNoTermination
RTSanitizerCommonLibc
RTInterception
CFLAGS ${SCUDO_CFLAGS}
LINK_LIBS ${SCUDO_DYNAMIC_LIBS}
PARENT_TARGET scudo)
endforeach()
add_compiler_rt_runtime(clang_rt.scudo_cxx
STATIC
ARCHS ${SCUDO_SUPPORTED_ARCH}
SOURCES ${SCUDO_CXX_SOURCES}
OBJECT_LIBS RTUbsan_cxx
CFLAGS ${SCUDO_CFLAGS}
PARENT_TARGET scudo)
add_compiler_rt_runtime(clang_rt.scudo
SHARED
ARCHS ${SCUDO_SUPPORTED_ARCH}
SOURCES ${SCUDO_SOURCES} ${SCUDO_CXX_SOURCES}
OBJECT_LIBS RTSanitizerCommonNoTermination
RTSanitizerCommonLibc
RTInterception
RTUbsan
RTUbsan_cxx
CFLAGS ${SCUDO_CFLAGS}
LINK_LIBS ${SCUDO_DYNAMIC_LIBS}
PARENT_TARGET scudo)
endif()

View File

@ -15,7 +15,7 @@ int main(int argc, char **argv)
if (!strcmp(argv[1], "pointers")) {
void *p = malloc(1U << 16);
assert(p);
free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 1));
free((void *)((uintptr_t)p | 1));
}
return 0;
}

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -o %t
// RUN: %clangxx_scudo %s -o %t
// RUN: not %run %t malloc 2>&1 | FileCheck %s
// RUN: not %run %t new 2>&1 | FileCheck %s
// RUN: not %run %t newarray 2>&1 | FileCheck %s

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -lstdc++ -o %t
// RUN: %clangxx_scudo %s -lstdc++ -o %t
// RUN: %run %t ownership 2>&1
// RUN: %run %t ownership-and-size 2>&1
// RUN: %run %t heap-size 2>&1

View File

@ -11,21 +11,24 @@ config.test_source_root = os.path.dirname(__file__)
# Path to the shared & static libraries
shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.so" % config.target_arch)
static_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.a" % config.target_arch)
static_libscudo_cxx = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo_cxx-%s.a" % config.target_arch)
whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo
whole_archive_cxx = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo_cxx
# Test suffixes.
config.suffixes = ['.c', '.cc', '.cpp']
# C flags.
# C & CXX flags.
c_flags = ([config.target_cflags] +
["-std=c++11",
"-pthread",
["-pthread",
"-fPIE",
"-pie",
"-O0",
"-UNDEBUG",
"-ldl",
"-Wl,--gc-sections"])
cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"])
# Android doesn't want -lrt.
if not config.android:
@ -37,6 +40,7 @@ def build_invocation(compile_flags):
# Add clang substitutions.
config.substitutions.append(("%clang ", build_invocation(c_flags)))
config.substitutions.append(("%clang_scudo ", build_invocation(c_flags) + whole_archive))
config.substitutions.append(("%clangxx_scudo ", build_invocation(cxx_flags) + whole_archive + whole_archive_cxx))
config.substitutions.append(("%shared_libscudo", shared_libscudo))
# Platform-specific default SCUDO_OPTIONS for lit tests.

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -lstdc++ -o %t
// RUN: %clangxx_scudo %s -lstdc++ -o %t
// RUN: %run %t 2>&1
// Tests that a regular workflow of allocation, memory fill and free works as

View File

@ -15,11 +15,11 @@
#include <unistd.h>
// Sometimes the headers may not have this...
extern "C" void *aligned_alloc(size_t alignment, size_t size);
void *aligned_alloc(size_t alignment, size_t size);
int main(int argc, char **argv)
{
void *p = nullptr;
void *p = NULL;
size_t alignment = 1U << 12;
size_t size = 1U << 12;
int err;

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -o %t
// RUN: %clangxx_scudo %s -o %t
// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s
// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1
// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -o %t
// RUN: %clangxx_scudo %s -o %t
// RUN: %run %t 2>&1
// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t 2>&1
// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s

View File

@ -12,7 +12,7 @@
#include <stdlib.h>
#include <string.h>
static void *global_p = nullptr;
static void *global_p = NULL;
void __init(void) {
global_p = malloc(1);

View File

@ -1,19 +1,19 @@
// Test that the preloaded runtime works without linking the static library.
// RUN: %clang %s -o %t
// RUN: %clang %s -lstdc++ -o %t
// RUN: env LD_PRELOAD=%shared_libscudo not %run %t 2>&1 | FileCheck %s
// This way of setting LD_PRELOAD does not work with Android test runner.
// REQUIRES: !android
#include <assert.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
void *p = malloc(sizeof(int));
int *p = new int;
assert(p);
free(p);
free(p);
*p = 0;
delete p;
delete p;
return 0;
}

View File

@ -61,7 +61,7 @@ int main(int argc, char **argv)
free(p);
// Eventually the chunk should become available again.
bool found = false;
char found = 0;
for (int i = 0; i < 0x200 && !found; i++) {
p = malloc(size);
assert(p);

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -o %t
// RUN: %clangxx_scudo %s -o %t
// RUN: rm -rf %T/random_shuffle_tmp_dir
// RUN: mkdir %T/random_shuffle_tmp_dir
// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out1

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -lstdc++ -o %t
// RUN: %clangxx_scudo %s -lstdc++ -o %t
// RUN: %run %t pointers 2>&1
// RUN: %run %t contents 2>&1
// RUN: %run %t usablesize 2>&1

View File

@ -36,7 +36,7 @@ int main(int argc, char **argv)
assert(p);
memset(p, 'A', size); // This should not trigger anything.
// Set up the SIGSEGV handler now, as the rest should trigger an AV.
sigaction(SIGSEGV, &a, nullptr);
sigaction(SIGSEGV, &a, NULL);
if (!strcmp(argv[1], "after")) {
for (int i = 0; i < page_size; i++)
p[size + i] = 'A';

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo -fsized-deallocation %s -o %t
// RUN: %clangxx_scudo -fsized-deallocation %s -o %t
// RUN: %env_scudo_opts=DeleteSizeMismatch=1 %run %t gooddel 2>&1
// RUN: %env_scudo_opts=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s
// RUN: %env_scudo_opts=DeleteSizeMismatch=0 %run %t baddel 2>&1

View File

@ -1,4 +1,4 @@
// RUN: %clang_scudo %s -lstdc++ -o %t
// RUN: %clangxx_scudo %s -lstdc++ -o %t
// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s
// RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t malloc 2>&1
// RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s

View File

@ -20,7 +20,7 @@ pthread_t tid[kMaxNumThreads];
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
bool go = false;
char go = 0;
void *thread_fun(void *arg) {
pthread_mutex_lock(&mutex);
@ -51,7 +51,7 @@ int main(int argc, char** argv) {
for (int i = 0; i < num_threads; i++)
pthread_create(&tid[i], 0, thread_fun, 0);
pthread_mutex_lock(&mutex);
go = true;
go = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
for (int i = 0; i < num_threads; i++)

View File

@ -19,7 +19,7 @@ size_t round_up_to(size_t size, size_t alignment) {
int main(int argc, char **argv)
{
void *p = nullptr;
void *p = NULL;
size_t size, page_size;
assert(argc == 2);