Skip to content

Commit 2b6ef24

Browse files
author
Esben Sparre Andreasen
committed
JS: add utilities to DefensiveProgramming.qll
1 parent 8086e88 commit 2b6ef24

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

javascript/ql/src/semmle/javascript/DefensiveProgramming.qll

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,86 @@ module Internal {
4646
}
4747
}
4848

49+
/**
50+
* Gets the inner expression of `e`, with any surrounding parentheses and boolean nots removed.
51+
* `polarity` is true iff the inner expression is nested in an even number of negations.
52+
*/
53+
private Expr stripNotsAndParens(Expr e, boolean polarity) {
54+
exists (Expr inner |
55+
inner = e.stripParens() |
56+
if inner instanceof LogNotExpr then
57+
(result = stripNotsAndParens(inner.(LogNotExpr).getOperand(), polarity.booleanNot()))
58+
else
59+
(result = inner and polarity = true)
60+
)
61+
}
62+
63+
/**
64+
* An equality test for `null` and `undefined`.
65+
*/
66+
private abstract class UndefinedNullTest extends EqualityTest {
67+
/** Gets the unique Boolean value that this test evaluates to, if any. */
68+
abstract boolean getTheTestResult();
69+
70+
/**
71+
* Gets the expression that is tested for being `null` or `undefined`.
72+
*/
73+
abstract Expr getOperand();
74+
}
75+
76+
/**
77+
* A dis- or conjunction that tests if an expression is `null` or `undefined` in either branch.
78+
*/
79+
private class CompositeUndefinedNullTestPart extends DefensiveExpression {
80+
81+
UndefinedNullTest test;
82+
83+
boolean polarity;
84+
85+
CompositeUndefinedNullTestPart(){
86+
exists (BinaryExpr composite, Variable v, Expr op, Expr opOther, UndefinedNullTest testOther |
87+
composite instanceof LogAndExpr or
88+
composite instanceof LogOrExpr |
89+
composite.hasOperands(op, opOther) and
90+
this = op.flow() and
91+
test = stripNotsAndParens(op, polarity) and
92+
testOther = stripNotsAndParens(opOther, _) and
93+
test.getOperand().(VarRef).getVariable() = v and
94+
testOther.getOperand().(VarRef).getVariable() = v
95+
)
96+
}
97+
98+
override boolean getTheTestResult() {
99+
polarity = true and result = test.getTheTestResult()
100+
or
101+
polarity = false and result = test.getTheTestResult().booleanNot()
102+
}
103+
104+
}
105+
106+
/**
107+
* A test for `undefined` or `null` in an if-statement.
108+
*/
109+
private class SanityCheckingUndefinedNullGuard extends DefensiveExpression {
110+
111+
UndefinedNullTest test;
112+
113+
boolean polarity;
114+
115+
SanityCheckingUndefinedNullGuard() {
116+
exists (IfStmt c |
117+
this = c.getCondition().flow() and
118+
test = stripNotsAndParens(c.getCondition(), polarity) and
119+
test.getOperand() instanceof VarRef
120+
)
121+
}
122+
123+
override boolean getTheTestResult() {
124+
polarity = true and result = test.getTheTestResult()
125+
or
126+
polarity = false and result = test.getTheTestResult().booleanNot()
127+
}
128+
129+
}
130+
49131
}

0 commit comments

Comments
 (0)