|  | // RUN: %clang_safestack %s -pthread -o %t | 
|  | // RUN: %run %t | 
|  |  | 
|  | // Test unsafe stack deallocation with custom stack sizes, in particular ensure | 
|  | // that we correctly deallocate small stacks and don't accidentally deallocate | 
|  | // adjacent memory. | 
|  |  | 
|  | #include <pthread.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | volatile int step = 0; | 
|  |  | 
|  | void *wait_until(void *ptr) { | 
|  | while ((int)ptr != step) | 
|  | usleep(1000); | 
|  |  | 
|  | volatile char buf[64]; | 
|  | buf[0] = 0; | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) { | 
|  | pthread_t t1, t2, t3; | 
|  |  | 
|  | pthread_attr_t small_stack_attr; | 
|  | pthread_attr_init(&small_stack_attr); | 
|  | pthread_attr_setstacksize(&small_stack_attr, 65536); | 
|  |  | 
|  | if (pthread_create(&t3, NULL, wait_until, (void *)3)) | 
|  | abort(); | 
|  | if (pthread_create(&t1, &small_stack_attr, wait_until, (void *)1)) | 
|  | abort(); | 
|  | if (pthread_create(&t2, NULL, wait_until, (void *)2)) | 
|  | abort(); | 
|  |  | 
|  | step = 1; | 
|  | if (pthread_join(t1, NULL)) | 
|  | abort(); | 
|  |  | 
|  | step = 2; | 
|  | if (pthread_join(t2, NULL)) | 
|  | abort(); | 
|  |  | 
|  | step = 3; | 
|  | if (pthread_join(t3, NULL)) | 
|  | abort(); | 
|  |  | 
|  | pthread_attr_destroy(&small_stack_attr); | 
|  | return 0; | 
|  | } |