Skip to content

Commit 4193fa6

Browse files
committed
CON40-C
1 parent 4081fc8 commit 4193fa6

15 files changed

+266
-0
lines changed

.vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"files.associations": {
3+
"atomic": "c",
4+
"memory": "c"
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# CON39-C: Do not join or detach a thread that was previously joined or detached
2+
3+
This query implements the CERT-C rule CON39-C:
4+
5+
> Do not join or detach a thread that was previously joined or detached
6+
7+
8+
## CERT
9+
10+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
11+
12+
## Implementation notes
13+
14+
None
15+
16+
## References
17+
18+
* CERT-C: [CON39-C: Do not join or detach a thread that was previously joined or detached](https://wiki.sei.cmu.edu/confluence/display/c)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @id c/cert/thread-was-previously-joined-or-detached
3+
* @name CON39-C: Do not join or detach a thread that was previously joined or detached
4+
* @description Joining or detaching a previously joined or detached thread can lead to undefined
5+
* program behavior.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/con39-c
10+
* correctness
11+
* concurrency
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
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
38+
where
39+
not isExcluded(x, Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery()) and
40+
select
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# CON40-C: Do not refer to an atomic variable twice in an expression
2+
3+
This query implements the CERT-C rule CON40-C:
4+
5+
> Do not refer to an atomic variable twice in an expression
6+
7+
8+
## CERT
9+
10+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
11+
12+
## Implementation notes
13+
14+
None
15+
16+
## References
17+
18+
* CERT-C: [CON40-C: Do not refer to an atomic variable twice in an expression](https://wiki.sei.cmu.edu/confluence/display/c)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @id c/cert/atomic-variable-twice-in-expression
3+
* @name CON40-C: Do not refer to an atomic variable twice in an expression
4+
* @description Atomic variables that are referred to twice in the same expression can produce
5+
* unpredictable program behavior.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/cert/id/con40-c
10+
* correctness
11+
* concurrency
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
18+
from MacroInvocation mi, Variable v, Locatable whereFound
19+
where
20+
not isExcluded(whereFound, Concurrency5Package::atomicVariableTwiceInExpressionQuery()) and
21+
(
22+
// There isn't a way to safely use this construct in a away that is also
23+
// possible the reliably detect so advise against using it.
24+
(
25+
mi.getMacroName() = ["atomic_store", "atomic_store_explicit"]
26+
or
27+
// This construct is generally safe, but must be used in a loop. To lower
28+
// the false positive rate we don't look at the conditions of the loop and
29+
// instead assume if it is found in a looping construct that it is likely
30+
// related to the safety property.
31+
mi.getMacroName() = ["atomic_compare_exchange_weak", "atomic_compare_exchange_weak_explicit"] and
32+
not exists(Loop l | mi.getAGeneratedElement().(Expr).getParent*() = l)
33+
) and
34+
whereFound = mi
35+
)
36+
or
37+
mi.getMacroName() = "ATOMIC_VAR_INIT" and
38+
exists(Expr av |
39+
av = mi.getAGeneratedElement() and
40+
av = v.getAnAssignedValue() and
41+
exists(Assignment m |
42+
not m instanceof AssignXorExpr and
43+
m.getLValue().(VariableAccess).getTarget() = v and
44+
whereFound = m
45+
)
46+
)
47+
select mi, "Atomic variable possibly referred to twice in an $@.", whereFound, "expression"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No expected results have yet been specified
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql

c/cert/test/rules/CON39-C/test.c

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.c:6:19:6:40 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:32:3:32:10 | ... += ... | expression |
2+
| test.c:6:19:6:40 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:33:3:33:13 | ... = ... | expression |
3+
| test.c:10:3:10:23 | atomic_store(a,b) | Atomic variable possibly referred to twice in an $@. | test.c:10:3:10:23 | atomic_store(a,b) | expression |
4+
| test.c:11:3:11:35 | atomic_store_explicit(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:35 | atomic_store_explicit(a,b,c) | expression |
5+
| test.c:24:3:24:48 | atomic_compare_exchange_weak(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:24:3:24:48 | atomic_compare_exchange_weak(a,b,c) | expression |
6+
| test.c:25:3:26:45 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:26:45 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | expression |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/CON40-C/AtomicVariableTwiceInExpression.ql

c/cert/test/rules/CON40-C/test.c

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <stdatomic.h>
2+
#include <stdbool.h>
3+
4+
static bool fl1 = ATOMIC_VAR_INIT(false);
5+
static bool fl2 = ATOMIC_VAR_INIT(false);
6+
static bool fl3 = ATOMIC_VAR_INIT(false);
7+
static bool fl4 = ATOMIC_VAR_INIT(false);
8+
9+
void f1() {
10+
atomic_store(&fl1, 0); // NON_COMPLIANT
11+
atomic_store_explicit(&fl1, 0, 0); // NON_COMPLIANT
12+
}
13+
14+
void f2() {
15+
do {
16+
} while (!atomic_compare_exchange_weak(&fl2, &fl2, &fl2)); // COMPLIANT
17+
18+
do {
19+
} while (!atomic_compare_exchange_weak_explicit(&fl2, &fl2, &fl2, &fl2,
20+
&fl2)); // COMPLIANT
21+
}
22+
23+
void f3() {
24+
atomic_compare_exchange_weak(&fl2, &fl2, &fl2); // NON_COMPLIANT
25+
atomic_compare_exchange_weak_explicit(&fl2, &fl2, &fl2, &fl2,
26+
&fl2); // NON_COMPLIANT
27+
}
28+
29+
void f4() { fl3 ^= true; }
30+
31+
void f5() {
32+
fl3 += 1; // NON_COMPLIANT
33+
fl3 = 1 + 1; // NON_COMPLIANT
34+
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
#define atomic_compare_exchange_weak(a, b, c) 0
22
#define atomic_compare_exchange_weak_explicit(a, b, c, d, e) 0
3+
#define atomic_load(a) 0
4+
#define atomic_load_explicit(a, b)
5+
#define atomic_store(a, b) 0
6+
#define atomic_store_explicit(a,b,c) 0
7+
#define ATOMIC_VAR_INIT(value) (value)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Concurrency5Query =
7+
TThreadWasPreviouslyJoinedOrDetachedQuery() or
8+
TAtomicVariableTwiceInExpressionQuery()
9+
10+
predicate isConcurrency5QueryMetadata(Query query, string queryId, string ruleId) {
11+
query =
12+
// `Query` instance for the `threadWasPreviouslyJoinedOrDetached` query
13+
Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery() and
14+
queryId =
15+
// `@id` for the `threadWasPreviouslyJoinedOrDetached` query
16+
"c/cert/thread-was-previously-joined-or-detached" and
17+
ruleId = "CON39-C"
18+
or
19+
query =
20+
// `Query` instance for the `atomicVariableTwiceInExpression` query
21+
Concurrency5Package::atomicVariableTwiceInExpressionQuery() and
22+
queryId =
23+
// `@id` for the `atomicVariableTwiceInExpression` query
24+
"c/cert/atomic-variable-twice-in-expression" and
25+
ruleId = "CON40-C"
26+
}
27+
28+
module Concurrency5Package {
29+
Query threadWasPreviouslyJoinedOrDetachedQuery() {
30+
//autogenerate `Query` type
31+
result =
32+
// `Query` type for `threadWasPreviouslyJoinedOrDetached` query
33+
TQueryC(TConcurrency5PackageQuery(TThreadWasPreviouslyJoinedOrDetachedQuery()))
34+
}
35+
36+
Query atomicVariableTwiceInExpressionQuery() {
37+
//autogenerate `Query` type
38+
result =
39+
// `Query` type for `atomicVariableTwiceInExpression` query
40+
TQueryC(TConcurrency5PackageQuery(TAtomicVariableTwiceInExpressionQuery()))
41+
}
42+
}

cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Concurrency1
77
import Concurrency2
88
import Concurrency3
99
import Concurrency4
10+
import Concurrency5
1011
import Contracts1
1112
import Contracts3
1213
import Declarations1
@@ -39,6 +40,7 @@ newtype TCQuery =
3940
TConcurrency2PackageQuery(Concurrency2Query q) or
4041
TConcurrency3PackageQuery(Concurrency3Query q) or
4142
TConcurrency4PackageQuery(Concurrency4Query q) or
43+
TConcurrency5PackageQuery(Concurrency5Query q) or
4244
TContracts1PackageQuery(Contracts1Query q) or
4345
TContracts3PackageQuery(Contracts3Query q) or
4446
TDeclarations1PackageQuery(Declarations1Query q) or
@@ -71,6 +73,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) {
7173
isConcurrency2QueryMetadata(query, queryId, ruleId) or
7274
isConcurrency3QueryMetadata(query, queryId, ruleId) or
7375
isConcurrency4QueryMetadata(query, queryId, ruleId) or
76+
isConcurrency5QueryMetadata(query, queryId, ruleId) or
7477
isContracts1QueryMetadata(query, queryId, ruleId) or
7578
isContracts3QueryMetadata(query, queryId, ruleId) or
7679
isDeclarations1QueryMetadata(query, queryId, ruleId) or

rule_packages/c/Concurrency5.json

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"CERT-C": {
3+
"CON39-C": {
4+
"properties": {
5+
"obligation": "rule"
6+
},
7+
"queries": [
8+
{
9+
"description": "Joining or detaching a previously joined or detached thread can lead to undefined program behavior.",
10+
"kind": "problem",
11+
"name": "Do not join or detach a thread that was previously joined or detached",
12+
"precision": "high",
13+
"severity": "error",
14+
"short_name": "ThreadWasPreviouslyJoinedOrDetached",
15+
"tags": [
16+
"correctness",
17+
"concurrency"
18+
]
19+
}
20+
],
21+
"title": "Do not join or detach a thread that was previously joined or detached"
22+
},
23+
"CON40-C": {
24+
"properties": {
25+
"obligation": "rule"
26+
},
27+
"queries": [
28+
{
29+
"description": "Atomic variables that are referred to twice in the same expression can produce unpredictable program behavior.",
30+
"kind": "problem",
31+
"name": "Do not refer to an atomic variable twice in an expression",
32+
"precision": "very-high",
33+
"severity": "error",
34+
"short_name": "AtomicVariableTwiceInExpression",
35+
"tags": [
36+
"correctness",
37+
"concurrency"
38+
]
39+
}
40+
],
41+
"title": "Do not refer to an atomic variable twice in an expression"
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)