|  | // RUN: %clang_analyze_cc1 \ | 
|  | // RUN:   -analyzer-checker=unix.BlockInCriticalSection \ | 
|  | // RUN:   -std=c++11 \ | 
|  | // RUN:   -analyzer-output text \ | 
|  | // RUN:   -verify %s | 
|  |  | 
|  | void sleep(int x) {} | 
|  |  | 
|  | namespace std { | 
|  | struct mutex { | 
|  | void lock() {} | 
|  | void unlock() {} | 
|  | }; | 
|  | template<typename T> | 
|  | struct lock_guard { | 
|  | lock_guard<T>(std::mutex) {} | 
|  | ~lock_guard<T>() {} | 
|  | }; | 
|  | template<typename T> | 
|  | struct unique_lock { | 
|  | unique_lock<T>(std::mutex) {} | 
|  | ~unique_lock<T>() {} | 
|  | }; | 
|  | template<typename T> | 
|  | struct not_real_lock { | 
|  | not_real_lock<T>(std::mutex) {} | 
|  | }; | 
|  | } // namespace std | 
|  |  | 
|  | struct FILE; | 
|  | int getc(FILE *stream); | 
|  | char* fgets(char *str, FILE *stream); | 
|  | using ssize_t = long long; | 
|  | using size_t = unsigned long long; | 
|  | ssize_t read(int fd, void *buf, size_t count); | 
|  | ssize_t recv(int sockfd, void *buf, size_t len, int flags); | 
|  |  | 
|  | struct pthread_mutex_t; | 
|  | int pthread_mutex_lock(pthread_mutex_t *mutex); | 
|  | int pthread_mutex_trylock(pthread_mutex_t *mutex); | 
|  | int pthread_mutex_unlock(pthread_mutex_t *mutex); | 
|  |  | 
|  | struct mtx_t; | 
|  | int mtx_lock(mtx_t *mutex); | 
|  | int mtx_timedlock(mtx_t *mutex); | 
|  | int mtx_trylock(mtx_t *mutex); | 
|  | int mtx_unlock(mtx_t *mutex); | 
|  |  | 
|  | // global params for dummy function calls | 
|  | FILE *stream; | 
|  | char *str; | 
|  | int fd; | 
|  | void *buf; | 
|  | size_t count; | 
|  | int sockfd; | 
|  | size_t len; | 
|  | int flags; | 
|  |  | 
|  | void testBlockInCriticalSectionWithStdMutex() { | 
|  | std::mutex m; | 
|  | m.lock(); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionWithPthreadMutex(pthread_mutex_t *mutex) { | 
|  | pthread_mutex_lock(mutex); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | pthread_mutex_unlock(mutex); | 
|  |  | 
|  | pthread_mutex_trylock(mutex); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | pthread_mutex_unlock(mutex); | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionC11Locks(mtx_t *mutex) { | 
|  | mtx_lock(mutex); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | mtx_unlock(mutex); | 
|  |  | 
|  | mtx_timedlock(mutex); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | mtx_unlock(mutex); | 
|  |  | 
|  | mtx_trylock(mutex); // expected-note 5{{Entering critical section here}} | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}} | 
|  | fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}} | 
|  | read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'read' inside of critical section}} | 
|  | recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}} | 
|  | mtx_unlock(mutex); | 
|  | } | 
|  |  | 
|  | void testMultipleBlockingCalls() { | 
|  | std::mutex m; | 
|  | m.lock(); // expected-note 1{{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | sleep(2); // no-warning | 
|  | } | 
|  |  | 
|  | void testMultipleMutexesMultipleBlockingCalls() { | 
|  | std::mutex m, n, k; | 
|  | m.lock(); // expected-note 2{{Entering critical section here}} | 
|  | n.lock(); // expected-note 2{{Entering critical section here}} | 
|  | k.lock(); // expected-note 1{{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | k.unlock(); | 
|  | sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | } | 
|  |  | 
|  |  | 
|  | void testRecursiveAcquisition() { | 
|  | std::mutex m; | 
|  | m.lock(); // expected-note {{Entering critical section for the 1st time here}} | 
|  | m.lock(); // expected-note {{Entering critical section for the 2nd time here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void testRecursiveAcquisitionWithMultipleBlockingCalls() { | 
|  | std::mutex m; | 
|  | m.lock(); // expected-note 1{{Entering critical section for the 1st time here}} | 
|  | // expected-note@-1 {{Entering critical section here}} | 
|  | m.lock(); // expected-note 1{{Entering critical section for the 2nd time here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | // this next 'sleep' call is only in the critical section of the first lock | 
|  | sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void testRecursiveAcquisitionWithMultipleMutexes() { | 
|  | std::mutex m, n; | 
|  | m.lock(); // expected-note 1{{Entering critical section here}} | 
|  | n.lock(); // expected-note 2{{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | // this next 'sleep' call is only in the critical section of mutex 'n' | 
|  | sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | n.unlock(); | 
|  | } | 
|  |  | 
|  |  | 
|  | void testNestedMutexes() { | 
|  | std::mutex m, n, k; | 
|  | m.lock(); // expected-note 3{{Entering critical section here}} | 
|  | n.lock(); // expected-note 2{{Entering critical section here}} | 
|  | k.lock(); // expected-note 1{{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | k.unlock(); | 
|  | sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | n.unlock(); | 
|  | sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | sleep(4); // no-warning | 
|  | } | 
|  |  | 
|  | void testNonOverlappingMutexes() { | 
|  | std::mutex m; | 
|  | m.lock(); // There should be no warning here | 
|  | m.unlock(); | 
|  | m.lock(); // expected-note {{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void testMixedMutexLocksWithIntermittentUnlock() { | 
|  | std::mutex m, n, k; | 
|  | m.lock(); // expected-note {{Entering critical section here}} | 
|  | n.lock(); // the problem is not is this lock's critical section | 
|  | n.unlock(); | 
|  | k.lock(); // same as for n.lock() | 
|  | k.unlock(); | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void f() { | 
|  | sleep(1000); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionInterProcedural() { | 
|  | std::mutex m; | 
|  | m.lock(); // expected-note {{Entering critical section here}} | 
|  | f(); // expected-note {{Calling 'f'}} | 
|  | m.unlock(); | 
|  | } | 
|  |  | 
|  | void unknown_function_that_may_lock(std::mutex &); | 
|  | void testBlockInCriticalSectionUnexpectedUnlock() { | 
|  | std::mutex m; | 
|  | unknown_function_that_may_lock(m); | 
|  | m.unlock(); | 
|  | sleep(1); // no-warning | 
|  | m.lock(); // expected-note {{Entering critical section here}} | 
|  | sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionLockGuard() { | 
|  | std::mutex g_mutex; | 
|  | std::not_real_lock<std::mutex> not_real_lock(g_mutex); | 
|  | sleep(1); // no-warning | 
|  |  | 
|  | std::lock_guard<std::mutex> lock(g_mutex); // expected-note {{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionLockGuardNested() { | 
|  | testBlockInCriticalSectionLockGuard(); // expected-note {{Calling 'testBlockInCriticalSectionLockGuard'}} | 
|  | sleep(1); // no-warning | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionUniqueLock() { | 
|  | std::mutex g_mutex; | 
|  | std::not_real_lock<std::mutex> not_real_lock(g_mutex); | 
|  | sleep(1); // no-warning | 
|  |  | 
|  | std::unique_lock<std::mutex> lock(g_mutex); // expected-note {{Entering critical section here}} | 
|  | sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | } | 
|  |  | 
|  | void testBlockInCriticalSectionUniqueLockNested() { | 
|  | testBlockInCriticalSectionUniqueLock(); // expected-note {{Calling 'testBlockInCriticalSectionUniqueLock'}} | 
|  | sleep(1); // no-warning | 
|  | } | 
|  |  | 
|  | void testTrylockCurrentlyFalsePositive(pthread_mutex_t *m) { | 
|  | // expected-note@+4 {{Assuming the condition is true}} | 
|  | // expected-note@+3 {{Taking true branch}} | 
|  | // expected-note@+2 {{Assuming the condition is false}} | 
|  | // expected-note@+1 {{Taking false branch}} | 
|  | if (pthread_mutex_trylock(m) == 0) { // expected-note 2 {{Entering critical section here}} | 
|  | // FIXME: we are entering the critical section only in the true branch | 
|  | sleep(10); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | pthread_mutex_unlock(m); | 
|  | } else { | 
|  | sleep(10); // expected-warning {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}} | 
|  | // FIXME: this is a false positive, the lock was not acquired | 
|  | } | 
|  | } |