11import semmle.code.java.arithmetic.Overflow
2- import semmle.code.java.controlflow.Dominance
3- import semmle.code.java.dataflow.DefUse
42import 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
59
610/**
711 * Holds if the type of `exp` is narrower than or equal to `numType`,
@@ -15,102 +19,138 @@ predicate narrowerThanOrEqualTo(ArithExpr exp, NumType numType) {
1519 )
1620}
1721
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 )
2375 )
2476}
2577
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 ) )
3581}
3682
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+ )
43100 )
44- or
45- guardedAbs ( e , use )
46101}
47102
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 )
54111 )
112+ or
113+ negative ( e )
114+ or
115+ e .( MethodAccess ) .getMethod ( ) instanceof MethodMathMin
55116}
56117
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 )
85126 )
127+ or
128+ positive ( e )
129+ or
130+ e .( MethodAccess ) .getMethod ( ) instanceof MethodMathMax
86131}
87132
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 ( ) )
96144 or
97- e instanceof PostIncExpr
145+ exists ( CastExpr c | c . getExpr ( ) = e and t2 = c . getType ( ) )
98146 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 ( ) )
102148 or
103- e instanceof PreDecExpr and guardedGreater ( e , priorAccess ( use ) )
149+ exists ( Parameter p | p . getAnArgument ( ) = e and t2 = p . getType ( ) )
104150 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+ )
114154 )
115155}
116156
@@ -124,7 +164,77 @@ private predicate inBitwiseAnd(Expr exp) {
124164}
125165
126166/** Holds if overflow/underflow is irrelevant for this expression. */
127- predicate overflowIrrelevant ( ArithExpr exp ) {
167+ predicate overflowIrrelevant ( Expr exp ) {
128168 inBitwiseAnd ( exp ) or
129169 exp .getEnclosingCallable ( ) instanceof HashCodeMethod
130170}
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