// Bugs caught within missing GCD dispatch blocks result in thread being reported as T-1 // with an empty stack. // This tests that dispatch_apply blocks can capture valid thread number and stack. // RUN: %clang_asan %s -o %t // RUN: not %run %t func 2>&1 | FileCheck %s --check-prefixes=CHECK-FUNC,CHECK // RUN: not %run %t block 2>&1 | FileCheck %s --check-prefixes=CHECK-BLOCK,CHECK #include #include #include __attribute__((noinline)) void access_memory_frame(char *x) { *x = 0; } __attribute__((noinline)) void test_dispatch_apply() { char *x = (char *)malloc(4); dispatch_apply(8, dispatch_get_global_queue(0, 0), ^(size_t i) { access_memory_frame(&x[i]); }); } typedef struct { char *data; } Context; void da_func(void *ctx, size_t i) { Context *c = (Context *)ctx; access_memory_frame(&c->data[i]); } __attribute__((noinline)) void test_dispatch_apply_f() { Context *ctx = (Context *)malloc(sizeof(Context)); ctx->data = (char *)malloc(4); dispatch_apply_f(8, dispatch_get_global_queue(0, 0), ctx, da_func); } int main(int argc, const char *argv[]) { if (strcmp(argv[1], "func") == 0) { fprintf(stderr, "Test dispatch_apply with function\n"); // CHECK-FUNC: dispatch_apply with function test_dispatch_apply_f(); } else if (strcmp(argv[1], "block") == 0) { fprintf(stderr, "Test dispatch_apply with block\n"); // CHECK-BLOCK: dispatch_apply with block test_dispatch_apply(); } else { abort(); } return 0; } // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow // CHECK: #0 0x{{.*}} in {{.*}}access_memory_frame // CHECK-NOT: T-1