JavaScript: Introduce new query `UnclearOperatorPrecedence`.

This commit is contained in:
Max Schaefer 2018-09-28 13:04:52 +01:00
Родитель a63b7fc215
Коммит 768368498f
9 изменённых файлов: 97 добавлений и 2 удалений

Просмотреть файл

@ -15,9 +15,10 @@
| **Query** | **Tags** | **Purpose** |
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). Results are not shown on LGTM by default. |
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
| Replacement of a substring with itself (`js/identity-replacement`) | correctness, security, external/cwe/cwe-116 | Highlights string replacements that replace a string with itself, which usually indicates a mistake. Results shown on LGTM by default. |
| Host header poisoning in email generation | security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. |
| Replacement of a substring with itself (`js/identity-replacement`) | correctness, security, external/cwe/cwe-116 | Highlights string replacements that replace a string with itself, which usually indicates a mistake. Results shown on LGTM by default. |
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
| Unclear precedence of nested operators (`js/unclear-operator-precedence`) | maintainability, correctness, external/cwe/cwe-783 | Highlights nested binary operators whose relative precedence is easy to misunderstand. Results shown on LGTM by default. |
## Changes to existing queries

Просмотреть файл

@ -5,6 +5,7 @@
+ semmlecode-javascript-queries/Expressions/SuspiciousInvocation.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/Expressions/SuspiciousPropAccess.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/Expressions/UnboundEventHandlerReceiver.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/Expressions/UnclearOperatorPrecedence.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/Expressions/UnknownDirective.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/Expressions/WhitespaceContradictsPrecedence.ql: /Correctness/Expressions
+ semmlecode-javascript-queries/LanguageFeatures/IllegalInvocation.ql: /Correctness/Language Features

Просмотреть файл

@ -0,0 +1,46 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Nested expressions that rely on less well-known operator precedence rules can be
hard to read and understand. They could even indicate a bug where the author of the
code misunderstood the precedence rules.
</p>
</overview>
<recommendation>
<p>
Use parentheses or additional whitespace to clarify grouping.
</p>
</recommendation>
<example>
<p>
Consider the following snippet of code:
</p>
<sample src="examples/UnclearOperatorPrecedence.js" />
<p>
It might look like this tests whether <code>x</code> and <code>y</code> have any bits in
common, but in fact <code>==</code> binds more tightly than <code>&amp;</code>, so the test
is equivalent to <code>x &amp; (y == 0)</code>.
</p>
<p>
If this is the intended interpretation, parentheses should be used to clarify this. You could
also consider adding extra whitespace around <code>&amp;</code> or removing whitespace
around <code>==</code> to make it visually apparent that it binds less tightly:
<code>x &amp; y==0</code>.
</p>
<p>
Probably the best approach in this case, though, would be to use the <code>&amp;&amp;</code>
operator instead to clarify the intended interpretation: <code>x &amp;&amp; y == 0</code>.
</p>
</example>
<references>
<li>Mozilla Developer Network, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence">Operator precedence</a>.</li>
</references>
</qhelp>

Просмотреть файл

@ -0,0 +1,29 @@
/**
* @name Unclear precedence of nested operators
* @description Nested expressions involving binary bitwise operators and comparisons are easy
* to misunderstand without additional disambiguating parentheses or whitespace.
* @kind problem
* @problem.severity recommendation
* @id js/unclear-operator-precedence
* @tags maintainability
* correctness
* statistical
* non-attributable
* external/cwe/cwe-783
* @precision very-high
*/
import javascript
from BitwiseBinaryExpr bit, Comparison rel, Expr other
where bit.hasOperands(rel, other) and
// only flag if whitespace doesn't clarify the nesting (note that if `bit` has less
// whitespace than `rel`, it will be reported by `js/whitespace-contradicts-precedence`)
bit.getWhitespaceAroundOperator() = rel.getWhitespaceAroundOperator() and
// don't flag if the other operand is itself a comparison,
// since the nesting tends to be visually more obvious in such cases
not other instanceof Comparison and
// don't flag occurrences in minified code
not rel.getTopLevel().isMinified()
select rel, "The '" + rel.getOperator() + "' operator binds more tightly than " +
"'" + bit.getOperator() + "', which may not be obvious in this case."

Просмотреть файл

@ -0,0 +1,3 @@
if (x & y == 0) {
// ...
}

Просмотреть файл

@ -0,0 +1,3 @@
| tst.js:1:9:1:17 | 0x0A != 0 | The '!=' operator binds more tightly than '&', which may not be obvious in this case. |
| tst.js:6:1:6:7 | x !== y | The '!==' operator binds more tightly than '&', which may not be obvious in this case. |
| tst.js:10:3:10:6 | b==c | The '==' operator binds more tightly than '&', which may not be obvious in this case. |

Просмотреть файл

@ -0,0 +1 @@
Expressions/UnclearOperatorPrecedence.ql

Просмотреть файл

@ -0,0 +1,10 @@
x.f() & 0x0A != 0; // NOT OK
x.f() & (0x0A != 0); // OK
x.f() & 0x0A != 0; // OK
x.f() & 0x0A!=0; // OK
x !== y & 1; // NOT OK
x > 0 & x < 10; // OK
a&b==c; // NOT OK

Просмотреть файл

@ -0,0 +1 @@
a&b==c; // OK (minified file)