@@ -17,6 +17,7 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1717import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
1818import semmle.code.cpp.controlflow.Guards
1919import semmle.code.cpp.ir.dataflow.DataFlow
20+ import semmle.code.cpp.valuenumbering.GlobalValueNumbering
2021
2122/**
2223 * Holds if `sub` is guarded by a condition which ensures that
@@ -34,45 +35,108 @@ predicate isGuarded(SubExpr sub, Expr left, Expr right) {
3435}
3536
3637/**
37- * Holds if `n` is known or suspected to be less than or equal to
38- * `sub.getLeftOperand() `.
38+ * Gets an expression that is less than or equal to `sub.getLeftOperand()`.
39+ * These serve as the base cases for `exprIsSubLeftOrLess `.
3940 */
40- predicate exprIsSubLeftOrLess ( SubExpr sub , DataFlow :: Node n ) {
41+ Expr exprIsLeftOrLessBase ( SubExpr sub ) {
4142 interestingSubExpr ( sub , _) and // Manual magic
42- (
43- n .asExpr ( ) = sub .getLeftOperand ( )
43+ exists ( Expr e | globalValueNumber ( e ) .getAnExpr ( ) = sub .getLeftOperand ( ) |
44+ // sub = e - x
45+ // result = e
46+ // so:
47+ // result <= e
48+ result = e
49+ or
50+ // sub = e - x
51+ // result = e & y
52+ // so:
53+ // result = e & y <= e
54+ result .( BitwiseAndExpr ) .getAnOperand ( ) = e
4455 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- )
56+ exists ( SubExpr s |
57+ // sub = e - x
58+ // result = s
59+ // s = e - y
60+ // y >= 0
61+ // so:
62+ // result = e - y <= e
63+ result = s and
64+ s .getLeftOperand ( ) = e and
65+ lowerBound ( s .getRightOperand ( ) .getFullyConverted ( ) ) >= 0
5266 )
5367 or
54- exists ( DataFlow:: Node other |
55- // guard constraining `sub`
56- exprIsSubLeftOrLess ( sub , other ) and
57- isGuarded ( sub , other .asExpr ( ) , n .asExpr ( ) ) // other >= n
68+ exists ( Expr other |
69+ // sub = e - x
70+ // result = a
71+ // a = e + y
72+ // y <= 0
73+ // so:
74+ // result = e + y <= e + 0 = e
75+ result .( AddExpr ) .hasOperands ( e , other ) and
76+ upperBound ( other .getFullyConverted ( ) ) <= 0
5877 )
5978 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
79+ exists ( DivExpr d |
80+ // sub = e - x
81+ // result = d
82+ // d = e / y
83+ // y >= 1
84+ // so:
85+ // result = e / y <= e / 1 = e
86+ result = d and
87+ d .getLeftOperand ( ) = e and
88+ lowerBound ( d .getRightOperand ( ) .getFullyConverted ( ) ) >= 1
6689 )
6790 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
91+ exists ( RShiftExpr rs |
92+ // sub = e - x
93+ // result = rs
94+ // rs = e >> y
95+ // so:
96+ // result = e >> y <= e
97+ result = rs and
98+ rs .getLeftOperand ( ) = e
99+ )
100+ )
101+ }
102+
103+ /**
104+ * Holds if `n` is known or suspected to be less than or equal to
105+ * `sub.getLeftOperand()`.
106+ */
107+ predicate exprIsSubLeftOrLess ( SubExpr sub , DataFlow:: Node n ) {
108+ n .asExpr ( ) = exprIsLeftOrLessBase ( sub )
109+ or
110+ exists ( DataFlow:: Node other |
111+ // dataflow
112+ exprIsSubLeftOrLess ( sub , other ) and
113+ (
114+ DataFlow:: localFlowStep ( n , other ) or
115+ DataFlow:: localFlowStep ( other , n )
74116 )
75117 )
118+ or
119+ exists ( DataFlow:: Node other |
120+ // guard constraining `sub`
121+ exprIsSubLeftOrLess ( sub , other ) and
122+ isGuarded ( sub , other .asExpr ( ) , n .asExpr ( ) ) // other >= n
123+ )
124+ or
125+ exists ( DataFlow:: Node other , float p , float q |
126+ // linear access of `other`
127+ exprIsSubLeftOrLess ( sub , other ) and
128+ linearAccess ( n .asExpr ( ) , other .asExpr ( ) , p , q ) and // n = p * other + q
129+ p <= 1 and
130+ q <= 0
131+ )
132+ or
133+ exists ( DataFlow:: Node other , float p , float q |
134+ // linear access of `n`
135+ exprIsSubLeftOrLess ( sub , other ) and
136+ linearAccess ( other .asExpr ( ) , n .asExpr ( ) , p , q ) and // other = p * n + q
137+ p >= 1 and
138+ q >= 0
139+ )
76140}
77141
78142predicate interestingSubExpr ( SubExpr sub , RelationalOperation ro ) {
0 commit comments