@@ -11,7 +11,7 @@ private import SsaReadPositionCommon
1111private import Sign
1212
1313/** Gets the sign of `e` if this can be directly determined. */
14- Sign certainExprSign ( Expr e ) {
14+ private Sign certainExprSign ( Expr e ) {
1515 exists ( int i | e .( ConstantIntegerExpr ) .getIntValue ( ) = i |
1616 i < 0 and result = TNeg ( )
1717 or
@@ -42,7 +42,7 @@ Sign certainExprSign(Expr e) {
4242}
4343
4444/** Holds if the sign of `e` is too complicated to determine. */
45- predicate unknownSign ( Expr e ) {
45+ private predicate unknownSign ( Expr e ) {
4646 not exists ( certainExprSign ( e ) ) and
4747 (
4848 exists ( IntegerLiteral lit | lit = e and not exists ( lit .getValue ( ) .toInt ( ) ) )
@@ -55,7 +55,7 @@ predicate unknownSign(Expr e) {
5555 not fromtyp instanceof NumericOrCharType
5656 )
5757 or
58- unknownIntegerAccess ( e )
58+ numericExprWithUnknownSign ( e )
5959 )
6060}
6161
@@ -185,29 +185,32 @@ private predicate hasGuard(SsaVariable v, SsaReadPosition pos, Sign s) {
185185 s = TZero ( ) and zeroBound ( _, v , pos )
186186}
187187
188+ /**
189+ * Gets a possible sign of `v` at `pos` based on its definition, where the sign
190+ * might be ruled out by a guard.
191+ */
188192pragma [ noinline]
189193private Sign guardedSsaSign ( SsaVariable v , SsaReadPosition pos ) {
190- // SSA variable can have sign `result`
191194 result = ssaDefSign ( v ) and
192195 pos .hasReadOfVar ( v ) and
193- // there are guards at this position on `v` that might restrict it to be sign `result`.
194- // (So we need to check if they are satisfied)
195196 hasGuard ( v , pos , result )
196197}
197198
199+ /**
200+ * Gets a possible sign of `v` at `pos` based on its definition, where no guard
201+ * can rule it out.
202+ */
198203pragma [ noinline]
199204private Sign unguardedSsaSign ( SsaVariable v , SsaReadPosition pos ) {
200- // SSA variable can have sign `result`
201205 result = ssaDefSign ( v ) and
202206 pos .hasReadOfVar ( v ) and
203- // there's no guard at this position on `v` that might restrict it to be sign `result`.
204207 not hasGuard ( v , pos , result )
205208}
206209
207210/**
208- * Gets the sign of `v` at read position `pos`, when there's at least one guard
209- * on `v` at position `pos`. Each bound corresponding to a given sign must be met
210- * in order for `v` to be of that sign.
211+ * Gets a possible sign of `v` at read position `pos`, where a guard could have
212+ * ruled out the sign but does not.
213+ * This does not check that the definition of `v` also allows the sign.
211214 */
212215private Sign guardedSsaSignOk ( SsaVariable v , SsaReadPosition pos ) {
213216 result = TPos ( ) and
@@ -221,7 +224,7 @@ private Sign guardedSsaSignOk(SsaVariable v, SsaReadPosition pos) {
221224}
222225
223226/** Gets a possible sign for `v` at `pos`. */
224- Sign ssaSign ( SsaVariable v , SsaReadPosition pos ) {
227+ private Sign ssaSign ( SsaVariable v , SsaReadPosition pos ) {
225228 result = unguardedSsaSign ( v , pos )
226229 or
227230 result = guardedSsaSign ( v , pos ) and
@@ -230,7 +233,7 @@ Sign ssaSign(SsaVariable v, SsaReadPosition pos) {
230233
231234/** Gets a possible sign for `v`. */
232235pragma [ nomagic]
233- Sign ssaDefSign ( SsaVariable v ) {
236+ private Sign ssaDefSign ( SsaVariable v ) {
234237 result = explicitSsaDefSign ( v )
235238 or
236239 result = implicitSsaDefSign ( v )
@@ -242,6 +245,40 @@ Sign ssaDefSign(SsaVariable v) {
242245 )
243246}
244247
248+ /** Returns the sign of explicit SSA definition `v`. */
249+ private Sign explicitSsaDefSign ( SsaVariable v ) {
250+ exists ( VariableUpdate def | def = getExplicitSsaAssignment ( v ) |
251+ result = exprSign ( getExprFromSsaAssignment ( def ) )
252+ or
253+ anySign ( result ) and explicitSsaDefWithAnySign ( def )
254+ or
255+ result = exprSign ( getIncrementOperand ( def ) ) .inc ( )
256+ or
257+ result = exprSign ( getDecrementOperand ( def ) ) .dec ( )
258+ )
259+ }
260+
261+ /** Returns the sign of implicit SSA definition `v`. */
262+ private Sign implicitSsaDefSign ( SsaVariable v ) {
263+ result = fieldSign ( getImplicitSsaDeclaration ( v ) )
264+ or
265+ anySign ( result ) and nonFieldImplicitSsaDefinition ( v )
266+ }
267+
268+ /** Gets a possible sign for `f`. */
269+ private Sign fieldSign ( Field f ) {
270+ if not fieldWithUnknownSign ( f )
271+ then
272+ result = exprSign ( getAssignedValueToField ( f ) )
273+ or
274+ fieldIncrementOperationOperand ( f ) and result = fieldSign ( f ) .inc ( )
275+ or
276+ fieldDecrementOperationOperand ( f ) and result = fieldSign ( f ) .dec ( )
277+ or
278+ result = specificFieldSign ( f )
279+ else anySign ( result )
280+ }
281+
245282/** Gets a possible sign for `e`. */
246283cached
247284Sign exprSign ( Expr e ) {
@@ -250,18 +287,23 @@ Sign exprSign(Expr e) {
250287 or
251288 not exists ( certainExprSign ( e ) ) and
252289 (
253- unknownSign ( e )
290+ anySign ( s ) and unknownSign ( e )
254291 or
255- exists ( SsaVariable v | getARead ( v ) = e | s = ssaVariableSign ( v , e ) )
292+ exists ( SsaVariable v | getARead ( v ) = e |
293+ s = ssaSign ( v , any ( SsaReadPositionBlock bb | getAnExpression ( bb ) = e ) )
294+ or
295+ not exists ( SsaReadPositionBlock bb | getAnExpression ( bb ) = e ) and
296+ s = ssaDefSign ( v )
297+ )
256298 or
257- e =
258- any ( VarAccess access |
259- not exists ( SsaVariable v | getARead ( v ) = access ) and
260- (
261- s = fieldSign ( getField ( access .( FieldAccess ) ) ) or
262- not access instanceof FieldAccess
263- )
299+ exists ( VarAccess access | access = e |
300+ not exists ( SsaVariable v | getARead ( v ) = access ) and
301+ (
302+ s = fieldSign ( getField ( access .( FieldAccess ) ) )
303+ or
304+ anySign ( s ) and not access instanceof FieldAccess
264305 )
306+ )
265307 or
266308 s = specificSubExprSign ( e )
267309 )
@@ -272,6 +314,41 @@ Sign exprSign(Expr e) {
272314 )
273315}
274316
317+ /** Gets a possible sign for `e` from the signs of its child nodes. */
318+ private Sign specificSubExprSign ( Expr e ) {
319+ result = exprSign ( getASubExprWithSameSign ( e ) )
320+ or
321+ exists ( DivExpr div | div = e |
322+ result = exprSign ( div .getLeftOperand ( ) ) and
323+ result != TZero ( ) and
324+ div .getRightOperand ( ) .( RealLiteral ) .getValue ( ) .toFloat ( ) = 0
325+ )
326+ or
327+ exists ( UnaryOperation unary | unary = e |
328+ result = exprSign ( unary .getOperand ( ) ) .applyUnaryOp ( unary .getOp ( ) )
329+ )
330+ or
331+ exists ( Sign s1 , Sign s2 | binaryOpSigns ( e , s1 , s2 ) |
332+ result = s1 .applyBinaryOp ( s2 , e .( BinaryOperation ) .getOp ( ) )
333+ )
334+ }
335+
336+ pragma [ noinline]
337+ private predicate binaryOpSigns ( Expr e , Sign lhs , Sign rhs ) {
338+ lhs = binaryOpLhsSign ( e ) and
339+ rhs = binaryOpRhsSign ( e )
340+ }
341+
342+ private Sign binaryOpLhsSign ( BinaryOperation e ) { result = exprSign ( e .getLeftOperand ( ) ) }
343+
344+ private Sign binaryOpRhsSign ( BinaryOperation e ) { result = exprSign ( e .getRightOperand ( ) ) }
345+
346+ /**
347+ * Dummy predicate that holds for any sign. This is added to improve readability
348+ * of cases where the sign is unrestricted.
349+ */
350+ predicate anySign ( Sign s ) { any ( ) }
351+
275352/** Holds if `e` can be positive and cannot be negative. */
276353predicate positive ( Expr e ) {
277354 exprSign ( e ) = TPos ( ) and
0 commit comments