xref: /llvm-project/clang/test/Analysis/block-in-critical-section.cpp (revision 6ef785c9517e8e44ddda8263e5f319b44f56cff8)
1 // RUN: %clang_analyze_cc1 \
2 // RUN:   -analyzer-checker=unix.BlockInCriticalSection \
3 // RUN:   -std=c++11 \
4 // RUN:   -analyzer-output text \
5 // RUN:   -verify %s
6 
sleep(int x)7 void sleep(int x) {}
8 
9 namespace std {
10 struct mutex {
lockstd::mutex11   void lock() {}
unlockstd::mutex12   void unlock() {}
13 };
14 template<typename T>
15 struct lock_guard {
lock_guardstd::lock_guard16   lock_guard<T>(std::mutex) {}
17   ~lock_guard<T>() {}
18 };
19 template<typename T>
20 struct unique_lock {
unique_lockstd::unique_lock21   unique_lock<T>(std::mutex) {}
22   ~unique_lock<T>() {}
23 };
24 template<typename T>
25 struct not_real_lock {
not_real_lockstd::not_real_lock26   not_real_lock<T>(std::mutex) {}
27 };
28 } // namespace std
29 
30 struct FILE;
31 int getc(FILE *stream);
32 char* fgets(char *str, FILE *stream);
33 using ssize_t = long long;
34 using size_t = unsigned long long;
35 ssize_t read(int fd, void *buf, size_t count);
36 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
37 
38 struct pthread_mutex_t;
39 int pthread_mutex_lock(pthread_mutex_t *mutex);
40 int pthread_mutex_trylock(pthread_mutex_t *mutex);
41 int pthread_mutex_unlock(pthread_mutex_t *mutex);
42 
43 struct mtx_t;
44 int mtx_lock(mtx_t *mutex);
45 int mtx_timedlock(mtx_t *mutex);
46 int mtx_trylock(mtx_t *mutex);
47 int mtx_unlock(mtx_t *mutex);
48 
49 // global params for dummy function calls
50 FILE *stream;
51 char *str;
52 int fd;
53 void *buf;
54 size_t count;
55 int sockfd;
56 size_t len;
57 int flags;
58 
testBlockInCriticalSectionWithStdMutex()59 void testBlockInCriticalSectionWithStdMutex() {
60   std::mutex m;
61   m.lock(); // expected-note 5{{Entering critical section here}}
62   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
63             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
64   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
65           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
66   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
67            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
68   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
69           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
70   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
71           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
72   m.unlock();
73 }
74 
testBlockInCriticalSectionWithPthreadMutex(pthread_mutex_t * mutex)75 void testBlockInCriticalSectionWithPthreadMutex(pthread_mutex_t *mutex) {
76   pthread_mutex_lock(mutex); // expected-note 5{{Entering critical section here}}
77   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
78             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
79   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
80           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
81   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
82            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
83   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
84           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
85   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
86           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
87   pthread_mutex_unlock(mutex);
88 
89   pthread_mutex_trylock(mutex); // expected-note 5{{Entering critical section here}}
90   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
91             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
92   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
93           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
94   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
95            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
96   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
97           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
98   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
99           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
100   pthread_mutex_unlock(mutex);
101 }
102 
testBlockInCriticalSectionC11Locks(mtx_t * mutex)103 void testBlockInCriticalSectionC11Locks(mtx_t *mutex) {
104   mtx_lock(mutex); // expected-note 5{{Entering critical section here}}
105   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
106             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
107   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
108           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
109   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
110            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
111   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
112           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
113   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
114           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
115   mtx_unlock(mutex);
116 
117   mtx_timedlock(mutex); // expected-note 5{{Entering critical section here}}
118   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
119             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
120   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
121           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
122   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
123            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
124   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
125           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
126   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
127           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
128   mtx_unlock(mutex);
129 
130   mtx_trylock(mutex); // expected-note 5{{Entering critical section here}}
131   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
132             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
133   getc(stream); // expected-warning {{Call to blocking function 'getc' inside of critical section}}
134           // expected-note@-1 {{Call to blocking function 'getc' inside of critical section}}
135   fgets(str, stream); // expected-warning {{Call to blocking function 'fgets' inside of critical section}}
136            // expected-note@-1 {{Call to blocking function 'fgets' inside of critical section}}
137   read(fd, buf, count); // expected-warning {{Call to blocking function 'read' inside of critical section}}
138           // expected-note@-1 {{Call to blocking function 'read' inside of critical section}}
139   recv(sockfd, buf, count, flags); // expected-warning {{Call to blocking function 'recv' inside of critical section}}
140           // expected-note@-1 {{Call to blocking function 'recv' inside of critical section}}
141   mtx_unlock(mutex);
142 }
143 
testMultipleBlockingCalls()144 void testMultipleBlockingCalls() {
145   std::mutex m;
146   m.lock(); // expected-note 1{{Entering critical section here}}
147   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
148             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
149   m.unlock();
150   sleep(2); // no-warning
151 }
152 
testMultipleMutexesMultipleBlockingCalls()153 void testMultipleMutexesMultipleBlockingCalls() {
154   std::mutex m, n, k;
155   m.lock(); // expected-note 2{{Entering critical section here}}
156   n.lock(); // expected-note 2{{Entering critical section here}}
157   k.lock(); // expected-note 1{{Entering critical section here}}
158   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
159             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
160   k.unlock();
161   sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
162             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
163 }
164 
165 
testRecursiveAcquisition()166 void testRecursiveAcquisition() {
167   std::mutex m;
168   m.lock(); // expected-note {{Entering critical section for the 1st time here}}
169   m.lock(); // expected-note {{Entering critical section for the 2nd time here}}
170   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
171             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
172   m.unlock();
173   m.unlock();
174 }
175 
testRecursiveAcquisitionWithMultipleBlockingCalls()176 void testRecursiveAcquisitionWithMultipleBlockingCalls() {
177   std::mutex m;
178   m.lock(); // expected-note 1{{Entering critical section for the 1st time here}}
179             // expected-note@-1 {{Entering critical section here}}
180   m.lock(); // expected-note 1{{Entering critical section for the 2nd time here}}
181   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
182             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
183   m.unlock();
184   // this next 'sleep' call is only in the critical section of the first lock
185   sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
186             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
187   m.unlock();
188 }
189 
testRecursiveAcquisitionWithMultipleMutexes()190 void testRecursiveAcquisitionWithMultipleMutexes() {
191   std::mutex m, n;
192   m.lock(); // expected-note 1{{Entering critical section here}}
193   n.lock(); // expected-note 2{{Entering critical section here}}
194   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
195             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
196   m.unlock();
197   // this next 'sleep' call is only in the critical section of mutex 'n'
198   sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
199             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
200   n.unlock();
201 }
202 
203 
testNestedMutexes()204 void testNestedMutexes() {
205   std::mutex m, n, k;
206   m.lock(); // expected-note 3{{Entering critical section here}}
207   n.lock(); // expected-note 2{{Entering critical section here}}
208   k.lock(); // expected-note 1{{Entering critical section here}}
209   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
210             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
211   k.unlock();
212   sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
213             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
214   n.unlock();
215   sleep(3); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
216             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
217   m.unlock();
218   sleep(4); // no-warning
219 }
220 
testNonOverlappingMutexes()221 void testNonOverlappingMutexes() {
222   std::mutex m;
223   m.lock(); // There should be no warning here
224   m.unlock();
225   m.lock(); // expected-note {{Entering critical section here}}
226   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
227             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
228   m.unlock();
229 }
230 
testMixedMutexLocksWithIntermittentUnlock()231 void testMixedMutexLocksWithIntermittentUnlock() {
232   std::mutex m, n, k;
233   m.lock(); // expected-note {{Entering critical section here}}
234   n.lock(); // the problem is not is this lock's critical section
235   n.unlock();
236   k.lock(); // same as for n.lock()
237   k.unlock();
238   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
239             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
240   m.unlock();
241 }
242 
f()243 void f() {
244   sleep(1000); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
245                // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
246 }
247 
testBlockInCriticalSectionInterProcedural()248 void testBlockInCriticalSectionInterProcedural() {
249   std::mutex m;
250   m.lock(); // expected-note {{Entering critical section here}}
251   f(); // expected-note {{Calling 'f'}}
252   m.unlock();
253 }
254 
255 void unknown_function_that_may_lock(std::mutex &);
testBlockInCriticalSectionUnexpectedUnlock()256 void testBlockInCriticalSectionUnexpectedUnlock() {
257   std::mutex m;
258   unknown_function_that_may_lock(m);
259   m.unlock();
260   sleep(1); // no-warning
261   m.lock(); // expected-note {{Entering critical section here}}
262   sleep(2); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
263             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
264 }
265 
testBlockInCriticalSectionLockGuard()266 void testBlockInCriticalSectionLockGuard() {
267   std::mutex g_mutex;
268   std::not_real_lock<std::mutex> not_real_lock(g_mutex);
269   sleep(1); // no-warning
270 
271   std::lock_guard<std::mutex> lock(g_mutex); // expected-note {{Entering critical section here}}
272   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
273             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
274 }
275 
testBlockInCriticalSectionLockGuardNested()276 void testBlockInCriticalSectionLockGuardNested() {
277   testBlockInCriticalSectionLockGuard(); // expected-note {{Calling 'testBlockInCriticalSectionLockGuard'}}
278   sleep(1); // no-warning
279 }
280 
testBlockInCriticalSectionUniqueLock()281 void testBlockInCriticalSectionUniqueLock() {
282   std::mutex g_mutex;
283   std::not_real_lock<std::mutex> not_real_lock(g_mutex);
284   sleep(1); // no-warning
285 
286   std::unique_lock<std::mutex> lock(g_mutex); // expected-note {{Entering critical section here}}
287   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
288             // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
289 }
290 
testBlockInCriticalSectionUniqueLockNested()291 void testBlockInCriticalSectionUniqueLockNested() {
292   testBlockInCriticalSectionUniqueLock(); // expected-note {{Calling 'testBlockInCriticalSectionUniqueLock'}}
293   sleep(1); // no-warning
294 }
295 
testTrylockCurrentlyFalsePositive(pthread_mutex_t * m)296 void testTrylockCurrentlyFalsePositive(pthread_mutex_t *m) {
297                                        // expected-note@+4 {{Assuming the condition is true}}
298                                        // expected-note@+3 {{Taking true branch}}
299                                        // expected-note@+2 {{Assuming the condition is false}}
300                                        // expected-note@+1 {{Taking false branch}}
301   if (pthread_mutex_trylock(m) == 0) { // expected-note 2 {{Entering critical section here}}
302                                        // FIXME: we are entering the critical section only in the true branch
303     sleep(10); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
304                // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
305     pthread_mutex_unlock(m);
306   } else {
307     sleep(10); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
308                // expected-note@-1 {{Call to blocking function 'sleep' inside of critical section}}
309                // FIXME: this is a false positive, the lock was not acquired
310   }
311 }
312