mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #4362 from tamasvajk/feature/sign-analysis-cleanup
Sign analysis cleanup
This commit is contained in:
@@ -3,6 +3,25 @@ newtype TSign =
|
||||
TZero() or
|
||||
TPos()
|
||||
|
||||
newtype TUnarySignOperation =
|
||||
TNegOp() or
|
||||
TIncOp() or
|
||||
TDecOp() or
|
||||
TBitNotOp()
|
||||
|
||||
newtype TBinarySignOperation =
|
||||
TAddOp() or
|
||||
TSubOp() or
|
||||
TMulOp() or
|
||||
TDivOp() or
|
||||
TRemOp() or
|
||||
TBitAndOp() or
|
||||
TBitOrOp() or
|
||||
TBitXorOp() or
|
||||
TLShiftOp() or
|
||||
TRShiftOp() or
|
||||
TURShiftOp()
|
||||
|
||||
/** Class representing expression signs (+, -, 0). */
|
||||
class Sign extends TSign {
|
||||
/** Gets the string representation of this sign. */
|
||||
@@ -67,6 +86,12 @@ class Sign extends TSign {
|
||||
this = TNeg() and s = TPos()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after subtracting an expression with sign `s` from an expression
|
||||
* that has this sign.
|
||||
*/
|
||||
Sign sub(Sign s) { result = add(s.neg()) }
|
||||
|
||||
/**
|
||||
* Gets a possible sign after multiplying an expression with sign `s` to an expression
|
||||
* that has this sign.
|
||||
@@ -216,4 +241,40 @@ class Sign extends TSign {
|
||||
or
|
||||
result != TNeg() and this = TPos() and s != TZero()
|
||||
}
|
||||
|
||||
/** Perform `op` on this sign. */
|
||||
Sign applyUnaryOp(TUnarySignOperation op) {
|
||||
op = TIncOp() and result = inc()
|
||||
or
|
||||
op = TDecOp() and result = dec()
|
||||
or
|
||||
op = TNegOp() and result = neg()
|
||||
or
|
||||
op = TBitNotOp() and result = bitnot()
|
||||
}
|
||||
|
||||
/** Perform `op` on this sign and sign `s`. */
|
||||
Sign applyBinaryOp(Sign s, TBinarySignOperation op) {
|
||||
op = TAddOp() and result = add(s)
|
||||
or
|
||||
op = TSubOp() and result = sub(s)
|
||||
or
|
||||
op = TMulOp() and result = mul(s)
|
||||
or
|
||||
op = TDivOp() and result = div(s)
|
||||
or
|
||||
op = TRemOp() and result = rem(s)
|
||||
or
|
||||
op = TBitAndOp() and result = bitand(s)
|
||||
or
|
||||
op = TBitOrOp() and result = bitor(s)
|
||||
or
|
||||
op = TBitXorOp() and result = bitxor(s)
|
||||
or
|
||||
op = TLShiftOp() and result = lshift(s)
|
||||
or
|
||||
op = TRShiftOp() and result = rshift(s)
|
||||
or
|
||||
op = TURShiftOp() and result = urshift(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ private import SsaReadPositionCommon
|
||||
private import Sign
|
||||
|
||||
/** Gets the sign of `e` if this can be directly determined. */
|
||||
Sign certainExprSign(Expr e) {
|
||||
private Sign certainExprSign(Expr e) {
|
||||
exists(int i | e.(ConstantIntegerExpr).getIntValue() = i |
|
||||
i < 0 and result = TNeg()
|
||||
or
|
||||
@@ -42,7 +42,7 @@ Sign certainExprSign(Expr e) {
|
||||
}
|
||||
|
||||
/** Holds if the sign of `e` is too complicated to determine. */
|
||||
predicate unknownSign(Expr e) {
|
||||
private predicate unknownSign(Expr e) {
|
||||
not exists(certainExprSign(e)) and
|
||||
(
|
||||
exists(IntegerLiteral lit | lit = e and not exists(lit.getValue().toInt()))
|
||||
@@ -55,7 +55,7 @@ predicate unknownSign(Expr e) {
|
||||
not fromtyp instanceof NumericOrCharType
|
||||
)
|
||||
or
|
||||
unknownIntegerAccess(e)
|
||||
numericExprWithUnknownSign(e)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,29 +185,32 @@ private predicate hasGuard(SsaVariable v, SsaReadPosition pos, Sign s) {
|
||||
s = TZero() and zeroBound(_, v, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SsaVariable v, SsaReadPosition pos) {
|
||||
// SSA variable can have sign `result`
|
||||
result = ssaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
// there are guards at this position on `v` that might restrict it to be sign `result`.
|
||||
// (So we need to check if they are satisfied)
|
||||
hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SsaVariable v, SsaReadPosition pos) {
|
||||
// SSA variable can have sign `result`
|
||||
result = ssaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
// there's no guard at this position on `v` that might restrict it to be sign `result`.
|
||||
not hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sign of `v` at read position `pos`, when there's at least one guard
|
||||
* on `v` at position `pos`. Each bound corresponding to a given sign must be met
|
||||
* in order for `v` to be of that sign.
|
||||
* Gets a possible sign of `v` at read position `pos`, where a guard could have
|
||||
* ruled out the sign but does not.
|
||||
* This does not check that the definition of `v` also allows the sign.
|
||||
*/
|
||||
private Sign guardedSsaSignOk(SsaVariable v, SsaReadPosition pos) {
|
||||
result = TPos() and
|
||||
@@ -221,7 +224,7 @@ private Sign guardedSsaSignOk(SsaVariable v, SsaReadPosition pos) {
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v` at `pos`. */
|
||||
Sign ssaSign(SsaVariable v, SsaReadPosition pos) {
|
||||
private Sign ssaSign(SsaVariable v, SsaReadPosition pos) {
|
||||
result = unguardedSsaSign(v, pos)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
@@ -230,7 +233,7 @@ Sign ssaSign(SsaVariable v, SsaReadPosition pos) {
|
||||
|
||||
/** Gets a possible sign for `v`. */
|
||||
pragma[nomagic]
|
||||
Sign ssaDefSign(SsaVariable v) {
|
||||
private Sign ssaDefSign(SsaVariable v) {
|
||||
result = explicitSsaDefSign(v)
|
||||
or
|
||||
result = implicitSsaDefSign(v)
|
||||
@@ -242,6 +245,40 @@ Sign ssaDefSign(SsaVariable v) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns the sign of explicit SSA definition `v`. */
|
||||
private Sign explicitSsaDefSign(SsaVariable v) {
|
||||
exists(VariableUpdate def | def = getExplicitSsaAssignment(v) |
|
||||
result = exprSign(getExprFromSsaAssignment(def))
|
||||
or
|
||||
anySign(result) and explicitSsaDefWithAnySign(def)
|
||||
or
|
||||
result = exprSign(getIncrementOperand(def)).inc()
|
||||
or
|
||||
result = exprSign(getDecrementOperand(def)).dec()
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns the sign of implicit SSA definition `v`. */
|
||||
private Sign implicitSsaDefSign(SsaVariable v) {
|
||||
result = fieldSign(getImplicitSsaDeclaration(v))
|
||||
or
|
||||
anySign(result) and nonFieldImplicitSsaDefinition(v)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `f`. */
|
||||
private Sign fieldSign(Field f) {
|
||||
if not fieldWithUnknownSign(f)
|
||||
then
|
||||
result = exprSign(getAssignedValueToField(f))
|
||||
or
|
||||
fieldIncrementOperationOperand(f) and result = fieldSign(f).inc()
|
||||
or
|
||||
fieldDecrementOperationOperand(f) and result = fieldSign(f).dec()
|
||||
or
|
||||
result = specificFieldSign(f)
|
||||
else anySign(result)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `e`. */
|
||||
cached
|
||||
Sign exprSign(Expr e) {
|
||||
@@ -250,18 +287,23 @@ Sign exprSign(Expr e) {
|
||||
or
|
||||
not exists(certainExprSign(e)) and
|
||||
(
|
||||
unknownSign(e)
|
||||
anySign(s) and unknownSign(e)
|
||||
or
|
||||
exists(SsaVariable v | getARead(v) = e | s = ssaVariableSign(v, e))
|
||||
exists(SsaVariable v | getARead(v) = e |
|
||||
s = ssaSign(v, any(SsaReadPositionBlock bb | getAnExpression(bb) = e))
|
||||
or
|
||||
not exists(SsaReadPositionBlock bb | getAnExpression(bb) = e) and
|
||||
s = ssaDefSign(v)
|
||||
)
|
||||
or
|
||||
e =
|
||||
any(VarAccess access |
|
||||
not exists(SsaVariable v | getARead(v) = access) and
|
||||
(
|
||||
s = fieldSign(getField(access.(FieldAccess))) or
|
||||
not access instanceof FieldAccess
|
||||
)
|
||||
exists(VarAccess access | access = e |
|
||||
not exists(SsaVariable v | getARead(v) = access) and
|
||||
(
|
||||
s = fieldSign(getField(access.(FieldAccess)))
|
||||
or
|
||||
anySign(s) and not access instanceof FieldAccess
|
||||
)
|
||||
)
|
||||
or
|
||||
s = specificSubExprSign(e)
|
||||
)
|
||||
@@ -272,6 +314,41 @@ Sign exprSign(Expr e) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `e` from the signs of its child nodes. */
|
||||
private Sign specificSubExprSign(Expr e) {
|
||||
result = exprSign(getASubExprWithSameSign(e))
|
||||
or
|
||||
exists(DivExpr div | div = e |
|
||||
result = exprSign(div.getLeftOperand()) and
|
||||
result != TZero() and
|
||||
div.getRightOperand().(RealLiteral).getValue().toFloat() = 0
|
||||
)
|
||||
or
|
||||
exists(UnaryOperation unary | unary = e |
|
||||
result = exprSign(unary.getOperand()).applyUnaryOp(unary.getOp())
|
||||
)
|
||||
or
|
||||
exists(Sign s1, Sign s2 | binaryOpSigns(e, s1, s2) |
|
||||
result = s1.applyBinaryOp(s2, e.(BinaryOperation).getOp())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) {
|
||||
lhs = binaryOpLhsSign(e) and
|
||||
rhs = binaryOpRhsSign(e)
|
||||
}
|
||||
|
||||
private Sign binaryOpLhsSign(BinaryOperation e) { result = exprSign(e.getLeftOperand()) }
|
||||
|
||||
private Sign binaryOpRhsSign(BinaryOperation e) { result = exprSign(e.getRightOperand()) }
|
||||
|
||||
/**
|
||||
* Dummy predicate that holds for any sign. This is added to improve readability
|
||||
* of cases where the sign is unrestricted.
|
||||
*/
|
||||
predicate anySign(Sign s) { any() }
|
||||
|
||||
/** Holds if `e` can be positive and cannot be negative. */
|
||||
predicate positive(Expr e) {
|
||||
exprSign(e) = TPos() and
|
||||
|
||||
@@ -6,6 +6,7 @@ module Private {
|
||||
private import semmle.code.java.dataflow.SSA as Ssa
|
||||
private import semmle.code.java.controlflow.Guards as G
|
||||
private import java as J
|
||||
private import Sign
|
||||
import Impl
|
||||
|
||||
class ConstantIntegerExpr = RU::ConstantIntegerExpr;
|
||||
@@ -36,6 +37,132 @@ module Private {
|
||||
|
||||
class NumericOrCharType = J::NumericOrCharType;
|
||||
|
||||
class VariableUpdate = J::VariableUpdate;
|
||||
|
||||
class Field = J::Field;
|
||||
|
||||
class DivExpr = J::DivExpr;
|
||||
|
||||
/** Class to represent float and double literals. */
|
||||
class RealLiteral extends J::Literal {
|
||||
RealLiteral() {
|
||||
this instanceof J::FloatingPointLiteral or
|
||||
this instanceof J::DoubleLiteral
|
||||
}
|
||||
}
|
||||
|
||||
/** Class to represent unary operation. */
|
||||
class UnaryOperation extends J::Expr {
|
||||
UnaryOperation() {
|
||||
this instanceof J::PreIncExpr or
|
||||
this instanceof J::PreDecExpr or
|
||||
this instanceof J::MinusExpr or
|
||||
this instanceof J::BitNotExpr
|
||||
}
|
||||
|
||||
/** Returns the operand of this expression. */
|
||||
Expr getOperand() {
|
||||
result = this.(J::PreIncExpr).getExpr() or
|
||||
result = this.(J::PreDecExpr).getExpr() or
|
||||
result = this.(J::MinusExpr).getExpr() or
|
||||
result = this.(J::BitNotExpr).getExpr()
|
||||
}
|
||||
|
||||
/** Returns the operation representing this expression. */
|
||||
TUnarySignOperation getOp() {
|
||||
this instanceof J::PreIncExpr and result = TIncOp()
|
||||
or
|
||||
this instanceof J::PreDecExpr and result = TDecOp()
|
||||
or
|
||||
this instanceof J::MinusExpr and result = TNegOp()
|
||||
or
|
||||
this instanceof J::BitNotExpr and result = TBitNotOp()
|
||||
}
|
||||
}
|
||||
|
||||
/** Class to represent binary operation. */
|
||||
class BinaryOperation extends J::Expr {
|
||||
BinaryOperation() {
|
||||
this instanceof J::AddExpr or
|
||||
this instanceof J::AssignAddExpr or
|
||||
this instanceof J::SubExpr or
|
||||
this instanceof J::AssignSubExpr or
|
||||
this instanceof J::MulExpr or
|
||||
this instanceof J::AssignMulExpr or
|
||||
this instanceof J::DivExpr or
|
||||
this instanceof J::AssignDivExpr or
|
||||
this instanceof J::RemExpr or
|
||||
this instanceof J::AssignRemExpr or
|
||||
this instanceof J::AndBitwiseExpr or
|
||||
this instanceof J::AssignAndExpr or
|
||||
this instanceof J::OrBitwiseExpr or
|
||||
this instanceof J::AssignOrExpr or
|
||||
this instanceof J::XorBitwiseExpr or
|
||||
this instanceof J::AssignXorExpr or
|
||||
this instanceof J::LShiftExpr or
|
||||
this instanceof J::AssignLShiftExpr or
|
||||
this instanceof J::RShiftExpr or
|
||||
this instanceof J::AssignRShiftExpr or
|
||||
this instanceof J::URShiftExpr or
|
||||
this instanceof J::AssignURShiftExpr
|
||||
}
|
||||
|
||||
/** Returns the operation representing this expression. */
|
||||
TBinarySignOperation getOp() {
|
||||
this instanceof J::AddExpr and result = TAddOp()
|
||||
or
|
||||
this instanceof J::AssignAddExpr and result = TAddOp()
|
||||
or
|
||||
this instanceof J::SubExpr and result = TSubOp()
|
||||
or
|
||||
this instanceof J::AssignSubExpr and result = TSubOp()
|
||||
or
|
||||
this instanceof J::MulExpr and result = TMulOp()
|
||||
or
|
||||
this instanceof J::AssignMulExpr and result = TMulOp()
|
||||
or
|
||||
this instanceof J::DivExpr and result = TDivOp()
|
||||
or
|
||||
this instanceof J::AssignDivExpr and result = TDivOp()
|
||||
or
|
||||
this instanceof J::RemExpr and result = TRemOp()
|
||||
or
|
||||
this instanceof J::AssignRemExpr and result = TRemOp()
|
||||
or
|
||||
this instanceof J::AndBitwiseExpr and result = TBitAndOp()
|
||||
or
|
||||
this instanceof J::AssignAndExpr and result = TBitAndOp()
|
||||
or
|
||||
this instanceof J::OrBitwiseExpr and result = TBitOrOp()
|
||||
or
|
||||
this instanceof J::AssignOrExpr and result = TBitOrOp()
|
||||
or
|
||||
this instanceof J::XorBitwiseExpr and result = TBitXorOp()
|
||||
or
|
||||
this instanceof J::AssignXorExpr and result = TBitXorOp()
|
||||
or
|
||||
this instanceof J::LShiftExpr and result = TLShiftOp()
|
||||
or
|
||||
this instanceof J::AssignLShiftExpr and result = TLShiftOp()
|
||||
or
|
||||
this instanceof J::RShiftExpr and result = TRShiftOp()
|
||||
or
|
||||
this instanceof J::AssignRShiftExpr and result = TRShiftOp()
|
||||
or
|
||||
this instanceof J::URShiftExpr and result = TURShiftOp()
|
||||
or
|
||||
this instanceof J::AssignURShiftExpr and result = TURShiftOp()
|
||||
}
|
||||
|
||||
Expr getLeftOperand() {
|
||||
result = this.(J::BinaryExpr).getLeftOperand() or result = this.(J::AssignOp).getDest()
|
||||
}
|
||||
|
||||
Expr getRightOperand() {
|
||||
result = this.(J::BinaryExpr).getRightOperand() or result = this.(J::AssignOp).getRhs()
|
||||
}
|
||||
}
|
||||
|
||||
predicate ssaRead = RU::ssaRead/2;
|
||||
|
||||
predicate guardControlsSsaRead = RU::guardControlsSsaRead/3;
|
||||
@@ -55,14 +182,20 @@ private module Impl {
|
||||
|
||||
class UnsignedNumericType = CharacterType;
|
||||
|
||||
/** Gets the character value of expression `e`. */
|
||||
string getCharValue(Expr e) { result = e.(CharacterLiteral).getValue() }
|
||||
|
||||
/** Gets the constant `float` value of non-`ConstantIntegerExpr` expressions. */
|
||||
float getNonIntegerValue(Expr e) {
|
||||
result = e.(LongLiteral).getValue().toFloat() or
|
||||
result = e.(FloatingPointLiteral).getValue().toFloat() or
|
||||
result = e.(DoubleLiteral).getValue().toFloat()
|
||||
}
|
||||
|
||||
string getCharValue(Expr e) { result = e.(CharacterLiteral).getValue() }
|
||||
|
||||
/**
|
||||
* Holds if `e` is an access to the size of a container (`string`, `Map`, or
|
||||
* `Collection`).
|
||||
*/
|
||||
predicate containerSizeAccess(Expr e) {
|
||||
e.(MethodAccess).getMethod() instanceof StringLengthMethod
|
||||
or
|
||||
@@ -71,9 +204,15 @@ private module Impl {
|
||||
e.(MethodAccess).getMethod() instanceof MapSizeMethod
|
||||
}
|
||||
|
||||
/** Holds if `e` is by definition strictly positive. */
|
||||
predicate positiveExpression(Expr e) { none() }
|
||||
|
||||
predicate unknownIntegerAccess(Expr e) {
|
||||
/**
|
||||
* Holds if `e` has type `NumericOrCharType`, but the sign of `e` is unknown.
|
||||
*/
|
||||
predicate numericExprWithUnknownSign(Expr e) {
|
||||
// The expression types handled in the predicate complements the expression
|
||||
// types handled in `specificSubExprSign`.
|
||||
e instanceof ArrayAccess and e.getType() instanceof NumericOrCharType
|
||||
or
|
||||
e instanceof MethodAccess and e.getType() instanceof NumericOrCharType
|
||||
@@ -81,56 +220,69 @@ private module Impl {
|
||||
e instanceof ClassInstanceExpr and e.getType() instanceof NumericOrCharType
|
||||
}
|
||||
|
||||
Sign explicitSsaDefSign(SsaVariable v) {
|
||||
exists(VariableUpdate def | def = v.(SsaExplicitUpdate).getDefiningExpr() |
|
||||
result = exprSign(def.(VariableAssign).getSource())
|
||||
or
|
||||
exists(EnhancedForStmt for | def = for.getVariable())
|
||||
or
|
||||
result = exprSign(def.(PostIncExpr).getExpr()).inc()
|
||||
or
|
||||
result = exprSign(def.(PreIncExpr).getExpr()).inc()
|
||||
or
|
||||
result = exprSign(def.(PostDecExpr).getExpr()).dec()
|
||||
or
|
||||
result = exprSign(def.(PreDecExpr).getExpr()).dec()
|
||||
or
|
||||
exists(AssignOp a | a = def and result = exprSign(a))
|
||||
)
|
||||
/** Returns the underlying variable update of the explicit SSA variable `v`. */
|
||||
VariableUpdate getExplicitSsaAssignment(SsaVariable v) {
|
||||
result = v.(SsaExplicitUpdate).getDefiningExpr()
|
||||
}
|
||||
|
||||
Sign implicitSsaDefSign(SsaVariable v) {
|
||||
result = fieldSign(v.(SsaImplicitUpdate).getSourceVariable().getVariable())
|
||||
/** Returns the assignment of the variable update `def`. */
|
||||
Expr getExprFromSsaAssignment(VariableUpdate def) {
|
||||
result = def.(VariableAssign).getSource()
|
||||
or
|
||||
result = fieldSign(v.(SsaImplicitInit).getSourceVariable().getVariable())
|
||||
or
|
||||
exists(Parameter p | v.(SsaImplicitInit).isParameterDefinition(p))
|
||||
exists(AssignOp a | a = def and result = a)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
Sign ssaVariableSign(SsaVariable v, Expr e) {
|
||||
result = ssaSign(v, any(SsaReadPositionBlock bb | getAnExpression(bb) = e))
|
||||
or
|
||||
not exists(SsaReadPositionBlock bb | getAnExpression(bb) = e) and
|
||||
result = ssaDefSign(v)
|
||||
/** Holds if `def` can have any sign. */
|
||||
predicate explicitSsaDefWithAnySign(VariableUpdate def) {
|
||||
exists(EnhancedForStmt for | def = for.getVariable())
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `f`. */
|
||||
Sign fieldSign(Field f) {
|
||||
result = exprSign(f.getAnAssignedValue())
|
||||
or
|
||||
exists(PostIncExpr inc | inc.getExpr() = f.getAnAccess() and result = fieldSign(f).inc())
|
||||
or
|
||||
exists(PreIncExpr inc | inc.getExpr() = f.getAnAccess() and result = fieldSign(f).inc())
|
||||
or
|
||||
exists(PostDecExpr inc | inc.getExpr() = f.getAnAccess() and result = fieldSign(f).dec())
|
||||
or
|
||||
exists(PreDecExpr inc | inc.getExpr() = f.getAnAccess() and result = fieldSign(f).dec())
|
||||
or
|
||||
exists(AssignOp a | a.getDest() = f.getAnAccess() | result = exprSign(a))
|
||||
or
|
||||
/** Returns the operand of the operation if `def` is a decrement. */
|
||||
Expr getDecrementOperand(Element e) {
|
||||
result = e.(PostDecExpr).getExpr() or result = e.(PreDecExpr).getExpr()
|
||||
}
|
||||
|
||||
/** Returns the operand of the operation if `def` is an increment. */
|
||||
Expr getIncrementOperand(Element e) {
|
||||
result = e.(PostIncExpr).getExpr() or result = e.(PreIncExpr).getExpr()
|
||||
}
|
||||
|
||||
/** Gets the variable underlying the implicit SSA variable `v`. */
|
||||
Variable getImplicitSsaDeclaration(SsaVariable v) {
|
||||
result = v.(SsaImplicitUpdate).getSourceVariable().getVariable() or
|
||||
result = v.(SsaImplicitInit).getSourceVariable().getVariable()
|
||||
}
|
||||
|
||||
/** Holds if the variable underlying the implicit SSA variable `v` is not a field. */
|
||||
predicate nonFieldImplicitSsaDefinition(SsaImplicitInit v) {
|
||||
exists(Parameter p | v.isParameterDefinition(p))
|
||||
}
|
||||
|
||||
/** Returned an expression that is assigned to `f`. */
|
||||
Expr getAssignedValueToField(Field f) {
|
||||
result = f.getAnAssignedValue() or
|
||||
result = any(AssignOp a | a.getDest() = f.getAnAccess())
|
||||
}
|
||||
|
||||
/** Holds if `f` can have any sign. */
|
||||
predicate fieldWithUnknownSign(Field f) {
|
||||
exists(ReflectiveFieldAccess rfa | rfa.inferAccessedField() = f)
|
||||
or
|
||||
}
|
||||
|
||||
/** Holds if `f` is accessed in an increment operation. */
|
||||
predicate fieldIncrementOperationOperand(Field f) {
|
||||
any(PostIncExpr inc).getExpr() = f.getAnAccess() or
|
||||
any(PreIncExpr inc).getExpr() = f.getAnAccess()
|
||||
}
|
||||
|
||||
/** Holds if `f` is accessed in a decrement operation. */
|
||||
predicate fieldDecrementOperationOperand(Field f) {
|
||||
any(PostDecExpr dec).getExpr() = f.getAnAccess() or
|
||||
any(PreDecExpr dec).getExpr() = f.getAnAccess()
|
||||
}
|
||||
|
||||
/** Returns possible signs of `f` based on the declaration. */
|
||||
Sign specificFieldSign(Field f) {
|
||||
if f.fromSource()
|
||||
then not exists(f.getInitializer()) and result = TZero()
|
||||
else
|
||||
@@ -142,89 +294,17 @@ private module Impl {
|
||||
else
|
||||
if f.hasName("MIN_VALUE")
|
||||
then result = TNeg()
|
||||
else any()
|
||||
else anySign(result)
|
||||
}
|
||||
|
||||
Sign specificSubExprSign(Expr e) {
|
||||
result = exprSign(e.(AssignExpr).getSource())
|
||||
or
|
||||
result = exprSign(e.(PlusExpr).getExpr())
|
||||
or
|
||||
result = exprSign(e.(PostIncExpr).getExpr())
|
||||
or
|
||||
result = exprSign(e.(PostDecExpr).getExpr())
|
||||
or
|
||||
result = exprSign(e.(PreIncExpr).getExpr()).inc()
|
||||
or
|
||||
result = exprSign(e.(PreDecExpr).getExpr()).dec()
|
||||
or
|
||||
result = exprSign(e.(MinusExpr).getExpr()).neg()
|
||||
or
|
||||
result = exprSign(e.(BitNotExpr).getExpr()).bitnot()
|
||||
or
|
||||
exists(DivExpr div |
|
||||
div = e and
|
||||
result = exprSign(div.getLeftOperand()) and
|
||||
result != TZero()
|
||||
|
|
||||
div.getRightOperand().(FloatingPointLiteral).getValue().toFloat() = 0 or
|
||||
div.getRightOperand().(DoubleLiteral).getValue().toFloat() = 0
|
||||
)
|
||||
or
|
||||
exists(Sign s1, Sign s2 | binaryOpSigns(e, s1, s2) |
|
||||
(e instanceof AssignAddExpr or e instanceof AddExpr) and
|
||||
result = s1.add(s2)
|
||||
or
|
||||
(e instanceof AssignSubExpr or e instanceof SubExpr) and
|
||||
result = s1.add(s2.neg())
|
||||
or
|
||||
(e instanceof AssignMulExpr or e instanceof MulExpr) and
|
||||
result = s1.mul(s2)
|
||||
or
|
||||
(e instanceof AssignDivExpr or e instanceof DivExpr) and
|
||||
result = s1.div(s2)
|
||||
or
|
||||
(e instanceof AssignRemExpr or e instanceof RemExpr) and
|
||||
result = s1.rem(s2)
|
||||
or
|
||||
(e instanceof AssignAndExpr or e instanceof AndBitwiseExpr) and
|
||||
result = s1.bitand(s2)
|
||||
or
|
||||
(e instanceof AssignOrExpr or e instanceof OrBitwiseExpr) and
|
||||
result = s1.bitor(s2)
|
||||
or
|
||||
(e instanceof AssignXorExpr or e instanceof XorBitwiseExpr) and
|
||||
result = s1.bitxor(s2)
|
||||
or
|
||||
(e instanceof AssignLShiftExpr or e instanceof LShiftExpr) and
|
||||
result = s1.lshift(s2)
|
||||
or
|
||||
(e instanceof AssignRShiftExpr or e instanceof RShiftExpr) and
|
||||
result = s1.rshift(s2)
|
||||
or
|
||||
(e instanceof AssignURShiftExpr or e instanceof URShiftExpr) and
|
||||
result = s1.urshift(s2)
|
||||
)
|
||||
or
|
||||
result = exprSign(e.(ChooseExpr).getAResultExpr())
|
||||
or
|
||||
result = exprSign(e.(CastExpr).getExpr())
|
||||
}
|
||||
|
||||
private Sign binaryOpLhsSign(Expr e) {
|
||||
result = exprSign(e.(BinaryExpr).getLeftOperand()) or
|
||||
result = exprSign(e.(AssignOp).getDest())
|
||||
}
|
||||
|
||||
private Sign binaryOpRhsSign(Expr e) {
|
||||
result = exprSign(e.(BinaryExpr).getRightOperand()) or
|
||||
result = exprSign(e.(AssignOp).getRhs())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) {
|
||||
lhs = binaryOpLhsSign(e) and
|
||||
rhs = binaryOpRhsSign(e)
|
||||
/** Returns a sub expression of `e` for expression types where the sign depends on the child. */
|
||||
Expr getASubExprWithSameSign(Expr e) {
|
||||
result = e.(AssignExpr).getSource() or
|
||||
result = e.(PlusExpr).getExpr() or
|
||||
result = e.(PostIncExpr).getExpr() or
|
||||
result = e.(PostDecExpr).getExpr() or
|
||||
result = e.(ChooseExpr).getAResultExpr() or
|
||||
result = e.(CastExpr).getExpr()
|
||||
}
|
||||
|
||||
Expr getARead(SsaVariable v) { result = v.getAUse() }
|
||||
|
||||
@@ -18,4 +18,5 @@ string getASignString(Expr e) {
|
||||
}
|
||||
|
||||
from Expr e
|
||||
where e.getEnclosingCallable().fromSource()
|
||||
select e, strictconcat(string s | s = getASignString(e) | s, " ")
|
||||
|
||||
Reference in New Issue
Block a user