@@ -359,6 +359,18 @@ private int lengthInBase10(float f) {
359
359
result = f .log10 ( ) .floor ( ) + 1
360
360
}
361
361
362
+ /**
363
+ * Gets the number of hex digits required to represent the integer represented by `f`.
364
+ *
365
+ * `f` is assumed to be nonnegative.
366
+ */
367
+ bindingset [ f]
368
+ private int lengthInBase16 ( float f ) {
369
+ f = 0 and result = 1
370
+ or
371
+ result = ( f .log2 ( ) / 4.0 ) .floor ( ) + 1
372
+ }
373
+
362
374
/**
363
375
* A class to represent format strings that occur as arguments to invocations of formatting functions.
364
376
*/
@@ -1221,23 +1233,42 @@ class FormatLiteral extends Literal {
1221
1233
or
1222
1234
this .getConversionChar ( n ) .toLowerCase ( ) = "x" and
1223
1235
// e.g. "12345678"
1224
- exists ( int sizeBytes , int baseLen |
1225
- sizeBytes =
1226
- min ( int bytes |
1227
- bytes = this .getIntegralDisplayType ( n ) .getSize ( )
1236
+ exists ( int baseLen , int typeBasedBound , int valueBasedBound |
1237
+ typeBasedBound =
1238
+ min ( int digits |
1239
+ digits = 2 * this .getIntegralDisplayType ( n ) .getSize ( )
1228
1240
or
1229
1241
exists ( IntegralType t |
1230
1242
t = this .getUse ( ) .getConversionArgument ( n ) .getType ( ) .getUnderlyingType ( )
1231
1243
|
1232
- t .isUnsigned ( ) and bytes = t .getSize ( )
1244
+ t .isUnsigned ( ) and
1245
+ digits = 2 * t .getSize ( )
1233
1246
)
1234
1247
) and
1235
- baseLen = sizeBytes * 2 and
1236
- (
1237
- if this .hasAlternateFlag ( n ) then len = 2 + baseLen else len = baseLen // "0x"
1238
- )
1239
- ) and
1240
- reason = TTypeBoundsAnalysis ( )
1248
+ exists ( Expr arg , float lower , float upper , float typeLower , float typeUpper |
1249
+ arg = this .getUse ( ) .getConversionArgument ( n ) and
1250
+ lower = lowerBound ( arg .getFullyConverted ( ) ) and
1251
+ upper = upperBound ( arg .getFullyConverted ( ) ) and
1252
+ typeLower = exprMinVal ( arg .getFullyConverted ( ) ) and
1253
+ typeUpper = exprMaxVal ( arg .getFullyConverted ( ) )
1254
+ |
1255
+ valueBasedBound =
1256
+ lengthInBase16 ( max ( float cand |
1257
+ // If lower can be negative we use `(unsigned)-1` as the candidate value.
1258
+ lower < 0 and
1259
+ cand = 2 .pow ( any ( IntType t | t .isUnsigned ( ) ) .getSize ( ) * 8 )
1260
+ or
1261
+ cand = upper
1262
+ ) ) and
1263
+ (
1264
+ if lower > typeLower or upper < typeUpper
1265
+ then reason = TValueFlowAnalysis ( )
1266
+ else reason = TTypeBoundsAnalysis ( )
1267
+ )
1268
+ ) and
1269
+ baseLen = valueBasedBound .minimum ( typeBasedBound ) and
1270
+ if this .hasAlternateFlag ( n ) then len = 2 + baseLen else len = baseLen // "0x"
1271
+ )
1241
1272
or
1242
1273
this .getConversionChar ( n ) .toLowerCase ( ) = "p" and
1243
1274
exists ( PointerType ptrType , int baseLen |
0 commit comments