Skip to content

Commit f52cf26

Browse files
committed
Refactor specificSubExprSign
1 parent f03146d commit f52cf26

6 files changed

Lines changed: 399 additions & 146 deletions

File tree

csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@ newtype TSign =
33
TZero() or
44
TPos()
55

6+
newtype TUnarySignOperation =
7+
TNegOp() or
8+
TIncOp() or
9+
TDecOp() or
10+
TBitNotOp()
11+
12+
newtype TBinarySignOperation =
13+
TAddOp() or
14+
TSubOp() or
15+
TMulOp() or
16+
TDivOp() or
17+
TRemOp() or
18+
TBitAndOp() or
19+
TBitOrOp() or
20+
TBitXorOp() or
21+
TLShiftOp() or
22+
TRShiftOp() or
23+
TURShiftOp()
24+
625
/** Class representing expression signs (+, -, 0). */
726
class Sign extends TSign {
827
/** Gets the string representation of this sign. */
@@ -67,6 +86,12 @@ class Sign extends TSign {
6786
this = TNeg() and s = TPos()
6887
}
6988

89+
/**
90+
* Gets a possible sign after subtracting an expression with sign `s` from an expression
91+
* that has this sign.
92+
*/
93+
Sign sub(Sign s) { result = add(s.neg()) }
94+
7095
/**
7196
* Gets a possible sign after multiplying an expression with sign `s` to an expression
7297
* that has this sign.
@@ -216,4 +241,40 @@ class Sign extends TSign {
216241
or
217242
result != TNeg() and this = TPos() and s != TZero()
218243
}
244+
245+
/** Perform `op` on this sign. */
246+
Sign applyUnaryOp(TUnarySignOperation op) {
247+
op = TIncOp() and result = inc()
248+
or
249+
op = TDecOp() and result = dec()
250+
or
251+
op = TNegOp() and result = neg()
252+
or
253+
op = TBitNotOp() and result = bitnot()
254+
}
255+
256+
/** Perform `op` on this sign and sign `s`. */
257+
Sign applyBinaryOp(Sign s, TBinarySignOperation op) {
258+
op = TAddOp() and result = add(s)
259+
or
260+
op = TSubOp() and result = sub(s)
261+
or
262+
op = TMulOp() and result = mul(s)
263+
or
264+
op = TDivOp() and result = div(s)
265+
or
266+
op = TRemOp() and result = rem(s)
267+
or
268+
op = TBitAndOp() and result = bitand(s)
269+
or
270+
op = TBitOrOp() and result = bitor(s)
271+
or
272+
op = TBitXorOp() and result = bitxor(s)
273+
or
274+
op = TLShiftOp() and result = lshift(s)
275+
or
276+
op = TRShiftOp() and result = rshift(s)
277+
or
278+
op = TURShiftOp() and result = urshift(s)
279+
}
219280
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,36 @@ Sign exprSign(Expr e) {
326326
)
327327
}
328328

329+
/** Gets a possible sign for `e` from the signs of its child nodes. */
330+
Sign specificSubExprSign(Expr e) {
331+
result = exprSign(getASubExpr(e))
332+
or
333+
e =
334+
any(DivExpr div |
335+
result = exprSign(div.getLeftOperand()) and
336+
result != TZero() and
337+
div.getRightOperand().(RealLiteral).getValue().toFloat() = 0
338+
)
339+
or
340+
exists(UnaryExpr unary | unary = e |
341+
result = exprSign(unary.getOperand()).applyUnaryOp(unary.getOp())
342+
)
343+
or
344+
exists(Sign s1, Sign s2 | binaryOpSigns(e, s1, s2) |
345+
result = s1.applyBinaryOp(s2, e.(BinaryExpr).getOp())
346+
)
347+
}
348+
349+
pragma[noinline]
350+
private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) {
351+
lhs = binaryOpLhsSign(e) and
352+
rhs = binaryOpRhsSign(e)
353+
}
354+
355+
Sign binaryOpLhsSign(BinaryOperation e) { result = exprSign(e.getLeftOperand()) }
356+
357+
Sign binaryOpRhsSign(BinaryOperation e) { result = exprSign(e.getRightOperand()) }
358+
329359
/**
330360
* Dummy predicate that holds for any sign. This is added to improve readability
331361
* of cases where the sign is unrestricted.

csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll

Lines changed: 79 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ module Private {
3838

3939
class Field = CS::Field;
4040

41+
class RealLiteral = CS::RealLiteral;
42+
43+
class DivExpr = CS::DivExpr;
44+
45+
class BinaryOperation = CS::BinaryOperation;
46+
4147
predicate ssaRead = SU::ssaRead/2;
4248
}
4349

@@ -196,80 +202,88 @@ private module Impl {
196202
not e instanceof NullCoalescingExpr
197203
}
198204

199-
/** Gets a possible sign for `e` from the signs of its child nodes. */
200-
Sign specificSubExprSign(Expr e) {
201-
// The expression types that are handled here should be excluded in `unknownIntegerAccess`.
202-
// Keep them in sync.
203-
result = exprSign(e.(AssignExpr).getRValue())
204-
or
205-
result = exprSign(e.(AssignOperation).getExpandedAssignment())
206-
or
207-
result = exprSign(e.(UnaryPlusExpr).getOperand())
208-
or
209-
result = exprSign(e.(PostIncrExpr).getOperand())
210-
or
211-
result = exprSign(e.(PostDecrExpr).getOperand())
212-
or
213-
result = exprSign(e.(PreIncrExpr).getOperand()).inc()
214-
or
215-
result = exprSign(e.(PreDecrExpr).getOperand()).dec()
216-
or
217-
result = exprSign(e.(UnaryMinusExpr).getOperand()).neg()
218-
or
219-
result = exprSign(e.(ComplementExpr).getOperand()).bitnot()
220-
or
221-
e =
222-
any(DivExpr div |
223-
result = exprSign(div.getLeftOperand()) and
224-
result != TZero() and
225-
div.getRightOperand().(RealLiteral).getValue().toFloat() = 0
226-
)
227-
or
228-
exists(Sign s1, Sign s2 | binaryOpSigns(e, s1, s2) |
229-
e instanceof AddExpr and result = s1.add(s2)
205+
/** Returns a sub expression of `e` for expression types where the sign depends on the child. */
206+
Expr getASubExpr(Expr e) {
207+
result = e.(AssignExpr).getRValue() or
208+
result = e.(AssignOperation).getExpandedAssignment() or
209+
result = e.(UnaryPlusExpr).getOperand() or
210+
result = e.(PostIncrExpr).getOperand() or
211+
result = e.(PostDecrExpr).getOperand() or
212+
result = e.(ConditionalExpr).getAChild() or
213+
result = e.(NullCoalescingExpr).getAChild() or
214+
result = e.(SwitchExpr).getACase().getBody() or
215+
result = e.(SwitchCaseExpr).getBody() or
216+
result = e.(LocalVariableDeclAndInitExpr).getInitializer() or
217+
result = e.(RefExpr).getExpr() or
218+
result = e.(CastExpr).getExpr()
219+
}
220+
221+
/** Class to represent unary expressions. */
222+
class UnaryExpr extends Expr {
223+
UnaryExpr() {
224+
this instanceof PreIncrExpr or
225+
this instanceof PreDecrExpr or
226+
this instanceof UnaryMinusExpr or
227+
this instanceof ComplementExpr
228+
}
229+
230+
/** Returns the operand of this expression. */
231+
Expr getOperand() {
232+
result = this.(PreIncrExpr).getOperand() or
233+
result = this.(PreDecrExpr).getOperand() or
234+
result = this.(UnaryMinusExpr).getOperand() or
235+
result = this.(ComplementExpr).getOperand()
236+
}
237+
238+
/** Returns the operation representing this expression. */
239+
TUnarySignOperation getOp() {
240+
this instanceof PreIncrExpr and result = TIncOp()
230241
or
231-
e instanceof SubExpr and result = s1.add(s2.neg())
242+
this instanceof PreDecrExpr and result = TDecOp()
232243
or
233-
e instanceof MulExpr and result = s1.mul(s2)
244+
this instanceof UnaryMinusExpr and result = TNegOp()
234245
or
235-
e instanceof DivExpr and result = s1.div(s2)
246+
this instanceof ComplementExpr and result = TBitNotOp()
247+
}
248+
}
249+
250+
/** Class to represent binary expressions. */
251+
class BinaryExpr extends Expr {
252+
BinaryExpr() {
253+
this instanceof AddExpr or
254+
this instanceof SubExpr or
255+
this instanceof MulExpr or
256+
this instanceof DivExpr or
257+
this instanceof RemExpr or
258+
this instanceof BitwiseAndExpr or
259+
this instanceof BitwiseOrExpr or
260+
this instanceof BitwiseXorExpr or
261+
this instanceof LShiftExpr or
262+
this instanceof RShiftExpr
263+
}
264+
265+
/** Returns the operation representing this expression. */
266+
TBinarySignOperation getOp() {
267+
this instanceof AddExpr and result = TAddOp()
236268
or
237-
e instanceof RemExpr and result = s1.rem(s2)
269+
this instanceof SubExpr and result = TSubOp()
238270
or
239-
e instanceof BitwiseAndExpr and result = s1.bitand(s2)
271+
this instanceof MulExpr and result = TMulOp()
240272
or
241-
e instanceof BitwiseOrExpr and result = s1.bitor(s2)
273+
this instanceof DivExpr and result = TDivOp()
242274
or
243-
e instanceof BitwiseXorExpr and result = s1.bitxor(s2)
275+
this instanceof RemExpr and result = TRemOp()
244276
or
245-
e instanceof LShiftExpr and result = s1.lshift(s2)
277+
this instanceof BitwiseAndExpr and result = TBitAndOp()
246278
or
247-
e instanceof RShiftExpr and result = s1.rshift(s2)
248-
)
249-
or
250-
result = exprSign(e.(ConditionalExpr).getAChild())
251-
or
252-
result = exprSign(e.(NullCoalescingExpr).getAChild())
253-
or
254-
result = exprSign(e.(SwitchExpr).getACase().getBody())
255-
or
256-
result = exprSign(e.(CastExpr).getExpr())
257-
or
258-
result = exprSign(e.(SwitchCaseExpr).getBody())
259-
or
260-
result = exprSign(e.(LocalVariableDeclAndInitExpr).getInitializer())
261-
or
262-
result = exprSign(e.(RefExpr).getExpr())
263-
}
264-
265-
private Sign binaryOpLhsSign(BinaryOperation e) { result = exprSign(e.getLeftOperand()) }
266-
267-
private Sign binaryOpRhsSign(BinaryOperation e) { result = exprSign(e.getRightOperand()) }
268-
269-
pragma[noinline]
270-
private predicate binaryOpSigns(Expr e, Sign lhs, Sign rhs) {
271-
lhs = binaryOpLhsSign(e) and
272-
rhs = binaryOpRhsSign(e)
279+
this instanceof BitwiseOrExpr and result = TBitOrOp()
280+
or
281+
this instanceof BitwiseXorExpr and result = TBitXorOp()
282+
or
283+
this instanceof LShiftExpr and result = TLShiftOp()
284+
or
285+
this instanceof RShiftExpr and result = TRShiftOp()
286+
}
273287
}
274288

275289
Expr getARead(Ssa::Definition v) { result = v.getARead() }

java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@ newtype TSign =
33
TZero() or
44
TPos()
55

6+
newtype TUnarySignOperation =
7+
TNegOp() or
8+
TIncOp() or
9+
TDecOp() or
10+
TBitNotOp()
11+
12+
newtype TBinarySignOperation =
13+
TAddOp() or
14+
TSubOp() or
15+
TMulOp() or
16+
TDivOp() or
17+
TRemOp() or
18+
TBitAndOp() or
19+
TBitOrOp() or
20+
TBitXorOp() or
21+
TLShiftOp() or
22+
TRShiftOp() or
23+
TURShiftOp()
24+
625
/** Class representing expression signs (+, -, 0). */
726
class Sign extends TSign {
827
/** Gets the string representation of this sign. */
@@ -67,6 +86,12 @@ class Sign extends TSign {
6786
this = TNeg() and s = TPos()
6887
}
6988

89+
/**
90+
* Gets a possible sign after subtracting an expression with sign `s` from an expression
91+
* that has this sign.
92+
*/
93+
Sign sub(Sign s) { result = add(s.neg()) }
94+
7095
/**
7196
* Gets a possible sign after multiplying an expression with sign `s` to an expression
7297
* that has this sign.
@@ -216,4 +241,40 @@ class Sign extends TSign {
216241
or
217242
result != TNeg() and this = TPos() and s != TZero()
218243
}
244+
245+
/** Perform `op` on this sign. */
246+
Sign applyUnaryOp(TUnarySignOperation op) {
247+
op = TIncOp() and result = inc()
248+
or
249+
op = TDecOp() and result = dec()
250+
or
251+
op = TNegOp() and result = neg()
252+
or
253+
op = TBitNotOp() and result = bitnot()
254+
}
255+
256+
/** Perform `op` on this sign and sign `s`. */
257+
Sign applyBinaryOp(Sign s, TBinarySignOperation op) {
258+
op = TAddOp() and result = add(s)
259+
or
260+
op = TSubOp() and result = sub(s)
261+
or
262+
op = TMulOp() and result = mul(s)
263+
or
264+
op = TDivOp() and result = div(s)
265+
or
266+
op = TRemOp() and result = rem(s)
267+
or
268+
op = TBitAndOp() and result = bitand(s)
269+
or
270+
op = TBitOrOp() and result = bitor(s)
271+
or
272+
op = TBitXorOp() and result = bitxor(s)
273+
or
274+
op = TLShiftOp() and result = lshift(s)
275+
or
276+
op = TRShiftOp() and result = rshift(s)
277+
or
278+
op = TURShiftOp() and result = urshift(s)
279+
}
219280
}

0 commit comments

Comments
 (0)