1
1
import semmle.code.java.arithmetic.Overflow
2
- import semmle.code.java.controlflow.Dominance
3
- import semmle.code.java.dataflow.DefUse
4
2
import semmle.code.java.controlflow.Guards
3
+ private import semmle.code.java.dataflow.SSA
4
+ private import semmle.code.java.dataflow.DataFlow
5
+ private import semmle.code.java.dataflow.RangeAnalysis
6
+ private import semmle.code.java.dataflow.RangeUtils
7
+ private import semmle.code.java.dataflow.SignAnalysis
8
+ private import semmle.code.java.controlflow.internal.GuardsLogic
5
9
6
10
/**
7
11
* Holds if the type of `exp` is narrower than or equal to `numType`,
@@ -15,102 +19,138 @@ predicate narrowerThanOrEqualTo(ArithExpr exp, NumType numType) {
15
19
)
16
20
}
17
21
18
- /** Holds if the size of this use is guarded using `Math.abs`. */
19
- predicate guardedAbs ( ArithExpr e , Expr use ) {
20
- exists ( MethodAccess m | m .getMethod ( ) instanceof MethodAbs |
21
- m .getArgument ( 0 ) = use and
22
- guardedLesser ( e , m )
22
+ private Guard sizeGuard ( SsaVariable v , boolean branch , boolean upper ) {
23
+ exists ( ComparisonExpr comp | comp = result |
24
+ comp .getLesserOperand ( ) = ssaRead ( v , 0 ) and
25
+ (
26
+ branch = true and upper = true
27
+ or
28
+ branch = false and upper = false
29
+ )
30
+ or
31
+ comp .getGreaterOperand ( ) = ssaRead ( v , 0 ) and
32
+ (
33
+ branch = true and upper = false
34
+ or
35
+ branch = false and upper = true
36
+ )
37
+ or
38
+ exists ( MethodAccess ma |
39
+ ma .getMethod ( ) instanceof MethodAbs and
40
+ ma .getArgument ( 0 ) = ssaRead ( v , 0 ) and
41
+ (
42
+ comp .getLesserOperand ( ) = ma and branch = true
43
+ or
44
+ comp .getGreaterOperand ( ) = ma and branch = false
45
+ ) and
46
+ ( upper = false or upper = true )
47
+ )
48
+ or
49
+ // overflow test
50
+ exists ( AddExpr add , RValue use , Expr pos |
51
+ use = ssaRead ( v , 0 ) and
52
+ add .hasOperands ( use , pos ) and
53
+ positive ( use ) and
54
+ positive ( pos ) and
55
+ upper = true
56
+ |
57
+ comp .getLesserOperand ( ) .getProperExpr ( ) = add and
58
+ comp .getGreaterOperand ( ) .( IntegerLiteral ) .getIntValue ( ) = 0 and
59
+ branch = false
60
+ or
61
+ comp .getGreaterOperand ( ) .getProperExpr ( ) = add and
62
+ comp .getLesserOperand ( ) .( IntegerLiteral ) .getIntValue ( ) = 0 and
63
+ branch = true
64
+ )
65
+ )
66
+ or
67
+ result .isEquality ( ssaRead ( v , 0 ) , _, branch ) and
68
+ ( upper = true or upper = false )
69
+ or
70
+ exists ( MethodAccess call , Method m , int ix |
71
+ call = result and
72
+ call .getArgument ( ix ) = ssaRead ( v , 0 ) and
73
+ call .getMethod ( ) .getSourceDeclaration ( ) = m and
74
+ m = customSizeGuard ( ix , branch , upper )
23
75
)
24
76
}
25
77
26
- /** Holds if the size of this use is guarded to be less than something. */
27
- predicate guardedLesser ( ArithExpr e , Expr use ) {
28
- exists ( ConditionBlock c , ComparisonExpr guard |
29
- use = guard .getLesserOperand ( ) and
30
- guard = c .getCondition ( ) and
31
- c .controls ( e .getBasicBlock ( ) , true )
32
- )
33
- or
34
- guardedAbs ( e , use )
78
+ private Guard derivedSizeGuard ( SsaVariable v , boolean branch , boolean upper ) {
79
+ result = sizeGuard ( v , branch , upper ) or
80
+ exists ( boolean branch0 | implies_v3 ( result , branch , derivedSizeGuard ( v , branch0 , upper ) , branch0 ) )
35
81
}
36
82
37
- /** Holds if the size of this use is guarded to be greater than something. */
38
- predicate guardedGreater ( ArithExpr e , Expr use ) {
39
- exists ( ConditionBlock c , ComparisonExpr guard |
40
- use = guard .getGreaterOperand ( ) and
41
- guard = c .getCondition ( ) and
42
- c .controls ( e .getBasicBlock ( ) , true )
83
+ private Method customSizeGuard ( int index , boolean retval , boolean upper ) {
84
+ exists ( Parameter p , SsaImplicitInit v |
85
+ result .getReturnType ( ) .( PrimitiveType ) .hasName ( "boolean" ) and
86
+ not result .isOverridable ( ) and
87
+ p .getCallable ( ) = result and
88
+ not p .isVarargs ( ) and
89
+ p .getType ( ) instanceof NumericOrCharType and
90
+ p .getPosition ( ) = index and
91
+ v .isParameterDefinition ( p ) and
92
+ forex ( ReturnStmt ret |
93
+ ret .getEnclosingCallable ( ) = result and
94
+ exists ( Expr res | res = ret .getResult ( ) |
95
+ not res .( BooleanLiteral ) .getBooleanValue ( ) = retval .booleanNot ( )
96
+ )
97
+ |
98
+ ret .getResult ( ) = derivedSizeGuard ( v , retval , upper )
99
+ )
43
100
)
44
- or
45
- guardedAbs ( e , use )
46
101
}
47
102
48
- /** Holds if this expression is (crudely) guarded by `use`. */
49
- predicate guarded ( ArithExpr e , Expr use ) {
50
- exists ( ConditionBlock c , ComparisonExpr guard |
51
- use = guard .getAnOperand ( ) and
52
- guard = c .getCondition ( ) and
53
- c .controls ( e .getBasicBlock ( ) , true )
103
+ /**
104
+ * Holds if `e` is bounded in a way that is likely to prevent overflow.
105
+ */
106
+ predicate guardedLessThanSomething ( Expr e ) {
107
+ exists ( SsaVariable v , Guard guard , boolean branch |
108
+ e = v .getAUse ( ) and
109
+ guard = sizeGuard ( v .getAPhiInputOrPriorDef * ( ) , branch , true ) and
110
+ guard .controls ( e .getBasicBlock ( ) , branch )
54
111
)
112
+ or
113
+ negative ( e )
114
+ or
115
+ e .( MethodAccess ) .getMethod ( ) instanceof MethodMathMin
55
116
}
56
117
57
- /** A prior use of the same variable that could see the same value. */
58
- VarAccess priorAccess ( VarAccess access ) { useUsePair ( result , access ) }
59
-
60
- /** Holds if `e` is guarded against overflow by `use`. */
61
- predicate guardedAgainstOverflow ( ArithExpr e , VarAccess use ) {
62
- use = e .getAnOperand ( ) and
63
- (
64
- // overflow possible if large
65
- e instanceof AddExpr and guardedLesser ( e , priorAccess ( use ) )
66
- or
67
- e instanceof PreIncExpr and guardedLesser ( e , priorAccess ( use ) )
68
- or
69
- e instanceof PostIncExpr and guardedLesser ( e , priorAccess ( use ) )
70
- or
71
- // overflow unlikely with subtraction
72
- e instanceof SubExpr
73
- or
74
- e instanceof PreDecExpr
75
- or
76
- e instanceof PostDecExpr
77
- or
78
- // overflow possible if large or small
79
- e instanceof MulExpr and
80
- guardedLesser ( e , priorAccess ( use ) ) and
81
- guardedGreater ( e , priorAccess ( use ) )
82
- or
83
- // overflow possible if MIN_VALUE
84
- e instanceof DivExpr and guardedGreater ( e , priorAccess ( use ) )
118
+ /**
119
+ * Holds if `e` is bounded in a way that is likely to prevent underflow.
120
+ */
121
+ predicate guardedGreaterThanSomething ( Expr e ) {
122
+ exists ( SsaVariable v , Guard guard , boolean branch |
123
+ e = v .getAUse ( ) and
124
+ guard = sizeGuard ( v .getAPhiInputOrPriorDef * ( ) , branch , false ) and
125
+ guard .controls ( e .getBasicBlock ( ) , branch )
85
126
)
127
+ or
128
+ positive ( e )
129
+ or
130
+ e .( MethodAccess ) .getMethod ( ) instanceof MethodMathMax
86
131
}
87
132
88
- /** Holds if `e` is guarded against underflow by `use`. */
89
- predicate guardedAgainstUnderflow ( ArithExpr e , VarAccess use ) {
90
- use = e .getAnOperand ( ) and
91
- (
92
- // underflow unlikely for addition
93
- e instanceof AddExpr
94
- or
95
- e instanceof PreIncExpr
133
+ /** Holds if `e` occurs in a context where it will be upcast to a wider type. */
134
+ predicate upcastToWiderType ( Expr e ) {
135
+ exists ( NumType t1 , NumType t2 |
136
+ t1 = e .getType ( ) and
137
+ (
138
+ t2 .widerThan ( t1 )
139
+ or
140
+ t1 instanceof CharacterType and t2 .getWidthRank ( ) >= 3
141
+ )
142
+ |
143
+ exists ( Variable v | v .getAnAssignedValue ( ) = e and t2 = v .getType ( ) )
96
144
or
97
- e instanceof PostIncExpr
145
+ exists ( CastExpr c | c . getExpr ( ) = e and t2 = c . getType ( ) )
98
146
or
99
- // underflow possible if use is left operand and small
100
- e instanceof SubExpr and
101
- ( use = e .getRightOperand ( ) or guardedGreater ( e , priorAccess ( use ) ) )
147
+ exists ( ReturnStmt ret | ret .getResult ( ) = e and t2 = ret .getEnclosingCallable ( ) .getReturnType ( ) )
102
148
or
103
- e instanceof PreDecExpr and guardedGreater ( e , priorAccess ( use ) )
149
+ exists ( Parameter p | p . getAnArgument ( ) = e and t2 = p . getType ( ) )
104
150
or
105
- e instanceof PostDecExpr and guardedGreater ( e , priorAccess ( use ) )
106
- or
107
- // underflow possible if large or small
108
- e instanceof MulExpr and
109
- guardedLesser ( e , priorAccess ( use ) ) and
110
- guardedGreater ( e , priorAccess ( use ) )
111
- or
112
- // underflow possible if MAX_VALUE
113
- e instanceof DivExpr and guardedLesser ( e , priorAccess ( use ) )
151
+ exists ( ConditionalExpr cond | cond .getTrueExpr ( ) = e or cond .getFalseExpr ( ) = e |
152
+ t2 = cond .getType ( )
153
+ )
114
154
)
115
155
}
116
156
@@ -124,7 +164,77 @@ private predicate inBitwiseAnd(Expr exp) {
124
164
}
125
165
126
166
/** Holds if overflow/underflow is irrelevant for this expression. */
127
- predicate overflowIrrelevant ( ArithExpr exp ) {
167
+ predicate overflowIrrelevant ( Expr exp ) {
128
168
inBitwiseAnd ( exp ) or
129
169
exp .getEnclosingCallable ( ) instanceof HashCodeMethod
130
170
}
171
+
172
+ /**
173
+ * Holds if `n` is unlikely to be part in a path from some source containing
174
+ * numeric data to some arithmetic expression that may overflow/underflow.
175
+ */
176
+ private predicate unlikelyNode ( DataFlow:: Node n ) {
177
+ n .getTypeBound ( ) instanceof TypeObject and
178
+ not exists ( CastExpr cast |
179
+ DataFlow:: localFlow ( n , DataFlow:: exprNode ( cast .getExpr ( ) ) ) and
180
+ cast .getType ( ) instanceof NumericOrCharType
181
+ )
182
+ }
183
+
184
+ /** Holds if `n` is likely guarded against overflow. */
185
+ predicate overflowBarrier ( DataFlow:: Node n ) {
186
+ n .getType ( ) instanceof BooleanType or
187
+ guardedLessThanSomething ( n .asExpr ( ) ) or
188
+ unlikelyNode ( n ) or
189
+ upcastToWiderType ( n .asExpr ( ) ) or
190
+ overflowIrrelevant ( n .asExpr ( ) )
191
+ }
192
+
193
+ /** Holds if `n` is likely guarded against underflow. */
194
+ predicate underflowBarrier ( DataFlow:: Node n ) {
195
+ n .getType ( ) instanceof BooleanType or
196
+ guardedGreaterThanSomething ( n .asExpr ( ) ) or
197
+ unlikelyNode ( n ) or
198
+ upcastToWiderType ( n .asExpr ( ) ) or
199
+ overflowIrrelevant ( n .asExpr ( ) )
200
+ }
201
+
202
+ /**
203
+ * Holds if `use` is an operand of `exp` that acts as a sink for
204
+ * overflow-related dataflow.
205
+ */
206
+ predicate overflowSink ( ArithExpr exp , VarAccess use ) {
207
+ exp .getAnOperand ( ) = use and
208
+ (
209
+ // overflow unlikely for subtraction and division
210
+ exp instanceof AddExpr or
211
+ exp instanceof PreIncExpr or
212
+ exp instanceof PostIncExpr or
213
+ exp instanceof MulExpr
214
+ ) and
215
+ not guardedLessThanSomething ( use ) and
216
+ // Exclude widening conversions of tainted values due to binary numeric promotion (JLS 5.6.2)
217
+ // unless there is an enclosing cast down to a narrower type.
218
+ narrowerThanOrEqualTo ( exp , use .getType ( ) ) and
219
+ not overflowIrrelevant ( exp )
220
+ }
221
+
222
+ /**
223
+ * Holds if `use` is an operand of `exp` that acts as a sink for
224
+ * underflow-related dataflow.
225
+ */
226
+ predicate underflowSink ( ArithExpr exp , VarAccess use ) {
227
+ exp .getAnOperand ( ) = use and
228
+ (
229
+ // underflow unlikely for addition and division
230
+ exp .( SubExpr ) .getLeftOperand ( ) = use or
231
+ exp instanceof PreDecExpr or
232
+ exp instanceof PostDecExpr or
233
+ exp instanceof MulExpr
234
+ ) and
235
+ not guardedGreaterThanSomething ( use ) and
236
+ // Exclude widening conversions of tainted values due to binary numeric promotion (JLS 5.6.2)
237
+ // unless there is an enclosing cast down to a narrower type.
238
+ narrowerThanOrEqualTo ( exp , use .getType ( ) ) and
239
+ not overflowIrrelevant ( exp )
240
+ }
0 commit comments