Skip to content

Commit 75a95ff

Browse files
authored
Merge pull request #15602 from asgerf/js/block-logical-and-flow
JS: Fix flow through &&
2 parents 337db6b + 18db769 commit 75a95ff

File tree

8 files changed

+38
-2
lines changed

8 files changed

+38
-2
lines changed

javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1693,7 +1693,11 @@ module DataFlow {
16931693
exists(Expr predExpr, Expr succExpr |
16941694
pred = valueNode(predExpr) and succ = valueNode(succExpr)
16951695
|
1696-
predExpr = succExpr.(LogicalBinaryExpr).getAnOperand()
1696+
predExpr = succExpr.(LogicalOrExpr).getAnOperand()
1697+
or
1698+
predExpr = succExpr.(NullishCoalescingExpr).getAnOperand()
1699+
or
1700+
predExpr = succExpr.(LogicalAndExpr).getRightOperand()
16971701
or
16981702
predExpr = succExpr.(ConditionalExpr).getABranch()
16991703
or

javascript/ql/lib/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,26 @@ private class AnalyzedBinaryExpr extends DataFlow::AnalyzedValueNode {
238238
}
239239
}
240240

241+
pragma[nomagic]
242+
private predicate falsyValue(AbstractValue value) { value.getBooleanValue() = false }
243+
244+
/**
245+
* Flow analysis for `&&` operators.
246+
*/
247+
private class AnalyzedLogicalAndExpr extends DataFlow::AnalyzedValueNode {
248+
override LogicalAndExpr astNode;
249+
250+
pragma[nomagic]
251+
private AnalyzedValueNode leftOperand() { result = astNode.getLeftOperand().analyze() }
252+
253+
override AbstractValue getALocalValue() {
254+
result = super.getALocalValue()
255+
or
256+
result = this.leftOperand().getALocalValue() and
257+
falsyValue(result)
258+
}
259+
}
260+
241261
/**
242262
* Gets the `n`th operand of the given `+` or `+=` expression.
243263
*/
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: fix
3+
---
4+
* The left operand of the `&&` operator no longer propagates data flow by default.

javascript/ql/test/library-tests/DataFlow/tests.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,6 @@ flowStep
10221022
| tst.js:4:9:4:12 | "hi" | tst.js:4:5:4:12 | y |
10231023
| tst.js:9:2:9:2 | x | tst.js:9:1:9:3 | (x) |
10241024
| tst.js:10:4:10:4 | y | tst.js:10:1:10:4 | x, y |
1025-
| tst.js:11:1:11:1 | x | tst.js:11:1:11:6 | x && y |
10261025
| tst.js:11:1:11:1 | x | tst.js:12:1:12:1 | x |
10271026
| tst.js:11:1:11:1 | x | tst.js:12:1:12:1 | x |
10281027
| tst.js:11:6:11:6 | y | tst.js:11:1:11:6 | x && y |

javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ typeInferenceMismatch
154154
| json-stringify.js:2:16:2:23 | source() | json-stringify.js:42:8:42:51 | JSON.st ... urce))) |
155155
| json-stringify.js:2:16:2:23 | source() | json-stringify.js:45:8:45:23 | fastJson(source) |
156156
| json-stringify.js:3:15:3:22 | source() | json-stringify.js:8:8:8:31 | jsonStr ... (taint) |
157+
| logical-and.js:2:17:2:24 | source() | logical-and.js:4:10:4:24 | "safe" && taint |
157158
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |
158159
| nested-props.js:9:18:9:25 | source() | nested-props.js:10:10:10:16 | obj.x.y |
159160
| nested-props.js:35:13:35:20 | source() | nested-props.js:36:10:36:20 | doLoad(obj) |

javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
| importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text |
7474
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
7575
| indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x |
76+
| logical-and.js:2:17:2:24 | source() | logical-and.js:4:10:4:24 | "safe" && taint |
7677
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |
7778
| nested-props.js:9:18:9:25 | source() | nested-props.js:10:10:10:16 | obj.x.y |
7879
| nested-props.js:35:13:35:20 | source() | nested-props.js:36:10:36:20 | doLoad(obj) |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function test() {
2+
var taint = source();
3+
4+
sink("safe" && taint); // NOT OK
5+
sink(taint && "safe"); // OK
6+
}

javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
| UselessConditional.js:94:16:94:16 | x | This use of variable 'x' always evaluates to false. |
1919
| UselessConditional.js:100:13:100:24 | true && true | This expression always evaluates to true. |
2020
| UselessConditional.js:101:18:101:18 | x | This use of variable 'x' always evaluates to false. |
21+
| UselessConditional.js:102:13:102:20 | y && (x) | This expression always evaluates to false. |
2122
| UselessConditional.js:102:19:102:19 | x | This use of variable 'x' always evaluates to false. |
2223
| UselessConditional.js:103:23:103:23 | x | This use of variable 'x' always evaluates to false. |
2324
| UselessConditional.js:109:15:109:16 | {} | This expression always evaluates to true. |

0 commit comments

Comments
 (0)