@@ -22,11 +22,13 @@ import semmle.code.cpp.dataflow.DataFlow
22
22
* Holds if `sub` is guarded by a condition which ensures that
23
23
* `left >= right`.
24
24
*/
25
- pragma [ noinline ]
25
+ pragma [ nomagic ]
26
26
predicate isGuarded ( SubExpr sub , Expr left , Expr right ) {
27
- exists ( GuardCondition guard , int k |
28
- guard .controls ( sub .getBasicBlock ( ) , _) and
29
- guard .ensuresLt ( left , right , k , sub .getBasicBlock ( ) , false ) and
27
+ exprIsSubLeftOrLess ( pragma [ only_bind_into ] ( sub ) , _) and // Manual magic
28
+ exists ( GuardCondition guard , int k , BasicBlock bb |
29
+ pragma [ only_bind_into ] ( bb ) = sub .getBasicBlock ( ) and
30
+ guard .controls ( pragma [ only_bind_into ] ( bb ) , _) and
31
+ guard .ensuresLt ( left , right , k , bb , false ) and
30
32
k >= 0
31
33
)
32
34
}
@@ -36,47 +38,56 @@ predicate isGuarded(SubExpr sub, Expr left, Expr right) {
36
38
* `sub.getLeftOperand()`.
37
39
*/
38
40
predicate exprIsSubLeftOrLess ( SubExpr sub , DataFlow:: Node n ) {
39
- n .asExpr ( ) = sub .getLeftOperand ( )
40
- or
41
- exists ( DataFlow:: Node other |
42
- // dataflow
43
- exprIsSubLeftOrLess ( sub , other ) and
44
- (
45
- DataFlow:: localFlowStep ( n , other ) or
46
- DataFlow:: localFlowStep ( other , n )
41
+ interestingSubExpr ( sub , _) and // Manual magic
42
+ (
43
+ n .asExpr ( ) = sub .getLeftOperand ( )
44
+ or
45
+ exists ( DataFlow:: Node other |
46
+ // dataflow
47
+ exprIsSubLeftOrLess ( sub , other ) and
48
+ (
49
+ DataFlow:: localFlowStep ( n , other ) or
50
+ DataFlow:: localFlowStep ( other , n )
51
+ )
52
+ )
53
+ or
54
+ exists ( DataFlow:: Node other |
55
+ // guard constraining `sub`
56
+ exprIsSubLeftOrLess ( sub , other ) and
57
+ isGuarded ( sub , other .asExpr ( ) , n .asExpr ( ) ) // other >= n
58
+ )
59
+ or
60
+ exists ( DataFlow:: Node other , float p , float q |
61
+ // linear access of `other`
62
+ exprIsSubLeftOrLess ( sub , other ) and
63
+ linearAccess ( n .asExpr ( ) , other .asExpr ( ) , p , q ) and // n = p * other + q
64
+ p <= 1 and
65
+ q <= 0
66
+ )
67
+ or
68
+ exists ( DataFlow:: Node other , float p , float q |
69
+ // linear access of `n`
70
+ exprIsSubLeftOrLess ( sub , other ) and
71
+ linearAccess ( other .asExpr ( ) , n .asExpr ( ) , p , q ) and // other = p * n + q
72
+ p >= 1 and
73
+ q >= 0
47
74
)
48
- )
49
- or
50
- exists ( DataFlow:: Node other |
51
- // guard constraining `sub`
52
- exprIsSubLeftOrLess ( sub , other ) and
53
- isGuarded ( sub , other .asExpr ( ) , n .asExpr ( ) ) // other >= n
54
- )
55
- or
56
- exists ( DataFlow:: Node other , float p , float q |
57
- // linear access of `other`
58
- exprIsSubLeftOrLess ( sub , other ) and
59
- linearAccess ( n .asExpr ( ) , other .asExpr ( ) , p , q ) and // n = p * other + q
60
- p <= 1 and
61
- q <= 0
62
- )
63
- or
64
- exists ( DataFlow:: Node other , float p , float q |
65
- // linear access of `n`
66
- exprIsSubLeftOrLess ( sub , other ) and
67
- linearAccess ( other .asExpr ( ) , n .asExpr ( ) , p , q ) and // other = p * n + q
68
- p >= 1 and
69
- q >= 0
70
75
)
71
76
}
72
77
73
- from RelationalOperation ro , SubExpr sub
74
- where
75
- not isFromMacroDefinition ( ro ) and
78
+ predicate interestingSubExpr ( SubExpr sub , RelationalOperation ro ) {
76
79
not isFromMacroDefinition ( sub ) and
77
80
ro .getLesserOperand ( ) .getValue ( ) .toInt ( ) = 0 and
78
81
ro .getGreaterOperand ( ) = sub and
79
82
sub .getFullyConverted ( ) .getUnspecifiedType ( ) .( IntegralType ) .isUnsigned ( ) and
80
- exprMightOverflowNegatively ( sub .getFullyConverted ( ) ) and // generally catches false positives involving constants
81
- not exprIsSubLeftOrLess ( sub , DataFlow:: exprNode ( sub .getRightOperand ( ) ) ) // generally catches false positives where there's a relation between the left and right operands
83
+ // generally catches false positives involving constants
84
+ exprMightOverflowNegatively ( sub .getFullyConverted ( ) )
85
+ }
86
+
87
+ from RelationalOperation ro , SubExpr sub
88
+ where
89
+ interestingSubExpr ( sub , ro ) and
90
+ not isFromMacroDefinition ( ro ) and
91
+ // generally catches false positives where there's a relation between the left and right operands
92
+ not exprIsSubLeftOrLess ( sub , DataFlow:: exprNode ( sub .getRightOperand ( ) ) )
82
93
select ro , "Unsigned subtraction can never be negative."
0 commit comments