Refactor specificSubExprSign

This commit is contained in:
Tamas Vajk
2020-09-29 16:52:49 +02:00
parent f03146d12f
commit f52cf264ec
6 changed files with 404 additions and 151 deletions

View File

@@ -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)
}
}

View File

@@ -326,6 +326,36 @@ Sign exprSign(Expr e) {
)
}
/** Gets a possible sign for `e` from the signs of its child nodes. */
Sign specificSubExprSign(Expr e) {
result = exprSign(getASubExpr(e))
or
e =
any(DivExpr div |
result = exprSign(div.getLeftOperand()) and
result != TZero() and
div.getRightOperand().(RealLiteral).getValue().toFloat() = 0
)
or
exists(UnaryExpr 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.(BinaryExpr).getOp())
)
}
pragma[noinline]
private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) {
lhs = binaryOpLhsSign(e) and
rhs = binaryOpRhsSign(e)
}
Sign binaryOpLhsSign(BinaryOperation e) { result = exprSign(e.getLeftOperand()) }
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.

View File

@@ -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;
@@ -42,6 +43,135 @@ module Private {
class Field = J::Field;
class DivExpr = J::DivExpr;
class BinaryOperation extends J::Expr {
BinaryOperation() {
this instanceof J::BinaryExpr or
this instanceof J::AssignOp
}
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()
}
}
/** 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 expressions. */
class UnaryExpr extends J::Expr {
UnaryExpr() {
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 expressions. */
class BinaryExpr extends J::Expr {
BinaryExpr() {
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()
}
}
predicate ssaRead = RU::ssaRead/2;
predicate guardControlsSsaRead = RU::guardControlsSsaRead/3;
@@ -169,87 +299,14 @@ private module Impl {
else anySign(result)
}
/** Gets a possible sign for `e` from the signs of its child nodes. */
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 getASubExpr(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() }