1 | // RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -Wthread-safety-beta %s |
2 | |
3 | #define LOCKABLE __attribute__ ((lockable)) |
4 | #define SCOPED_LOCKABLE __attribute__ ((scoped_lockable)) |
5 | #define GUARDED_BY(x) __attribute__ ((guarded_by(x))) |
6 | #define GUARDED_VAR __attribute__ ((guarded_var)) |
7 | #define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x))) |
8 | #define PT_GUARDED_VAR __attribute__ ((pt_guarded_var)) |
9 | #define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__))) |
10 | #define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__))) |
11 | #define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__))) |
12 | #define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__))) |
13 | #define ASSERT_EXCLUSIVE_LOCK(...) __attribute__ ((assert_exclusive_lock(__VA_ARGS__))) |
14 | #define ASSERT_SHARED_LOCK(...) __attribute__ ((assert_shared_lock(__VA_ARGS__))) |
15 | #define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__))) |
16 | #define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__))) |
17 | #define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__))) |
18 | #define LOCK_RETURNED(x) __attribute__ ((lock_returned(x))) |
19 | #define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__))) |
20 | #define EXCLUSIVE_LOCKS_REQUIRED(...) \ |
21 | __attribute__ ((exclusive_locks_required(__VA_ARGS__))) |
22 | #define SHARED_LOCKS_REQUIRED(...) \ |
23 | __attribute__ ((shared_locks_required(__VA_ARGS__))) |
24 | #define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis)) |
25 | |
26 | // Define the mutex struct. |
27 | // Simplified only for test purpose. |
28 | struct LOCKABLE Mutex {}; |
29 | |
30 | struct Foo { |
31 | struct Mutex *mu_; |
32 | }; |
33 | |
34 | // Declare mutex lock/unlock functions. |
35 | void mutex_exclusive_lock(struct Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); |
36 | void mutex_shared_lock(struct Mutex *mu) SHARED_LOCK_FUNCTION(mu); |
37 | void mutex_unlock(struct Mutex *mu) UNLOCK_FUNCTION(mu); |
38 | void mutex_shared_unlock(struct Mutex *mu) __attribute__((release_shared_capability(mu))); |
39 | void mutex_exclusive_unlock(struct Mutex *mu) __attribute__((release_capability(mu))); |
40 | |
41 | // Define global variables. |
42 | struct Mutex mu1; |
43 | struct Mutex mu2 ACQUIRED_AFTER(mu1); |
44 | struct Foo foo_ = {&mu1}; |
45 | int a_ GUARDED_BY(foo_.mu_); |
46 | int *b_ PT_GUARDED_BY(foo_.mu_) = &a_; |
47 | int c_ GUARDED_VAR; |
48 | int *d_ PT_GUARDED_VAR = &c_; |
49 | |
50 | // Define test functions. |
51 | int Foo_fun1(int i) SHARED_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1) { |
52 | return i; |
53 | } |
54 | |
55 | int Foo_fun2(int i) EXCLUSIVE_LOCKS_REQUIRED(mu2) SHARED_LOCKS_REQUIRED(mu1) { |
56 | return i; |
57 | } |
58 | |
59 | int Foo_func3(int i) LOCKS_EXCLUDED(mu1, mu2) { |
60 | return i; |
61 | } |
62 | |
63 | static int Bar_fun1(int i) EXCLUSIVE_LOCKS_REQUIRED(mu1) { |
64 | return i; |
65 | } |
66 | |
67 | void set_value(int *a, int value) EXCLUSIVE_LOCKS_REQUIRED(foo_.mu_) { |
68 | *a = value; |
69 | } |
70 | |
71 | int get_value(int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){ |
72 | return *p; |
73 | } |
74 | |
75 | int main() { |
76 | |
77 | Foo_fun1(1); // expected-warning{{calling function 'Foo_fun1' requires holding mutex 'mu2'}} \ |
78 | expected-warning{{calling function 'Foo_fun1' requires holding mutex 'mu1' exclusively}} |
79 | |
80 | mutex_exclusive_lock(&mu1); // expected-note{{mutex acquired here}} |
81 | mutex_shared_lock(&mu2); |
82 | Foo_fun1(1); |
83 | |
84 | mutex_shared_lock(&mu1); // expected-warning{{acquiring mutex 'mu1' that is already held}} \ |
85 | expected-warning{{mutex 'mu1' must be acquired before 'mu2'}} |
86 | mutex_unlock(&mu1); |
87 | mutex_unlock(&mu2); |
88 | mutex_shared_lock(&mu1); |
89 | mutex_exclusive_lock(&mu2); |
90 | Foo_fun2(2); |
91 | |
92 | mutex_unlock(&mu2); |
93 | mutex_unlock(&mu1); |
94 | mutex_exclusive_lock(&mu1); |
95 | Bar_fun1(3); |
96 | mutex_unlock(&mu1); |
97 | |
98 | mutex_exclusive_lock(&mu1); |
99 | Foo_func3(4); // expected-warning{{cannot call function 'Foo_func3' while mutex 'mu1' is held}} |
100 | mutex_unlock(&mu1); |
101 | |
102 | Foo_func3(5); |
103 | |
104 | set_value(&a_, 0); // expected-warning{{calling function 'set_value' requires holding mutex 'foo_.mu_' exclusively}} |
105 | get_value(b_); // expected-warning{{calling function 'get_value' requires holding mutex 'foo_.mu_'}} |
106 | mutex_exclusive_lock(foo_.mu_); |
107 | set_value(&a_, 1); |
108 | mutex_unlock(foo_.mu_); |
109 | mutex_shared_lock(foo_.mu_); |
110 | (void)(get_value(b_) == 1); |
111 | mutex_unlock(foo_.mu_); |
112 | |
113 | c_ = 0; // expected-warning{{writing variable 'c_' requires holding any mutex exclusively}} |
114 | (void)(*d_ == 0); // expected-warning{{reading the value pointed to by 'd_' requires holding any mutex}} |
115 | mutex_exclusive_lock(foo_.mu_); |
116 | c_ = 1; |
117 | (void)(*d_ == 1); |
118 | mutex_unlock(foo_.mu_); |
119 | |
120 | mutex_exclusive_lock(&mu1); // expected-note {{mutex acquired here}} |
121 | mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' using shared access, expected exclusive access}} |
122 | mutex_exclusive_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' that was not held}} |
123 | |
124 | mutex_shared_lock(&mu1); // expected-note {{mutex acquired here}} |
125 | mutex_exclusive_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' using exclusive access, expected shared access}} |
126 | mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' that was not held}} |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | // We had a problem where we'd skip all attributes that follow a late-parsed |
132 | // attribute in a single __attribute__. |
133 | void run() __attribute__((guarded_by(mu1), guarded_by(mu1))); // expected-warning 2{{only applies to non-static data members and global variables}} |
134 | |