Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 20aa4e1

Browse files
committed
JS: handle sharp inequalities directly
1 parent 9d8d953 commit 20aa4e1

1 file changed

Lines changed: 33 additions & 27 deletions

File tree

javascript/ql/src/semmle/javascript/RangeAnalysis.qll

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ import javascript
7171
*
7272
* - We assume !(x <= y) means x > y, ignoring NaN.
7373
*
74-
* - We assume x < y means x <= y + 1, ignoring floats.
75-
*
7674
* - We assume integer arithmetic is exact, ignoring values above 2^53.
7775
*
7876
*/
@@ -281,19 +279,24 @@ module RangeAnalysis {
281279
*
282280
* The dual constraint `-B <= -A + c` is not included in this predicate.
283281
*/
284-
predicate comparisonEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int bias) {
282+
predicate comparisonEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int bias, boolean sharp) {
285283
// A <= B + c
286-
linearComparisonGuard(cfg, a, asign, "<=", b, bsign, bias)
284+
linearComparisonGuard(cfg, a, asign, "<=", b, bsign, bias) and
285+
sharp = false
287286
or
288-
// A <= B + c iff A < B + c + 1 (assuming A,B are integers)
289-
linearComparisonGuard(cfg, a, asign, "<", b, bsign, bias + 1)
287+
// A < B + c
288+
linearComparisonGuard(cfg, a, asign, "<", b, bsign, bias) and
289+
sharp = true
290290
or
291291
// A <= B + c iff B >= A - c
292-
linearComparisonGuard(cfg, b, bsign, ">=", a, asign, -bias)
292+
linearComparisonGuard(cfg, b, bsign, ">=", a, asign, -bias) and
293+
sharp = false
293294
or
294-
// A <= B + c iff B > A - c - 1 (assuming A,B are integers)
295-
linearComparisonGuard(cfg, b, bsign, ">", a, asign, -bias - 1)
295+
// A < B + c iff B > A - c
296+
linearComparisonGuard(cfg, b, bsign, ">", a, asign, -bias) and
297+
sharp = true
296298
or
299+
sharp = false and
297300
exists (string operator | operator = "==" or operator = "===" |
298301
// A == B + c iff A <= B + c and B <= A - c
299302
linearComparisonGuard(cfg, a, asign, operator, b, bsign, bias)
@@ -387,31 +390,31 @@ module RangeAnalysis {
387390
/**
388391
* The set of initial edges including those from dual constraints.
389392
*/
390-
private predicate seedEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c) {
393+
private predicate seedEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c, boolean sharp) {
391394
// A <= B + c
392-
comparisonEdge(cfg, a, asign, b, bsign, c)
395+
comparisonEdge(cfg, a, asign, b, bsign, c, sharp)
393396
or
394-
phiEdge(cfg, a, asign, b, bsign, c)
397+
phiEdge(cfg, a, asign, b, bsign, c) and sharp = false
395398
or
396-
constantEdge(cfg, a, asign, b, bsign, c)
399+
constantEdge(cfg, a, asign, b, bsign, c) and sharp = false
397400
}
398401

399-
private predicate seedEdgeWithDual(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c) {
402+
private predicate seedEdgeWithDual(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c, boolean sharp) {
400403
// A <= B + c
401-
seedEdge(cfg, a, asign, b, bsign, c)
404+
seedEdge(cfg, a, asign, b, bsign, c, sharp)
402405
or
403406
// -B <= -A + c (dual constraint)
404-
seedEdge(cfg, b, -bsign, a, -asign, c)
407+
seedEdge(cfg, b, -bsign, a, -asign, c, sharp)
405408
}
406409

407410
/**
408411
* Adds a negative and positive integer, but only if they are within in the same
409412
* order of magnitude.
410413
*/
411-
bindingset[x, y]
412-
private int wideningAddition(int x, int y) {
413-
x < 0 and
414-
y >= 0 and
414+
bindingset[x, sharpx, y, sharpy]
415+
private int wideningAddition(int x, boolean sharpx, int y, boolean sharpy) {
416+
(x < 0 or x = 0 and sharpx = true) and
417+
(y > 0 or y = 0 and sharpy = false) and
415418
(
416419
x = 0
417420
or
@@ -449,13 +452,14 @@ module RangeAnalysis {
449452
*
450453
* This means negative-weight cycles (contradictions) can be detected using simple cycle detection.
451454
*/
452-
private predicate extendedEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c) {
453-
seedEdgeWithDual(cfg, a, asign, b, bsign, c)
455+
private predicate extendedEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign, int c, boolean sharp) {
456+
seedEdgeWithDual(cfg, a, asign, b, bsign, c, sharp)
454457
or
455-
exists (DataFlow::Node mid, int midx, ControlFlowNode cfg1, int c1, ControlFlowNode cfg2, int c2 |
456-
extendedEdge(cfg1, a, asign, mid, midx, c1) and
457-
extendedEdge(cfg2, mid, midx, b, bsign, c2) and
458-
c = wideningAddition(c1, c2) and
458+
exists (DataFlow::Node mid, int midx, ControlFlowNode cfg1, int c1, ControlFlowNode cfg2, int c2, boolean sharp1, boolean sharp2 |
459+
extendedEdge(cfg1, a, asign, mid, midx, c1, sharp1) and
460+
extendedEdge(cfg2, mid, midx, b, bsign, c2, sharp2) and
461+
sharp = sharp1.booleanOr(sharp2) and
462+
c = wideningAddition(c1, sharp1, c2, sharp2) and
459463
// One of the two CFG nodes must dominate the other, and `cfg` must be bound to the dominated one.
460464
(
461465
// They are in the same basic block
@@ -481,7 +485,9 @@ module RangeAnalysis {
481485
* Holds if there is a negative-weight edge from src to dst.
482486
*/
483487
private predicate negativeEdge(ControlFlowNode cfg, DataFlow::Node a, int asign, DataFlow::Node b, int bsign) {
484-
exists (int weight | extendedEdge(cfg, a, asign, b, bsign, weight) |
488+
exists (int weight, boolean sharp | extendedEdge(cfg, a, asign, b, bsign, weight, sharp) |
489+
weight = 0 and sharp = true // a strict "< 0" edge counts as negative
490+
or
485491
weight < 0)
486492
}
487493

0 commit comments

Comments
 (0)