@@ -17,13 +17,15 @@ import codingstandards.c.Expr
1717import codingstandards.c.SideEffects
1818import codingstandards.c.Ordering
1919
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+ }
2325}
2426
25- predicate partOfFullExpr ( Expr e , FullExpr fe ) {
26- isOrHasSideEffect ( e ) and
27+ pragma [ noinline ]
28+ predicate partOfFullExpr ( VariableEffectOrAccess e , FullExpr fe ) {
2729 (
2830 e .( VariableEffect ) .getAnAccess ( ) = fe .getAChild + ( )
2931 or
@@ -42,62 +44,92 @@ class ConstituentExprOrdering extends Ordering::Configuration {
4244 }
4345}
4446
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+ )
5560}
5661
5762from
5863 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
6065where
6166 not isExcluded ( fullExpr , SideEffects3Package:: unsequencedSideEffectsQuery ( ) ) and
67+ // The two access are scoped to the same full expression.
6268 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
7073 (
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"
81108 )
82109 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
90129 ) and
91130 // Both are evaluated
92131 not exists ( ConditionalExpr ce |
93132 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
101133 )
102134select 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