@@ -15,6 +15,7 @@ import cpp
15
15
import codingstandards.c.cert
16
16
import codingstandards.cpp.Alignment
17
17
import semmle.code.cpp.dataflow.DataFlow
18
+ import semmle.code.cpp.dataflow.DataFlow2
18
19
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
19
20
import DataFlow:: PathGraph
20
21
@@ -40,14 +41,14 @@ abstract class ExprWithAlignment extends Expr {
40
41
class AddressOfAlignedVariableExpr extends AddressOfExpr , ExprWithAlignment {
41
42
AddressOfAlignedVariableExpr ( ) { this .getAddressable ( ) instanceof Variable }
42
43
43
- AlignAs alignAsAttribute ( ) { result = this .getAddressable ( ) .( Variable ) .getAnAttribute ( ) }
44
+ AlignAs getAlignAsAttribute ( ) { result = this .getAddressable ( ) .( Variable ) .getAnAttribute ( ) }
44
45
45
46
override int getAlignment ( ) {
46
- result = alignAsAttribute ( ) .getArgument ( 0 ) .getValueInt ( )
47
+ result = getAlignAsAttribute ( ) .getArgument ( 0 ) .getValueInt ( )
47
48
or
48
- result = alignAsAttribute ( ) .getArgument ( 0 ) .getValueType ( ) .getSize ( )
49
+ result = getAlignAsAttribute ( ) .getArgument ( 0 ) .getValueType ( ) .getSize ( )
49
50
or
50
- not exists ( alignAsAttribute ( ) ) and
51
+ not exists ( getAlignAsAttribute ( ) ) and
51
52
result = this .getAddressable ( ) .( Variable ) .getType ( ) .getAlignment ( )
52
53
}
53
54
@@ -76,40 +77,35 @@ class DefinedAlignmentAllocationExpr extends FunctionCall, ExprWithAlignment {
76
77
}
77
78
78
79
/**
79
- * A class extending `VariableAccess` and `ExprWithAlignment` to reason about the
80
- * alignment of pointers accessed based solely on the pointers' base types .
80
+ * An `Expr` of type `PointerType` but not `VoidPointerType`
81
+ * which is the unique non-`Conversion` expression of a `Cast` .
81
82
*/
82
- class DefaultAlignedPointerAccessExpr extends VariableAccess , ExprWithAlignment {
83
- DefaultAlignedPointerAccessExpr ( ) {
84
- this .getTarget ( ) .getUnspecifiedType ( ) instanceof PointerType and
85
- not this .getTarget ( ) .getUnspecifiedType ( ) instanceof VoidPointerType
86
- }
87
-
88
- override int getAlignment ( ) {
89
- result = this .getTarget ( ) .getType ( ) .( PointerType ) .getBaseType ( ) .getAlignment ( )
83
+ class UnconvertedCastFromNonVoidPointerExpr extends Expr {
84
+ UnconvertedCastFromNonVoidPointerExpr ( ) {
85
+ exists ( CStyleCast cast |
86
+ cast .getUnconverted ( ) = this and
87
+ this .getUnspecifiedType ( ) instanceof PointerType and
88
+ not this .getUnspecifiedType ( ) instanceof VoidPointerType
89
+ )
90
90
}
91
-
92
- override string getKind ( ) { result = "pointer base type" }
93
91
}
94
92
95
93
/**
96
- * A data-flow configuration for analysing the flow of `ExprWithAlignment` pointer expressions
97
- * to casts which perform pointer type conversions and potentially create pointer alignment issues .
94
+ * A class extending `UnconvertedCastFromNonVoidPointerExpr` and `ExprWithAlignment` to reason
95
+ * about the alignment of pointers accessed based solely on the pointers' base types .
98
96
*/
99
- class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow:: Configuration {
100
- ExprWithAlignmentToCStyleCastConfiguration ( ) {
101
- this = "ExprWithAlignmentToCStyleCastConfiguration"
97
+ class DefaultAlignedPointerExpr extends UnconvertedCastFromNonVoidPointerExpr , ExprWithAlignment {
98
+ DefaultAlignedPointerExpr ( ) {
99
+ not any ( AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig config )
100
+ .hasFlowTo ( DataFlow:: exprNode ( this ) )
102
101
}
103
102
104
- override predicate isSource ( DataFlow:: Node source ) {
105
- source .asExpr ( ) instanceof ExprWithAlignment
106
- }
103
+ override int getAlignment ( ) { result = this .getType ( ) .( PointerType ) .getBaseType ( ) .getAlignment ( ) }
107
104
108
- override predicate isSink ( DataFlow:: Node sink ) {
109
- exists ( CStyleCast cast |
110
- cast .getUnderlyingType ( ) instanceof PointerType and
111
- cast .getUnconverted ( ) = sink .asExpr ( )
112
- )
105
+ override string getKind ( ) {
106
+ result =
107
+ "pointer base type " +
108
+ this .getType ( ) .( PointerType ) .getBaseType ( ) .getUnspecifiedType ( ) .getName ( )
113
109
}
114
110
}
115
111
@@ -122,9 +118,9 @@ class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow::Configuration
122
118
* to exclude an `DefaultAlignedPointerAccessExpr` as a source if a preceding source
123
119
* defined by this configuration provides more accurate alignment information.
124
120
*/
125
- class AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig extends DataFlow :: Configuration {
126
- AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig ( ) {
127
- this = "AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig "
121
+ class AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig extends DataFlow2 :: Configuration {
122
+ AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig ( ) {
123
+ this = "AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig "
128
124
}
129
125
130
126
override predicate isSource ( DataFlow:: Node source ) {
@@ -133,7 +129,42 @@ class AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig extends DataF
133
129
}
134
130
135
131
override predicate isSink ( DataFlow:: Node sink ) {
136
- sink .asExpr ( ) instanceof DefaultAlignedPointerAccessExpr
132
+ sink .asExpr ( ) instanceof UnconvertedCastFromNonVoidPointerExpr
133
+ }
134
+ }
135
+
136
+ /**
137
+ * A data-flow configuration for analysing the flow of `ExprWithAlignment` pointer expressions
138
+ * to casts which perform pointer type conversions and potentially create pointer alignment issues.
139
+ */
140
+ class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow:: Configuration {
141
+ ExprWithAlignmentToCStyleCastConfiguration ( ) {
142
+ this = "ExprWithAlignmentToCStyleCastConfiguration"
143
+ }
144
+
145
+ override predicate isSource ( DataFlow:: Node source ) {
146
+ source .asExpr ( ) instanceof ExprWithAlignment
147
+ }
148
+
149
+ override predicate isSink ( DataFlow:: Node sink ) {
150
+ exists ( CStyleCast cast |
151
+ cast .getUnderlyingType ( ) instanceof PointerType and
152
+ cast .getUnconverted ( ) = sink .asExpr ( )
153
+ )
154
+ }
155
+
156
+ override predicate isBarrierOut ( DataFlow:: Node node ) {
157
+ // the default interprocedural data-flow model flows through any array assignment expressions
158
+ // to the qualifier (array base or pointer dereferenced) instead of the individual element
159
+ // that the assignment modifies. this default behaviour causes false positives for any future
160
+ // cast of the array base, so remove the assignment edge at the expense of false-negatives.
161
+ exists ( AssignExpr a |
162
+ node .asExpr ( ) = a .getRValue ( ) and
163
+ (
164
+ a .getLValue ( ) instanceof ArrayExpr or
165
+ a .getLValue ( ) instanceof PointerDereferenceExpr
166
+ )
167
+ )
137
168
}
138
169
}
139
170
@@ -145,24 +176,10 @@ where
145
176
any ( ExprWithAlignmentToCStyleCastConfiguration config ) .hasFlowPath ( source , sink ) and
146
177
source .getNode ( ) .asExpr ( ) = expr and
147
178
sink .getNode ( ) .asExpr ( ) = cast .getUnconverted ( ) and
148
- (
149
- // possibility 1: the source node (ExprWithAlignment) is NOT a DefaultAlignedPointerAccessExpr
150
- // meaning that its alignment info is accurate regardless of any preceding ExprWithAlignment nodes
151
- expr instanceof DefaultAlignedPointerAccessExpr
152
- implies
153
- (
154
- // possibility 2: the source node (ExprWithAlignment) IS a DefaultAlignedPointerAccessExpr
155
- // meaning that its alignment info is only accurate if no preceding ExprWithAlignment nodes exist
156
- not any ( AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig config )
157
- .hasFlowTo ( source .getNode ( ) ) and
158
- expr instanceof DefaultAlignedPointerAccessExpr and
159
- cast .getUnconverted ( ) instanceof VariableAccess
160
- )
161
- ) and
162
179
toBaseType = cast .getActualType ( ) .( PointerType ) .getBaseType ( ) and
163
180
alignmentTo = toBaseType .getAlignment ( ) and
164
181
alignmentFrom = expr .getAlignment ( ) and
165
- // only flag cases where the cast's target type has stricter alignment requirements than the source
182
+ // flag cases where the cast's target type has stricter alignment requirements than the source
166
183
alignmentFrom < alignmentTo
167
184
select sink , source , sink ,
168
185
"Cast from pointer with " + alignmentFrom +
0 commit comments