1//===-- main.c --------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#import <Foundation/Foundation.h>
10#import <pthread.h>
11
12long my_global;
13
14void *Thread1(void *arg) {
15    my_global = 42;
16    return NULL;
17}
18
19void *Thread2(void *arg) {
20    my_global = 144;
21    return NULL;
22}
23
24void TestDataRace1() {
25    pthread_t t1, t2;
26    pthread_create(&t1, NULL, Thread1, NULL);
27    pthread_create(&t2, NULL, Thread2, NULL);
28
29    pthread_join(t1, NULL);
30    pthread_join(t2, NULL);
31}
32
33void TestInvalidMutex() {
34    pthread_mutex_t m = {0};
35    pthread_mutex_lock(&m);
36
37    pthread_mutex_init(&m, NULL);
38    pthread_mutex_lock(&m);
39    pthread_mutex_unlock(&m);
40    pthread_mutex_destroy(&m);
41    pthread_mutex_lock(&m);
42}
43
44void TestMutexWrongLock() {
45    pthread_mutex_t m = {0};
46    pthread_mutex_init(&m, NULL);
47    pthread_mutex_unlock(&m);
48}
49
50long some_global;
51
52void TestDataRaceBlocks1() {
53    dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
54
55    for (int i = 0; i < 2; i++) {
56        dispatch_async(q, ^{
57            some_global++;  // race 1
58
59            usleep(100000);  // force the blocks to be on different threads
60        });
61    }
62
63    usleep(100000);
64    dispatch_barrier_sync(q, ^{ });
65}
66
67void TestDataRaceBlocks2() {
68    dispatch_queue_t q = dispatch_queue_create("my.queue2", DISPATCH_QUEUE_CONCURRENT);
69
70    char *c;
71
72    c = malloc((rand() % 1000) + 10);
73    for (int i = 0; i < 2; i++) {
74        dispatch_async(q, ^{
75            c[0] = 'x';  // race 2
76            fprintf(stderr, "tid: %p\n", pthread_self());
77            usleep(100000);  // force the blocks to be on different threads
78        });
79    }
80    dispatch_barrier_sync(q, ^{ });
81
82    free(c);
83}
84
85void TestUseAfterFree() {
86    char *c;
87
88    c = malloc((rand() % 1000) + 10);
89    free(c);
90    c[0] = 'x';
91}
92
93void TestRacePipe() {
94    dispatch_queue_t q = dispatch_queue_create("my.queue3", DISPATCH_QUEUE_CONCURRENT);
95
96    int a[2];
97    pipe(a);
98    int fd = a[0];
99
100    for (int i = 0; i < 2; i++) {
101        dispatch_async(q, ^{
102            write(fd, "abc", 3);
103            usleep(100000);  // force the blocks to be on different threads
104        });
105        dispatch_async(q, ^{
106            close(fd);
107            usleep(100000);
108        });
109    }
110
111    dispatch_barrier_sync(q, ^{ });
112}
113
114void TestThreadLeak() {
115    pthread_t t1;
116    pthread_create(&t1, NULL, Thread1, NULL);
117}
118
119int main(int argc, const char * argv[]) {
120    TestDataRace1();
121
122    TestInvalidMutex();
123
124    TestMutexWrongLock();
125
126    TestDataRaceBlocks1();
127
128    TestDataRaceBlocks2();
129
130    TestUseAfterFree();
131
132    TestRacePipe();
133
134    TestThreadLeak();
135
136    return 0;
137}
138