1
1
import go
2
2
3
- /**
4
- * Gets the maximum value of an integer (signed if `isSigned`
5
- * is true, unsigned otherwise) with `bitSize` bits.
6
- */
7
- float getMaxIntValue ( int bitSize , boolean isSigned ) {
8
- bitSize in [ 8 , 16 , 32 , 64 ] and
9
- (
10
- isSigned = true and result = 2 .pow ( bitSize - 1 ) - 1
11
- or
12
- isSigned = false and result = 2 .pow ( bitSize ) - 1
13
- )
3
+ /** The constant `math.MaxInt` or the constant `math.MaxUint`. */
4
+ abstract private class MaxIntOrMaxUint extends DeclaredConstant {
5
+ /**
6
+ * Gets the integer `x` such that `2.pow(x) - 1` is the value of this
7
+ * constant when the architecture has bit size `architectureBitSize`.
8
+ */
9
+ abstract int getX ( int architectureBitSize ) ;
10
+
11
+ /**
12
+ * Holds if the value of this constant given `architectureBitSize` minus
13
+ * `strictnessOffset` is less than or equal to `2.pow(b) - 1`.
14
+ */
15
+ predicate isBoundFor ( int b , int architectureBitSize , float strictnessOffset ) {
16
+ // 2.pow(x) - 1 - strictnessOffset <= 2.pow(b) - 1
17
+ exists ( int x |
18
+ x = this .getX ( architectureBitSize ) and
19
+ b = validBitSize ( ) and
20
+ (
21
+ strictnessOffset = 0 and x <= b
22
+ or
23
+ strictnessOffset = 1 and x <= b - 1
24
+ )
25
+ )
26
+ }
27
+ }
28
+
29
+ /** The constant `math.MaxInt`. */
30
+ private class MaxInt extends MaxIntOrMaxUint {
31
+ MaxInt ( ) { this .hasQualifiedName ( "math" , "MaxInt" ) }
32
+
33
+ override int getX ( int architectureBitSize ) {
34
+ architectureBitSize = [ 32 , 64 ] and result = architectureBitSize - 1
35
+ }
36
+ }
37
+
38
+ /** The constant `math.MaxUint`. */
39
+ private class MaxUint extends MaxIntOrMaxUint {
40
+ MaxUint ( ) { this .hasQualifiedName ( "math" , "MaxUint" ) }
41
+
42
+ override int getX ( int architectureBitSize ) {
43
+ architectureBitSize = [ 32 , 64 ] and result = architectureBitSize
44
+ }
14
45
}
15
46
16
47
/**
@@ -276,7 +307,7 @@ class UpperBoundCheckGuard extends DataFlow::RelationalComparisonNode {
276
307
predicate isBoundFor ( int bitSize , int architectureBitSize ) {
277
308
bitSize = validBitSize ( ) and
278
309
architectureBitSize = [ 32 , 64 ] and
279
- exists ( float bound , int b , float strictnessOffset |
310
+ exists ( int b , float strictnessOffset |
280
311
b = max ( int a | a = validBitSize ( ) and a < bitSize ) and
281
312
// For `x < c` the bound is `c-1`. For `x >= c` we will be an upper bound
282
313
// on the `branch` argument of `checks` is false, which is equivalent to
@@ -285,17 +316,11 @@ class UpperBoundCheckGuard extends DataFlow::RelationalComparisonNode {
285
316
then strictnessOffset = 1
286
317
else strictnessOffset = 0
287
318
|
288
- exists ( DeclaredConstant maxint , DeclaredConstant maxuint |
289
- maxint .hasQualifiedName ( "math" , "MaxInt" ) and maxuint .hasQualifiedName ( "math" , "MaxUint" )
290
- |
291
- if expr .getAnOperand ( ) = maxint .getAReference ( )
292
- then bound = getMaxIntValue ( architectureBitSize , true )
293
- else
294
- if expr .getAnOperand ( ) = maxuint .getAReference ( )
295
- then bound = getMaxIntValue ( architectureBitSize , false )
296
- else bound = expr .getAnOperand ( ) .getExactValue ( ) .toFloat ( )
297
- ) and
298
- bound - strictnessOffset <= 2 .pow ( b ) - 1
319
+ if expr .getAnOperand ( ) = any ( MaxIntOrMaxUint m ) .getAReference ( )
320
+ then
321
+ any ( MaxIntOrMaxUint m | expr .getAnOperand ( ) = m .getAReference ( ) )
322
+ .isBoundFor ( b , architectureBitSize , strictnessOffset )
323
+ else expr .getAnOperand ( ) .getExactValue ( ) .toFloat ( ) - strictnessOffset <= 2 .pow ( b ) - 1
299
324
)
300
325
}
301
326
0 commit comments