1- // Check that HwASan plays well with annotated makecontext/swapcontext .
2-
3- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
4- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
5- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
6- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
7- // RUN: seq 60 | xargs -i -- grep LOOPCHECK %s > %t.checks
8- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
9- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
10- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
11- // RUN: %clangxx_hwasan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
1+ // Test hwasan __sanitizer_start_switch_fiber and __sanitizer_finish_switch_fiber interface .
2+
3+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O0 %s -o %t && %run %t 2>&1 | FileCheck %s
4+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O1 %s -o %t && %run %t 2>&1 | FileCheck %s
5+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O2 %s -o %t && %run %t 2>&1 | FileCheck %s
6+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O3 %s -o %t && %run %t 2>&1 | FileCheck %s
7+ // RUN: seq 30 | xargs -i -- grep LOOPCHECK %s > %t.checks
8+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O0 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
9+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O1 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
10+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O2 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
11+ // RUN: %clangxx_hwasan -std=c++11 -lpthread -ldl - O3 %s -o %t && %run %t 2>&1 | FileCheck %t.checks --check-prefix LOOPCHECK
1212
1313//
14- // This test is too subtle to try on non-x86 arch for now.
1514// Android and musl do not support swapcontext.
16- // REQUIRES: x86-target-arch && glibc-2.27
15+ // REQUIRES: glibc-2.27
1716
1817#include < pthread.h>
1918#include < setjmp.h>
2221#include < sys/time.h>
2322#include < ucontext.h>
2423#include < unistd.h>
24+ #include < dlfcn.h>
2525
2626#include < sanitizer/common_interface_defs.h>
2727
@@ -125,31 +125,30 @@ int Run(int arg, int mode, char *child_stack) {
125125 }
126126 makecontext (&child_context, (void (*)())Child, 1 , mode);
127127 CallNoReturn ();
128- void *fake_stack_save;
129- __sanitizer_start_switch_fiber (&fake_stack_save, child_context.uc_stack .ss_sp ,
128+ __sanitizer_start_switch_fiber (nullptr , child_context.uc_stack .ss_sp ,
130129 child_context.uc_stack .ss_size );
131130 CallNoReturn ();
132131 if (swapcontext (&orig_context, &child_context) < 0 ) {
133132 perror (" swapcontext" );
134133 _exit (1 );
135134 }
136135 CallNoReturn ();
137- __sanitizer_finish_switch_fiber (fake_stack_save, &from_stack,
138- &from_stacksize);
136+ __sanitizer_finish_switch_fiber (nullptr , &from_stack, &from_stacksize);
139137 CallNoReturn ();
140138 printf (" Main context from: %p %zu\n " , from_stack, from_stacksize);
141139
142- // Touch childs's stack to make sure it's unpoisoned.
143- for (int i = 0 ; i < kStackSize ; i++) {
144- child_stack[i] = i;
145- }
146140 return child_stack[arg];
147141}
148142
149143void handler (int sig) { CallNoReturn (); }
150144
151145int main (int argc, char **argv) {
152- // removed huge stack test since hwasan has no huge stack limitations
146+ // This testcase is copied from ASan's swapcontext_annotation.cpp testcase
147+ // and adapted to HWASan:
148+ // 1. removed huge stack test since hwasan has no huge stack limitations
149+ // 2. stack allocations are now done with original malloc/free instead of
150+ // hwasan interceptor, since HWASan does not support tagged stack pointer
151+ // in longjmp (see __hwasan_handle_longjmp)
153152
154153 // set up a signal that will spam and trigger __hwasan_handle_vfork at
155154 // tricky moments
@@ -169,34 +168,45 @@ int main(int argc, char **argv) {
169168 _exit (1 );
170169 }
171170
172- char *heap = new char [kStackSize + 1 ];
173- next_child_stack = new char [kStackSize + 1 ];
174- char stack[kStackSize + 1 ];
171+ // We search malloc/free here because the original symbol is intercepted.
172+ // Unfortunately, hwasan does not support longjmp with tagged stack pointer,
173+ // so we use RTLD_NEXT to search original symbols assuming hwasan is
174+ // statically linked (default behavior currently).
175+ void *(*malloc_func)(size_t ) = (void *(*)(size_t )) dlsym (RTLD_NEXT, " malloc" );
176+ if (malloc_func == nullptr ) {
177+ perror (" dlsym malloc" );
178+ _exit (1 );
179+ }
180+ void (*free_func)(void *) = (void (*)(void *)) dlsym (RTLD_NEXT, " free" );
181+ if (free_func == nullptr ) {
182+ perror (" dlsym free" );
183+ _exit (1 );
184+ }
185+
186+ char *heap = (char *)malloc_func (kStackSize + 1 );
187+ next_child_stack = (char *)malloc_func (kStackSize + 1 );
175188 int ret = 0 ;
176189 // CHECK-NOT: WARNING: HWASan is ignoring requested __hwasan_handle_vfork
177190 for (unsigned int i = 0 ; i < 30 ; ++i) {
178- ret += Run (argc - 1 , 0 , stack);
179191 // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]
180192 // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288
181- ret += Run (argc - 1 , 1 , stack );
193+ ret += Run (argc - 1 , 0 , heap );
182194 // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]
183195 // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288
184- ret += Run (argc - 1 , 2 , stack );
196+ ret += Run (argc - 1 , 1 , heap );
185197 // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]]
186198 // LOOPCHECK: NextChild stack: [[NEXT_CHILD_STACK:0x[0-9a-f]*]]
187199 // LOOPCHECK: NextChild from: [[CHILD_STACK]] 524288
188200 // LOOPCHECK: Main context from: [[NEXT_CHILD_STACK]] 524288
189- ret += Run (argc - 1 , 0 , heap);
190- ret += Run (argc - 1 , 1 , heap);
191201 ret += Run (argc - 1 , 2 , heap);
192202 printf (" Iteration %d passed\n " , i);
193203 }
194204
195205 // CHECK: Test passed
196206 printf (" Test passed\n " );
197207
198- delete[] heap;
199- delete[] next_child_stack;
208+ free_func ( heap) ;
209+ free_func ( next_child_stack) ;
200210
201211 return ret;
202212}
0 commit comments