@@ -12,8 +12,17 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
12
12
private newtype TBufferWriteEstimationReason =
13
13
TUnspecifiedEstimateReason ( ) or
14
14
TTypeBoundsAnalysis ( ) or
15
+ TWidenedValueFlowAnalysis ( ) or
15
16
TValueFlowAnalysis ( )
16
17
18
+ private predicate gradeToReason ( int grade , TBufferWriteEstimationReason reason ) {
19
+ // when combining reasons, lower grade takes precedence
20
+ grade = 0 and reason = TUnspecifiedEstimateReason ( ) or
21
+ grade = 1 and reason = TTypeBoundsAnalysis ( ) or
22
+ grade = 2 and reason = TWidenedValueFlowAnalysis ( ) or
23
+ grade = 3 and reason = TValueFlowAnalysis ( )
24
+ }
25
+
17
26
/**
18
27
* A reason for a specific buffer write size estimate.
19
28
*/
@@ -32,7 +41,11 @@ abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason
32
41
* Combine estimate reasons. Used to give a reason for the size of a format string
33
42
* conversion given reasons coming from its individual specifiers.
34
43
*/
35
- abstract BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) ;
44
+ BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) {
45
+ exists ( int grade , int otherGrade | gradeToReason ( grade , this ) and gradeToReason ( otherGrade , other ) |
46
+ if otherGrade < grade then result = other else result = this
47
+ )
48
+ }
36
49
}
37
50
38
51
/**
@@ -44,12 +57,6 @@ class UnspecifiedEstimateReason extends BufferWriteEstimationReason, TUnspecifie
44
57
override string toString ( ) { result = "UnspecifiedEstimateReason" }
45
58
46
59
override string getDescription ( ) { result = "no reason specified" }
47
-
48
- override BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) {
49
- // this reason should not be used in format specifiers, so it should not be combined
50
- // with other reasons
51
- none ( )
52
- }
53
60
}
54
61
55
62
/**
@@ -60,12 +67,26 @@ class TypeBoundsAnalysis extends BufferWriteEstimationReason, TTypeBoundsAnalysi
60
67
override string toString ( ) { result = "TypeBoundsAnalysis" }
61
68
62
69
override string getDescription ( ) { result = "based on type bounds" }
70
+ }
63
71
64
- override BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) {
65
- other != TUnspecifiedEstimateReason ( ) and result = TTypeBoundsAnalysis ( )
66
- }
72
+ /**
73
+ * The estimation comes from non trivial bounds found via actual flow analysis,
74
+ * but a widening aproximation might have been used for variables in loops.
75
+ * For example
76
+ * ```
77
+ * for (int i = 0; i < 10; ++i) {
78
+ * int j = i + i;
79
+ * //... <- estimation done here based on j
80
+ * }
81
+ * ```
82
+ */
83
+ class WidenedValueFlowAnalysis extends BufferWriteEstimationReason , TWidenedValueFlowAnalysis {
84
+ override string toString ( ) { result = "WidenedValueFlowAnalysis" }
85
+
86
+ override string getDescription ( ) { result = "based on flow analysis of value bounds with a widening approximation" }
67
87
}
68
88
89
+
69
90
/**
70
91
* The estimation comes from non trivial bounds found via actual flow analysis.
71
92
* For example
@@ -80,10 +101,6 @@ class ValueFlowAnalysis extends BufferWriteEstimationReason, TValueFlowAnalysis
80
101
override string toString ( ) { result = "ValueFlowAnalysis" }
81
102
82
103
override string getDescription ( ) { result = "based on flow analysis of value bounds" }
83
-
84
- override BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) {
85
- other != TUnspecifiedEstimateReason ( ) and result = other
86
- }
87
104
}
88
105
89
106
class PrintfFormatAttribute extends FormatAttribute {
@@ -359,6 +376,17 @@ private int lengthInBase10(float f) {
359
376
result = f .log10 ( ) .floor ( ) + 1
360
377
}
361
378
379
+ private BufferWriteEstimationReason getEstimationReasonForIntegralExpression ( Expr expr ) {
380
+ // we consider the range analysis non trivial if it
381
+ // * constrained non-trivially both sides of a signed value, or
382
+ // * constrained non-trivially the positive side of an unsigned value
383
+ // expr should already be given as getFullyConverted
384
+ if upperBound ( expr ) < exprMaxVal ( expr ) and ( exprMinVal ( expr ) >= 0 or lowerBound ( expr ) > exprMinVal ( expr ) )
385
+ // next we check whether the estimate may have been widened
386
+ then if upperBoundMayBeWidened ( expr ) then result = TWidenedValueFlowAnalysis ( )
387
+ else result = TValueFlowAnalysis ( )
388
+ else result = TTypeBoundsAnalysis ( )
389
+ }
362
390
/**
363
391
* A class to represent format strings that occur as arguments to invocations of formatting functions.
364
392
*/
@@ -1158,11 +1186,9 @@ class FormatLiteral extends Literal {
1158
1186
// The second case uses range analysis to deduce a length that's shorter than the length
1159
1187
// of the number -2^31.
1160
1188
exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1161
- arg = this .getUse ( ) .getConversionArgument ( n ) and
1162
- lower = lowerBound ( arg .getFullyConverted ( ) ) and
1163
- upper = upperBound ( arg .getFullyConverted ( ) ) and
1164
- typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1165
- typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1189
+ arg = this .getUse ( ) .getConversionArgument ( n ) .getFullyConverted ( ) and
1190
+ lower = lowerBound ( arg ) and
1191
+ upper = upperBound ( arg )
1166
1192
|
1167
1193
valueBasedBound =
1168
1194
max ( int cand |
@@ -1179,11 +1205,7 @@ class FormatLiteral extends Literal {
1179
1205
else cand = lengthInBase10 ( upper )
1180
1206
)
1181
1207
) and
1182
- (
1183
- if lower > typeLower or upper < typeUpper
1184
- then reason = TValueFlowAnalysis ( )
1185
- else reason = TTypeBoundsAnalysis ( )
1186
- )
1208
+ reason = getEstimationReasonForIntegralExpression ( arg )
1187
1209
) and
1188
1210
len = valueBasedBound .minimum ( typeBasedBound )
1189
1211
)
@@ -1196,11 +1218,11 @@ class FormatLiteral extends Literal {
1196
1218
// The second case uses range analysis to deduce a length that's shorter than
1197
1219
// the length of the number 2^31 - 1.
1198
1220
exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1199
- arg = this .getUse ( ) .getConversionArgument ( n ) and
1200
- lower = lowerBound ( arg . getFullyConverted ( ) ) and
1201
- upper = upperBound ( arg . getFullyConverted ( ) ) and
1202
- typeLower = exprMinVal ( arg . getFullyConverted ( ) ) and
1203
- typeUpper = exprMaxVal ( arg . getFullyConverted ( ) )
1221
+ arg = this .getUse ( ) .getConversionArgument ( n ) . getFullyConverted ( ) and
1222
+ lower = lowerBound ( arg ) and
1223
+ upper = upperBound ( arg ) and
1224
+ typeLower = exprMinVal ( arg ) and
1225
+ typeUpper = exprMaxVal ( arg )
1204
1226
|
1205
1227
valueBasedBound =
1206
1228
lengthInBase10 ( max ( float cand |
@@ -1210,11 +1232,7 @@ class FormatLiteral extends Literal {
1210
1232
or
1211
1233
cand = upper
1212
1234
) ) and
1213
- (
1214
- if lower > typeLower or upper < typeUpper
1215
- then reason = TValueFlowAnalysis ( )
1216
- else reason = TTypeBoundsAnalysis ( )
1217
- )
1235
+ reason = getEstimationReasonForIntegralExpression ( arg )
1218
1236
) and
1219
1237
len = valueBasedBound .minimum ( typeBasedBound )
1220
1238
)
0 commit comments