Skip to content

Commit dbd81f2

Browse files
committed
import help
1 parent f4b0b04 commit dbd81f2

File tree

2 files changed

+314
-4
lines changed

2 files changed

+314
-4
lines changed

c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.md

Lines changed: 157 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,164 @@ This query implements the CERT-C rule CON31-C:
55
> Do not destroy a mutex while it is locked
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
Mutexes are used to protect shared data structures being concurrently accessed. If a mutex is destroyed while a thread is blocked waiting for that mutex, [critical sections](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-criticalsections) and shared data are no longer protected.
12+
13+
The C Standard, 7.26.4.1, paragraph 2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states
14+
15+
> The `mtx_destroy` function releases any resources used by the mutex pointed to by `mtx`. No threads can be blocked waiting for the mutex pointed to by `mtx`.
16+
17+
18+
This statement implies that destroying a mutex while a thread is waiting on it is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
19+
20+
## Noncompliant Code Example
21+
22+
This noncompliant code example creates several threads that each invoke the `do_work()` function, passing a unique number as an ID. The `do_work()` function initializes the `lock` mutex if the argument is 0 and destroys the mutex if the argument is `max_threads - 1`. In all other cases, the `do_work()` function provides normal processing. Each thread, except the final cleanup thread, increments the atomic `completed` variable when it is finished.
23+
24+
Unfortunately, this code contains several race conditions, allowing the mutex to be destroyed before it is unlocked. Additionally, there is no guarantee that `lock` will be initialized before it is passed to `mtx_lock()`. Each of these behaviors is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
25+
26+
```cpp
27+
#include <stdatomic.h>
28+
#include <stddef.h>
29+
#include <threads.h>
30+
31+
mtx_t lock;
32+
/* Atomic so multiple threads can modify safely */
33+
atomic_int completed = ATOMIC_VAR_INIT(0);
34+
enum { max_threads = 5 };
35+
36+
int do_work(void *arg) {
37+
int *i = (int *)arg;
38+
39+
if (*i == 0) { /* Creation thread */
40+
if (thrd_success != mtx_init(&lock, mtx_plain)) {
41+
/* Handle error */
42+
}
43+
atomic_store(&completed, 1);
44+
} else if (*i < max_threads - 1) { /* Worker thread */
45+
if (thrd_success != mtx_lock(&lock)) {
46+
/* Handle error */
47+
}
48+
/* Access data protected by the lock */
49+
atomic_fetch_add(&completed, 1);
50+
if (thrd_success != mtx_unlock(&lock)) {
51+
/* Handle error */
52+
}
53+
} else { /* Destruction thread */
54+
mtx_destroy(&lock);
55+
}
56+
return 0;
57+
}
58+
59+
int main(void) {
60+
thrd_t threads[max_threads];
61+
62+
for (size_t i = 0; i < max_threads; i++) {
63+
if (thrd_success != thrd_create(&threads[i], do_work, &i)) {
64+
/* Handle error */
65+
}
66+
}
67+
for (size_t i = 0; i < max_threads; i++) {
68+
if (thrd_success != thrd_join(threads[i], 0)) {
69+
/* Handle error */
70+
}
71+
}
72+
return 0;
73+
}
74+
75+
```
76+
77+
## Compliant Solution
78+
79+
This compliant solution eliminates the race conditions by initializing the mutex in `main()` before creating the threads and by destroying the mutex in `main()` after joining the threads:
80+
81+
```cpp
82+
#include <stdatomic.h>
83+
#include <stddef.h>
84+
#include <threads.h>
85+
86+
mtx_t lock;
87+
/* Atomic so multiple threads can increment safely */
88+
atomic_int completed = ATOMIC_VAR_INIT(0);
89+
enum { max_threads = 5 };
90+
91+
int do_work(void *dummy) {
92+
if (thrd_success != mtx_lock(&lock)) {
93+
/* Handle error */
94+
}
95+
/* Access data protected by the lock */
96+
atomic_fetch_add(&completed, 1);
97+
if (thrd_success != mtx_unlock(&lock)) {
98+
/* Handle error */
99+
}
100+
101+
return 0;
102+
}
103+
104+
int main(void) {
105+
thrd_t threads[max_threads];
106+
107+
if (thrd_success != mtx_init(&lock, mtx_plain)) {
108+
/* Handle error */
109+
}
110+
for (size_t i = 0; i < max_threads; i++) {
111+
if (thrd_success != thrd_create(&threads[i], do_work, NULL)) {
112+
/* Handle error */
113+
}
114+
}
115+
for (size_t i = 0; i < max_threads; i++) {
116+
if (thrd_success != thrd_join(threads[i], 0)) {
117+
/* Handle error */
118+
}
119+
}
120+
121+
mtx_destroy(&lock);
122+
return 0;
123+
}
124+
125+
```
126+
127+
## Risk Assessment
128+
129+
Destroying a mutex while it is locked may result in invalid control flow and data corruption.
130+
131+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> CON31-C </td> <td> Medium </td> <td> Probable </td> <td> High </td> <td> <strong>P4</strong> </td> <td> <strong>L3</strong> </td> </tr> </tbody> </table>
132+
133+
134+
## Automated Detection
135+
136+
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.0p0 </td> <td> <strong>CONCURRENCY.LOCALARG</strong> </td> <td> Local Variable Passed to Thread </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.2 </td> <td> <strong>C4961, C4962</strong> </td> <td> </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>4961, 4962 </strong> </td> <td> </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-CON31-a</strong> <strong>CERT_C-CON31-b</strong> <strong>CERT_C-CON31-c</strong> </td> <td> Do not destroy another thread's mutex Do not use resources that have been freed Do not free resources using invalid pointers </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022a </td> <td> <a> CERT C: Rule CON31-C </a> </td> <td> Checks for destruction of locked mutex (rule fully covered) </td> </tr> </tbody> </table>
137+
138+
139+
## Related Vulnerabilities
140+
141+
Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON31-C).
142+
143+
## Related Guidelines
144+
145+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
146+
147+
<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> CWE 2.11 </a> </td> <td> <a> CWE-667 </a> , Improper Locking </td> <td> 2017-07-10: CERT: Rule subset of CWE </td> </tr> </tbody> </table>
148+
149+
150+
## CERT-CWE Mapping Notes
151+
152+
[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes
153+
154+
**CWE-667 and CON31-C/POS48-C**
155+
156+
Intersection( CON31-C, POS48-C) = Ø
157+
158+
CWE-667 = Union, CON31-C, POS48-C, list) where list =
159+
160+
* Locking &amp; Unlocking issues besides unlocking another thread’s C mutex or pthread mutex.
161+
162+
## Bibliography
163+
164+
<table> <tbody> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> 7.26.4.1, "The <code>mtx_destroy</code> Function" </td> </tr> </tbody> </table>
165+
11166

12167
## Implementation notes
13168

c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.md

Lines changed: 157 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,164 @@ This query implements the CERT-C rule CON31-C:
55
> Do not destroy a mutex while it is locked
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
Mutexes are used to protect shared data structures being concurrently accessed. If a mutex is destroyed while a thread is blocked waiting for that mutex, [critical sections](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-criticalsections) and shared data are no longer protected.
12+
13+
The C Standard, 7.26.4.1, paragraph 2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states
14+
15+
> The `mtx_destroy` function releases any resources used by the mutex pointed to by `mtx`. No threads can be blocked waiting for the mutex pointed to by `mtx`.
16+
17+
18+
This statement implies that destroying a mutex while a thread is waiting on it is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
19+
20+
## Noncompliant Code Example
21+
22+
This noncompliant code example creates several threads that each invoke the `do_work()` function, passing a unique number as an ID. The `do_work()` function initializes the `lock` mutex if the argument is 0 and destroys the mutex if the argument is `max_threads - 1`. In all other cases, the `do_work()` function provides normal processing. Each thread, except the final cleanup thread, increments the atomic `completed` variable when it is finished.
23+
24+
Unfortunately, this code contains several race conditions, allowing the mutex to be destroyed before it is unlocked. Additionally, there is no guarantee that `lock` will be initialized before it is passed to `mtx_lock()`. Each of these behaviors is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
25+
26+
```cpp
27+
#include <stdatomic.h>
28+
#include <stddef.h>
29+
#include <threads.h>
30+
31+
mtx_t lock;
32+
/* Atomic so multiple threads can modify safely */
33+
atomic_int completed = ATOMIC_VAR_INIT(0);
34+
enum { max_threads = 5 };
35+
36+
int do_work(void *arg) {
37+
int *i = (int *)arg;
38+
39+
if (*i == 0) { /* Creation thread */
40+
if (thrd_success != mtx_init(&lock, mtx_plain)) {
41+
/* Handle error */
42+
}
43+
atomic_store(&completed, 1);
44+
} else if (*i < max_threads - 1) { /* Worker thread */
45+
if (thrd_success != mtx_lock(&lock)) {
46+
/* Handle error */
47+
}
48+
/* Access data protected by the lock */
49+
atomic_fetch_add(&completed, 1);
50+
if (thrd_success != mtx_unlock(&lock)) {
51+
/* Handle error */
52+
}
53+
} else { /* Destruction thread */
54+
mtx_destroy(&lock);
55+
}
56+
return 0;
57+
}
58+
59+
int main(void) {
60+
thrd_t threads[max_threads];
61+
62+
for (size_t i = 0; i < max_threads; i++) {
63+
if (thrd_success != thrd_create(&threads[i], do_work, &i)) {
64+
/* Handle error */
65+
}
66+
}
67+
for (size_t i = 0; i < max_threads; i++) {
68+
if (thrd_success != thrd_join(threads[i], 0)) {
69+
/* Handle error */
70+
}
71+
}
72+
return 0;
73+
}
74+
75+
```
76+
77+
## Compliant Solution
78+
79+
This compliant solution eliminates the race conditions by initializing the mutex in `main()` before creating the threads and by destroying the mutex in `main()` after joining the threads:
80+
81+
```cpp
82+
#include <stdatomic.h>
83+
#include <stddef.h>
84+
#include <threads.h>
85+
86+
mtx_t lock;
87+
/* Atomic so multiple threads can increment safely */
88+
atomic_int completed = ATOMIC_VAR_INIT(0);
89+
enum { max_threads = 5 };
90+
91+
int do_work(void *dummy) {
92+
if (thrd_success != mtx_lock(&lock)) {
93+
/* Handle error */
94+
}
95+
/* Access data protected by the lock */
96+
atomic_fetch_add(&completed, 1);
97+
if (thrd_success != mtx_unlock(&lock)) {
98+
/* Handle error */
99+
}
100+
101+
return 0;
102+
}
103+
104+
int main(void) {
105+
thrd_t threads[max_threads];
106+
107+
if (thrd_success != mtx_init(&lock, mtx_plain)) {
108+
/* Handle error */
109+
}
110+
for (size_t i = 0; i < max_threads; i++) {
111+
if (thrd_success != thrd_create(&threads[i], do_work, NULL)) {
112+
/* Handle error */
113+
}
114+
}
115+
for (size_t i = 0; i < max_threads; i++) {
116+
if (thrd_success != thrd_join(threads[i], 0)) {
117+
/* Handle error */
118+
}
119+
}
120+
121+
mtx_destroy(&lock);
122+
return 0;
123+
}
124+
125+
```
126+
127+
## Risk Assessment
128+
129+
Destroying a mutex while it is locked may result in invalid control flow and data corruption.
130+
131+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> CON31-C </td> <td> Medium </td> <td> Probable </td> <td> High </td> <td> <strong>P4</strong> </td> <td> <strong>L3</strong> </td> </tr> </tbody> </table>
132+
133+
134+
## Automated Detection
135+
136+
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.0p0 </td> <td> <strong>CONCURRENCY.LOCALARG</strong> </td> <td> Local Variable Passed to Thread </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.2 </td> <td> <strong>C4961, C4962</strong> </td> <td> </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>4961, 4962 </strong> </td> <td> </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-CON31-a</strong> <strong>CERT_C-CON31-b</strong> <strong>CERT_C-CON31-c</strong> </td> <td> Do not destroy another thread's mutex Do not use resources that have been freed Do not free resources using invalid pointers </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022a </td> <td> <a> CERT C: Rule CON31-C </a> </td> <td> Checks for destruction of locked mutex (rule fully covered) </td> </tr> </tbody> </table>
137+
138+
139+
## Related Vulnerabilities
140+
141+
Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON31-C).
142+
143+
## Related Guidelines
144+
145+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
146+
147+
<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> CWE 2.11 </a> </td> <td> <a> CWE-667 </a> , Improper Locking </td> <td> 2017-07-10: CERT: Rule subset of CWE </td> </tr> </tbody> </table>
148+
149+
150+
## CERT-CWE Mapping Notes
151+
152+
[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes
153+
154+
**CWE-667 and CON31-C/POS48-C**
155+
156+
Intersection( CON31-C, POS48-C) = Ø
157+
158+
CWE-667 = Union, CON31-C, POS48-C, list) where list =
159+
160+
* Locking &amp; Unlocking issues besides unlocking another thread’s C mutex or pthread mutex.
161+
162+
## Bibliography
163+
164+
<table> <tbody> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> 7.26.4.1, "The <code>mtx_destroy</code> Function" </td> </tr> </tbody> </table>
165+
11166

12167
## Implementation notes
13168

0 commit comments

Comments
 (0)