@@ -20,17 +20,22 @@ class BufferWriteEstimationReason extends TBufferWriteEstimationReason {
2020 }
2121
2222 string toString ( ) {
23- this = TTypeBoundsAnalysis ( ) and result = "based on type bounds" or
23+ this = TTypeBoundsAnalysis ( ) and result = "based on type bounds"
24+ or
2425 this = TValueFlowAnalysis ( ) and result = "based on flow analysis of value bounds"
2526 }
2627
2728 BufferWriteEstimationReason combineWith ( BufferWriteEstimationReason other ) {
28- ( this = TTypeBoundsAnalysis ( ) or other = TTypeBoundsAnalysis ( ) ) and result = TTypeBoundsAnalysis ( ) or
29- ( this = TValueFlowAnalysis ( ) and other = TValueFlowAnalysis ( ) ) and result = TValueFlowAnalysis ( )
29+ ( this = TTypeBoundsAnalysis ( ) or other = TTypeBoundsAnalysis ( ) ) and
30+ result = TTypeBoundsAnalysis ( )
31+ or
32+ ( this = TValueFlowAnalysis ( ) and other = TValueFlowAnalysis ( ) ) and
33+ result = TValueFlowAnalysis ( )
3034 }
3135}
3236
3337BufferWriteEstimationReason typeBoundsAnalysis ( ) { result = TTypeBoundsAnalysis ( ) }
38+
3439BufferWriteEstimationReason valueFlowAnalysis ( ) { result = TValueFlowAnalysis ( ) }
3540
3641class PrintfFormatAttribute extends FormatAttribute {
@@ -1014,6 +1019,8 @@ class FormatLiteral extends Literal {
10141019 * conversion specifier of this format string; has no result if this cannot
10151020 * be determined.
10161021 */
1022+ int getMaxConvertedLength ( int n ) { result = max ( int l | l = getMaxConvertedLength ( n , _) | l ) }
1023+
10171024 int getMaxConvertedLength ( int n , BufferWriteEstimationReason reason ) {
10181025 exists ( int len |
10191026 (
@@ -1026,10 +1033,12 @@ class FormatLiteral extends Literal {
10261033 ) and
10271034 (
10281035 this .getConversionChar ( n ) = "%" and
1029- len = 1 and reason = TValueFlowAnalysis ( )
1036+ len = 1 and
1037+ reason = TValueFlowAnalysis ( )
10301038 or
10311039 this .getConversionChar ( n ) .toLowerCase ( ) = "c" and
1032- len = 1 and reason = TValueFlowAnalysis ( ) // e.g. 'a'
1040+ len = 1 and
1041+ reason = TValueFlowAnalysis ( ) // e.g. 'a'
10331042 or
10341043 this .getConversionChar ( n ) .toLowerCase ( ) = "f" and
10351044 exists ( int dot , int afterdot |
@@ -1043,7 +1052,8 @@ class FormatLiteral extends Literal {
10431052 afterdot = 6
10441053 ) and
10451054 len = 1 + 309 + dot + afterdot
1046- ) and reason = TTypeBoundsAnalysis ( ) // e.g. -1e308="-100000"...
1055+ ) and
1056+ reason = TTypeBoundsAnalysis ( ) // e.g. -1e308="-100000"...
10471057 or
10481058 this .getConversionChar ( n ) .toLowerCase ( ) = "e" and
10491059 exists ( int dot , int afterdot |
@@ -1057,7 +1067,8 @@ class FormatLiteral extends Literal {
10571067 afterdot = 6
10581068 ) and
10591069 len = 1 + 1 + dot + afterdot + 1 + 1 + 3
1060- ) and reason = TTypeBoundsAnalysis ( ) // -1e308="-1.000000e+308"
1070+ ) and
1071+ reason = TTypeBoundsAnalysis ( ) // -1e308="-1.000000e+308"
10611072 or
10621073 this .getConversionChar ( n ) .toLowerCase ( ) = "g" and
10631074 exists ( int dot , int afterdot |
@@ -1080,77 +1091,79 @@ class FormatLiteral extends Literal {
10801091 // (e.g. 123456, 0.000123456 are just OK)
10811092 // so case %f can be at most P characters + 4 zeroes, sign, dot = P + 6
10821093 len = ( afterdot .maximum ( 1 ) + 6 ) .maximum ( 1 + 1 + dot + afterdot + 1 + 1 + 3 )
1083- ) and reason = TTypeBoundsAnalysis ( ) // (e.g. "-1.59203e-319")
1094+ ) and
1095+ reason = TTypeBoundsAnalysis ( ) // (e.g. "-1.59203e-319")
10841096 or
10851097 this .getConversionChar ( n ) .toLowerCase ( ) = [ "d" , "i" ] and
10861098 // e.g. -2^31 = "-2147483648"
10871099 exists ( float typeBasedBound , float valueBasedBound |
1088- // The first case handles length sub-specifiers
1089- // Subtract one in the exponent because one bit is for the sign.
1090- // Add 1 to account for the possible sign in the output.
1091- typeBasedBound = 1 + lengthInBase10 ( 2 .pow ( this .getIntegralDisplayType ( n ) .getSize ( ) * 8 - 1 ) ) and
1092- // The second case uses range analysis to deduce a length that's shorter than the length
1093- // of the number -2^31.
1094- exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1095- arg = this .getUse ( ) .getConversionArgument ( n ) and
1096- lower = lowerBound ( arg .getFullyConverted ( ) ) and
1097- upper = upperBound ( arg .getFullyConverted ( ) ) and
1098- typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1099- typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1100- |
1101- valueBasedBound =
1102- max ( int cand |
1103- // Include the sign bit in the length if it can be negative
1104- (
1105- if lower < 0
1106- then cand = 1 + lengthInBase10 ( lower .abs ( ) )
1107- else cand = lengthInBase10 ( lower )
1108- )
1109- or
1110- (
1111- if upper < 0
1112- then cand = 1 + lengthInBase10 ( upper .abs ( ) )
1113- else cand = lengthInBase10 ( upper )
1114- )
1115- ) and
1116- (
1117- if lower > typeLower or upper < typeUpper
1118- then reason = TValueFlowAnalysis ( )
1119- else reason = TTypeBoundsAnalysis ( )
1120- )
1121- ) and
1122- len = valueBasedBound .minimum ( typeBasedBound )
1100+ // The first case handles length sub-specifiers
1101+ // Subtract one in the exponent because one bit is for the sign.
1102+ // Add 1 to account for the possible sign in the output.
1103+ typeBasedBound =
1104+ 1 + lengthInBase10 ( 2 .pow ( this .getIntegralDisplayType ( n ) .getSize ( ) * 8 - 1 ) ) and
1105+ // The second case uses range analysis to deduce a length that's shorter than the length
1106+ // of the number -2^31.
1107+ exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1108+ arg = this .getUse ( ) .getConversionArgument ( n ) and
1109+ lower = lowerBound ( arg .getFullyConverted ( ) ) and
1110+ upper = upperBound ( arg .getFullyConverted ( ) ) and
1111+ typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1112+ typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1113+ |
1114+ valueBasedBound =
1115+ max ( int cand |
1116+ // Include the sign bit in the length if it can be negative
1117+ (
1118+ if lower < 0
1119+ then cand = 1 + lengthInBase10 ( lower .abs ( ) )
1120+ else cand = lengthInBase10 ( lower )
1121+ )
1122+ or
1123+ (
1124+ if upper < 0
1125+ then cand = 1 + lengthInBase10 ( upper .abs ( ) )
1126+ else cand = lengthInBase10 ( upper )
1127+ )
1128+ ) and
1129+ (
1130+ if lower > typeLower or upper < typeUpper
1131+ then reason = TValueFlowAnalysis ( )
1132+ else reason = TTypeBoundsAnalysis ( )
1133+ )
1134+ ) and
1135+ len = valueBasedBound .minimum ( typeBasedBound )
11231136 )
11241137 or
11251138 this .getConversionChar ( n ) .toLowerCase ( ) = "u" and
11261139 // e.g. 2^32 - 1 = "4294967295"
11271140 exists ( float typeBasedBound , float valueBasedBound |
1128- // The first case handles length sub-specifiers
1129- typeBasedBound = lengthInBase10 ( 2 .pow ( this .getIntegralDisplayType ( n ) .getSize ( ) * 8 ) - 1 ) and
1130- // The second case uses range analysis to deduce a length that's shorter than
1131- // the length of the number 2^31 - 1.
1132- exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1133- arg = this .getUse ( ) .getConversionArgument ( n ) and
1134- lower = lowerBound ( arg .getFullyConverted ( ) ) and
1135- upper = upperBound ( arg .getFullyConverted ( ) ) and
1136- typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1137- typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1138- |
1139- valueBasedBound =
1140- lengthInBase10 ( max ( float cand |
1141+ // The first case handles length sub-specifiers
1142+ typeBasedBound = lengthInBase10 ( 2 .pow ( this .getIntegralDisplayType ( n ) .getSize ( ) * 8 ) - 1 ) and
1143+ // The second case uses range analysis to deduce a length that's shorter than
1144+ // the length of the number 2^31 - 1.
1145+ exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1146+ arg = this .getUse ( ) .getConversionArgument ( n ) and
1147+ lower = lowerBound ( arg .getFullyConverted ( ) ) and
1148+ upper = upperBound ( arg .getFullyConverted ( ) ) and
1149+ typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1150+ typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1151+ |
1152+ valueBasedBound =
1153+ lengthInBase10 ( max ( float cand |
11411154 // If lower can be negative we use `(unsigned)-1` as the candidate value.
11421155 lower < 0 and
11431156 cand = 2 .pow ( any ( IntType t | t .isUnsigned ( ) ) .getSize ( ) * 8 )
11441157 or
11451158 cand = upper
11461159 ) ) and
1147- (
1148- if lower > typeLower or upper < typeUpper
1149- then reason = TValueFlowAnalysis ( )
1150- else reason = TTypeBoundsAnalysis ( )
1151- )
1152- ) and
1153- len = valueBasedBound .minimum ( typeBasedBound )
1160+ (
1161+ if lower > typeLower or upper < typeUpper
1162+ then reason = TValueFlowAnalysis ( )
1163+ else reason = TTypeBoundsAnalysis ( )
1164+ )
1165+ ) and
1166+ len = valueBasedBound .minimum ( typeBasedBound )
11541167 )
11551168 or
11561169 this .getConversionChar ( n ) .toLowerCase ( ) = "x" and
@@ -1170,7 +1183,8 @@ class FormatLiteral extends Literal {
11701183 (
11711184 if this .hasAlternateFlag ( n ) then len = 2 + baseLen else len = baseLen // "0x"
11721185 )
1173- ) and reason = TTypeBoundsAnalysis ( )
1186+ ) and
1187+ reason = TTypeBoundsAnalysis ( )
11741188 or
11751189 this .getConversionChar ( n ) .toLowerCase ( ) = "p" and
11761190 exists ( PointerType ptrType , int baseLen |
@@ -1179,7 +1193,8 @@ class FormatLiteral extends Literal {
11791193 (
11801194 if this .hasAlternateFlag ( n ) then len = 2 + baseLen else len = baseLen // "0x"
11811195 )
1182- ) and reason = TValueFlowAnalysis ( )
1196+ ) and
1197+ reason = TValueFlowAnalysis ( )
11831198 or
11841199 this .getConversionChar ( n ) .toLowerCase ( ) = "o" and
11851200 // e.g. 2^32 - 1 = "37777777777"
@@ -1198,7 +1213,8 @@ class FormatLiteral extends Literal {
11981213 (
11991214 if this .hasAlternateFlag ( n ) then len = 1 + baseLen else len = baseLen // "0"
12001215 )
1201- ) and reason = TTypeBoundsAnalysis ( )
1216+ ) and
1217+ reason = TTypeBoundsAnalysis ( )
12021218 or
12031219 this .getConversionChar ( n ) .toLowerCase ( ) = "s" and
12041220 len =
@@ -1218,6 +1234,10 @@ class FormatLiteral extends Literal {
12181234 * determining whether a buffer overflow is caused by long float to string
12191235 * conversions.
12201236 */
1237+ int getMaxConvertedLengthLimited ( int n ) {
1238+ result = max ( int l | l = getMaxConvertedLengthLimited ( n , _) | l )
1239+ }
1240+
12211241 int getMaxConvertedLengthLimited ( int n , BufferWriteEstimationReason reason ) {
12221242 if this .getConversionChar ( n ) .toLowerCase ( ) = "f"
12231243 then result = this .getMaxConvertedLength ( n , reason ) .minimum ( 8 )
@@ -1269,20 +1289,20 @@ class FormatLiteral extends Literal {
12691289 result =
12701290 this .getConstantPart ( n ) .length ( ) + this .getMaxConvertedLength ( n , headReason ) +
12711291 this .getMaxConvertedLengthAfter ( n + 1 , tailReason ) and
1272- reason = headReason .combineWith ( tailReason )
1292+ reason = headReason .combineWith ( tailReason )
12731293 )
12741294 }
12751295
12761296 private int getMaxConvertedLengthAfterLimited ( int n , BufferWriteEstimationReason reason ) {
12771297 if n = this .getNumConvSpec ( )
12781298 then result = this .getConstantSuffix ( ) .length ( ) + 1 and reason = TValueFlowAnalysis ( )
12791299 else
1280- exists ( BufferWriteEstimationReason headReason , BufferWriteEstimationReason tailReason |
1281- result =
1282- this .getConstantPart ( n ) .length ( ) + this .getMaxConvertedLengthLimited ( n , headReason ) +
1283- this .getMaxConvertedLengthAfterLimited ( n + 1 , tailReason ) and
1284- reason = headReason .combineWith ( tailReason )
1285- )
1300+ exists ( BufferWriteEstimationReason headReason , BufferWriteEstimationReason tailReason |
1301+ result =
1302+ this .getConstantPart ( n ) .length ( ) + this .getMaxConvertedLengthLimited ( n , headReason ) +
1303+ this .getMaxConvertedLengthAfterLimited ( n + 1 , tailReason ) and
1304+ reason = headReason .combineWith ( tailReason )
1305+ )
12861306 }
12871307
12881308 /**
0 commit comments