Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b9639e5

Browse filesBrowse files
committed
CON39-C
1 parent 4193fa6 commit b9639e5
Copy full SHA for b9639e5

File tree

7 files changed

+397
-30
lines changed
Filter options

7 files changed

+397
-30
lines changed

‎c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.md

Copy file name to clipboardExpand all lines: c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.md
+84-3Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,94 @@ This query implements the CERT-C rule CON39-C:
55
> Do not join or detach a thread that was previously joined or detached
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
The C Standard, 7.26.5.6 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states that a thread shall not be joined once it was previously joined or detached. Similarly, subclause 7.26.5.3 states that a thread shall not be detached once it was previously joined or detached. Violating either of these subclauses results in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
12+
13+
## Noncompliant Code Example
14+
15+
This noncompliant code example detaches a thread that is later joined.
16+
17+
```cpp
18+
#include <stddef.h>
19+
#include <threads.h>
20+
21+
int thread_func(void *arg) {
22+
/* Do work */
23+
thrd_detach(thrd_current());
24+
return 0;
25+
}
26+
27+
int main(void) {
28+
thrd_t t;
29+
30+
if (thrd_success != thrd_create(&t, thread_func, NULL)) {
31+
/* Handle error */
32+
return 0;
33+
}
34+
35+
if (thrd_success != thrd_join(t, 0)) {
36+
/* Handle error */
37+
return 0;
38+
}
39+
return 0;
40+
}
41+
```
42+
43+
## Compliant Solution
44+
45+
This compliant solution does not detach the thread. Its resources are released upon successfully joining with the main thread:
46+
47+
```cpp
48+
#include <stddef.h>
49+
#include <threads.h>
50+
51+
int thread_func(void *arg) {
52+
/* Do work */
53+
return 0;
54+
}
55+
56+
int main(void) {
57+
thrd_t t;
58+
59+
if (thrd_success != thrd_create(&t, thread_func, NULL)) {
60+
/* Handle error */
61+
return 0;
62+
}
63+
64+
if (thrd_success != thrd_join(t, 0)) {
65+
/* Handle error */
66+
return 0;
67+
}
68+
return 0;
69+
}
70+
```
71+
72+
## Risk Assessment
73+
74+
Joining or detaching a previously joined or detached thread is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
75+
76+
<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> CON39-C </td> <td> Low </td> <td> Likely </td> <td> Medium </td> <td> <strong>P6</strong> </td> <td> <strong>L2</strong> </td> </tr> </tbody> </table>
77+
78+
79+
## Automated Detection
80+
81+
<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.1p0 </td> <td> <strong>CONCURRENCY.TNJ</strong> </td> <td> Thread is not Joinable </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.3 </td> <td> <strong>C1776</strong> </td> <td> </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-CON39-a</strong> </td> <td> Do not join or detach a thread that was previously joined or detached </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022b </td> <td> <a> CERT C: Rule CON39-C </a> </td> <td> Checks for join or detach of a joined or detached thread (rule fully covered) </td> </tr> </tbody> </table>
82+
83+
84+
## Related Vulnerabilities
85+
86+
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+CON39-C).
87+
88+
## Bibliography
89+
90+
<table> <tbody> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> Subclause 7.26.5.3, "The <code>thrd_detach</code> Function" Subclause 7.26.5.6, "The <code>thrd_join</code> Function" </td> </tr> </tbody> </table>
91+
1192

1293
## Implementation notes
1394

14-
None
95+
It is use detach and join together in a multi-threaded program safely however to detect if it is done correctly in practice is very difficult. For this reason this query considers problematic usages of join and detach irrespective of the execution of the program and other synchronization and interprocess communication mechanisms that may be used.
1596

1697
## References
1798

‎c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql

Copy file name to clipboardExpand all lines: c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql
+33-23Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,37 @@
1414

1515
import cpp
1616
import codingstandards.c.cert
17-
18-
19-
20-
/**
21-
* Strategy for this one is to ensure that there are not two sinks to thrd_join
22-
or thrd_detach for a given
23-
24-
25-
Truth table:
26-
27-
Error if:
28-
29-
thread calls detach, parent calls join
30-
thread calls
31-
32-
Make sure there aren't multiple calls to join? Very had to do in practice.
33-
34-
You should call join OR detach, but not both.
35-
*/
36-
37-
from
17+
import codingstandards.cpp.Concurrency
18+
19+
// OK
20+
// 1) Thread calls detach parent DOES NOT call join
21+
// 2) Parent calls join, thread does NOT call detach()
22+
// NOT OK
23+
// 1) Thread calls detach, parent calls join
24+
// 2) Thread calls detach twice, parent does not call join
25+
// 3) Parent calls join twice, thread does not call detach
26+
from C11ThreadCreateCall tcc
3827
where
39-
not isExcluded(x, Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery()) and
40-
select
28+
not isExcluded(tcc, Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery()) and
29+
// Note: These cases can be simplified but they are presented like this for clarity
30+
// case 1 - calls to `thrd_join` and `thrd_detach` within the parent or
31+
// within the parent / child CFG.
32+
exists(C11ThreadWait tw, C11ThreadDetach dt |
33+
tw = getAThreadContextAwareSuccessor(tcc) and
34+
dt = getAThreadContextAwareSuccessor(tcc)
35+
)
36+
or
37+
// case 2 - multiple calls to `thrd_detach` within the threaded CFG.
38+
exists(C11ThreadDetach dt1, C11ThreadDetach dt2 |
39+
dt1 = getAThreadContextAwareSuccessor(tcc) and
40+
dt2 = getAThreadContextAwareSuccessor(tcc) and
41+
not dt1 = dt2
42+
)
43+
or
44+
// case 3 - multiple calls to `thrd_join` within the threaded CFG.
45+
exists(C11ThreadWait tw1, C11ThreadWait tw2 |
46+
tw1 = getAThreadContextAwareSuccessor(tcc) and
47+
tw2 = getAThreadContextAwareSuccessor(tcc) and
48+
not tw1 = tw2
49+
)
50+
select tcc, "Thread may call join or detach after the thread is joined or detached."

‎c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.md

Copy file name to clipboardExpand all lines: c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.md
+158-2Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,165 @@ This query implements the CERT-C rule CON40-C:
55
> Do not refer to an atomic variable twice in an expression
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
A consistent locking policy guarantees that multiple threads cannot simultaneously access or modify shared data. Atomic variables eliminate the need for locks by guaranteeing thread safety when certain operations are performed on them. The thread-safe operations on atomic variables are specified in the C Standard, subclauses 7.17.7 and 7.17.8 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\]. While atomic operations can be combined, combined operations do not provide the thread safety provided by individual atomic operations.
12+
13+
Every time an atomic variable appears on the left side of an assignment operator, including a compound assignment operator such as `*=`, an atomic write is performed on the variable. The use of the increment (++`)` or decrement `(--)` operators on an atomic variable constitutes an atomic read-and-write operation and is consequently thread-safe. Any reference of an atomic variable anywhere else in an expression indicates a distinct atomic read on the variable.
14+
15+
If the same atomic variable appears twice in an expression, then two atomic reads, or an atomic read and an atomic write, are required. Such a pair of atomic operations is not thread-safe, as another thread can modify the atomic variable between the two operations. Consequently, an atomic variable must not be referenced twice in the same expression.
16+
17+
## Noncompliant Code Example (atomic_bool)
18+
19+
This noncompliant code example declares a shared `atomic_bool` `flag` variable and provides a `toggle_flag()` method that negates the current value of `flag`:
20+
21+
```cpp
22+
#include <stdatomic.h>
23+
#include <stdbool.h>
24+
25+
static atomic_bool flag = ATOMIC_VAR_INIT(false);
26+
27+
void init_flag(void) {
28+
atomic_init(&flag, false);
29+
}
30+
31+
void toggle_flag(void) {
32+
bool temp_flag = atomic_load(&flag);
33+
temp_flag = !temp_flag;
34+
atomic_store(&flag, temp_flag);
35+
}
36+
37+
bool get_flag(void) {
38+
return atomic_load(&flag);
39+
}
40+
41+
```
42+
Execution of this code may result in unexpected behavior because the value of `flag` is read, negated, and written back. This occurs even though the read and write are both atomic.
43+
44+
Consider, for example, two threads that call `toggle_flag()`. The expected effect of toggling `flag` twice is that it is restored to its original value. However, the scenario in the following table leaves `flag` in the incorrect state.
45+
46+
`toggle_flag()` without Compare-and-Exchange
47+
48+
<table> <tbody> <tr> <th> Time </th> <th> <code>flag</code> </th> <th> Thread </th> <th> Action </th> </tr> <tr> <td> 1 </td> <td> <code>true</code> </td> <td> <em> t </em> <sub> 1 </sub> </td> <td> Reads the current value of <code>flag</code> , which is <code>true,</code> into a cache </td> </tr> <tr> <td> 2 </td> <td> <code>true</code> </td> <td> <em> t </em> <sub> 2 </sub> </td> <td> Reads the current value of <code>flag</code> , which is still <code>true,</code> into a different cache </td> </tr> <tr> <td> 3 </td> <td> <code>true</code> </td> <td> <em> t </em> <sub> 1 </sub> </td> <td> Toggles the temporary variable in the cache to <code>false</code> </td> </tr> <tr> <td> 4 </td> <td> <code>true</code> </td> <td> <em> t </em> <sub> 2 </sub> </td> <td> Toggles the temporary variable in the different cache to <code>false</code> </td> </tr> <tr> <td> 5 </td> <td> <code>false</code> </td> <td> <em> t </em> <sub> 1 </sub> </td> <td> Writes the cache variable's value to <code>flag</code> </td> </tr> <tr> <td> 6 </td> <td> <code>false</code> </td> <td> <em> t </em> <sub> 2 </sub> </td> <td> Writes the different cache variable's value to <code>flag</code> </td> </tr> </tbody> </table>
49+
As a result, the effect of the call by *t*<sub>2</sub> is not reflected in `flag`; the program behaves as if `toggle_flag()` was called only once, not twice.
50+
51+
52+
## Compliant Solution (atomic_compare_exchange_weak())
53+
54+
This compliant solution uses a compare-and-exchange to guarantee that the correct value is stored in `flag`. All updates are visible to other threads. The call to `atomic_compare_exchange_weak()` is in a loop in conformance with [CON41-C. Wrap functions that can fail spuriously in a loop](https://wiki.sei.cmu.edu/confluence/display/c/CON41-C.+Wrap+functions+that+can+fail+spuriously+in+a+loop).
55+
56+
```cpp
57+
#include <stdatomic.h>
58+
#include <stdbool.h>
59+
60+
static atomic_bool flag = ATOMIC_VAR_INIT(false);
61+
62+
void init_flag(void) {
63+
atomic_init(&flag, false);
64+
}
65+
66+
void toggle_flag(void) {
67+
bool old_flag = atomic_load(&flag);
68+
bool new_flag;
69+
do {
70+
new_flag = !old_flag;
71+
} while (!atomic_compare_exchange_weak(&flag, &old_flag, new_flag));
72+
}
73+
74+
bool get_flag(void) {
75+
return atomic_load(&flag);
76+
}
77+
```
78+
An alternative solution is to use the `atomic_flag` data type for managing Boolean values atomically. However, `atomic_flag` does not support a toggle operation.
79+
80+
## Compliant Solution (Compound Assignment)
81+
82+
This compliant solution uses the `^=` assignment operation to toggle `flag`. This operation is guaranteed to be atomic, according to the C Standard, 6.5.16.2, paragraph 3. This operation performs a bitwise-exclusive-or between its arguments, but for Boolean arguments, this is equivalent to negation.
83+
84+
```cpp
85+
#include <stdatomic.h>
86+
#include <stdbool.h>
87+
88+
static atomic_bool flag = ATOMIC_VAR_INIT(false);
89+
90+
void toggle_flag(void) {
91+
flag ^= 1;
92+
}
93+
94+
bool get_flag(void) {
95+
return flag;
96+
}
97+
```
98+
An alternative solution is to use a mutex to protect the atomic operation, but this solution loses the performance benefits of atomic variables.
99+
100+
## Noncompliant Code Example
101+
102+
This noncompliant code example takes an atomic global variable `n` and computes `n + (n - 1) + (n - 2) + ... + 1`, using the formula `n * (n + 1) / 2`:
103+
104+
```cpp
105+
#include <stdatomic.h>
106+
107+
atomic_int n = ATOMIC_VAR_INIT(0);
108+
109+
int compute_sum(void) {
110+
return n * (n + 1) / 2;
111+
}
112+
```
113+
The value of `n` may change between the two atomic reads of `n` in the expression, yielding an incorrect result.
114+
115+
## Compliant Solution
116+
117+
This compliant solution passes the atomic variable as a function argument, forcing the variable to be copied and guaranteeing a correct result. Note that the function's formal parameter need not be atomic, and the atomic variable can still be passed as an actual argument.
118+
119+
```cpp
120+
#include <stdatomic.h>
121+
122+
int compute_sum(int n) {
123+
return n * (n + 1) / 2;
124+
}
125+
126+
```
127+
128+
## Risk Assessment
129+
130+
When operations on atomic variables are assumed to be atomic, but are not atomic, surprising data races can occur, leading to corrupted data and invalid control flow.
131+
132+
<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> CON40-C </td> <td> Medium </td> <td> Probable </td> <td> Medium </td> <td> <strong>P8</strong> </td> <td> <strong>L2</strong> </td> </tr> </tbody> </table>
133+
134+
135+
## Automated Detection
136+
137+
<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> <strong>multiple-atomic-accesses</strong> </td> <td> Partially checked </td> </tr> <tr> <td> <a> Axivion Bauhaus Suite </a> </td> <td> 7.2.0 </td> <td> <strong>CertC-CON40</strong> </td> <td> </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.1p0 </td> <td> <strong>CONCURRENCY.MAA</strong> </td> <td> Multiple Accesses of Atomic </td> </tr> <tr> <td> <a> Coverity </a> </td> <td> 2017.07 </td> <td> <strong>EVALUATION_ORDER (partial)</strong> <strong>MISRA 2012 Rule 13.2</strong> <strong>VOLATILE_ATOICITY (possible)</strong> </td> <td> Implemented </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.3 </td> <td> <strong>C1114, C1115, C1116</strong> <strong>C++3171, C++4150</strong> </td> <td> </td> </tr> <tr> <td> <a> Klocwork </a> </td> <td> 2022.3 </td> <td> <strong>CERT.CONC.ATOMIC_TWICE_EXPR</strong> </td> <td> </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-CON40-a</strong> </td> <td> Do not refer to an atomic variable twice in an expression </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022b </td> <td> <a> CERT C: Rule CON40-C </a> </td> <td> Checks for: Atomic variable accessed twice in an expressiontomic variable accessed twice in an expression, atomic load and store sequence not atomictomic load and store sequence not atomic. Rule fully covered. </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>1114, 1115, 1116 </strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> <strong>multiple-atomic-accesses</strong> </td> <td> Partially checked </td> </tr> </tbody> </table>
138+
139+
140+
## Related Vulnerabilities
141+
142+
Search for [vulnerabilities](https://www.securecoding.cert.org/confluence/display/seccode/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+CON40-C).
143+
144+
## Related Guidelines
145+
146+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
147+
148+
<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-366 </a> , Race Condition within a Thread </td> <td> 2017-07-07: CERT: Rule subset of CWE </td> </tr> </tbody> </table>
149+
150+
151+
## CERT-CWE Mapping Notes
152+
153+
[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes
154+
155+
**CWE-366 and CON40-C**
156+
157+
CON40-C = Subset( CON43-C) Intersection( CON32-C, CON40-C) = Ø
158+
159+
CWE-366 = Union( CON40-C, list) where list =
160+
161+
* C data races that do not involve an atomic variable used twice within an expression
162+
163+
## Bibliography
164+
165+
<table> <tbody> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> 6.5.16.2, "Compound Assignment" 7.17, "Atomics" </td> </tr> </tbody> </table>
166+
11167
12168
## Implementation notes
13169
+8-1Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
No expected results have yet been specified
1+
| test.c:26:3:26:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
2+
| test.c:32:3:32:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
3+
| test.c:37:3:37:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
4+
| test.c:58:3:58:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
5+
| test.c:66:3:66:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
6+
| test.c:73:3:73:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
7+
| test.c:87:3:87:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |
8+
| test.c:94:3:94:13 | call to thrd_create | Thread may call join or detach after the thread is joined or detached. |

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.