summaryrefslogtreecommitdiff
path: root/test/esan
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
commit316d58822dada9440bd06ecfc758dcc2364d617c (patch)
treefe72ec2e6ce9a360dda74d9d57f7acdb0e3c39d6 /test/esan
parent0230fcf22fe7d19f03d981c9c2c59a3db0b72ea5 (diff)
Notes
Diffstat (limited to 'test/esan')
-rw-r--r--test/esan/TestCases/mmap-shadow-conflict.c24
-rw-r--r--test/esan/TestCases/struct-simple.cpp44
-rw-r--r--test/esan/TestCases/verbose-simple.c18
-rw-r--r--test/esan/Unit/hashtable.cpp179
-rw-r--r--test/esan/lit.cfg2
5 files changed, 232 insertions, 35 deletions
diff --git a/test/esan/TestCases/mmap-shadow-conflict.c b/test/esan/TestCases/mmap-shadow-conflict.c
index 4b3c58b06825c..8e86bba4adb1e 100644
--- a/test/esan/TestCases/mmap-shadow-conflict.c
+++ b/test/esan/TestCases/mmap-shadow-conflict.c
@@ -1,26 +1,40 @@
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
-// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck %s
+// 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.)
- // CHECK: Shadow scale=2 offset=0x440000000000
- // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
- // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
- // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
+ // 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: {{.*}}
diff --git a/test/esan/TestCases/struct-simple.cpp b/test/esan/TestCases/struct-simple.cpp
index c52154e094210..7ec9761fffa85 100644
--- a/test/esan/TestCases/struct-simple.cpp
+++ b/test/esan/TestCases/struct-simple.cpp
@@ -115,21 +115,21 @@ int main(int argc, char **argv) {
// 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: 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
+ // 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;
@@ -148,24 +148,24 @@ int main(int argc, char **argv) {
// 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: 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: 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: 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: 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
@@ -175,25 +175,25 @@ int main(int argc, char **argv) {
// 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: 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: 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: 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: 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
diff --git a/test/esan/TestCases/verbose-simple.c b/test/esan/TestCases/verbose-simple.c
index 0d867bf55d9ef..5ac37e159295f 100644
--- a/test/esan/TestCases/verbose-simple.c
+++ b/test/esan/TestCases/verbose-simple.c
@@ -1,14 +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 %s
+// 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.)
- // CHECK: Shadow scale=2 offset=0x440000000000
- // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
- // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
- // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
- // CHECK-NEXT: in esan::finalizeLibrary
- // CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
+ // 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;
}
diff --git a/test/esan/Unit/hashtable.cpp b/test/esan/Unit/hashtable.cpp
new file mode 100644
index 0000000000000..390a427da255b
--- /dev/null
+++ b/test/esan/Unit/hashtable.cpp
@@ -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.
diff --git a/test/esan/lit.cfg b/test/esan/lit.cfg
index cf16a6b5df44b..8b8457d66e00d 100644
--- a/test/esan/lit.cfg
+++ b/test/esan/lit.cfg
@@ -40,5 +40,5 @@ config.substitutions.append(('%env_esan_opts=',
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 != 'x86_64':
+if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'mips64'] :
config.unsupported = True