@@ -289,17 +289,27 @@ private predicate upperBoundCheckGuard(DataFlow::Node g, Expr e, boolean branch)
289289/** An upper bound check that compares a variable to a constant value. */
290290class UpperBoundCheckGuard extends DataFlow:: RelationalComparisonNode {
291291 UpperBoundCheckGuard ( ) {
292+ // Note that even though `x > c` and `x >= c` do not look like upper bound
293+ // checks, on the branches where they are false the conditions are `x <= c`
294+ // and `x < c` respectively, which are upper bound checks.
292295 count ( expr .getAnOperand ( ) .getExactValue ( ) ) = 1 and
293296 expr .getAnOperand ( ) .getType ( ) .getUnderlyingType ( ) instanceof IntegerType
294297 }
295298
296299 /**
297- * Holds if this upper bound check ensures the non-constant operand is less
298- * than or equal to `2^(b) - 1` for some `b` which is a valid bit size less
299- * than `bitSize`. In this case, the upper bound check is a barrier guard,
300- * because the flow should be for `b` instead of `bitSize`.
301- * `architectureBitSize` is used if the constant operand is `math.MaxInt` or
302- * `math.MaxUint`.
300+ * Holds if this upper bound check should stop flow for a flow state with bit
301+ * size `bitSize` and architecture bit size `architectureBitSize`.
302+ *
303+ * A flow state has bit size `bitSize` if that is the smallest valid bit size
304+ * `b` such that the maximum value that could get to that point is less than
305+ * or equal to `2^(b) - 1`. So the flow should be stopped if there is a valid
306+ * bit size `b` which is less than `bitSize` such that the maximum value that
307+ * could get to that point is than or equal to `2^(b) - 1`. In this case,
308+ * the upper bound check is a barrier guard, because the flow should have bit
309+ * size equal to the smallest such `b` instead of `bitSize`.
310+ *
311+ * The argument `architectureBitSize` is only used if the constant operand is
312+ * `math.MaxInt` or `math.MaxUint`.
303313 *
304314 * Note that we have to use floats here because integers in CodeQL are
305315 * represented by 32-bit signed integers, which cannot represent some of the
@@ -309,10 +319,12 @@ class UpperBoundCheckGuard extends DataFlow::RelationalComparisonNode {
309319 bitSize = validBitSize ( ) and
310320 architectureBitSize = [ 32 , 64 ] and
311321 exists ( int b , float strictnessOffset |
322+ // It is sufficient to check for the next valid bit size below `bitSize`.
312323 b = max ( int a | a = validBitSize ( ) and a < bitSize ) and
313- // For `x < c` the bound is `c-1`. For `x >= c` we will be an upper bound
314- // on the `branch` argument of `checks` is false, which is equivalent to
315- // `x < c`.
324+ // We will use the format `x <= c - strictnessOffset`. Since `x < c` is
325+ // the same as `x <= c-1`, we set `strictnessOffset` to 1 in this case.
326+ // For `x >= c` we will be dealing with the case where the `branch`
327+ // argument of `checks` is false, which is equivalent to `x < c`.
316328 if expr instanceof LssExpr or expr instanceof GeqExpr
317329 then strictnessOffset = 1
318330 else strictnessOffset = 0
@@ -321,7 +333,10 @@ class UpperBoundCheckGuard extends DataFlow::RelationalComparisonNode {
321333 then
322334 any ( MaxIntOrMaxUint m | expr .getAnOperand ( ) = m .getAReference ( ) )
323335 .isBoundFor ( b , architectureBitSize , strictnessOffset )
324- else expr .getAnOperand ( ) .getExactValue ( ) .toFloat ( ) - strictnessOffset <= 2 .pow ( b ) - 1
336+ else
337+ // We want `x <= c - strictnessOffset` to guarantee that `x <= 2^b - 1`,
338+ // which is equivalent to saying `c - strictnessOffset <= 2^b - 1`.
339+ expr .getAnOperand ( ) .getExactValue ( ) .toFloat ( ) - strictnessOffset <= 2 .pow ( b ) - 1
325340 )
326341 }
327342
0 commit comments