@@ -17,13 +17,15 @@ import codingstandards.c.Expr
17
17
import codingstandards.c.SideEffects
18
18
import codingstandards.c.Ordering
19
19
20
- predicate isOrHasSideEffect ( Expr e ) {
21
- e instanceof VariableEffect or
22
- any ( VariableEffect ve ) .getAnAccess ( ) = e
20
+ class VariableEffectOrAccess extends Expr {
21
+ VariableEffectOrAccess ( ) {
22
+ this instanceof VariableEffect or
23
+ this instanceof VariableAccess
24
+ }
23
25
}
24
26
25
- predicate partOfFullExpr ( Expr e , FullExpr fe ) {
26
- isOrHasSideEffect ( e ) and
27
+ pragma [ noinline ]
28
+ predicate partOfFullExpr ( VariableEffectOrAccess e , FullExpr fe ) {
27
29
(
28
30
e .( VariableEffect ) .getAnAccess ( ) = fe .getAChild + ( )
29
31
or
@@ -42,62 +44,92 @@ class ConstituentExprOrdering extends Ordering::Configuration {
42
44
}
43
45
}
44
46
45
- pragma [ noinline]
46
- predicate sameFullExpr ( FullExpr fe , Expr e1 , Expr e2 ) {
47
- partOfFullExpr ( e1 , fe ) and
48
- partOfFullExpr ( e2 , fe )
49
- }
50
-
51
- predicate destructureEffect ( VariableEffect ve , VariableAccess va , Variable v ) {
52
- ve .getAnAccess ( ) = va and
53
- va .getTarget ( ) = v and
54
- ve .getTarget ( ) = v
47
+ predicate sameFullExpr ( FullExpr fe , VariableAccess va1 , VariableAccess va2 ) {
48
+ partOfFullExpr ( va1 , fe ) and
49
+ partOfFullExpr ( va2 , fe ) and
50
+ va1 != va2 and
51
+ exists ( Variable v1 , Variable v2 |
52
+ // Use `pragma[only_bind_into]` to prevent CP between variable accesses.
53
+ va1 .getTarget ( ) = pragma [ only_bind_into ] ( v1 ) and va2 .getTarget ( ) = pragma [ only_bind_into ] ( v2 )
54
+ |
55
+ v1 .isVolatile ( ) and v2 .isVolatile ( )
56
+ or
57
+ not ( v1 .isVolatile ( ) and v2 .isVolatile ( ) ) and
58
+ v1 = v2
59
+ )
55
60
}
56
61
57
62
from
58
63
ConstituentExprOrdering orderingConfig , FullExpr fullExpr , VariableEffect variableEffect1 ,
59
- VariableEffect variableEffect2 , VariableAccess va1 , VariableAccess va2 , Variable v1 , Variable v2
64
+ VariableAccess va1 , VariableAccess va2 , Locatable placeHolder , string label
60
65
where
61
66
not isExcluded ( fullExpr , SideEffects3Package:: unsequencedSideEffectsQuery ( ) ) and
67
+ // The two access are scoped to the same full expression.
62
68
sameFullExpr ( fullExpr , va1 , va2 ) and
63
- destructureEffect ( variableEffect1 , va1 , v1 ) and
64
- destructureEffect ( variableEffect2 , va2 , v2 ) and
65
- // Exclude the same effect applying to different objects.
66
- // This occurs when on is a subject of the other.
67
- // For example, foo.bar = 1; where both foo and bar are objects modified by the assignment.
68
- variableEffect1 != variableEffect2 and
69
- // If the effect is not local (happens in a different function) we use the call with the access as a proxy.
69
+ // We are only interested in effects that change an object,
70
+ // i.e., exclude patterns suchs as `b->data[b->cursor++]` where `b` is considered modified and read or `foo.bar = 1` where `=` modifies to both `foo` and `bar`.
71
+ not variableEffect1 .isPartial ( ) and
72
+ variableEffect1 .getAnAccess ( ) = va1 and
70
73
(
71
- va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
72
- va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
73
- orderingConfig .isUnsequenced ( variableEffect1 , variableEffect2 )
74
- or
75
- va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
76
- not va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
77
- exists ( Call call |
78
- call .getAnArgument ( ) = va2 and call .getEnclosingStmt ( ) = va1 .getEnclosingStmt ( )
79
- |
80
- orderingConfig .isUnsequenced ( variableEffect1 , call )
74
+ exists ( VariableEffect variableEffect2 |
75
+ not variableEffect2 .isPartial ( ) and
76
+ variableEffect2 .getAnAccess ( ) = va2 and
77
+ // If the effect is not local (happens in a different function) we use the call with the access as a proxy.
78
+ (
79
+ va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
80
+ va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
81
+ orderingConfig .isUnsequenced ( variableEffect1 , variableEffect2 )
82
+ or
83
+ va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
84
+ not va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
85
+ exists ( Call call |
86
+ call .getAnArgument ( ) = va2 and call .getEnclosingStmt ( ) = va1 .getEnclosingStmt ( )
87
+ |
88
+ orderingConfig .isUnsequenced ( variableEffect1 , call )
89
+ )
90
+ or
91
+ not va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
92
+ va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
93
+ exists ( Call call |
94
+ call .getAnArgument ( ) = va1 and call .getEnclosingStmt ( ) = va2 .getEnclosingStmt ( )
95
+ |
96
+ orderingConfig .isUnsequenced ( call , variableEffect2 )
97
+ )
98
+ ) and
99
+ // Break the symmetry of the ordering relation by requiring that the first expression is located before the second.
100
+ // This builds upon the assumption that the expressions are part of the same full expression as specified in the ordering configuration.
101
+ exists ( int offset1 , int offset2 |
102
+ va1 .getLocation ( ) .charLoc ( _, offset1 , _) and
103
+ va2 .getLocation ( ) .charLoc ( _, offset2 , _) and
104
+ offset1 < offset2
105
+ ) and
106
+ placeHolder = variableEffect2 and
107
+ label = "side effect"
81
108
)
82
109
or
83
- not va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
84
- va2 .getEnclosingStmt ( ) = variableEffect2 .getEnclosingStmt ( ) and
85
- exists ( Call call |
86
- call .getAnArgument ( ) = va1 and call .getEnclosingStmt ( ) = va2 .getEnclosingStmt ( )
87
- |
88
- orderingConfig .isUnsequenced ( call , variableEffect2 )
89
- )
110
+ placeHolder = va2 and
111
+ label = "read" and
112
+ not exists ( VariableEffect variableEffect2 | variableEffect1 != variableEffect2 |
113
+ variableEffect2 .getAnAccess ( ) = va2
114
+ ) and
115
+ (
116
+ va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
117
+ orderingConfig .isUnsequenced ( variableEffect1 , va2 )
118
+ or
119
+ not va1 .getEnclosingStmt ( ) = variableEffect1 .getEnclosingStmt ( ) and
120
+ exists ( Call call |
121
+ call .getAnArgument ( ) = va1 and call .getEnclosingStmt ( ) = va2 .getEnclosingStmt ( )
122
+ |
123
+ orderingConfig .isUnsequenced ( call , va2 )
124
+ )
125
+ ) and
126
+ // The read is not used to compute the effect on the variable.
127
+ // E.g., exclude x = x + 1
128
+ not variableEffect1 .getAChild + ( ) = va2
90
129
) and
91
130
// Both are evaluated
92
131
not exists ( ConditionalExpr ce |
93
132
ce .getThen ( ) .getAChild * ( ) = va1 and ce .getElse ( ) .getAChild * ( ) = va2
94
- ) and
95
- // Break the symmetry of the ordering relation by requiring that the first expression is located before the second.
96
- // This builds upon the assumption that the expressions are part of the same full expression as specified in the ordering configuration.
97
- exists ( int offset1 , int offset2 |
98
- va1 .getLocation ( ) .charLoc ( _, offset1 , _) and
99
- va2 .getLocation ( ) .charLoc ( _, offset2 , _) and
100
- offset1 < offset2
101
133
)
102
134
select fullExpr , "The expression contains unsequenced $@ to $@ and $@ to $@." , variableEffect1 ,
103
- "side effect" , va1 , v1 . getName ( ) , variableEffect2 , "side effect" , va2 , v2 . getName ( )
135
+ "side effect" , va1 , va1 . getTarget ( ) , placeHolder , label , va2 , va2 . getTarget ( )
0 commit comments