@@ -359,6 +359,18 @@ private int lengthInBase10(float f) {
359359 result = f .log10 ( ) .floor ( ) + 1
360360}
361361
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+
362374/**
363375 * A class to represent format strings that occur as arguments to invocations of formatting functions.
364376 */
@@ -1221,23 +1233,42 @@ class FormatLiteral extends Literal {
12211233 or
12221234 this .getConversionChar ( n ) .toLowerCase ( ) = "x" and
12231235 // 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 ( )
12281240 or
12291241 exists ( IntegralType t |
12301242 t = this .getUse ( ) .getConversionArgument ( n ) .getType ( ) .getUnderlyingType ( )
12311243 |
1232- t .isUnsigned ( ) and bytes = t .getSize ( )
1244+ t .isUnsigned ( ) and
1245+ digits = 2 * t .getSize ( )
12331246 )
12341247 ) 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+ )
12411272 or
12421273 this .getConversionChar ( n ) .toLowerCase ( ) = "p" and
12431274 exists ( PointerType ptrType , int baseLen |
0 commit comments