1 // Test that mach_vm_[de]allocate resets shadow memory status.
2 //
3 // RUN: %clang_tsan %s -o %t
4 // RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'
5 
6 #include <mach/mach.h>
7 #include <mach/mach_vm.h>
8 #include <pthread.h>
9 #include <assert.h>
10 #include <stdio.h>
11 
12 #include "../test.h"
13 
14 const mach_vm_size_t alloc_size = sizeof(int);
15 static int *global_ptr;
16 
alloc()17 static int *alloc() {
18   mach_vm_address_t addr;
19   kern_return_t kr =
20       mach_vm_allocate(mach_task_self(), &addr, alloc_size, VM_FLAGS_ANYWHERE);
21   assert(kr == KERN_SUCCESS);
22   return (int *)addr;
23 }
24 
alloc_fixed(int * ptr)25 static void alloc_fixed(int *ptr) {
26   mach_vm_address_t addr = (mach_vm_address_t)ptr;
27   // Re-allocation via VM_FLAGS_FIXED sporadically fails.
28   kern_return_t kr =
29       mach_vm_allocate(mach_task_self(), &addr, alloc_size, VM_FLAGS_FIXED);
30   if (kr != KERN_SUCCESS)
31     global_ptr = NULL;
32 }
33 
dealloc(int * ptr)34 static void dealloc(int *ptr) {
35   kern_return_t kr =
36       mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)ptr, alloc_size);
37   assert(kr == KERN_SUCCESS);
38 }
39 
Thread(void * arg)40 static void *Thread(void *arg) {
41   *global_ptr = 7;  // Assignment 1
42 
43   // We want to test that TSan does not report a race between the two
44   // assignments to *global_ptr when the underlying memory is re-allocated
45   // between assignments. The calls to the API itself are racy though, so ignore
46   // them.
47   AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
48   dealloc(global_ptr);
49   alloc_fixed(global_ptr);
50   AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
51 
52   barrier_wait(&barrier);
53   return NULL;
54 }
55 
try_realloc_on_same_address()56 static bool try_realloc_on_same_address() {
57   barrier_init(&barrier, 2);
58   global_ptr = alloc();
59   pthread_t t;
60   pthread_create(&t, NULL, Thread, NULL);
61 
62   barrier_wait(&barrier);
63   if (global_ptr)
64     *global_ptr = 8;  // Assignment 2
65 
66   pthread_join(t, NULL);
67   dealloc(global_ptr);
68 
69   return global_ptr != NULL;
70 }
71 
main(int argc,const char * argv[])72 int main(int argc, const char *argv[]) {
73   bool success;
74   for (int i = 0; i < 10; i++) {
75     success = try_realloc_on_same_address();
76     if (success) break;
77   }
78 
79   if (!success)
80     fprintf(stderr, "Unable to set up testing condition; silently pass test\n");
81 
82   printf("Done.\n");
83   return 0;
84 }
85 
86 // CHECK: Done.
87