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

Skip to content

Commit ce53a7d

Browse files
author
Max Schaefer
authored
Merge pull request #1175 from psygnisfive/NullSensitiveContext
[JS] Null Sensitive Context (new library)
2 parents ae6c768 + fb40548 commit ce53a7d

5 files changed

Lines changed: 946 additions & 0 deletions

File tree

javascript/ql/src/semmle/javascript/Expr.qll

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,66 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
161161
* file that was extracted without type information.
162162
*/
163163
Type getType() { ast_node_type(this, result) }
164+
165+
/**
166+
* Holds if the syntactic context that the expression appears in relies on the expression
167+
* being non-null/non-undefined.
168+
*
169+
* A context relies on the subexpression being non-null/non-undefined if either...
170+
*
171+
* * Using null or undefined would cause a runtime error
172+
* * Using null or undefined would cause no error due to type conversion, but the
173+
* behavior in the broader context is sufficiently non-obvious to warrant explicitly
174+
* converting to ensure that readers understand the intent
175+
*/
176+
predicate inNullSensitiveContext() {
177+
exists(ExprOrStmt ctx |
178+
// bases cases
179+
this = ctx.(PropAccess).getBase()
180+
or
181+
this = ctx.(IndexExpr).getPropertyNameExpr()
182+
or
183+
this = ctx.(InvokeExpr).getCallee()
184+
or
185+
this = ctx.(BinaryExpr).getAnOperand() and
186+
not ctx instanceof LogicalBinaryExpr and // x LOGOP y is fine because of implicit conversion
187+
not ctx instanceof EqualityTest and // x EQOP y is fine because of implicit conversion and lack thereof
188+
not ctx.(BitOrExpr).getAnOperand().(NumberLiteral).getIntValue() = 0 and // x | 0 is fine because it's used to convert to numbers
189+
not ctx.(RShiftExpr).getRightOperand().(NumberLiteral).getIntValue() = 0 and // x >> 0 is fine because it's used to convert to numbers
190+
not ctx.(URShiftExpr).getRightOperand().(NumberLiteral).getIntValue() = 0 // x >>> 0 is fine because it's used to convert to numbers
191+
or
192+
this = ctx.(UnaryExpr).getOperand() and
193+
not ctx instanceof LogNotExpr and // !x is fine because of implicit conversion
194+
not ctx instanceof PlusExpr and // +x is fine because of implicit conversion
195+
not ctx instanceof VoidExpr // void x is fine because it explicitly is for capturing void things
196+
or
197+
this = ctx.(UpdateExpr).getOperand()
198+
or
199+
this = ctx.(CompoundAssignExpr).getLhs()
200+
or
201+
this = ctx.(CompoundAssignExpr).getRhs()
202+
or
203+
this = ctx.(AssignExpr).getRhs() and
204+
ctx.(AssignExpr).getLhs() instanceof DestructuringPattern
205+
or
206+
this = ctx.(SpreadElement).getOperand()
207+
or
208+
this = ctx.(ForOfStmt).getIterationDomain()
209+
or
210+
// recursive cases
211+
this = ctx.(ParExpr).getExpression() and
212+
ctx.(ParExpr).inNullSensitiveContext()
213+
or
214+
this = ctx.(SeqExpr).getLastOperand() and
215+
ctx.(SeqExpr).inNullSensitiveContext()
216+
or
217+
this = ctx.(LogicalBinaryExpr).getRightOperand() and
218+
ctx.(LogicalBinaryExpr).inNullSensitiveContext()
219+
or
220+
this = ctx.(ConditionalExpr).getABranch() and
221+
ctx.(ConditionalExpr).inNullSensitiveContext()
222+
)
223+
}
164224
}
165225

166226
/** An identifier. */
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
///////////////////
2+
// //
3+
// SHOULD FIND //
4+
// //
5+
///////////////////
6+
7+
foo[bar];
8+
foo.bar;
9+
new Foo;
10+
new Foo();
11+
foo.bar = 5;
12+
foo(bar);
13+
x + y;
14+
x - y;
15+
x * y;
16+
x / y;
17+
x % y;
18+
+x;
19+
-x;
20+
++x;
21+
x++;
22+
--x;
23+
x--;
24+
x += y;
25+
x -= y;
26+
x *= y;
27+
x /= y;
28+
x %= y;
29+
[x , y] = p;
30+
//[1,2,...xs]
31+
x & y;
32+
x | y;
33+
x ^ y;
34+
x << y;
35+
x >> y;
36+
x >>> y;
37+
~x;
38+
x &= y;
39+
x |= y;
40+
x ^= y;
41+
x <<= y;
42+
x >>= y;
43+
x >>>= y;
44+
for (let x of y) { }
45+
46+
47+
48+
///////////////////////
49+
// //
50+
// SHOULD NOT FIND //
51+
// //
52+
///////////////////////
53+
54+
x && y;
55+
x || y;
56+
!x;
57+
if (x) { }
58+
while (x) { }
59+
for (; y; z) { }
60+
for (let x in y) { }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import javascript
2+
3+
query predicate test_inNullSensitiveContext(Expr e) { e.inNullSensitiveContext() }

0 commit comments

Comments
 (0)