Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,32 @@
set(ESAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND ESAN_TEST_DEPS esan)
endif()
set(ESAN_TESTSUITES)
set(ESAN_TEST_ARCH ${ESAN_SUPPORTED_ARCH})
set(ESAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
foreach(arch ${ESAN_TEST_ARCH})
set(ESAN_TEST_TARGET_ARCH ${arch})
string(TOLOWER "-${arch}" ESAN_TEST_CONFIG_SUFFIX)
get_target_flags_for_arch(${arch} ESAN_TEST_TARGET_CFLAGS)
string(REPLACE ";" " " ESAN_TEST_TARGET_CFLAGS "${ESAN_TEST_TARGET_CFLAGS}")
string(TOUPPER ${arch} ARCH_UPPER_CASE)
set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg)
list(APPEND ESAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
endforeach()
# TODO(bruening): add Unit/ tests as well
add_lit_testsuite(check-esan "Running EfficiencySanitizer tests"
${ESAN_TESTSUITES}
DEPENDS ${ESAN_TEST_DEPS})
set_target_properties(check-esan PROPERTIES FOLDER "Compiler-RT Misc")

View File

@@ -0,0 +1,74 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %env_esan_opts="verbosity=1 record_snapshots=0" %run %t %t 2>&1 | FileCheck %s
#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static void testChildStackLimit(rlim_t StackLimit, char *ToRun) {
int Res;
struct rlimit Limit;
Limit.rlim_cur = RLIM_INFINITY;
Limit.rlim_max = RLIM_INFINITY;
Res = setrlimit(RLIMIT_STACK, &Limit);
if (Res != 0) {
// Probably our environment had a large limit and we ourselves got
// re-execed and can no longer raise our limit.
// We have to bail and emulate the regular test.
// We'd prefer to have branches in our FileCheck output to ensure the
// initial program was re-execed but this is the best we can do for now.
fprintf(stderr, "in esan::initializeLibrary\n");
fprintf(stderr, "==1234==The stack size limit is beyond the maximum supported.\n");
fprintf(stderr, "Re-execing with a stack size below 1TB.\n");
fprintf(stderr, "in esan::initializeLibrary\n");
fprintf(stderr, "done\n");
fprintf(stderr, "in esan::finalizeLibrary\n");
return;
}
pid_t Child = fork();
assert(Child >= 0);
if (Child > 0) {
pid_t WaitRes = waitpid(Child, NULL, 0);
assert(WaitRes == Child);
} else {
char *Args[2];
Args[0] = ToRun;
Args[1] = NULL;
Res = execv(ToRun, Args);
assert(0); // Should not be reached.
}
}
int main(int argc, char *argv[]) {
// The path to the program to exec must be passed in the first time.
if (argc == 2) {
fprintf(stderr, "Testing child with infinite stack\n");
testChildStackLimit(RLIM_INFINITY, argv[1]);
fprintf(stderr, "Testing child with 1TB stack\n");
testChildStackLimit(1ULL << 40, argv[1]);
}
fprintf(stderr, "done\n");
// CHECK: in esan::initializeLibrary
// CHECK: Testing child with infinite stack
// CHECK-NEXT: in esan::initializeLibrary
// CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported.
// CHECK-NEXT: Re-execing with a stack size below 1TB.
// CHECK-NEXT: in esan::initializeLibrary
// CHECK: done
// CHECK: in esan::finalizeLibrary
// CHECK: Testing child with 1TB stack
// CHECK-NEXT: in esan::initializeLibrary
// CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported.
// CHECK-NEXT: Re-execing with a stack size below 1TB.
// CHECK-NEXT: in esan::initializeLibrary
// CHECK: done
// CHECK-NEXT: in esan::finalizeLibrary
// CHECK: done
// CHECK-NEXT: in esan::finalizeLibrary
return 0;
}

View File

@@ -0,0 +1,20 @@
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
// RUN: %env_esan_opts=verbosity=3 %run %t 2>&1 | FileCheck %s
#include <string.h>
int main(int argc, char **argv) {
char Buf[2048];
const char Str[] = "TestStringOfParticularLength"; // 29 chars.
strcpy(Buf, Str);
strncpy(Buf, Str, 17);
return strncmp(Buf, Str, 17);
// CHECK: in esan::initializeLibrary
// CHECK: in esan::processRangeAccess {{.*}} 29
// CHECK: in esan::processRangeAccess {{.*}} 29
// CHECK: in esan::processRangeAccess {{.*}} 17
// CHECK: in esan::processRangeAccess {{.*}} 17
// CHECK: in esan::processRangeAccess {{.*}} 17
// CHECK: in esan::processRangeAccess {{.*}} 17
// CHECK: in esan::finalizeLibrary
}

View File

@@ -0,0 +1,44 @@
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
int main(int argc, char **argv) {
#if defined(__mips64)
void *Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ,
MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
#else
void *Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
#endif
if (Map == (void *)-1)
fprintf(stderr, "map failed\n");
else
fprintf(stderr, "mapped %p\n", Map);
#if defined(__mips64)
Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ,
MAP_ANON|MAP_PRIVATE, -1, 0);
#else
Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
MAP_ANON|MAP_PRIVATE, -1, 0);
#endif
fprintf(stderr, "mapped %p\n", Map);
// CHECK: in esan::initializeLibrary
// (There can be a re-exec for stack limit here.)
// x86_64: Shadow scale=2 offset=0x440000000000
// x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
// x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
// x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
// mips64: Shadow scale=2 offset=0x4400000000
// mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB)
// mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB)
// mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB)
// CHECK-NEXT: mmap conflict: {{.*}}
// CHECK-NEXT: map failed
// CHECK-NEXT: mmap conflict: {{.*}}
// CHECK-NEXT: mapped {{.*}}
// CHECK-NEXT: in esan::finalizeLibrary
return 0;
}

View File

@@ -0,0 +1,204 @@
// RUN: %clang_esan_frag -O0 %s -DPART1 -mllvm -esan-aux-field-info=0 -c -o %t-part1.o 2>&1
// RUN: %clang_esan_frag -O0 %s -DPART2 -c -o %t-part2.o 2>&1
// RUN: %clang_esan_frag -O0 %s -DMAIN -c -o %t-main.o 2>&1
// RUN: %clang_esan_frag -O0 %t-part1.o %t-part2.o %t-main.o -o %t 2>&1
// RUN: %env_esan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s
// We generate two different object files from this file with different
// macros, and then link them together. We do this to test how we handle
// separate compilation with multiple compilation units.
#include <stdio.h>
extern "C" {
void part1();
void part2();
}
//===-- compilation unit part1 without main function ----------------------===//
#ifdef PART1
struct A {
int x;
int y;
};
struct B {
float m;
double n;
};
union U {
float f;
double d;
};
// Same struct in both main and part1.
struct S {
int s1;
int s2;
};
// Different structs with the same name in main and part1.
struct D {
int d1;
int d2;
struct {
int x;
int y;
int z;
} ds[10];
};
void part1()
{
struct A a;
struct B b;
union U u;
struct S s;
struct D d;
for (int i = 0; i < (1 << 11); i++)
a.x = 0;
a.y = 1;
b.m = 2.0;
for (int i = 0; i < (1 << 21); i++) {
b.n = 3.0;
d.ds[3].y = 0;
}
u.f = 0.0;
u.d = 1.0;
s.s1 = 0;
d.d1 = 0;
}
#endif // PART1
//===-- compilation unit part2 without main function ----------------------===//
#ifdef PART2
// No struct in this part.
void part2()
{
// do nothing
}
#endif // PART2
//===-- compilation unit with main function -------------------------------===//
#ifdef MAIN
class C {
public:
struct {
int x;
int y;
} cs;
union {
float f;
double d;
} cu;
char c[10];
};
// Same struct in both main and part1.
struct S {
int s1;
int s2;
};
// Different structs with the same name in main and part1.
struct D {
int d1;
int d2;
int d3;
};
int main(int argc, char **argv) {
// CHECK: in esan::initializeLibrary
// CHECK: in esan::initializeCacheFrag
// CHECK-NEXT: in esan::processCompilationUnitInit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s)
// CHECK-NEXT: Register struct.A$2$11$11: 2 fields
// CHECK-NEXT: Register struct.B$2$3$2: 2 fields
// CHECK-NEXT: Register union.U$1$3: 1 fields
// CHECK-NEXT: Register struct.S$2$11$11: 2 fields
// CHECK-NEXT: Register struct.D$3$14$11$11: 3 fields
// CHECK-NEXT: Register struct.anon$3$11$11$11: 3 fields
// CHECK-NEXT: in esan::processCompilationUnitInit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
// CHECK-NEXT: in esan::processCompilationUnitInit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
// CHECK-NEXT: Register class.C$3$14$13$13: 3 fields
// CHECK-NEXT: Register struct.anon$2$11$11: 2 fields
// CHECK-NEXT: Register union.anon$1$3: 1 fields
// CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields
// CHECK-NEXT: Register struct.D$3$11$11$11: 3 fields
struct C c[2];
struct S s;
struct D d;
c[0].cs.x = 0;
c[1].cs.y = 1;
c[0].cu.f = 0.0;
c[1].cu.d = 1.0;
c[0].c[2] = 0;
s.s1 = 0;
d.d1 = 0;
d.d2 = 0;
part1();
part2();
return 0;
// CHECK: in esan::finalizeLibrary
// CHECK-NEXT: in esan::finalizeCacheFrag
// CHECK-NEXT: in esan::processCompilationUnitExit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s)
// CHECK-NEXT: Unregister class.C$3$14$13$13: 3 fields
// CHECK-NEXT: {{.*}} class C
// CHECK-NEXT: {{.*}} size = 32, count = 5, ratio = 3, array access = 5
// CHECK-NEXT: {{.*}} # 0: offset = 0, size = 8, count = 2, type = %struct.anon = type { i32, i32 }
// CHECK-NEXT: {{.*}} # 1: offset = 8, size = 8, count = 2, type = %union.anon = type { double }
// CHECK-NEXT: {{.*}} # 2: offset = 16, size = 10, count = 1, type = [10 x i8]
// CHECK-NEXT: Unregister struct.anon$2$11$11: 2 fields
// CHECK-NEXT: {{.*}} struct anon
// CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 1, array access = 0
// CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32
// CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32
// CHECK-NEXT: Unregister union.anon$1$3: 1 fields
// CHECK-NEXT: Unregister struct.S$2$11$11: 2 fields
// CHECK-NEXT: {{.*}} struct S
// CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 2, array access = 0
// CHECK-NEXT: {{.*}} # 0: count = 2
// CHECK-NEXT: {{.*}} # 1: count = 0
// CHECK-NEXT: Unregister struct.D$3$11$11$11: 3 fields
// CHECK-NEXT: {{.*}} struct D
// CHECK-NEXT: {{.*}} size = 12, count = 2, ratio = 2, array access = 0
// CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32
// CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32
// CHECK-NEXT: {{.*}} # 2: offset = 8, size = 4, count = 0, type = i32
// CHECK-NEXT: in esan::processCompilationUnitExit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s)
// CHECK-NEXT: in esan::processCompilationUnitExit
// CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s)
// CHECK-NEXT: Unregister struct.A$2$11$11: 2 fields
// CHECK-NEXT: {{.*}} struct A
// CHECK-NEXT: {{.*}} size = 8, count = 2049, ratio = 2048, array access = 0
// CHECK-NEXT: {{.*}} # 0: count = 2048
// CHECK-NEXT: {{.*}} # 1: count = 1
// CHECK-NEXT: Unregister struct.B$2$3$2: 2 fields
// CHECK-NEXT: {{.*}} struct B
// CHECK-NEXT: {{.*}} size = 16, count = 2097153, ratio = 2097152, array access = 0
// CHECK-NEXT: {{.*}} # 0: count = 1
// CHECK-NEXT: {{.*}} # 1: count = 2097152
// CHECK-NEXT: Unregister union.U$1$3: 1 fields
// CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields
// CHECK-NEXT: Unregister struct.D$3$14$11$11: 3 fields
// CHECK-NEXT: {{.*}} struct D
// CHECK-NEXT: {{.*}} size = 128, count = 2097153, ratio = 2097153, array access = 0
// CHECK-NEXT: {{.*}} # 0: count = 1
// CHECK-NEXT: {{.*}} # 1: count = 0
// CHECK-NEXT: {{.*}} # 2: count = 2097152
// CHECK-NEXT: Unregister struct.anon$3$11$11$11: 3 fields
// CHECK-NEXT: {{.*}} struct anon
// CHECK-NEXT: {{.*}} size = 12, count = 2097152, ratio = 4194304, array access = 2097152
// CHECK-NEXT: {{.*}} # 0: count = 0
// CHECK-NEXT: {{.*}} # 1: count = 2097152
// CHECK-NEXT: {{.*}} # 2: count = 0
// CHECK-NEXT: {{.*}}EfficiencySanitizer: total struct field access count = 6293518
}
#endif // MAIN

View File

@@ -0,0 +1,18 @@
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s
int main(int argc, char **argv) {
// CHECK: in esan::initializeLibrary
// (There can be a re-exec for stack limit here.)
// x86_64: Shadow scale=2 offset=0x440000000000
// x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
// x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
// x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
// mips64: Shadow scale=2 offset=0x4400000000
// mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB)
// mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB)
// mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB)
// CHECK: in esan::finalizeLibrary
// CHECK: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
return 0;
}

View File

@@ -0,0 +1,33 @@
// Test shadow faults during esan initialization as well as
// faults during dlsym's calloc during interceptor init.
//
// RUN: %clang_esan_wset %s -o %t
// RUN: %run %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Our goal is to emulate an instrumented allocator, whose calloc
// invoked from dlsym will trigger shadow faults, to test an
// early shadow fault during esan interceptor init.
// We do this by replacing calloc:
void *calloc(size_t size, size_t n) {
// Unfortunately we can't print anything to make the test
// ensure we got here b/c the sanitizer interceptors can't
// handle that during interceptor init.
// Ensure we trigger a shadow write fault:
int x[16];
x[0] = size;
// Now just emulate calloc.
void *res = malloc(size*n);
memset(res, 0, size*n);
return res;
}
int main(int argc, char **argv) {
printf("all done\n");
return 0;
}
// CHECK: all done

View File

@@ -0,0 +1,20 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
#include <string.h>
int main(int argc, char **argv) {
const int size = 128*1024*1024;
char *p = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
// Test the slowpath at different cache line boundaries.
for (int i = 0; i < 630; i++)
memset((char *)p + 63*i, i, 63*i);
munmap(p, size);
return 0;
// CHECK: {{.*}} EfficiencySanitizer: the total working set size: 77 KB (12{{[0-9]+}} cache lines)
}

View File

@@ -0,0 +1,74 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN
// RUN: %clang -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ESAN
// FIXME: Re-enable once PR33590 is fixed.
// UNSUPPORTED: x86_64
#include <sanitizer/esan_interface.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
const int size = 0x1 << 25; // 523288 cache lines
const int iters = 6;
int main(int argc, char **argv) {
char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// To avoid flakiness stemming from whether the sideline thread
// is scheduled enough on a loaded test machine, we coordinate
// with esan itself:
if (__esan_get_sample_count) {
while (__esan_get_sample_count() < 4) {
for (int i = 0; i < size; ++i)
buf[i] = i;
sched_yield();
}
}
// Ensure a non-esan build works without ifdefs:
if (__esan_report) {
// We should get 2 roughly identical reports:
__esan_report();
}
munmap(buf, size);
fprintf(stderr, "all done\n");
// CHECK-NO-ESAN: all done
// We only check for a few samples here to reduce the chance of flakiness:
// CHECK-ESAN: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
// CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec
// CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec
// CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec
// CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
// CHECK-ESAN-NEXT: all done
// CHECK-ESAN-NEXT: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
// CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms
// CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms
// CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec
// CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec
// CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec
// CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
return 0;
}

View File

@@ -0,0 +1,46 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s
// FIXME: Re-enable once PR33590 is fixed.
// UNSUPPORTED: x86_64
#include <sanitizer/esan_interface.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
const int size = 0x1 << 25; // 523288 cache lines
int main(int argc, char **argv) {
char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// To avoid flakiness stemming from whether the sideline thread
// is scheduled enough on a loaded test machine, we coordinate
// with esan itself:
if (__esan_get_sample_count) {
while (__esan_get_sample_count() < 4) {
for (int i = 0; i < size; ++i)
buf[i] = i;
sched_yield();
}
}
munmap(buf, size);
// We only check for a few samples here to reduce the chance of flakiness.
// CHECK: =={{[0-9]+}}== Total number of samples: {{[0-9]+}}
// CHECK-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms
// CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK: =={{[0-9]+}}== Samples array #1 at period 80 ms
// CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines)
// CHECK: =={{[0-9]+}}== Samples array #2 at period 320 ms
// CHECK: =={{[0-9]+}}== Samples array #3 at period 1280 ms
// CHECK: =={{[0-9]+}}== Samples array #4 at period 5120 ms
// CHECK: =={{[0-9]+}}== Samples array #5 at period 20 sec
// CHECK: =={{[0-9]+}}== Samples array #6 at period 81 sec
// CHECK: =={{[0-9]+}}== Samples array #7 at period 327 sec
// CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines)
return 0;
}

View File

@@ -0,0 +1,75 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s
#include <assert.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
sigjmp_buf mark;
static void SignalHandler(int Sig) {
if (Sig == SIGSEGV) {
fprintf(stderr, "Handling SIGSEGV for signal\n");
siglongjmp(mark, 1);
}
exit(1);
}
static void SigactionHandler(int Sig, siginfo_t *Info, void *Ctx) {
if (Sig == SIGSEGV) {
fprintf(stderr, "Handling SIGSEGV for sigaction\n");
siglongjmp(mark, 1);
}
exit(1);
}
int main(int argc, char **argv) {
__sighandler_t Prior = signal(SIGSEGV, SignalHandler);
assert(Prior == SIG_DFL);
if (sigsetjmp(mark, 1) == 0)
*((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV
fprintf(stderr, "Past longjmp for signal\n");
Prior = signal(SIGSEGV, SIG_DFL);
assert(Prior == SignalHandler);
struct sigaction SigAct;
SigAct.sa_sigaction = SigactionHandler;
int Res = sigfillset(&SigAct.sa_mask);
assert(Res == 0);
SigAct.sa_flags = SA_SIGINFO;
Res = sigaction(SIGSEGV, &SigAct, NULL);
assert(Res == 0);
if (sigsetjmp(mark, 1) == 0)
*((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV
fprintf(stderr, "Past longjmp for sigaction\n");
Res = sigaction(SIGSEGV, NULL, &SigAct);
assert(Res == 0);
assert(SigAct.sa_sigaction == SigactionHandler);
// Test blocking SIGSEGV and raising a shadow fault.
sigset_t Set;
sigemptyset(&Set);
sigaddset(&Set, SIGSEGV);
Res = sigprocmask(SIG_BLOCK, &Set, NULL);
// Make a large enough mapping that its start point will be before any
// prior library-region shadow access.
char *buf = (char *)mmap(0, 640*1024, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
buf[0] = 4;
munmap(buf, 640*1024);
fprintf(stderr, "Past blocked-SIGSEGV shadow fault\n");
return 0;
}
// CHECK: Handling SIGSEGV for signal
// CHECK-NEXT: Past longjmp for signal
// CHECK-NEXT: Handling SIGSEGV for sigaction
// CHECK-NEXT: Past longjmp for sigaction
// CHECK-NEXT: Past blocked-SIGSEGV shadow fault
// CHECK: {{.*}} EfficiencySanitizer: the total working set size: {{[0-9]+}} Bytes ({{[0-9][0-9]}} cache lines)

View File

@@ -0,0 +1,33 @@
// RUN: %clang_esan_wset -O0 %s -o %t 2>&1
// RUN: %run %t 2>&1 | FileCheck %s
// FIXME: Re-enable once PR33590 is fixed.
// UNSUPPORTED: x86_64
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
const int size = 0x1 << 25; // 523288 cache lines
const int line_size = 64;
int main(int argc, char **argv) {
char *bufA = (char *)malloc(sizeof(char) * line_size);
char bufB[64];
char *bufC = (char *)mmap(0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
bufA[0] = 0;
// This additional access to the same line should not increase the line
// count: but it's difficult to make a non-flaky test that measures the
// lines down to the ones digit so right now we're not really testing that.
// If we add a heap-only mode we may be able to be more precise.
bufA[1] = 0;
bufB[33] = 1;
for (int i = 0; i < size; i += line_size)
bufC[i] = 0;
free(bufA);
munmap(bufC, 0x4000);
// CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (524{{[0-9][0-9][0-9]}} cache lines)
return 0;
}

View File

@@ -0,0 +1,61 @@
// RUN: %clangxx_unit -O0 %s -o %t 2>&1
// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s
#include "esan/esan_circular_buffer.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include <assert.h>
#include <stdio.h>
static const int TestBufCapacity = 4;
// The buffer should have a capacity of TestBufCapacity.
void testBuffer(__esan::CircularBuffer<int> *Buf) {
assert(Buf->size() == 0);
assert(Buf->empty());
Buf->push_back(1);
assert(Buf->back() == 1);
assert((*Buf)[0] == 1);
assert(Buf->size() == 1);
assert(!Buf->empty());
Buf->push_back(2);
Buf->push_back(3);
Buf->push_back(4);
Buf->push_back(5);
assert((*Buf)[0] == 2);
assert(Buf->size() == 4);
Buf->pop_back();
assert((*Buf)[0] == 2);
assert(Buf->size() == 3);
Buf->pop_back();
Buf->pop_back();
assert((*Buf)[0] == 2);
assert(Buf->size() == 1);
assert(!Buf->empty());
Buf->pop_back();
assert(Buf->empty());
}
int main()
{
// Test initialize/free.
__esan::CircularBuffer<int> GlobalBuf;
GlobalBuf.initialize(TestBufCapacity);
testBuffer(&GlobalBuf);
GlobalBuf.free();
// Test constructor/free.
__esan::CircularBuffer<int> *LocalBuf;
static char placeholder[sizeof(*LocalBuf)];
LocalBuf = new(placeholder) __esan::CircularBuffer<int>(TestBufCapacity);
testBuffer(LocalBuf);
LocalBuf->free();
fprintf(stderr, "All checks passed.\n");
// CHECK: All checks passed.
return 0;
}

View File

@@ -0,0 +1,179 @@
// RUN: %clangxx_unit -esan-instrument-loads-and-stores=0 -O0 %s -o %t 2>&1
// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s
#include "esan/esan_hashtable.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class MyData {
public:
MyData(const char *Str) : RefCount(0) { Buf = strdup(Str); }
~MyData() {
fprintf(stderr, " Destructor: %s.\n", Buf);
free(Buf);
}
bool operator==(MyData &Cmp) { return strcmp(Buf, Cmp.Buf) == 0; }
operator size_t() const {
size_t Res = 0;
for (int i = 0; i < strlen(Buf); ++i)
Res ^= Buf[i];
return Res;
}
char *Buf;
int RefCount;
};
// We use a smart pointer wrapper to free the payload on hashtable removal.
struct MyDataPayload {
MyDataPayload() : Data(nullptr) {}
explicit MyDataPayload(MyData *Data) : Data(Data) { ++Data->RefCount; }
~MyDataPayload() {
if (Data && --Data->RefCount == 0) {
fprintf(stderr, "Deleting %s.\n", Data->Buf);
delete Data;
}
}
MyDataPayload(const MyDataPayload &Copy) {
Data = Copy.Data;
++Data->RefCount;
}
MyDataPayload & operator=(const MyDataPayload &Copy) {
if (this != &Copy) {
this->~MyDataPayload();
Data = Copy.Data;
++Data->RefCount;
}
return *this;
}
bool operator==(MyDataPayload &Cmp) { return *Data == *Cmp.Data; }
operator size_t() const { return (size_t)*Data; }
MyData *Data;
};
int main()
{
__esan::HashTable<int, int> IntTable;
assert(IntTable.size() == 0);
// Test iteration on an empty table.
int Count = 0;
for (auto Iter = IntTable.begin(); Iter != IntTable.end();
++Iter, ++Count) {
// Empty.
}
assert(Count == 0);
bool Added = IntTable.add(4, 42);
assert(Added);
assert(!IntTable.add(4, 42));
assert(IntTable.size() == 1);
int Value;
bool Found = IntTable.lookup(4, Value);
assert(Found && Value == 42);
// Test iterator.
IntTable.lock();
for (auto Iter = IntTable.begin(); Iter != IntTable.end();
++Iter, ++Count) {
assert((*Iter).Key == 4);
assert((*Iter).Data == 42);
}
IntTable.unlock();
assert(Count == 1);
assert(Count == IntTable.size());
assert(!IntTable.remove(5));
assert(IntTable.remove(4));
// Test a more complex payload.
__esan::HashTable<int, MyDataPayload> DataTable(4);
MyDataPayload NewData(new MyData("mystring"));
Added = DataTable.add(4, NewData);
assert(Added);
MyDataPayload FoundData;
Found = DataTable.lookup(4, FoundData);
assert(Found && strcmp(FoundData.Data->Buf, "mystring") == 0);
assert(!DataTable.remove(5));
assert(DataTable.remove(4));
// Test resize.
for (int i = 0; i < 4; ++i) {
MyDataPayload MoreData(new MyData("delete-at-end"));
Added = DataTable.add(i+1, MoreData);
assert(Added);
assert(!DataTable.add(i+1, MoreData));
}
for (int i = 0; i < 4; ++i) {
Found = DataTable.lookup(i+1, FoundData);
assert(Found && strcmp(FoundData.Data->Buf, "delete-at-end") == 0);
}
DataTable.lock();
Count = 0;
for (auto Iter = DataTable.begin(); Iter != DataTable.end();
++Iter, ++Count) {
int Key = (*Iter).Key;
FoundData = (*Iter).Data;
assert(Key >= 1 && Key <= 4);
assert(strcmp(FoundData.Data->Buf, "delete-at-end") == 0);
}
DataTable.unlock();
assert(Count == 4);
assert(Count == DataTable.size());
// Ensure the iterator supports a range-based for loop.
DataTable.lock();
Count = 0;
for (auto Pair : DataTable) {
assert(Pair.Key >= 1 && Pair.Key <= 4);
assert(strcmp(Pair.Data.Data->Buf, "delete-at-end") == 0);
++Count;
}
DataTable.unlock();
assert(Count == 4);
assert(Count == DataTable.size());
// Test payload freeing via smart pointer wrapper.
__esan::HashTable<MyDataPayload, MyDataPayload, true> DataKeyTable;
MyDataPayload DataA(new MyData("string AB"));
DataKeyTable.lock();
Added = DataKeyTable.add(DataA, DataA);
assert(Added);
Found = DataKeyTable.lookup(DataA, FoundData);
assert(Found && strcmp(FoundData.Data->Buf, "string AB") == 0);
MyDataPayload DataB(new MyData("string AB"));
Added = DataKeyTable.add(DataB, DataB);
assert(!Added);
DataKeyTable.remove(DataB); // Should free the DataA payload.
DataKeyTable.unlock();
// Test custom functors.
struct CustomHash {
size_t operator()(int Key) const { return Key % 4; }
};
struct CustomEqual {
bool operator()(int Key1, int Key2) const { return Key1 %4 == Key2 % 4; }
};
__esan::HashTable<int, int, false, CustomHash, CustomEqual> ModTable;
Added = ModTable.add(2, 42);
assert(Added);
Added = ModTable.add(6, 42);
assert(!Added);
fprintf(stderr, "All checks passed.\n");
return 0;
}
// CHECK: Deleting mystring.
// CHECK-NEXT: Destructor: mystring.
// CHECK-NEXT: All checks passed.
// CHECK-NEXT: Deleting string AB.
// CHECK-NEXT: Destructor: string AB.
// CHECK-NEXT: Deleting string AB.
// CHECK-NEXT: Destructor: string AB.
// CHECK-NEXT: Deleting delete-at-end.
// CHECK-NEXT: Destructor: delete-at-end.
// CHECK-NEXT: Deleting delete-at-end.
// CHECK-NEXT: Destructor: delete-at-end.
// CHECK-NEXT: Deleting delete-at-end.
// CHECK-NEXT: Destructor: delete-at-end.
// CHECK-NEXT: Deleting delete-at-end.
// CHECK-NEXT: Destructor: delete-at-end.

View File

@@ -0,0 +1,44 @@
# -*- Python -*-
import os
# Setup config name.
config.name = 'EfficiencySanitizer' + config.name_suffix
# Setup source root.
config.test_source_root = os.path.dirname(__file__)
# Setup default compiler flags used with -fsanitize=efficiency option.
base_cflags = ([config.target_cflags] + config.debug_info_flags)
base_cxxflags = config.cxx_mode_flags + base_cflags
frag_cflags = (["-fsanitize=efficiency-cache-frag"] + base_cflags)
wset_cflags = (["-fsanitize=efficiency-working-set"] + base_cflags)
esan_incdir = config.test_source_root + "/../../lib"
unit_cxxflags = (["-I%s" % esan_incdir, "-std=c++11",
# We need to link with the esan runtime.
# Tests should pass %env_esan_opts="record_snapshots=0".
"-fsanitize=efficiency-working-set"] + base_cxxflags)
def build_invocation(compile_flags):
return " " + " ".join([config.clang] + compile_flags) + " "
config.substitutions.append( ("%clang ",
build_invocation(base_cflags)) )
config.substitutions.append( ("%clang_esan_frag ",
build_invocation(frag_cflags)) )
config.substitutions.append( ("%clang_esan_wset ",
build_invocation(wset_cflags)) )
config.substitutions.append( ("%clangxx_unit",
build_invocation(unit_cxxflags)) )
default_esan_opts = ''
config.substitutions.append(('%env_esan_opts=',
'env ESAN_OPTIONS=' + default_esan_opts))
# Default test suffixes.
config.suffixes = ['.c', '.cpp']
# EfficiencySanitizer tests are currently supported on Linux x86-64 only.
if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'mips64'] :
config.unsupported = True

View File

@@ -0,0 +1,14 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
# Tool-specific config options.
config.name_suffix = "@ESAN_TEST_CONFIG_SUFFIX@"
config.esan_lit_source_dir = "@ESAN_LIT_SOURCE_DIR@"
config.target_cflags = "@ESAN_TEST_TARGET_CFLAGS@"
config.target_arch = "@ESAN_TEST_TARGET_ARCH@"
# Load common config for all compiler-rt lit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
# Load tool-specific config that would do the real work.
lit_config.load_config(config, "@ESAN_LIT_SOURCE_DIR@/lit.cfg")