-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathInvalidMemoryOrderArgument.ql
More file actions
112 lines (96 loc) · 3.76 KB
/
InvalidMemoryOrderArgument.ql
File metadata and controls
112 lines (96 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* @id c/misra/invalid-memory-order-argument
* @name RULE-21-25: All memory synchronization operations shall be executed in sequentially consistent order
* @description Only the memory ordering of 'memory_order_seq_cst' is fully portable and consistent.
* @kind path-problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-21-25
* external/misra/c/2012/amendment4
* correctness
* concurrency
* external/misra/obligation/required
*/
import cpp
import codingstandards.c.misra
import codingstandards.cpp.StdFunctionOrMacro
import semmle.code.cpp.dataflow.new.DataFlow
class MemoryOrderEnum extends Enum {
MemoryOrderEnum() {
this.hasGlobalOrStdName("memory_order")
or
exists(TypedefType t |
t.getName() = "memory_order" and
t.getBaseType() = this
)
}
}
/* A member of the set of memory orders defined in the `memory_order` enum */
class MemoryOrder extends EnumConstant {
MemoryOrder() { getDeclaringEnum() instanceof MemoryOrderEnum }
int getIntValue() { result = getValue().toInt() }
}
/* This is the only standardized memory order, allowed by RULE-21-25. */
class AllowedMemoryOrder extends MemoryOrder {
AllowedMemoryOrder() { getName() = "memory_order_seq_cst" }
}
/* An expression referring to a memory order */
class MemoryOrderConstantAccess extends EnumConstantAccess {
MemoryOrderConstantAccess() { getTarget() instanceof MemoryOrder }
predicate isAllowedOrder() { getTarget() instanceof AllowedMemoryOrder }
}
/* An expression with a constant value that equals a `MemoryOrder` constant */
class MemoryOrderConstantExpr extends Expr {
MemoryOrder ord;
MemoryOrderConstantExpr() {
if this instanceof MemoryOrderConstantAccess
then ord = this.(MemoryOrderConstantAccess).getTarget()
else ord.getIntValue() = getValue().toInt()
}
/* Get the name of the `MemoryOrder` this expression is valued as. */
string getMemoryOrderString() { result = ord.getName() }
}
module MemoryOrderFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
// Direct usage of memory order constant
exists(MemoryOrderConstantAccess constant |
node.asExpr() = constant and
not constant.isAllowedOrder()
)
or
// A literal with a disallowed constant integer value
exists(Literal literal |
node.asExpr() = literal and
not literal.getValue().toInt() = any(AllowedMemoryOrder a).getValue().toInt()
)
}
predicate isSink(DataFlow::Node node) {
exists(AtomicallySequencedCall call |
call.getAMemoryOrderArgument() = node.asExpr()
)
}
}
module MemoryOrderFlow = DataFlow::Global<MemoryOrderFlowConfig>;
import MemoryOrderFlow::PathGraph
/**
* If the node is a memory order constant, or shares a value with a memory order constant, then
* return the name of that constant. Otherwise, simply print the node.
*/
string describeMemoryOrderNode(DataFlow::Node node) {
if node.asExpr() instanceof MemoryOrderConstantExpr
then result = node.asExpr().(MemoryOrderConstantExpr).getMemoryOrderString()
else result = node.toString()
}
from
Expr argument, AtomicallySequencedCall function, string value, MemoryOrderFlow::PathNode source,
MemoryOrderFlow::PathNode sink
where
not isExcluded(argument, Concurrency6Package::invalidMemoryOrderArgumentQuery()) and
MemoryOrderFlow::flowPath(source, sink) and
argument = sink.getNode().asExpr() and
value = describeMemoryOrderNode(source.getNode()) and
// Double check that we didn't find flow from something equivalent to the allowed value.
not value = any(AllowedMemoryOrder e).getName() and
function.getAMemoryOrderArgument() = argument
select argument, source, sink, "Invalid memory order '$@' in call to function '$@'.", value, value,
function, function.getName()