| #import <Foundation/Foundation.h> | |
| #import <pthread.h> | |
| long my_global; | |
| void *Thread1(void *arg) { | |
| my_global = 42; | |
| return NULL; | |
| } | |
| void *Thread2(void *arg) { | |
| my_global = 144; | |
| return NULL; | |
| } | |
| void TestDataRace1() { | |
| pthread_t t1, t2; | |
| pthread_create(&t1, NULL, Thread1, NULL); | |
| pthread_create(&t2, NULL, Thread2, NULL); | |
| pthread_join(t1, NULL); | |
| pthread_join(t2, NULL); | |
| } | |
| void TestInvalidMutex() { | |
| pthread_mutex_t m = {0}; | |
| pthread_mutex_lock(&m); | |
| pthread_mutex_init(&m, NULL); | |
| pthread_mutex_lock(&m); | |
| pthread_mutex_unlock(&m); | |
| pthread_mutex_destroy(&m); | |
| pthread_mutex_lock(&m); | |
| } | |
| void TestMutexWrongLock() { | |
| pthread_mutex_t m = {0}; | |
| pthread_mutex_init(&m, NULL); | |
| pthread_mutex_unlock(&m); | |
| } | |
| long some_global; | |
| void TestDataRaceBlocks1() { | |
| dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); | |
| for (int i = 0; i < 2; i++) { | |
| dispatch_async(q, ^{ | |
| some_global++; // race 1 | |
| usleep(100000); // force the blocks to be on different threads | |
| }); | |
| } | |
| usleep(100000); | |
| dispatch_barrier_sync(q, ^{ }); | |
| } | |
| void TestDataRaceBlocks2() { | |
| dispatch_queue_t q = dispatch_queue_create("my.queue2", DISPATCH_QUEUE_CONCURRENT); | |
| char *c; | |
| c = malloc((rand() % 1000) + 10); | |
| for (int i = 0; i < 2; i++) { | |
| dispatch_async(q, ^{ | |
| c[0] = 'x'; // race 2 | |
| fprintf(stderr, "tid: %p\n", pthread_self()); | |
| usleep(100000); // force the blocks to be on different threads | |
| }); | |
| } | |
| dispatch_barrier_sync(q, ^{ }); | |
| free(c); | |
| } | |
| void TestUseAfterFree() { | |
| char *c; | |
| c = malloc((rand() % 1000) + 10); | |
| free(c); | |
| c[0] = 'x'; | |
| } | |
| void TestRacePipe() { | |
| dispatch_queue_t q = dispatch_queue_create("my.queue3", DISPATCH_QUEUE_CONCURRENT); | |
| int a[2]; | |
| pipe(a); | |
| int fd = a[0]; | |
| for (int i = 0; i < 2; i++) { | |
| dispatch_async(q, ^{ | |
| write(fd, "abc", 3); | |
| usleep(100000); // force the blocks to be on different threads | |
| }); | |
| dispatch_async(q, ^{ | |
| close(fd); | |
| usleep(100000); | |
| }); | |
| } | |
| dispatch_barrier_sync(q, ^{ }); | |
| } | |
| void TestThreadLeak() { | |
| pthread_t t1; | |
| pthread_create(&t1, NULL, Thread1, NULL); | |
| } | |
| int main(int argc, const char * argv[]) { | |
| TestDataRace1(); | |
| TestInvalidMutex(); | |
| TestMutexWrongLock(); | |
| TestDataRaceBlocks1(); | |
| TestDataRaceBlocks2(); | |
| TestUseAfterFree(); | |
| TestRacePipe(); | |
| TestThreadLeak(); | |
| return 0; | |
| } |