xref: /llvm-project/compiler-rt/test/asan/TestCases/Linux/odr_indicator_unregister.cpp (revision e185850ce735ade5924129bec56a5954c443cf17)
1 // Test that captures the current behavior of indicator-based ASan ODR checker
2 // when globals get unregistered.
3 //
4 // RUN: %clangxx_asan -g -O0 -DSHARED_LIB -DSIZE=1 %s -fPIC -shared -o %t-so-1.so
5 // RUN: %clangxx_asan -g -O0 -DSHARED_LIB -DSIZE=2 %s -fPIC -shared -o %t-so-2.so
6 // RUN: %clangxx_asan -g -O0 %s %libdl -Wl,--export-dynamic -o %t
7 // RUN: %env_asan_opts=report_globals=2:detect_odr_violation=1 %run %t 2>&1 | FileCheck %s
8 
9 // FIXME: Checks do not match on Android.
10 // UNSUPPORTED: android
11 
12 #include <cstdlib>
13 #include <dlfcn.h>
14 #include <stdio.h>
15 #include <string>
16 
17 #ifdef SHARED_LIB
18 namespace foo {
19 char G[SIZE];
20 }
21 #else // SHARED_LIB
22 void *dlopen_or_die(std::string &path) {
23   void *handle = dlopen(path.c_str(), RTLD_NOW);
24   if (handle) {
25     printf("Successfully called dlopen() on %s\n", path.c_str());
26   } else {
27     printf("Error in dlopen(): %s\n", dlerror());
28     std::exit(1);
29   }
30 
31   return handle;
32 }
33 
34 void dlclose_or_die(void *handle, std::string &path) {
35   if (!dlclose(handle)) {
36     printf("Successfully called dlclose() on %s\n", path.c_str());
37   } else {
38     printf("Error in dlclose(): %s\n", dlerror());
39     std::exit(1);
40   }
41 }
42 
43 namespace foo {
44 char G[1];
45 }
46 
47 // main has its own version of foo::G
48 // CHECK: Added Global[[MAIN_G:[^\s]+]] size=1/32 name=foo::G {{.*}}
49 int main(int argc, char *argv[]) {
50   std::string base_path = std::string(argv[0]);
51 
52   std::string path1 = base_path + "-so-1.so";
53   // dlopen() brings another foo::G but it matches MAIN_G in size so it's not a
54   // violation
55   //
56   //
57   // CHECK: Added Global[[SO1_G:[^\s]+]] size=1/32 name=foo::G {{.*}}
58   // CHECK-NOT: ERROR: AddressSanitizer: odr-violation
59   void *handle1 = dlopen_or_die(path1);
60   // CHECK: Removed Global[[SO1_G]] size=1/32 name=foo::G {{.*}}
61   dlclose_or_die(handle1, path1);
62 
63   // At this point the indicator for foo::G is switched to UNREGISTERED for
64   // **both** MAIN_G and SO1_G because the indicator value is shared.
65 
66   std::string path2 = base_path + "-so-2.so";
67   // CHECK: Added Global[[SO2_G:[^\s]+]] size=2/32 name=foo::G {{.*}}
68   //
69   // This brings another foo::G but now different in size from MAIN_G. We
70   // should've reported a violation, but we actually don't because of what's
71   // described on line60
72   //
73   // CHECK-NOT: ERROR: AddressSanitizer: odr-violation
74   void *handle2 = dlopen_or_die(path2);
75   // CHECK: Removed Global[[MAIN_G]] size=1/32 name=foo::G {{.*}}
76   // CHECK: Removed Global[[SO2_G]] size=2/32 name=foo::G {{.*}}
77 }
78 
79 #endif // SHARED_LIB
80