@@ -12,8 +12,17 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
1212private newtype TBufferWriteEstimationReason =
1313 TUnspecifiedEstimateReason ( ) or
1414 TTypeBoundsAnalysis ( ) or
15+ TWidenedValueFlowAnalysis ( ) or
1516 TValueFlowAnalysis ( )
1617
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+
1726/**
1827 * A reason for a specific buffer write size estimate.
1928 */
@@ -32,7 +41,11 @@ abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason
3241 * Combine estimate reasons. Used to give a reason for the size of a format string
3342 * conversion given reasons coming from its individual specifiers.
3443 */
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+ }
3649}
3750
3851/**
@@ -44,12 +57,6 @@ class UnspecifiedEstimateReason extends BufferWriteEstimationReason, TUnspecifie
4457 override string toString ( ) { result = "UnspecifiedEstimateReason" }
4558
4659 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- }
5360}
5461
5562/**
@@ -60,12 +67,26 @@ class TypeBoundsAnalysis extends BufferWriteEstimationReason, TTypeBoundsAnalysi
6067 override string toString ( ) { result = "TypeBoundsAnalysis" }
6168
6269 override string getDescription ( ) { result = "based on type bounds" }
70+ }
6371
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" }
6787}
6888
89+
6990/**
7091 * The estimation comes from non trivial bounds found via actual flow analysis.
7192 * For example
@@ -80,10 +101,6 @@ class ValueFlowAnalysis extends BufferWriteEstimationReason, TValueFlowAnalysis
80101 override string toString ( ) { result = "ValueFlowAnalysis" }
81102
82103 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- }
87104}
88105
89106class PrintfFormatAttribute extends FormatAttribute {
@@ -359,6 +376,17 @@ private int lengthInBase10(float f) {
359376 result = f .log10 ( ) .floor ( ) + 1
360377}
361378
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+ }
362390/**
363391 * A class to represent format strings that occur as arguments to invocations of formatting functions.
364392 */
@@ -1158,11 +1186,9 @@ class FormatLiteral extends Literal {
11581186 // The second case uses range analysis to deduce a length that's shorter than the length
11591187 // of the number -2^31.
11601188 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 )
11661192 |
11671193 valueBasedBound =
11681194 max ( int cand |
@@ -1179,11 +1205,7 @@ class FormatLiteral extends Literal {
11791205 else cand = lengthInBase10 ( upper )
11801206 )
11811207 ) and
1182- (
1183- if lower > typeLower or upper < typeUpper
1184- then reason = TValueFlowAnalysis ( )
1185- else reason = TTypeBoundsAnalysis ( )
1186- )
1208+ reason = getEstimationReasonForIntegralExpression ( arg )
11871209 ) and
11881210 len = valueBasedBound .minimum ( typeBasedBound )
11891211 )
@@ -1196,11 +1218,11 @@ class FormatLiteral extends Literal {
11961218 // The second case uses range analysis to deduce a length that's shorter than
11971219 // the length of the number 2^31 - 1.
11981220 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 )
12041226 |
12051227 valueBasedBound =
12061228 lengthInBase10 ( max ( float cand |
@@ -1210,11 +1232,7 @@ class FormatLiteral extends Literal {
12101232 or
12111233 cand = upper
12121234 ) ) and
1213- (
1214- if lower > typeLower or upper < typeUpper
1215- then reason = TValueFlowAnalysis ( )
1216- else reason = TTypeBoundsAnalysis ( )
1217- )
1235+ reason = getEstimationReasonForIntegralExpression ( arg )
12181236 ) and
12191237 len = valueBasedBound .minimum ( typeBasedBound )
12201238 )
0 commit comments