Merge branch 'master' of github.com:github/codeql into OptionalSanitizer

This commit is contained in:
Erik Krogh Kristensen
2020-05-26 13:59:57 +02:00
234 changed files with 1779 additions and 872 deletions

View File

@@ -16,6 +16,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications.
## Changes to libraries
* The library `VCS.qll` and all queries that imported it have been removed.
* The data-flow library has been improved, which affects most security queries by potentially
adding more results. Flow through functions now takes nested field reads/writes into account.
For example, the library is able to track flow from `taint()` to `sink()` via the method
@@ -39,3 +40,5 @@ The following changes in version 1.25 affect C/C++ analysis in all applications.
}
};
```
* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library.

View File

@@ -3,8 +3,10 @@
## General improvements
* Support for the following frameworks and libraries has been improved:
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [bluebird](http://bluebirdjs.com/)
- [express](https://www.npmjs.com/package/express)
- [fastify](https://www.npmjs.com/package/fastify)
- [fstream](https://www.npmjs.com/package/fstream)
- [jGrowl](https://github.com/stanlemon/jGrowl)
- [jQuery](https://jquery.com/)
@@ -13,12 +15,11 @@
- [mssql](https://www.npmjs.com/package/mssql)
- [mysql](https://www.npmjs.com/package/mysql)
- [pg](https://www.npmjs.com/package/pg)
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [sequelize](https://www.npmjs.com/package/sequelize)
- [spanner](https://www.npmjs.com/package/spanner)
- [sqlite](https://www.npmjs.com/package/sqlite)
- [ssh2](https://www.npmjs.com/package/ssh2)
- [ssh2-streams](https://www.npmjs.com/package/ssh2-streams)
- [ssh2](https://www.npmjs.com/package/ssh2)
* TypeScript 3.9 is now supported.
@@ -35,42 +36,43 @@
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. |
| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. |
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. |
| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. |
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. |
| Client-side cross-site scripting (`js/xss`) | Less results | This query no longer flags optionally sanitized values. |
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. |
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. |
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
The following low-precision queries are no longer run by default on LGTM (their results already were not displayed):
- `js/angular/dead-event-listener`
- `js/angular/unused-dependency`
- `js/conflicting-html-attribute`
- `js/useless-assignment-to-global`
- `js/too-many-parameters`
- `js/unused-property`
- `js/bitwise-sign-check`
- `js/comparison-of-identical-expressions`
- `js/misspelled-identifier`
- `js/jsdoc/malformed-param-tag`
- `js/jsdoc/unknown-parameter`
- `js/jsdoc/missing-parameter`
- `js/omitted-array-element`
- `js/conflicting-html-attribute`
- `js/ignored-setter-parameter`
- `js/jsdoc/malformed-param-tag`
- `js/jsdoc/missing-parameter`
- `js/jsdoc/unknown-parameter`
- `js/json-in-javascript-file`
- `js/misspelled-identifier`
- `js/nested-loops-with-same-variable`
- `js/node/cyclic-import`
- `js/node/unused-npm-dependency`
- `js/single-run-loop`
- `js/nested-loops-with-same-variable`
- `js/omitted-array-element`
- `js/return-outside-function`
- `js/single-run-loop`
- `js/too-many-parameters`
- `js/unused-property`
- `js/useless-assignment-to-global`
## Changes to libraries
@@ -80,3 +82,4 @@ The following low-precision queries are no longer run by default on LGTM (their
- `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph.
- `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result.
- `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern.
* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function".

View File

@@ -6,29 +6,50 @@
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
/**
* Holds if `fde` has a parameter declaration that's clear on the minimum
* number of parameters. This is essentially true for everything except
* `()`-declarations.
*/
private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) {
fde.hasVoidParamList()
or
fde.getNumberOfParameters() > 0
or
fde.isDefinition()
}
/* Holds if function was ()-declared, but not (void)-declared or K&R-defined. */
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
not hasDefiniteNumberOfParameters(fde)
)
}
// True if this file (or header) was compiled as a C file
/* Holds if this file (or header) was compiled as a C file. */
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
/** Holds if `fc` is a call to `f` with too few arguments. */
predicate tooFewArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
// This query should only have results on C (not C++) functions that have a
// `()` parameter list somewhere. If it has results on other functions, then
// it's probably because the extractor only saw a partial compilation.
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
// Produce an alert when all declarations that are authoritative on the
// parameter count specify a parameter count larger than the number of call
// arguments.
forex(FunctionDeclarationEntry fde |
fde = f.getADeclarationEntry() and
hasDefiniteNumberOfParameters(fde)
|
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
}

View File

@@ -1,27 +0,0 @@
/**
* @name Churned lines per file
* @description Number of churned lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-churn
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentChurnForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,27 +0,0 @@
/**
* @name Added lines per file
* @description Number of added lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-lines-added
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentAdditionsForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,27 +0,0 @@
/**
* @name Deleted lines per file
* @description Number of deleted lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-lines-deleted
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentDeletionsForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,18 +0,0 @@
/**
* @name Number of authors
* @description Number of distinct authors for each file.
* @kind treemap
* @id cpp/historical-number-of-authors
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, count(Author author | author.getAnEditedFile() = f)

View File

@@ -1,19 +0,0 @@
/**
* @name Number of file-level changes
* @description The number of file-level changes made (by version
* control history).
* @kind treemap
* @id cpp/historical-number-of-changes
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, count(Commit svn | f = svn.getAnAffectedFile() and not artificialChange(svn))

View File

@@ -1,21 +0,0 @@
/**
* @name Number of co-committed files
* @description The average number of other files that are touched
* whenever a file is affected by a commit.
* @kind treemap
* @id cpp/historical-number-of-co-commits
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) }
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, avg(Commit commit | commit.getAnAffectedFile() = f | committedFiles(commit) - 1)

View File

@@ -1,37 +0,0 @@
/**
* @name Number of re-commits for each file
* @description A re-commit is taken to mean a commit to a file that
* was touched less than five days ago.
* @kind treemap
* @id cpp/historical-number-of-re-commits
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
predicate inRange(Commit first, Commit second) {
first.getAnAffectedFile() = second.getAnAffectedFile() and
first != second and
exists(int n |
n = first.getDate().daysTo(second.getDate()) and
n >= 0 and
n < 5
)
}
int recommitsForFile(File f) {
result =
count(Commit recommit |
f = recommit.getAnAffectedFile() and
exists(Commit prev | inRange(prev, recommit))
)
}
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, recommitsForFile(f)

View File

@@ -1,27 +0,0 @@
/**
* @name Number of recent authors
* @description Number of distinct authors that have recently made
* changes.
* @kind treemap
* @id cpp/historical-number-of-recent-authors
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f,
count(Author author |
exists(Commit e |
e = author.getACommit() and
f = e.getAnAffectedFile() and
e.daysToNow() <= 180 and
not artificialChange(e)
)
)

View File

@@ -1,24 +0,0 @@
/**
* @name Recently changed files
* @description Number of files recently edited.
* @kind treemap
* @id cpp/historical-number-of-recent-changed-files
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where
exists(Commit e |
e.getAnAffectedFile() = f and
e.daysToNow() <= 180 and
not artificialChange(e)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, 1

View File

@@ -1,25 +0,0 @@
/**
* @name Recent changes
* @description Number of recent commits to this file.
* @kind treemap
* @id cpp/historical-number-of-recent-changes
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
count(Commit e |
e.getAnAffectedFile() = f and
e.daysToNow() <= 180 and
not artificialChange(e)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1 +1,7 @@
/**
* DEPRECATED: use `import cpp` instead of `import default`.
*
* Provides classes and predicates for working with C/C++ code.
*/
import cpp

View File

@@ -1,3 +1,5 @@
/** Provides classes for detecting duplicate or similar code. */
import cpp
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
@@ -8,9 +10,12 @@ private predicate tokenLocation(string path, int sl, int sc, int ec, int el, Cop
tokens(copy, index, sl, sc, ec, el)
}
/** A token block used for detection of duplicate and similar code. */
class Copy extends @duplication_or_similarity {
/** Gets the index of the last token in this block. */
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
/** Gets the index of the token in this block starting at the location `loc`, if any. */
int tokenStartingAt(Location loc) {
exists(string filepath, int startline, int startcol |
loc.hasLocationInfo(filepath, startline, startcol, _, _) and
@@ -18,6 +23,7 @@ class Copy extends @duplication_or_similarity {
)
}
/** Gets the index of the token in this block ending at the location `loc`, if any. */
int tokenEndingAt(Location loc) {
exists(string filepath, int endline, int endcol |
loc.hasLocationInfo(filepath, _, _, endline, endcol) and
@@ -25,24 +31,38 @@ class Copy extends @duplication_or_similarity {
)
}
/** Gets the line on which the first token in this block starts. */
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
/** Gets the column on which the first token in this block starts. */
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
/** Gets the line on which the last token in this block ends. */
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
/** Gets the column on which the last token in this block ends. */
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
/** Gets the number of lines containing at least (part of) one token in this block. */
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
/** Gets an opaque identifier for the equivalence class of this block. */
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
/** Gets the source file in which this block appears. */
File sourceFile() {
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
name.replaceAll("\\", "/") = relativePath(result)
)
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
@@ -53,25 +73,30 @@ class Copy extends @duplication_or_similarity {
endcolumn = sourceEndColumn()
}
/** Gets a textual representation of this element. */
string toString() { none() }
}
/** A block of duplicated code. */
class DuplicateBlock extends Copy, @duplication {
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
}
/** A block of similar code. */
class SimilarBlock extends Copy, @similarity {
override string toString() {
result = "Similar code: " + sourceLines() + " almost duplicated lines."
}
}
/** Gets a function with a body and a location. */
FunctionDeclarationEntry sourceMethod() {
result.isDefinition() and
exists(result.getLocation()) and
numlines(unresolveElement(result.getFunction()), _, _, _)
}
/** Gets the number of member functions in `c` with a body and a location. */
int numberOfSourceMethods(Class c) {
result =
count(FunctionDeclarationEntry m |
@@ -108,6 +133,10 @@ private predicate duplicateStatement(
)
}
/**
* Holds if `m1` is a function with `total` lines, and `m2` is a function
* that has `duplicate` lines in common with `m1`.
*/
predicate duplicateStatements(
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total
) {
@@ -115,13 +144,16 @@ predicate duplicateStatements(
total = strictcount(statementInMethod(m1))
}
/**
* Find pairs of methods are identical
*/
/** Holds if `m` and other are identical functions. */
predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) {
exists(int total | duplicateStatements(m, other, total, total))
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is similar to a line somewhere else.
*/
predicate similarLines(File f, int line) {
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
@@ -152,6 +184,7 @@ private predicate similarLinesCoveredFiles(File f, File otherFile) {
)
}
/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */
predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
similarLinesCoveredFiles(f, otherFile) and
@@ -166,6 +199,11 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
)
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is duplicated by a line somewhere else.
*/
predicate duplicateLines(File f, int line) {
exists(DuplicateBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
@@ -182,6 +220,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F
)
}
/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */
predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
exists(int coveredApprox |
@@ -206,6 +245,7 @@ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
)
}
/** Holds if most of `f` (`percent`%) is similar to `other`. */
predicate similarFiles(File f, File other, int percent) {
exists(int covered, int total |
similarLinesCovered(f, covered, other) and
@@ -216,6 +256,7 @@ predicate similarFiles(File f, File other, int percent) {
not duplicateFiles(f, other, _)
}
/** Holds if most of `f` (`percent`%) is duplicated by `other`. */
predicate duplicateFiles(File f, File other, int percent) {
exists(int covered, int total |
duplicateLinesCovered(f, covered, other) and
@@ -225,6 +266,10 @@ predicate duplicateFiles(File f, File other, int percent) {
)
}
/**
* Holds if most member functions of `c` (`numDup` out of `total`) are
* duplicates of member functions in `other`.
*/
predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup =
strictcount(FunctionDeclarationEntry m1 |
@@ -240,6 +285,11 @@ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total)
(numDup * 100) / total > 80
}
/**
* Holds if most member functions of `c` are duplicates of member functions in
* `other`. Provides the human-readable `message` to describe the amount of
* duplication.
*/
predicate mostlyDuplicateClass(Class c, Class other, string message) {
exists(int numDup, int total |
mostlyDuplicateClassBase(c, other, numDup, total) and
@@ -264,12 +314,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
)
}
/** Holds if `f` and `other` are similar or duplicates. */
predicate fileLevelDuplication(File f, File other) {
similarFiles(f, other, _) or duplicateFiles(f, other, _)
}
/**
* Holds if most member functions of `c` are duplicates of member functions in
* `other`.
*/
predicate classLevelDuplication(Class c, Class other) { mostlyDuplicateClass(c, other, _) }
/**
* Holds if `line` in `f` should be allowed to be duplicated. This is the case
* for `#include` directives.
*/
predicate whitelistedLineForDuplication(File f, int line) {
exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line)
}

View File

@@ -1,92 +0,0 @@
import cpp
class Commit extends @svnentry {
Commit() {
svnaffectedfiles(this, _, _) and
exists(date svnDate, date snapshotDate |
svnentries(this, _, _, svnDate, _) and
snapshotDate(snapshotDate) and
svnDate <= snapshotDate
)
}
string toString() { result = this.getRevisionName() }
string getRevisionName() { svnentries(this, result, _, _, _) }
string getAuthor() { svnentries(this, _, result, _, _) }
date getDate() { svnentries(this, _, _, result, _) }
int getChangeSize() { svnentries(this, _, _, _, result) }
string getMessage() { svnentrymsg(this, result) }
string getAnAffectedFilePath(string action) {
exists(File rawFile | svnaffectedfiles(this, unresolveElement(rawFile), action) |
result = rawFile.getAbsolutePath()
)
}
string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) }
File getAnAffectedFile(string action) {
// Workaround for incorrect keys in SVN data
exists(File svnFile | svnFile.getAbsolutePath() = result.getAbsolutePath() |
svnaffectedfiles(this, unresolveElement(svnFile), action)
) and
exists(result.getMetrics().getNumberOfLinesOfCode())
}
File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) }
private predicate churnForFile(File f, int added, int deleted) {
// Workaround for incorrect keys in SVN data
exists(File svnFile | svnFile.getAbsolutePath() = f.getAbsolutePath() |
svnchurn(this, unresolveElement(svnFile), added, deleted)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
}
int getRecentChurnForFile(File f) {
exists(int added, int deleted | churnForFile(f, added, deleted) and result = added + deleted)
}
int getRecentAdditionsForFile(File f) { churnForFile(f, result, _) }
int getRecentDeletionsForFile(File f) { churnForFile(f, _, result) }
predicate isRecent() { recentCommit(this) }
int daysToNow() {
exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0)
}
}
class Author extends string {
Author() { exists(Commit e | this = e.getAuthor()) }
Commit getACommit() { result.getAuthor() = this }
File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() }
}
predicate recentCommit(Commit e) {
exists(date snapshotDate, date commitDate, int days |
snapshotDate(snapshotDate) and
e.getDate() = commitDate and
days = commitDate.daysTo(snapshotDate) and
days >= 0 and
days <= 60
)
}
date firstChange(File f) {
result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin)
}
predicate firstCommit(Commit e) {
not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate())
}
predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 }

View File

@@ -1,20 +0,0 @@
/**
* @name Defect from SVN
* @description A test case for creating a defect from SVN data.
* @kind problem
* @problem.severity warning
* @tags external-data
* @deprecated
*/
import cpp
import external.ExternalArtifact
import external.VCS
predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) }
predicate maxCommits(int i) { i = max(File f, int j | numCommits(f, j) | j) }
from File f, int i
where numCommits(f, i) and maxCommits(i)
select f, "This file has " + i + " commits."

View File

@@ -1,17 +0,0 @@
/**
* @name Metric from SVN
* @description Find number of commits for a file
* @treemap.warnOn lowValues
* @metricType file
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) }
from File f, int i
where numCommits(f, i)
select f, i

View File

@@ -1,25 +0,0 @@
/**
* @name Filter: exclude results from files that have not recently been
* edited
* @description Use this filter to return results only if they are
* located in files that have been modified in the 60 days
* before the date of the snapshot.
* @kind problem
* @id cpp/recent-defects-filter
* @tags filter
* external-data
* @deprecated
*/
import cpp
import external.DefectFilter
import external.VCS
pragma[noopt]
private predicate recent(File file) {
exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e))
}
from DefectResult res
where recent(res.getFile())
select res, res.getMessage()

View File

@@ -1,25 +0,0 @@
/**
* @name Metric filter: exclude results from files that have not
* recently been edited
* @description Use this filter to return results only if they are
* located in files that have been modified in the 60 days
* before the snapshot.
* @kind treemap
* @id cpp/recent-defects-for-metric-filter
* @tags filter
* external-data
* @deprecated
*/
import cpp
import external.MetricFilter
import external.VCS
pragma[noopt]
private predicate recent(File file) {
exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e))
}
from MetricResult res
where recent(res.getFile())
select res, res.getValue()

View File

@@ -1 +1,7 @@
/**
* DEPRECATED: Objective C is no longer supported.
*
* Import `cpp` instead of `objc`.
*/
import cpp

View File

@@ -98,7 +98,12 @@ class Declaration extends Locatable, @declaration {
this.hasQualifiedName(namespaceQualifier, "", baseName)
}
override string toString() { result = this.getName() }
/**
* Gets a description of this `Declaration` for display purposes.
*/
string getDescription() { result = this.getName() }
final override string toString() { result = this.getDescription() }
/**
* Gets the name of this declaration.

View File

@@ -79,7 +79,10 @@ class Namespace extends NameQualifyingElement, @namespace {
/** Gets the metric namespace. */
MetricNamespace getMetrics() { result = this }
override string toString() { result = this.getQualifiedName() }
/** Gets a version of the `QualifiedName` that is more suitable for display purposes. */
string getFriendlyName() { result = this.getQualifiedName() }
final override string toString() { result = getFriendlyName() }
/** Gets a declaration of (part of) this namespace. */
NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this }
@@ -104,7 +107,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
namespace_decls(underlyingElement(this), unresolveElement(result), _, _)
}
override string toString() { result = this.getNamespace().toString() }
override string toString() { result = this.getNamespace().getFriendlyName() }
/**
* Gets the location of the token preceding the namespace declaration
@@ -150,7 +153,7 @@ class UsingDeclarationEntry extends UsingEntry {
*/
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using " + this.getDeclaration().toString() }
override string toString() { result = "using " + this.getDeclaration().getDescription() }
}
/**
@@ -169,7 +172,7 @@ class UsingDirectiveEntry extends UsingEntry {
*/
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using namespace " + this.getNamespace().toString() }
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
}
/**
@@ -204,7 +207,7 @@ class GlobalNamespace extends Namespace {
*/
deprecated string getFullName() { result = this.getName() }
override string toString() { result = "(global namespace)" }
override string getFriendlyName() { result = "(global namespace)" }
}
/**

View File

@@ -260,24 +260,33 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
*/
int getIndex() { param_decl_bind(underlyingElement(this), result, _) }
private string getAnonymousParameterDescription() {
not exists(getName()) and
exists(string idx |
idx =
((getIndex() + 1).toString() + "th")
.replaceAll("1th", "1st")
.replaceAll("2th", "2nd")
.replaceAll("3th", "3rd")
.replaceAll("11st", "11th")
.replaceAll("12nd", "12th")
.replaceAll("13rd", "13th") and
if exists(getCanonicalName())
then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter"
else result = "declaration of " + idx + " parameter"
)
}
override string toString() {
if exists(getName())
then result = super.toString()
else
exists(string idx |
idx =
((getIndex() + 1).toString() + "th")
.replaceAll("1th", "1st")
.replaceAll("2th", "2nd")
.replaceAll("3th", "3rd")
.replaceAll("11st", "11th")
.replaceAll("12nd", "12th")
.replaceAll("13rd", "13th")
|
if exists(getCanonicalName())
then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter"
else result = "declaration of " + idx + " parameter"
)
isDefinition() and
result = "definition of " + getName()
or
not isDefinition() and
if getName() = getCanonicalName()
then result = "declaration of " + getName()
else result = "declaration of " + getCanonicalName() + " as " + getName()
or
result = getAnonymousParameterDescription()
}
/**

View File

@@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
/** Gets the name of this XML file. */
override string getName() { result = File.super.getAbsolutePath() }
@@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
}
/**

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -86,7 +86,7 @@ class Closure extends Class {
result.getName() = "operator()"
}
override string toString() { result = "decltype([...](...){...})" }
override string getDescription() { result = "decltype([...](...){...})" }
}
/**
@@ -99,7 +99,7 @@ class Closure extends Class {
* ```
*/
class LambdaCapture extends Locatable, @lambdacapture {
override string toString() { result = getField().toString() }
override string toString() { result = getField().getName() }
override string getCanonicalQLClass() { result = "LambdaCapture" }

View File

@@ -5,6 +5,7 @@ private import semmle.code.cpp.ir.dataflow.DataFlow2
private import semmle.code.cpp.ir.dataflow.DataFlow3
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.Taint
private import semmle.code.cpp.models.interfaces.DataFlow
@@ -170,11 +171,34 @@ private predicate hasUpperBoundsCheck(Variable var) {
)
}
private predicate nodeIsBarrierEqualityCandidate(
DataFlow::Node node, Operand access, Variable checkedVar
) {
readsVariable(node.asInstruction(), checkedVar) and
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
}
private predicate nodeIsBarrier(DataFlow::Node node) {
exists(Variable checkedVar |
readsVariable(node.asInstruction(), checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
or
exists(Variable checkedVar, Operand access |
/*
* This node is guarded by a condition that forces the accessed variable
* to equal something else. For example:
* ```
* x = taintsource()
* if (x == 10) {
* taintsink(x); // not considered tainted
* }
* ```
*/
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
}
private predicate nodeIsBarrierIn(DataFlow::Node node) {

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -1,4 +1,4 @@
import default
import cpp
from Class c, string n
where n = count(Class x | x.getName() = c.getName()) + " distinct class(es) called " + c.getName()

View File

@@ -1,4 +1,4 @@
import default
import cpp
import semmle.code.cpp.models.implementations.Allocation
query predicate newExprs(

View File

@@ -1,4 +1,4 @@
import default
import cpp
string getValueCategoryString(Expr expr) {
if expr.isLValueCategory()

View File

@@ -1,4 +1,4 @@
import default
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis
import semmle.code.cpp.ir.internal.IntegerConstant

View File

@@ -1,4 +1,4 @@
import default
import cpp
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis
import semmle.code.cpp.ir.implementation.raw.IR
import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis

View File

@@ -1,4 +1,4 @@
import default
import cpp
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasConfiguration
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR

View File

@@ -1,4 +1,4 @@
import default
import cpp
query predicate classUuids(Class cls, string uuid) {
if exists(cls.getUuid()) then uuid = cls.getUuid() else uuid = ""

View File

@@ -2,7 +2,7 @@ import cpp
class FunctionMonkeyPatch extends Function {
language[monotonicAggregates]
override string toString() {
override string getDescription() {
exists(string name, string templateArgs, string args |
result = name + templateArgs + args and
name = this.getQualifiedName() and
@@ -30,7 +30,9 @@ class FunctionMonkeyPatch extends Function {
}
class ParameterMonkeyPatch extends Parameter {
override string toString() { result = super.getType().getName() + " " + super.toString() }
override string getDescription() {
result = super.getType().getName() + " " + super.getDescription()
}
}
from Element e, Element ti

View File

@@ -1,7 +1,7 @@
| templates.cpp:9:5:9:14 | using c |
| usings.cpp:8:1:8:11 | using nf |
| usings.cpp:9:1:9:17 | using namespace N |
| usings.cpp:18:3:18:13 | using bf |
| usings.cpp:21:5:21:14 | using gf |
| usings.cpp:34:3:34:20 | using tbf |
| usings.cpp:42:5:42:22 | using foo |
| templates.cpp:9:5:9:14 | using c | UsingDeclarationEntry, enclosingElement:std |
| usings.cpp:8:1:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) |
| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) |
| usings.cpp:18:3:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D |
| usings.cpp:21:5:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } |
| usings.cpp:34:3:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD |
| usings.cpp:42:5:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar |

View File

@@ -1,4 +1,14 @@
import cpp
string describe(UsingEntry ue) {
ue instanceof UsingDeclarationEntry and
result = "UsingDeclarationEntry"
or
ue instanceof UsingDirectiveEntry and
result = "UsingDirectiveEntry"
or
result = "enclosingElement:" + ue.getEnclosingElement().toString()
}
from UsingEntry ue
select ue
select ue, concat(describe(ue), ", ")

View File

@@ -1,7 +0,0 @@
| templates.cpp:9:5:9:14 | using c | file://:0:0:0:0 | std |
| usings.cpp:8:1:8:11 | using nf | file://:0:0:0:0 | (global namespace) |
| usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) |
| usings.cpp:18:3:18:13 | using bf | usings.cpp:16:8:16:8 | D |
| usings.cpp:21:5:21:14 | using gf | usings.cpp:20:13:23:3 | { ... } |
| usings.cpp:34:3:34:20 | using tbf | usings.cpp:32:8:32:9 | TD |
| usings.cpp:42:5:42:22 | using foo | usings.cpp:41:11:41:15 | nsbar |

View File

@@ -1,5 +0,0 @@
import cpp
from UsingEntry ue, Element e
where e = ue.getEnclosingElement()
select ue, e

View File

@@ -68,6 +68,26 @@ edges
| test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... |
| test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s |
| test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s |
| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument |
| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument |
| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi |
| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi |
| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... |
| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... |
| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... |
| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... |
| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... |
| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... |
| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... |
| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... |
| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... |
| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... |
| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... |
| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... |
| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... |
| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... |
| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... |
| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... |
nodes
| field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv |
| field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... |
@@ -140,6 +160,32 @@ nodes
| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
| test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... |
| test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... |
| test.cpp:241:2:241:32 | Chi | semmle.label | Chi |
| test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:249:20:249:33 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:301:19:301:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:301:19:301:32 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:309:19:309:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:309:19:309:32 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... |
#select
| field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) |
| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
@@ -155,3 +201,8 @@ nodes
| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) |
| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) |
| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) |
| test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) |
| test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) |
| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (getenv) |
| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (getenv) |

View File

@@ -236,3 +236,81 @@ void more_cases() {
my_func(100); // GOOD
my_func(local_size); // GOOD
}
bool get_size(int &out_size) {
out_size = atoi(getenv("USER"));
return true;
}
void equality_cases() {
{
int size1 = atoi(getenv("USER"));
int size2 = atoi(getenv("USER"));
if (size1 == 100)
{
malloc(size2 * sizeof(int)); // BAD
}
if (size2 == 100)
{
malloc(size2 * sizeof(int)); // GOOD
}
}
{
int size = atoi(getenv("USER"));
if (size != 100)
return;
malloc(size * sizeof(int)); // GOOD
}
{
int size;
if ((get_size(size)) && (size == 100))
{
malloc(size * sizeof(int)); // GOOD
}
}
{
int size;
if ((get_size(size)) && (size != 100))
{
malloc(size * sizeof(int)); // BAD
}
}
{
int size;
if ((!get_size(size)) || (size != 100))
return;
malloc(size * sizeof(int)); // GOOD
}
{
int size;
if ((!get_size(size)) || (size == 100))
return;
malloc(size * sizeof(int)); // BAD
}
{
int size = atoi(getenv("USER"));
if ((size == 50) || (size == 100))
{
malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE]
}
}
{
int size = atoi(getenv("USER"));
if (size != 50 && size != 100)
return;
malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE]
}
}

View File

@@ -5,5 +5,4 @@
| test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value |
| test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |
| test.c:76:3:76:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |
| test.c:114:9:114:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:108:17:108:23 | 2147483647 | Extreme value |
| test.c:124:9:124:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:118:17:118:23 | 2147483647 | Extreme value |

View File

@@ -111,7 +111,7 @@ void test_guards3(int cond) {
if (x != 0) return;
return x + 1; // GOOD [FALSE POSITIVE]
return x + 1; // GOOD
}
void test_guards4(int cond) {

View File

@@ -1160,26 +1160,6 @@ class UsingStmt extends Stmt, @using_stmt {
* ```
*/
Expr getAnExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getExpr() instead.
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
deprecated Expr getExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getBody() instead.
* Gets the body of this `using` statement.
*/
deprecated Stmt getBody() { none() }
}
/**
@@ -1212,7 +1192,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt {
* }
* ```
*/
override Expr getExpr() { result = this.getChild(0) }
Expr getExpr() { result = this.getChild(0) }
override Expr getAnExpr() {
result = this.getAVariableDeclExpr().getInitializer()
@@ -1221,7 +1201,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt {
}
/** Gets the body of this `using` statement. */
override Stmt getBody() { result.getParent() = this }
Stmt getBody() { result.getParent() = this }
override string toString() { result = "using (...) {...}" }
}

View File

@@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
/** Gets the name of this XML file. */
override string getName() { result = File.super.getAbsolutePath() }
@@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
}
/**

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -0,0 +1,17 @@
public boolean shouldOverrideUrlLoading(WebView view, String url) {
{
Uri uri = Uri.parse(url);
// BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification
if (uri.getHost() != null && uri.getHost().endsWith("example.com")) {
return false;
}
}
{
Uri uri = Uri.parse(url);
// GOOD: full domain match
if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) {
return false;
}
}
}

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.</p>
</overview>
<recommendation>
<p>Verify the whole host and domain (FQDN) or check endsWith dot+domain.</p>
</recommendation>
<example>
<p>The following example shows two ways of verifying host domain. In the 'BAD' case,
verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.</p>
<sample src="IncorrectURLVerification.java" />
</example>
<references>
<li>
<a href="https://drive.google.com/file/d/0BwMN49Gzo3x6T1N5WGQ4TTNlMHBOb1ZRQTVEWnVBZjFUaE5N/view">Common Android app vulnerabilities from Sebastian Porst of Google</a>
</li>
<li>
<a href="https://www.bugcrowd.com/resources/webinars/overview-of-common-android-app-vulnerabilities/">Common Android app vulnerabilities from bugcrowd</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,97 @@
/**
* @id java/incorrect-url-verification
* @name Incorrect URL verification
* @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification.
* @kind problem
* @tags security
* external/cwe-939
*/
import java
/**
* The Java class `android.R.string` specific to Android applications, which contains references to application specific resources defined in /res/values/strings.xml.
* For example, <resources>...<string name="host">example.com</string>...</resources> in the application com.example.android.web can be referred as R.string.host with the type com.example.android.web.R$string
*/
class AndroidRString extends RefType {
AndroidRString() { this.hasQualifiedName(_, "R$string") }
}
/**
* The Java class `android.net.Uri` and `java.net.URL`.
*/
class Uri extends RefType {
Uri() {
hasQualifiedName("android.net", "Uri") or
hasQualifiedName("java.net", "URL")
}
}
/**
* The method `getHost()` declared in `android.net.Uri` and `java.net.URL`.
*/
class UriGetHostMethod extends Method {
UriGetHostMethod() {
getDeclaringType() instanceof Uri and
hasName("getHost") and
getNumberOfParameters() = 0
}
}
/**
* The method access with incorrect string comparision
*/
class HostVerificationMethodAccess extends MethodAccess {
HostVerificationMethodAccess() {
(
this.getMethod().hasName("endsWith") or
this.getMethod().hasName("contains") or
this.getMethod().hasName("indexOf")
) and
this.getMethod().getNumberOfParameters() = 1 and
(
this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." //string constant comparison e.g. uri.getHost().endsWith("example.com")
or
this
.getArgument(0)
.(AddExpr)
.getLeftOperand()
.(VarAccess)
.getVariable()
.getAnAssignedValue()
.(StringLiteral)
.getRepresentedString()
.charAt(0) != "." //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com")
or
this
.getArgument(0)
.(AddExpr)
.getLeftOperand()
.(StringLiteral)
.getRepresentedString()
.charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName)
or
exists(MethodAccess ma, Method m, Field f |
this.getArgument(0) = ma and
ma.getMethod() = m and
m.hasName("getString") and
m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and
ma.getArgument(0).(FieldRead).getField() = f and
f.getDeclaringType() instanceof AndroidRString
) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key)
or
this
.getArgument(0)
.(VarAccess)
.getVariable()
.getAnAssignedValue()
.(StringLiteral)
.getRepresentedString()
.charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName)
)
}
}
from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma
where hma.getQualifier() = uma and uma.getMethod() = um
select hma, "Method has potentially $@ ", hma.getArgument(0), "improper URL verification"

View File

@@ -22,8 +22,7 @@ class TypeAuthorizedUrl extends Class {
}
/**
* The class
* `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`.
* The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`.
*/
class TypeAbstractRequestMatcherRegistry extends Class {
TypeAbstractRequestMatcherRegistry() {
@@ -34,38 +33,44 @@ class TypeAbstractRequestMatcherRegistry extends Class {
}
/**
* The class
* `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`.
* The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`.
*/
class TypeEndpointRequestMatcher extends Class {
TypeEndpointRequestMatcher() {
class TypeEndpointRequest extends Class {
TypeEndpointRequest() {
this
.hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet",
"EndpointRequest$EndpointRequestMatcher")
"EndpointRequest")
}
}
/** A call to `EndpointRequest.toAnyEndpoint` method. */
class ToAnyEndpointCall extends MethodAccess {
ToAnyEndpointCall() {
getMethod().hasName("toAnyEndpoint") and
getMethod().getDeclaringType() instanceof TypeEndpointRequest
}
}
/**
* A call to `HttpSecurity.requestMatcher` method with argument of type
* `EndpointRequestMatcher`.
* A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`.
*/
class RequestMatcherCall extends MethodAccess {
RequestMatcherCall() {
getMethod().hasName("requestMatcher") and
getMethod().getDeclaringType() instanceof TypeHttpSecurity and
getArgument(0).getType() instanceof TypeEndpointRequestMatcher
getArgument(0) instanceof ToAnyEndpointCall
}
}
/**
* A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to
* `EndpointRequestMatcher` type.
* A call to `HttpSecurity.requestMatchers` method with lambda argument
* `RequestMatcher.toAnyEndpoint()`.
*/
class RequestMatchersCall extends MethodAccess {
RequestMatchersCall() {
getMethod().hasName("requestMatchers") and
getMethod().getDeclaringType() instanceof TypeHttpSecurity and
getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher
getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall
}
}
@@ -92,9 +97,6 @@ class PermitAllCall extends MethodAccess {
or
// .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...]
authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall
or
// http.authorizeRequests([...]).[...]
authorizeRequestsCall.getQualifier() instanceof VarAccess
|
// [...].authorizeRequests(r -> r.anyRequest().permitAll()) or
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
@@ -117,6 +119,22 @@ class PermitAllCall extends MethodAccess {
this.getQualifier() = anyRequestCall
)
)
or
exists(AuthorizeRequestsCall authorizeRequestsCall |
// http.authorizeRequests([...]).[...]
authorizeRequestsCall.getQualifier() instanceof VarAccess
|
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and
this.getQualifier() instanceof RegistryRequestMatchersCall
or
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
authorizeRequestsCall.getNumArgument() = 0 and
exists(RegistryRequestMatchersCall registryRequestMatchersCall |
registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and
this.getQualifier() = registryRequestMatchersCall
)
)
}
}
@@ -129,13 +147,13 @@ class AnyRequestCall extends MethodAccess {
}
/**
* A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type
* `EndpointRequestMatcher`.
* A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument
* `RequestMatcher.toAnyEndpoint()`.
*/
class RegistryRequestMatchersCall extends MethodAccess {
RegistryRequestMatchersCall() {
getMethod().hasName("requestMatchers") and
getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and
getAnArgument().getType() instanceof TypeEndpointRequestMatcher
getAnArgument() instanceof ToAnyEndpointCall
}
}

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -66,9 +66,6 @@ abstract class Configuration extends string {
*/
predicate isBarrier(Node node) { none() }
/** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
deprecated predicate isBarrierEdge(Node node1, Node node2) { none() }
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }

View File

@@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
/** Gets the name of this XML file. */
override string getName() { result = File.super.getAbsolutePath() }
@@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
}
/**

View File

@@ -37,4 +37,68 @@ public class SpringBootActuators {
protected void configureOk2(HttpSecurity http) throws Exception {
http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint());
}
protected void configureOk3(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
protected void configureOk4(HttpSecurity http) throws Exception {
http.authorizeRequests(authz -> authz.anyRequest().permitAll());
}
protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll());
}
protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll();
}
protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception {
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
}
protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
}
protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception {
http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
}
protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception {
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll());
}
protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception {
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
}
protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest());
}
protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
}
protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception {
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
}
protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
}
protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception {
http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
}
protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception {
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()));
}
protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception {
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
}
}

View File

@@ -7,6 +7,10 @@ public final class EndpointRequest {
public static EndpointRequestMatcher toAnyEndpoint() {
return null;
}
public static EndpointRequestMatcher to(String... endpoints) {
return null;
}
public static final class EndpointRequestMatcher extends AbstractRequestMatcher {}

View File

@@ -261,6 +261,11 @@ predicate similarContainers(StmtContainer sc, StmtContainer other, float percent
)
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is similar to a line somewhere else.
*/
predicate similarLines(File f, int line) {
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
@@ -275,6 +280,7 @@ private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, Fil
)
}
/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */
pragma[noopt]
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
@@ -296,6 +302,11 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile)
)
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is duplicated by a line somewhere else.
*/
predicate duplicateLines(File f, int line) {
exists(DuplicateBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
@@ -312,6 +323,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F
)
}
/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */
pragma[noopt]
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
@@ -333,6 +345,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile
)
}
/** Holds if most of `f` (`percent`%) is similar to `other`. */
predicate similarFiles(File f, File other, int percent) {
exists(int covered, int total |
similarLinesCovered(f, covered, other) and
@@ -343,6 +356,7 @@ predicate similarFiles(File f, File other, int percent) {
not duplicateFiles(f, other, _)
}
/** Holds if most of `f` (`percent`%) is duplicated by `other`. */
predicate duplicateFiles(File f, File other, int percent) {
exists(int covered, int total |
duplicateLinesCovered(f, covered, other) and

View File

@@ -152,6 +152,18 @@ private class RequireVariable extends Variable {
*/
private predicate moduleInFile(Module m, File f) { m.getFile() = f }
/**
* Holds if `nd` may refer to `require`, either directly or modulo local data flow.
*/
cached
private predicate isRequire(DataFlow::Node nd) {
nd.asExpr() = any(RequireVariable req).getAnAccess() and
// `mjs` files explicitly disallow `require`
not nd.getFile().getExtension() = "mjs"
or
isRequire(nd.getAPredecessor())
}
/**
* A `require` import.
*
@@ -162,12 +174,7 @@ private predicate moduleInFile(Module m, File f) { m.getFile() = f }
* ```
*/
class Require extends CallExpr, Import {
cached
Require() {
any(RequireVariable req).getAnAccess() = getCallee() and
// `mjs` files explicitly disallow `require`
not getFile().getExtension() = "mjs"
}
Require() { isRequire(getCallee().flow()) }
override PathExpr getImportedPath() { result = getArgument(0) }
@@ -257,8 +264,8 @@ private class RequirePath extends PathExprCandidate {
RequirePath() {
this = any(Require req).getArgument(0)
or
exists(RequireVariable req, MethodCallExpr reqres |
reqres.getReceiver() = req.getAnAccess() and
exists(MethodCallExpr reqres |
isRequire(reqres.getReceiver().flow()) and
reqres.getMethodName() = "resolve" and
this = reqres.getArgument(0)
)

View File

@@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
/** Gets the name of this XML file. */
override string getName() { result = File.super.getAbsolutePath() }
@@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override string toString() { result = XMLParent.super.toString() }
override string toString() { result = getName() }
}
/**

View File

@@ -151,11 +151,14 @@ private module CachedSteps {
) {
calls(invk, f) and
(
exists(int i, Parameter p |
f.getParameter(i) = p and
not p.isRestParameter() and
arg = invk.getArgument(i) and
parm = DataFlow::parameterNode(p)
exists(int i | arg = invk.getArgument(i) |
exists(Parameter p |
f.getParameter(i) = p and
not p.isRestParameter() and
parm = DataFlow::parameterNode(p)
)
or
parm = reflectiveParameterAccess(f, i)
)
or
arg = invk.(DataFlow::CallNode).getReceiver() and
@@ -185,6 +188,22 @@ private module CachedSteps {
)
}
/**
* Gets a data-flow node inside `f` that refers to the `arguments` object of `f`.
*/
private DataFlow::Node argumentsAccess(Function f) {
result.getContainer().getEnclosingContainer*() = f and
result.analyze().getAValue().(AbstractArguments).getFunction() = f
}
/**
* Gets a data-flow node that refers to the `i`th parameter of `f` through its `arguments`
* object.
*/
private DataFlow::SourceNode reflectiveParameterAccess(Function f, int i) {
result.(DataFlow::PropRead).accesses(argumentsAccess(f), any(string p | i = p.toInt()))
}
/**
* Holds if there is a flow step from `pred` to `succ` through parameter passing
* to a function call.

View File

@@ -0,0 +1,291 @@
/**
* Provides classes for working with [Fastify](https://www.fastify.io/) applications.
*/
import javascript
import semmle.javascript.frameworks.HTTP
/**
* Provides classes for working with [Fastify](https://www.fastify.io/) applications.
*/
module Fastify {
/**
* An expression that creates a new Fastify server.
*/
abstract class ServerDefinition extends HTTP::Servers::StandardServerDefinition { }
/**
* A standard way to create a Fastify server.
*/
class StandardServerDefinition extends ServerDefinition {
StandardServerDefinition() {
this = DataFlow::moduleImport("fastify").getAnInvocation().asExpr()
}
}
/**
* A function used as a Fastify route handler.
*
* By default, only handlers installed by a Fastify route setup are recognized,
* but support for other kinds of route handlers can be added by implementing
* additional subclasses of this class.
*/
abstract class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode {
/**
* Gets the parameter of the route handler that contains the request object.
*/
abstract DataFlow::ParameterNode getRequestParameter();
/**
* Gets the parameter of the route handler that contains the reply object.
*/
abstract DataFlow::ParameterNode getReplyParameter();
}
/**
* A Fastify route handler installed by a route setup.
*/
class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode {
StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) }
override DataFlow::ParameterNode getReplyParameter() { result = this.getParameter(1) }
}
/**
* A Fastify reply source, that is, the `reply` parameter of a
* route handler.
*/
private class ReplySource extends HTTP::Servers::ResponseSource {
RouteHandler rh;
ReplySource() { this = rh.getReplyParameter() }
/**
* Gets the route handler that provides this response.
*/
override RouteHandler getRouteHandler() { result = rh }
}
/**
* A Fastify request source, that is, the request parameter of a
* route handler.
*/
private class RequestSource extends HTTP::Servers::RequestSource {
RouteHandler rh;
RequestSource() { this = rh.getRequestParameter() }
/**
* Gets the route handler that handles this request.
*/
override RouteHandler getRouteHandler() { result = rh }
}
/**
* A call to a Fastify method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
string methodName;
RouteSetup() {
this.getMethodName() = methodName and
methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] and
server.flowsTo(this.getReceiver())
}
override DataFlow::SourceNode getARouteHandler() {
result = getARouteHandler(DataFlow::TypeBackTracker::end())
}
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and
result = this.getARouteHandlerExpr().getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t))
}
override Expr getServer() { result = server }
/** Gets an argument that represents a route handler being registered. */
private DataFlow::Node getARouteHandlerExpr() {
if methodName = "route"
then
result =
this
.flow()
.(DataFlow::MethodCallNode)
.getOptionArgument(0,
["onRequest", "preParsing", "preValidation", "preHandler", "preSerialization",
"onSend", "onResponse", "handler"])
else result = getLastArgument().flow()
}
}
/**
* An access to a user-controlled Fastify request input.
*/
private class RequestInputAccess extends HTTP::RequestInputAccess {
RouteHandler rh;
string kind;
RequestInputAccess() {
exists(string name | this = rh.getARequestSource().ref().getAPropertyRead(name) |
kind = "parameter" and
name = ["params", "query"]
or
kind = "body" and
name = "body"
)
}
override RouteHandler getRouteHandler() { result = rh }
override string getKind() { result = kind }
override predicate isUserControlledObject() {
kind = "body" and
(
usesFastifyPlugin(rh,
DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"]))
or
usesMiddleware(rh,
any(ExpressLibraries::BodyParser bodyParser | bodyParser.producesUserControlledObjects()))
)
or
kind = "parameter" and
usesFastifyPlugin(rh, DataFlow::moduleImport("fastify-qs"))
}
}
/**
* Holds if `rh` uses `plugin`.
*/
private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) {
exists(RouteSetup setup |
plugin
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("register")
.getArgument(0)) and // only matches the plugins that apply to all routes
rh = setup.getARouteHandler()
)
}
/**
* Holds if `rh` uses `plugin`.
*/
private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) {
exists(RouteSetup setup |
middleware
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("use")
.getArgument(0)) and // only matches the middlewares that apply to all routes
rh = setup.getARouteHandler()
)
}
/**
* An access to a header on a Fastify request.
*/
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
RouteHandler rh;
RequestHeaderAccess() {
this = rh.getARequestSource().ref().getAPropertyRead("headers").getAPropertyRead()
}
override string getAHeaderName() {
result = this.(DataFlow::PropRead).getPropertyName().toLowerCase()
}
override RouteHandler getRouteHandler() { result = rh }
override string getKind() { result = "header" }
}
/**
* An argument passed to the `send` or `end` method of an HTTP response object.
*/
private class ResponseSendArgument extends HTTP::ResponseSendArgument {
RouteHandler rh;
ResponseSendArgument() {
this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0).asExpr()
or
this = rh.(DataFlow::FunctionNode).getAReturn().asExpr()
}
override RouteHandler getRouteHandler() { result = rh }
}
/**
* An invocation of the `redirect` method of an HTTP response object.
*/
private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr {
RouteHandler rh;
RedirectInvocation() {
this = rh.getAResponseSource().ref().getAMethodCall("redirect").asExpr()
}
override Expr getUrlArgument() { result = this.getLastArgument() }
override RouteHandler getRouteHandler() { result = rh }
}
/**
* An invocation that sets a single header of the HTTP response.
*/
private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition,
DataFlow::MethodCallNode {
RouteHandler rh;
SetOneHeader() {
this = rh.getAResponseSource().ref().getAMethodCall("header") and
this.getNumArgument() = 2
}
override RouteHandler getRouteHandler() { result = rh }
}
/**
* An invocation that sets any number of headers of the HTTP response.
*/
class SetMultipleHeaders extends HTTP::ExplicitHeaderDefinition, DataFlow::MethodCallNode {
RouteHandler rh;
SetMultipleHeaders() {
this = rh.getAResponseSource().ref().getAMethodCall("headers") and
this.getNumArgument() = 1
}
/**
* Gets a reference to the multiple headers object that is to be set.
*/
private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) }
override predicate definesExplicitly(string headerName, Expr headerValue) {
exists(string header |
getAHeaderSource().hasPropertyWrite(header, headerValue.flow()) and
headerName = header.toLowerCase()
)
}
override RouteHandler getRouteHandler() { result = rh }
override Expr getNameExpr() {
exists(DataFlow::PropWrite write |
this.getAHeaderSource().flowsTo(write.getBase()) and
result = write.getPropertyNameExpr()
)
}
}
}

View File

@@ -4,3 +4,4 @@ import semmle.javascript.frameworks.Koa
import semmle.javascript.frameworks.NodeJSLib
import semmle.javascript.frameworks.Restify
import semmle.javascript.frameworks.Connect
import semmle.javascript.frameworks.Fastify

View File

@@ -0,0 +1,10 @@
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:16:2:16 | x |
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:4:28:4:39 | arguments[0] |
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:10:11:10 | 2 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:5:25:5:36 | arguments[1] |
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:13:11:13 | 3 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:7:24:7:30 | args[2] |
| sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:5:4:5:5 | 23 | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:11:3:11 | x |
| tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:20:4:20:8 | "arg" | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:13:16:13 | a |
| tst.js:35:1:35:7 | g(true) | tst.js:35:3:35:6 | true | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:12:32:12 | b |
| tst.js:44:1:44:5 | o.m() | tst.js:44:1:44:1 | o | tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:39:4:39:3 | this |
| tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:11:87:24 | { p: x, ...o } |
| tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:11:98:24 | [ x, ...rest ] |

View File

@@ -0,0 +1,6 @@
import javascript
import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
from DataFlow::Node invk, DataFlow::Node arg, Function f, DataFlow::SourceNode parm
where FlowSteps::argumentPassing(invk, arg, f, parm)
select invk, arg, f, parm

View File

@@ -0,0 +1,12 @@
(function() {
function f(x) {
let firstArg = x;
let alsoFirstArg = arguments[0];
let secondArg = arguments[1];
let args = arguments;
let thirdArg = args[2];
arguments = {};
let notFirstArg = arguments[0];
}
f(1, 2, 3);
})();

View File

@@ -1,3 +1,42 @@
| arguments.js:1:1:12:2 | (functi ... 3);\\n}) | arguments.js:1:1:12:2 | (functi ... 3);\\n}) |
| arguments.js:1:1:12:4 | (functi ... );\\n})() | arguments.js:1:1:12:4 | (functi ... );\\n})() |
| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:2:12:1 | functio ... , 3);\\n} |
| arguments.js:2:14:2:14 | f | arguments.js:2:14:2:14 | f |
| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x |
| arguments.js:3:13:3:20 | firstArg | arguments.js:3:13:3:20 | firstArg |
| arguments.js:3:13:3:24 | firstArg = x | arguments.js:3:13:3:24 | firstArg = x |
| arguments.js:3:24:3:24 | x | arguments.js:3:24:3:24 | x |
| arguments.js:4:13:4:24 | alsoFirstArg | arguments.js:4:13:4:24 | alsoFirstArg |
| arguments.js:4:13:4:39 | alsoFir ... ents[0] | arguments.js:4:13:4:39 | alsoFir ... ents[0] |
| arguments.js:4:28:4:36 | arguments | arguments.js:4:28:4:36 | arguments |
| arguments.js:4:28:4:39 | arguments[0] | arguments.js:4:28:4:39 | arguments[0] |
| arguments.js:4:38:4:38 | 0 | arguments.js:4:38:4:38 | 0 |
| arguments.js:5:13:5:21 | secondArg | arguments.js:5:13:5:21 | secondArg |
| arguments.js:5:13:5:36 | secondA ... ents[1] | arguments.js:5:13:5:36 | secondA ... ents[1] |
| arguments.js:5:25:5:33 | arguments | arguments.js:5:25:5:33 | arguments |
| arguments.js:5:25:5:36 | arguments[1] | arguments.js:5:25:5:36 | arguments[1] |
| arguments.js:5:35:5:35 | 1 | arguments.js:5:35:5:35 | 1 |
| arguments.js:6:13:6:16 | args | arguments.js:6:13:6:16 | args |
| arguments.js:6:13:6:28 | args = arguments | arguments.js:6:13:6:28 | args = arguments |
| arguments.js:6:20:6:28 | arguments | arguments.js:6:20:6:28 | arguments |
| arguments.js:7:13:7:20 | thirdArg | arguments.js:7:13:7:20 | thirdArg |
| arguments.js:7:13:7:30 | thirdArg = args[2] | arguments.js:7:13:7:30 | thirdArg = args[2] |
| arguments.js:7:24:7:27 | args | arguments.js:7:24:7:27 | args |
| arguments.js:7:24:7:30 | args[2] | arguments.js:7:24:7:30 | args[2] |
| arguments.js:7:29:7:29 | 2 | arguments.js:7:29:7:29 | 2 |
| arguments.js:8:9:8:17 | arguments | arguments.js:8:9:8:17 | arguments |
| arguments.js:8:9:8:22 | arguments = {} | arguments.js:8:9:8:22 | arguments = {} |
| arguments.js:8:21:8:22 | {} | arguments.js:8:21:8:22 | {} |
| arguments.js:9:13:9:23 | notFirstArg | arguments.js:9:13:9:23 | notFirstArg |
| arguments.js:9:13:9:38 | notFirs ... ents[0] | arguments.js:9:13:9:38 | notFirs ... ents[0] |
| arguments.js:9:27:9:35 | arguments | arguments.js:9:27:9:35 | arguments |
| arguments.js:9:27:9:38 | arguments[0] | arguments.js:9:27:9:38 | arguments[0] |
| arguments.js:9:37:9:37 | 0 | arguments.js:9:37:9:37 | 0 |
| arguments.js:11:5:11:5 | f | arguments.js:11:5:11:5 | f |
| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:5:11:14 | f(1, 2, 3) |
| arguments.js:11:7:11:7 | 1 | arguments.js:11:7:11:7 | 1 |
| arguments.js:11:10:11:10 | 2 | arguments.js:11:10:11:10 | 2 |
| arguments.js:11:13:11:13 | 3 | arguments.js:11:13:11:13 | 3 |
| eval.js:1:10:1:10 | k | eval.js:1:10:1:10 | k |
| eval.js:2:7:2:7 | x | eval.js:2:7:2:7 | x |
| eval.js:2:7:2:12 | x = 42 | eval.js:2:7:2:12 | x = 42 |

View File

@@ -1,3 +1,16 @@
| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) |
| arguments.js:2:5:2:5 | arguments | arguments.js:4:28:4:36 | arguments |
| arguments.js:2:5:2:5 | arguments | arguments.js:5:25:5:33 | arguments |
| arguments.js:2:5:2:5 | arguments | arguments.js:6:20:6:28 | arguments |
| arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:14:2:14 | f |
| arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f |
| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x |
| arguments.js:2:16:2:16 | x | arguments.js:3:24:3:24 | x |
| arguments.js:6:13:6:28 | args | arguments.js:7:24:7:27 | args |
| arguments.js:6:20:6:28 | arguments | arguments.js:6:13:6:28 | args |
| arguments.js:8:9:8:22 | arguments | arguments.js:9:27:9:35 | arguments |
| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments |
| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments = {} |
| eval.js:2:7:2:12 | x | eval.js:4:3:4:3 | x |
| eval.js:2:11:2:12 | 42 | eval.js:2:7:2:12 | x |
| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x |

View File

@@ -1,3 +1,10 @@
| arguments.js:4:38:4:38 | 0 | 0 |
| arguments.js:5:35:5:35 | 1 | 1 |
| arguments.js:7:29:7:29 | 2 | 2 |
| arguments.js:9:37:9:37 | 0 | 0 |
| arguments.js:11:7:11:7 | 1 | 1 |
| arguments.js:11:10:11:10 | 2 | 2 |
| arguments.js:11:13:11:13 | 3 | 3 |
| eval.js:2:11:2:12 | 42 | 42 |
| sources.js:4:12:4:13 | 19 | 19 |
| sources.js:5:4:5:5 | 23 | 23 |

View File

@@ -1,3 +1,13 @@
| arguments.js:1:1:12:4 | exceptional return of (functi ... );\\n})() | call |
| arguments.js:1:2:12:1 | exceptional return of anonymous function | call |
| arguments.js:2:5:10:5 | exceptional return of function f | call |
| arguments.js:2:16:2:16 | x | call |
| arguments.js:4:28:4:39 | arguments[0] | heap |
| arguments.js:5:25:5:36 | arguments[1] | heap |
| arguments.js:7:24:7:30 | args[2] | heap |
| arguments.js:9:27:9:38 | arguments[0] | heap |
| arguments.js:11:5:11:14 | exceptional return of f(1, 2, 3) | call |
| arguments.js:11:5:11:14 | f(1, 2, 3) | call |
| eval.js:1:1:5:1 | exceptional return of function k | call |
| eval.js:2:7:2:12 | x | eval |
| eval.js:3:3:3:6 | eval | global |

View File

@@ -1,3 +1,4 @@
| arguments.js:2:16:2:16 | x |
| sources.js:1:6:1:6 | x |
| sources.js:3:11:3:11 | x |
| sources.js:9:14:9:18 | array |

View File

@@ -1,3 +1,16 @@
| arguments.js:1:1:1:0 | this |
| arguments.js:1:1:12:4 | (functi ... );\\n})() |
| arguments.js:1:2:1:1 | this |
| arguments.js:1:2:12:1 | functio ... , 3);\\n} |
| arguments.js:2:5:2:4 | this |
| arguments.js:2:5:10:5 | functio ... ;\\n } |
| arguments.js:2:16:2:16 | x |
| arguments.js:4:28:4:39 | arguments[0] |
| arguments.js:5:25:5:36 | arguments[1] |
| arguments.js:7:24:7:30 | args[2] |
| arguments.js:8:21:8:22 | {} |
| arguments.js:9:27:9:38 | arguments[0] |
| arguments.js:11:5:11:14 | f(1, 2, 3) |
| eval.js:1:1:1:0 | this |
| eval.js:1:1:1:0 | this |
| eval.js:1:1:5:1 | functio ... eval`\\n} |

View File

@@ -11,6 +11,8 @@
| d.js:7:1:7:14 | require('foo') |
| e.js:5:1:5:18 | require("process") |
| f.js:2:1:2:7 | r("fs") |
| g.js:1:1:1:96 | (proces ... https") |
| g.js:1:43:1:61 | require("electron") |
| index.js:1:12:1:26 | require('path') |
| index.js:2:1:2:41 | require ... b.js")) |
| mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') |

View File

@@ -0,0 +1 @@
(process && "renderer" === process.type ? require("electron").remote.require : require)("https");

View File

@@ -31,6 +31,7 @@ typeInferenceMismatch
| callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x |
| callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y |
| callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y |
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() |
| captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x |
| closure.js:6:15:6:22 | source() | closure.js:8:8:8:31 | string. ... (taint) |
| closure.js:6:15:6:22 | source() | closure.js:9:8:9:25 | string.trim(taint) |

Some files were not shown because too many files have changed in this diff Show More