From 25985e901bf5020f0fb6d9e7857d6c081d47e1fe Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 26 Sep 2019 17:53:10 +0200 Subject: [PATCH 001/148] Python: Remove a few false positives from `py/unused-import`. --- python/ql/src/Imports/UnusedImport.ql | 25 ++++++++++++++++--- .../Imports/unused/imports_test.py | 14 +++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 6d927550c0c..d87b0efd254 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -58,16 +58,28 @@ predicate imported_module_used_in_doctest(Import imp) { } predicate imported_module_used_in_typehint(Import imp) { - exists(string modname | - imp.getAName().getAsname().(Name).getId() = modname - and + exists(string modname, Location loc | + imp.getAName().getAsname().(Name).getId() = modname and + loc.getFile() = imp.getScope().(Module).getFile() + | /* Look for typehints containing the patterns: * # type: …name… */ exists(Comment typehint | - typehint.getLocation().getFile() = imp.getScope().(Module).getFile() and + loc = typehint.getLocation() and typehint.getText().regexpMatch("# type:.*" + modname + ".*") ) + or + // Type hint is inside a string annotation, as needed for forward references + exists(string typehint, Expr annotation | + annotation = any(Arguments a).getAnAnnotation() + or + annotation = any(AnnAssign a).getAnnotation() + | + annotation.pointsTo(Value::forString(typehint)) and + loc = annotation.getLocation() and + typehint.regexpMatch(".*\\b" + modname + "\\b.*") + ) ) } @@ -100,6 +112,11 @@ predicate unused_import(Import imp, Variable name) { not imported_module_used_in_doctest(imp) and not imported_module_used_in_typehint(imp) + and + /* Only consider import statements that actually point-to something (possibly an unknown module). + * If this is not the case, it's likely that the import statement never gets executed. + */ + imp.getAName().getValue().pointsTo(_) } diff --git a/python/ql/test/query-tests/Imports/unused/imports_test.py b/python/ql/test/query-tests/Imports/unused/imports_test.py index a1b457f0422..cf2024ac183 100644 --- a/python/ql/test/query-tests/Imports/unused/imports_test.py +++ b/python/ql/test/query-tests/Imports/unused/imports_test.py @@ -76,3 +76,17 @@ import typing foo = None # type: typing.Optional[int] + +# OK since the import statement is never executed +if False: + import never_imported + +# OK since the imported module is used in a forward-referenced type annotation. +import only_used_in_parameter_annotation + +def func(x: 'Optional[only_used_in_parameter_annotation]'): + pass + +import only_used_in_annotated_assignment + +var : 'Optional[only_used_in_annotated_assignment]' = 5 From 4341e88fc4dbeeb24aae204c0288693d3e87bd04 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 13:03:27 +0200 Subject: [PATCH 002/148] Python: Clean up comments in preparation for autoformat. --- python/ql/src/Imports/UnusedImport.ql | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index d87b0efd254..951e7f87513 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -20,7 +20,7 @@ predicate global_name_used(Module m, Variable name) { u.getEnclosingModule() = m ) or - /* A use of an undefined class local variable, will use the global variable */ + // A use of an undefined class local variable, will use the global variable exists(Name u, LocalVariable v | u.uses(v) and v.getId() = name.getId() and @@ -33,10 +33,10 @@ predicate global_name_used(Module m, Variable name) { predicate all_not_understood(Module m) { exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | - /* __all__ is not defined as a simple list */ + // `__all__` is not defined as a simple list not m.declaredInAll(_) or - /* __all__ is modified */ + // `__all__` is modified exists(Call c | c.getFunc().(Attribute).getObject() = a.getALoad()) ) } @@ -45,10 +45,9 @@ predicate imported_module_used_in_doctest(Import imp) { exists(string modname | imp.getAName().getAsname().(Name).getId() = modname and - /* Look for doctests containing the patterns: - * >>> …name… - * ... …name… - */ + // Look for doctests containing the patterns: + // >>> …name… + // ... …name… exists(StrConst doc | doc.getEnclosingModule() = imp.getScope() and doc.isDocString() and @@ -62,9 +61,8 @@ predicate imported_module_used_in_typehint(Import imp) { imp.getAName().getAsname().(Name).getId() = modname and loc.getFile() = imp.getScope().(Module).getFile() | - /* Look for typehints containing the patterns: - * # type: …name… - */ + // Look for type hints containing the patterns: + // # type: …name… exists(Comment typehint | loc = typehint.getLocation() and typehint.getText().regexpMatch("# type:.*" + modname + ".*") @@ -95,10 +93,10 @@ predicate unused_import(Import imp, Variable name) { and not global_name_used(imp.getScope(), name) and - /* Imports in __init__.py are used to force module loading */ + // Imports in `__init__.py` are used to force module loading not imp.getEnclosingModule().isPackageInit() and - /* Name may be imported for use in epytext documentation */ + // Name may be imported for use in epytext documentation not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | cmt.getLocation().getFile() = imp.getLocation().getFile() @@ -106,16 +104,15 @@ predicate unused_import(Import imp, Variable name) { and not name_acceptable_for_unused_variable(name) and - /* Assume that opaque `__all__` includes imported module */ + // Assume that opaque `__all__` includes imported module not all_not_understood(imp.getEnclosingModule()) and not imported_module_used_in_doctest(imp) and not imported_module_used_in_typehint(imp) and - /* Only consider import statements that actually point-to something (possibly an unknown module). - * If this is not the case, it's likely that the import statement never gets executed. - */ + // Only consider import statements that actually point-to something (possibly an unknown module). + // If this is not the case, it's likely that the import statement never gets executed. imp.getAName().getValue().pointsTo(_) } From 9878e4fe263f54120fe282810274377a06f9cc01 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 13:04:17 +0200 Subject: [PATCH 003/148] Python: Apply four-space autoformat. --- python/ql/src/Imports/UnusedImport.ql | 53 +++++++++------------------ 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 951e7f87513..3ac04e2e4d2 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -14,7 +14,7 @@ import python import Variables.Definition predicate global_name_used(Module m, Variable name) { - exists (Name u, GlobalVariable v | + exists(Name u, GlobalVariable v | u.uses(v) and v.getId() = name.getId() and u.getEnclosingModule() = m @@ -31,8 +31,7 @@ predicate global_name_used(Module m, Variable name) { /** Holds if a module has `__all__` but we don't understand it */ predicate all_not_understood(Module m) { - exists(GlobalVariable a | - a.getId() = "__all__" and a.getScope() = m | + exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | // `__all__` is not defined as a simple list not m.declaredInAll(_) or @@ -43,8 +42,7 @@ predicate all_not_understood(Module m) { predicate imported_module_used_in_doctest(Import imp) { exists(string modname | - imp.getAName().getAsname().(Name).getId() = modname - and + imp.getAName().getAsname().(Name).getId() = modname and // Look for doctests containing the patterns: // >>> …name… // ... …name… @@ -60,7 +58,7 @@ predicate imported_module_used_in_typehint(Import imp) { exists(string modname, Location loc | imp.getAName().getAsname().(Name).getId() = modname and loc.getFile() = imp.getScope().(Module).getFile() - | + | // Look for type hints containing the patterns: // # type: …name… exists(Comment typehint | @@ -73,7 +71,7 @@ predicate imported_module_used_in_typehint(Import imp) { annotation = any(Arguments a).getAnAnnotation() or annotation = any(AnnAssign a).getAnnotation() - | + | annotation.pointsTo(Value::forString(typehint)) and loc = annotation.getLocation() and typehint.regexpMatch(".*\\b" + modname + "\\b.*") @@ -81,43 +79,28 @@ predicate imported_module_used_in_typehint(Import imp) { ) } - predicate unused_import(Import imp, Variable name) { - ((Name)imp.getAName().getAsname()).getVariable() = name - and - not imp.getAnImportedModuleName() = "__future__" - and - not imp.getEnclosingModule().declaredInAll(name.getId()) - and - imp.getScope() = imp.getEnclosingModule() - and - not global_name_used(imp.getScope(), name) - and + imp.getAName().getAsname().(Name).getVariable() = name and + not imp.getAnImportedModuleName() = "__future__" and + not imp.getEnclosingModule().declaredInAll(name.getId()) and + imp.getScope() = imp.getEnclosingModule() and + not global_name_used(imp.getScope(), name) and // Imports in `__init__.py` are used to force module loading - not imp.getEnclosingModule().isPackageInit() - and + not imp.getEnclosingModule().isPackageInit() and // Name may be imported for use in epytext documentation - not exists(Comment cmt | - cmt.getText().matches("%L{" + name.getId() + "}%") | + not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | cmt.getLocation().getFile() = imp.getLocation().getFile() - ) - and - not name_acceptable_for_unused_variable(name) - and + ) and + not name_acceptable_for_unused_variable(name) and // Assume that opaque `__all__` includes imported module - not all_not_understood(imp.getEnclosingModule()) - and - not imported_module_used_in_doctest(imp) - and - not imported_module_used_in_typehint(imp) - and - // Only consider import statements that actually point-to something (possibly an unknown module). + not all_not_understood(imp.getEnclosingModule()) and + not imported_module_used_in_doctest(imp) and + not imported_module_used_in_typehint(imp) and + // Only consider import statements that actually point-to something (possibly an unknown module). // If this is not the case, it's likely that the import statement never gets executed. imp.getAName().getValue().pointsTo(_) } - from Stmt s, Variable name where unused_import(s, name) select s, "Import of '" + name.getId() + "' is not used." - From 0ccc0057f95314fa179a80216558bb6704eb1a94 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 8 Oct 2019 15:04:11 +0200 Subject: [PATCH 004/148] add Deferred model to Promises.qll --- change-notes/1.23/analysis-javascript.md | 1 + .../ql/src/semmle/javascript/Promises.qll | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 04b5e6cb541..87b12c19230 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -38,3 +38,4 @@ ## Changes to QL libraries * `Expr.getDocumentation()` now handles chain assignments. +* Added `Deferred` as a promise library in Promises.qll diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 858064e85a0..794a866aee2 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -32,6 +32,39 @@ module Bluebird { } } +/** + * Provides classes for working with various Deferred implementations + */ +module Deferred { + private DataFlow::SourceNode deferred() { + exists(VarAccess var, DataFlow::NewNode instantiation | + var.getName() = "Deferred" and + result = DataFlow::exprNode(var).getALocalSource() and + // Sanity check that result really is a Deferred implementation + instantiation = result.getAnInstantiation() and + exists(instantiation.getAMemberCall("resolve")) + ) + } + + /** + * A promise object created by a Deferred constructor + */ + private class DeferredPromiseDefinition extends PromiseDefinition, DataFlow::NewNode { + DeferredPromiseDefinition() { this = deferred().getAnInstantiation() } + + override DataFlow::FunctionNode getExecutor() { result = getCallback(0) } + } + + /** + * A resolved promise created by a `new Deferred().resolve()` call. + */ + class ResolvedDeferredPromiseDefinition extends ResolvedPromiseDefinition { + ResolvedDeferredPromiseDefinition() { this = any(DeferredPromiseDefinition def).getAMemberCall("resolve") } + + override DataFlow::Node getValue() { result = getArgument(0) } + } +} + /** * Provides classes for working with the `q` library (https://github.com/kriskowal/q). */ From 411ed702fb1eabc9f308a34abe6105b688d12c36 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 9 Oct 2019 13:50:12 +0200 Subject: [PATCH 005/148] change change-notes --- change-notes/1.23/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 87b12c19230..70d903cb944 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -9,6 +9,7 @@ - [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) * The call graph has been improved to resolve method calls in more cases. This may produce more security alerts. +* Promises derived from a Deferred object are now recognized. ## New queries @@ -38,4 +39,3 @@ ## Changes to QL libraries * `Expr.getDocumentation()` now handles chain assignments. -* Added `Deferred` as a promise library in Promises.qll From c7eb0f17a9e35a0d9e0be951373df7bcad9c4f87 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 9 Oct 2019 13:59:00 +0200 Subject: [PATCH 006/148] add TaintTracking test for new Deferred model --- .../TaintTracking/BasicTaintTracking.expected | 1 + .../ql/test/library-tests/TaintTracking/promise.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 2722f67d6fd..77592a2e855 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -69,6 +69,7 @@ typeInferenceMismatch | promise.js:5:25:5:32 | source() | promise.js:5:8:5:33 | bluebir ... urce()) | | promise.js:10:24:10:31 | source() | promise.js:10:8:10:32 | Promise ... urce()) | | promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise | +| promise.js:22:23:22:30 | source() | promise.js:22:7:22:31 | promise ... urce()) | | sanitizer-guards.js:2:11:2:18 | source() | sanitizer-guards.js:4:8:4:8 | x | | sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:15:10:15:15 | this.x | | sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:21:14:21:19 | this.x | diff --git a/javascript/ql/test/library-tests/TaintTracking/promise.js b/javascript/ql/test/library-tests/TaintTracking/promise.js index cd5351720ba..87e89451d99 100644 --- a/javascript/ql/test/library-tests/TaintTracking/promise.js +++ b/javascript/ql/test/library-tests/TaintTracking/promise.js @@ -12,3 +12,12 @@ function closure() { resolver.resolve(source()); sink(resolver.promise); // NOT OK } + +class Deferred { + +} + +function deferred() { + var promise = new Deferred(); + sink(promise.resolve(source())); // NOT OK +} \ No newline at end of file From 4ec825b5b6f3dbb1ba8c5e20bf70963772c9bda0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 9 Oct 2019 16:18:04 +0200 Subject: [PATCH 007/148] made model of Deferred more precise --- .../ql/src/semmle/javascript/Promises.qll | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 794a866aee2..362bb2f5063 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -37,10 +37,23 @@ module Bluebird { */ module Deferred { private DataFlow::SourceNode deferred() { - exists(VarAccess var, DataFlow::NewNode instantiation | - var.getName() = "Deferred" and - result = DataFlow::exprNode(var).getALocalSource() and - // Sanity check that result really is a Deferred implementation + ( + exists(Variable var | + var.getName() = "Deferred" and + (var.getADeclaration() instanceof LocalNamespaceDecl or var.getScope() instanceof GlobalScope) and + result = DataFlow::valueNode(var.getADefinition()) + ) + or + result.(DataFlow::ParameterNode).getName() = "Deferred" + or + exists(Function f | + f.getName() = "Deferred" and + result = DataFlow::valueNode(f) + ) + ) + and + // Sanity check that it is a Deferred implementation + exists(DataFlow::NewNode instantiation | instantiation = result.getAnInstantiation() and exists(instantiation.getAMemberCall("resolve")) ) From 0a6b343820e43fd47efa61cf8acec0deab53c458 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 10 Oct 2019 11:50:34 +0200 Subject: [PATCH 008/148] add "class Deferred{...}" as potential Deferred implementation to fix the tests --- javascript/ql/src/semmle/javascript/Promises.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 362bb2f5063..488adebab6e 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -46,10 +46,15 @@ module Deferred { or result.(DataFlow::ParameterNode).getName() = "Deferred" or - exists(Function f | + exists(Function f | f.getName() = "Deferred" and result = DataFlow::valueNode(f) ) + or + exists(ClassDefinition c | + c.getName() = "Deferred" and + result = DataFlow::valueNode(c) + ) ) and // Sanity check that it is a Deferred implementation From 31009d979d323eb496530ae99c9f719ebed67272 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 11 Oct 2019 12:04:34 +0200 Subject: [PATCH 009/148] add type tracking to detect instances --- .../ql/src/semmle/javascript/Promises.qll | 73 ++++++++++++------- .../library-tests/TaintTracking/promise.js | 2 + 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 488adebab6e..13eb1e8114e 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -36,39 +36,60 @@ module Bluebird { * Provides classes for working with various Deferred implementations */ module Deferred { - private DataFlow::SourceNode deferred() { - ( - exists(Variable var | + class DeferredClass extends DataFlow::SourceNode { + DeferredClass() { + exists(Variable var | var.getName() = "Deferred" and - (var.getADeclaration() instanceof LocalNamespaceDecl or var.getScope() instanceof GlobalScope) and - result = DataFlow::valueNode(var.getADefinition()) - ) - or - result.(DataFlow::ParameterNode).getName() = "Deferred" - or - exists(Function f | - f.getName() = "Deferred" and - result = DataFlow::valueNode(f) + ( + var.getADeclaration() instanceof LocalNamespaceDecl or + var.getScope() instanceof GlobalScope + ) and + this = DataFlow::valueNode(var.getADefinition()) ) or - exists(ClassDefinition c | - c.getName() = "Deferred" and - result = DataFlow::valueNode(c) + this.(DataFlow::ParameterNode).getName() = "Deferred" + or + exists(Function f | + f.getName() = "Deferred" and + this = DataFlow::valueNode(f) ) - ) - and - // Sanity check that it is a Deferred implementation - exists(DataFlow::NewNode instantiation | - instantiation = result.getAnInstantiation() and - exists(instantiation.getAMemberCall("resolve")) - ) + or + exists(ClassDefinition c | + c.getName() = "Deferred" and + this = DataFlow::valueNode(c) + ) + } + } + + class DeferredInstance extends DataFlow::NewNode { + DeferredClass deferredClass; + + DeferredInstance() { this = deferredClass.getAnInstantiation() } + + private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + t.start() and + result = this + or + exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) + } + + DeferredClass getDeferredClass() { result = deferredClass } + + DataFlow::CallNode getPromiseMemberCall(string methodName) { + result = ref(DataFlow::TypeTracker::end()).getAMemberCall(methodName) + } } /** * A promise object created by a Deferred constructor */ - private class DeferredPromiseDefinition extends PromiseDefinition, DataFlow::NewNode { - DeferredPromiseDefinition() { this = deferred().getAnInstantiation() } + private class DeferredPromiseDefinition extends PromiseDefinition, DeferredInstance { + DeferredPromiseDefinition() { + this = any(DeferredClass c | + exists(any(DeferredInstance i | i.getDeferredClass() = c).getPromiseMemberCall("resolve")) and + exists(any(DeferredInstance i | i.getDeferredClass() = c).getPromiseMemberCall("reject")) + ).getAnInstantiation() + } override DataFlow::FunctionNode getExecutor() { result = getCallback(0) } } @@ -77,7 +98,9 @@ module Deferred { * A resolved promise created by a `new Deferred().resolve()` call. */ class ResolvedDeferredPromiseDefinition extends ResolvedPromiseDefinition { - ResolvedDeferredPromiseDefinition() { this = any(DeferredPromiseDefinition def).getAMemberCall("resolve") } + ResolvedDeferredPromiseDefinition() { + this = any(DeferredPromiseDefinition def).getPromiseMemberCall("resolve") + } override DataFlow::Node getValue() { result = getArgument(0) } } diff --git a/javascript/ql/test/library-tests/TaintTracking/promise.js b/javascript/ql/test/library-tests/TaintTracking/promise.js index 87e89451d99..d16e57241e8 100644 --- a/javascript/ql/test/library-tests/TaintTracking/promise.js +++ b/javascript/ql/test/library-tests/TaintTracking/promise.js @@ -20,4 +20,6 @@ class Deferred { function deferred() { var promise = new Deferred(); sink(promise.resolve(source())); // NOT OK + + new Deferred().reject("foo") // <- a reject has to exist. } \ No newline at end of file From 592cb18bf486ba6f8b37abf291516e365d4f8e25 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 16:28:38 +0200 Subject: [PATCH 010/148] add array callbacks to useOfReturnlessFunction query --- .../ql/src/Expressions/ExprHasNoEffect.ql | 115 +---------------- .../ql/src/Expressions/ExprHasNoEffect.qll | 121 ++++++++++++++++++ .../src/Statements/UseOfReturnlessFunction.ql | 63 ++++++++- 3 files changed, 178 insertions(+), 121 deletions(-) diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.ql b/javascript/ql/src/Expressions/ExprHasNoEffect.ql index 14024ec8f38..929e84616f0 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.ql +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.ql @@ -13,122 +13,9 @@ */ import javascript -import DOMProperties -import semmle.javascript.frameworks.xUnit -import semmle.javascript.RestrictedLocations import ExprHasNoEffect -/** - * Holds if `e` is of the form `x;` or `e.p;` and has a JSDoc comment containing a tag. - * In that case, it is probably meant as a declaration and shouldn't be flagged by this query. - * - * This will still flag cases where the JSDoc comment contains no tag at all (and hence carries - * no semantic information), and expression statements with an ordinary (non-JSDoc) comment - * attached to them. - */ -predicate isDeclaration(Expr e) { - (e instanceof VarAccess or e instanceof PropAccess) and - exists(e.getParent().(ExprStmt).getDocumentation().getATag()) -} - -/** - * Holds if there exists a getter for a property called `name` anywhere in the program. - */ -predicate isGetterProperty(string name) { - // there is a call of the form `Object.defineProperty(..., name, descriptor)` ... - exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() | - // ... where `descriptor` defines a getter - defProp.hasPropertyAttributeWrite("get", _) - or - // ... where `descriptor` may define a getter - exists(DataFlow::SourceNode descriptor | descriptor.flowsTo(defProp.getPropertyDescriptor()) | - descriptor.isIncomplete(_) - or - // minimal escape analysis for the descriptor - exists(DataFlow::InvokeNode invk | - not invk = defProp and - descriptor.flowsTo(invk.getAnArgument()) - ) - ) - ) - or - // there is an object expression with a getter property `name` - exists(ObjectExpr obj | obj.getPropertyByName(name) instanceof PropertyGetter) -} - -/** - * A property access that may invoke a getter. - */ -class GetterPropertyAccess extends PropAccess { - override predicate isImpure() { isGetterProperty(getPropertyName()) } -} - -/** - * Holds if `c` is an indirect eval call of the form `(dummy, eval)(...)`, where - * `dummy` is some expression whose value is discarded, and which simply - * exists to prevent the call from being interpreted as a direct eval. - */ -predicate isIndirectEval(CallExpr c, Expr dummy) { - exists(SeqExpr seq | seq = c.getCallee().stripParens() | - dummy = seq.getOperand(0) and - seq.getOperand(1).(GlobalVarAccess).getName() = "eval" and - seq.getNumOperands() = 2 - ) -} - -/** - * Holds if `c` is a call of the form `(dummy, e[p])(...)`, where `dummy` is - * some expression whose value is discarded, and which simply exists - * to prevent the call from being interpreted as a method call. - */ -predicate isReceiverSuppressingCall(CallExpr c, Expr dummy, PropAccess callee) { - exists(SeqExpr seq | seq = c.getCallee().stripParens() | - dummy = seq.getOperand(0) and - seq.getOperand(1) = callee and - seq.getNumOperands() = 2 - ) -} - -/** - * Holds if evaluating `e` has no side effects (except potentially allocating - * and initializing a new object). - * - * For calls, we do not check whether their arguments have any side effects: - * even if they do, the call itself is useless and should be flagged by this - * query. - */ -predicate noSideEffects(Expr e) { - e.isPure() - or - // `new Error(...)`, `new SyntaxError(...)`, etc. - forex(Function f | f = e.flow().(DataFlow::NewNode).getACallee() | - f.(ExternalType).getASupertype*().getName() = "Error" - ) -} from Expr e -where - noSideEffects(e) and - inVoidContext(e) and - // disregard pure expressions wrapped in a void(...) - not e instanceof VoidExpr and - // filter out directives (unknown directives are handled by UnknownDirective.ql) - not exists(Directive d | e = d.getExpr()) and - // or about externs - not e.inExternsFile() and - // don't complain about declarations - not isDeclaration(e) and - // exclude DOM properties, which sometimes have magical auto-update properties - not isDOMProperty(e.(PropAccess).getPropertyName()) and - // exclude xUnit.js annotations - not e instanceof XUnitAnnotation and - // exclude common patterns that are most likely intentional - not isIndirectEval(_, e) and - not isReceiverSuppressingCall(_, e, _) and - // exclude anonymous function expressions as statements; these can only arise - // from a syntax error we already flag - not exists(FunctionExpr fe, ExprStmt es | fe = e | - fe = es.getExpr() and - not exists(fe.getName()) - ) +where hasNoEffect(e) select e.(FirstLineOf), "This expression has no effect." diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.qll b/javascript/ql/src/Expressions/ExprHasNoEffect.qll index 858f719ba0a..822bcbb26fa 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.qll +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.qll @@ -3,6 +3,9 @@ */ import javascript +import DOMProperties +import semmle.javascript.frameworks.xUnit +import semmle.javascript.RestrictedLocations /** * Holds if `e` appears in a syntactic context where its value is discarded. @@ -37,3 +40,121 @@ predicate inVoidContext(Expr e) { or exists(LogicalBinaryExpr logical | e = logical.getRightOperand() and inVoidContext(logical)) } + + +/** + * Holds if `e` is of the form `x;` or `e.p;` and has a JSDoc comment containing a tag. + * In that case, it is probably meant as a declaration and shouldn't be flagged by this query. + * + * This will still flag cases where the JSDoc comment contains no tag at all (and hence carries + * no semantic information), and expression statements with an ordinary (non-JSDoc) comment + * attached to them. + */ +predicate isDeclaration(Expr e) { + (e instanceof VarAccess or e instanceof PropAccess) and + exists(e.getParent().(ExprStmt).getDocumentation().getATag()) +} + +/** + * Holds if there exists a getter for a property called `name` anywhere in the program. + */ +predicate isGetterProperty(string name) { + // there is a call of the form `Object.defineProperty(..., name, descriptor)` ... + exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() | + // ... where `descriptor` defines a getter + defProp.hasPropertyAttributeWrite("get", _) + or + // ... where `descriptor` may define a getter + exists(DataFlow::SourceNode descriptor | descriptor.flowsTo(defProp.getPropertyDescriptor()) | + descriptor.isIncomplete(_) + or + // minimal escape analysis for the descriptor + exists(DataFlow::InvokeNode invk | + not invk = defProp and + descriptor.flowsTo(invk.getAnArgument()) + ) + ) + ) + or + // there is an object expression with a getter property `name` + exists(ObjectExpr obj | obj.getPropertyByName(name) instanceof PropertyGetter) +} + +/** + * A property access that may invoke a getter. + */ +class GetterPropertyAccess extends PropAccess { + override predicate isImpure() { isGetterProperty(getPropertyName()) } +} + +/** + * Holds if `c` is an indirect eval call of the form `(dummy, eval)(...)`, where + * `dummy` is some expression whose value is discarded, and which simply + * exists to prevent the call from being interpreted as a direct eval. + */ +predicate isIndirectEval(CallExpr c, Expr dummy) { + exists(SeqExpr seq | seq = c.getCallee().stripParens() | + dummy = seq.getOperand(0) and + seq.getOperand(1).(GlobalVarAccess).getName() = "eval" and + seq.getNumOperands() = 2 + ) +} + +/** + * Holds if `c` is a call of the form `(dummy, e[p])(...)`, where `dummy` is + * some expression whose value is discarded, and which simply exists + * to prevent the call from being interpreted as a method call. + */ +predicate isReceiverSuppressingCall(CallExpr c, Expr dummy, PropAccess callee) { + exists(SeqExpr seq | seq = c.getCallee().stripParens() | + dummy = seq.getOperand(0) and + seq.getOperand(1) = callee and + seq.getNumOperands() = 2 + ) +} + +/** + * Holds if evaluating `e` has no side effects (except potentially allocating + * and initializing a new object). + * + * For calls, we do not check whether their arguments have any side effects: + * even if they do, the call itself is useless and should be flagged by this + * query. + */ +predicate noSideEffects(Expr e) { + e.isPure() + or + // `new Error(...)`, `new SyntaxError(...)`, etc. + forex(Function f | f = e.flow().(DataFlow::NewNode).getACallee() | + f.(ExternalType).getASupertype*().getName() = "Error" + ) +} + +/** + * Holds if the expression `e` should be reported as having no effect. + */ +predicate hasNoEffect(Expr e) { + noSideEffects(e) and + inVoidContext(e) and + // disregard pure expressions wrapped in a void(...) + not e instanceof VoidExpr and + // filter out directives (unknown directives are handled by UnknownDirective.ql) + not exists(Directive d | e = d.getExpr()) and + // or about externs + not e.inExternsFile() and + // don't complain about declarations + not isDeclaration(e) and + // exclude DOM properties, which sometimes have magical auto-update properties + not isDOMProperty(e.(PropAccess).getPropertyName()) and + // exclude xUnit.js annotations + not e instanceof XUnitAnnotation and + // exclude common patterns that are most likely intentional + not isIndirectEval(_, e) and + not isReceiverSuppressingCall(_, e, _) and + // exclude anonymous function expressions as statements; these can only arise + // from a syntax error we already flag + not exists(FunctionExpr fe, ExprStmt es | fe = e | + fe = es.getExpr() and + not exists(fe.getName()) + ) +} \ No newline at end of file diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index c63127b83a3..61a485313e4 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -82,17 +82,66 @@ predicate alwaysThrows(Function f) { ) } -from DataFlow::CallNode call -where +predicate callToVoidFunction(DataFlow::CallNode call, Function func) { not call.isIndefinite(_) and - forex(Function f | f = call.getACallee() | + func = call.getACallee() and + forall(Function f | f = call.getACallee() | returnsVoid(f) and not isStub(f) and not alwaysThrows(f) + ) +} + +predicate hasNonVoidCallbackMethod(string name) { + name = "every" or + name = "filter" or + name = "find" or + name = "findIndex" or + name = "flatMap" or + name = "map" or + name = "reduce" or + name = "reduceRight" or + name = "some" or + name = "sort" +} + +DataFlow::SourceNode array(DataFlow::TypeTracker t) { + t.start() and result instanceof DataFlow::ArrayCreationNode + or + exists (DataFlow::TypeTracker t2 | + result = array(t2).track(t2, t) + ) +} + +DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } + +predicate voidArrayCallback(DataFlow::MethodCallNode call, Function func) { + hasNonVoidCallbackMethod(call.getMethodName()) and + func = call.getAnArgument().getALocalSource().asExpr() and + 1 = count(DataFlow::Node arg | arg = call.getAnArgument() and arg.getALocalSource().asExpr() instanceof Function) and + returnsVoid(func) and + not isStub(func) and + not alwaysThrows(func) and + ( + call.getReceiver().getALocalSource() = array() + or + call.getCalleeNode() instanceof LodashUnderscore::Member + ) +} + +from DataFlow::CallNode call, Function func, string name, string msg +where + ( + callToVoidFunction(call, func) and + msg = "the $@ does not return anything, yet the return value is used." and + name = "function " + call.getCalleeName() + or + voidArrayCallback(call, func) and + msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + "() is used." and + name = "callback function" ) and - not benignContext(call.asExpr()) and - + // Avoid double reporting from js/useless-expression + not hasNoEffect(func.getBodyStmt(func.getNumBodyStmt() - 1).(ExprStmt).getExpr()) and // anonymous one-shot closure. Those are used in weird ways and we ignore them. not oneshotClosure(call.asExpr()) select - call, "the function $@ does not return anything, yet the return value is used.", call.getACallee(), call.getCalleeName() - + call, msg, func, name From a7c1c34e1e48a311057ae223d545ed59a54439ee Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 11 Oct 2019 17:14:58 +0200 Subject: [PATCH 011/148] fix test output, and add new test for array callbacks --- .../UseOfReturnlessFunction.expected | 11 ++++++----- .../Statements/UseOfReturnlessFunction/tst.js | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected index 500d900ff9e..0dc283d5edc 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected @@ -1,5 +1,6 @@ -| tst.js:20:17:20:33 | onlySideEffects() | the function $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | onlySideEffects | -| tst.js:24:13:24:29 | onlySideEffects() | the function $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | onlySideEffects | -| tst.js:30:20:30:36 | onlySideEffects() | the function $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | onlySideEffects | -| tst.js:53:10:53:34 | bothOnl ... fects() | the function $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | bothOnlyHaveSideEffects | -| tst.js:53:10:53:34 | bothOnl ... fects() | the function $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | bothOnlyHaveSideEffects | +| tst.js:20:17:20:33 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | +| tst.js:24:13:24:29 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | +| tst.js:30:20:30:36 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | +| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | +| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | +| tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter() is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function | diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js index 8bb49f7e761..1306c6e7f65 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js @@ -68,4 +68,11 @@ var h = returnsValue() || alwaysThrows(); // OK! console.log(h); + + function equals(x, y) { + return x === y; + } + + var foo = [1,2,3].filter(n => {equals(n, 3)}) // NOT OK! + console.log(foo); })(); \ No newline at end of file From 28056791a57d53a265cf6348d71e93a4aa60a4f8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 14 Oct 2019 14:14:26 +0200 Subject: [PATCH 012/148] add .getALocalSource() when testing for lodash-members --- javascript/ql/src/Statements/UseOfReturnlessFunction.ql | 6 +++--- .../UseOfReturnlessFunction.expected | 1 + .../query-tests/Statements/UseOfReturnlessFunction/tst.js | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 61a485313e4..2d70cecb0d3 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -113,8 +113,8 @@ DataFlow::SourceNode array(DataFlow::TypeTracker t) { DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } -predicate voidArrayCallback(DataFlow::MethodCallNode call, Function func) { - hasNonVoidCallbackMethod(call.getMethodName()) and +predicate voidArrayCallback(DataFlow::CallNode call, Function func) { + hasNonVoidCallbackMethod(call.getCalleeName()) and func = call.getAnArgument().getALocalSource().asExpr() and 1 = count(DataFlow::Node arg | arg = call.getAnArgument() and arg.getALocalSource().asExpr() instanceof Function) and returnsVoid(func) and @@ -123,7 +123,7 @@ predicate voidArrayCallback(DataFlow::MethodCallNode call, Function func) { ( call.getReceiver().getALocalSource() = array() or - call.getCalleeNode() instanceof LodashUnderscore::Member + call.getCalleeNode().getALocalSource() instanceof LodashUnderscore::Member ) } diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected index 0dc283d5edc..98ae4e3696c 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected @@ -4,3 +4,4 @@ | tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | | tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | | tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter() is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function | +| tst.js:80:12:80:50 | filter( ... 3) } ) | the $@ does not return anything, yet the return value from the call to filter() is used. | tst.js:80:28:80:48 | x => { ... x, 3) } | callback function | diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js index 1306c6e7f65..2b523223e91 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js @@ -75,4 +75,8 @@ var foo = [1,2,3].filter(n => {equals(n, 3)}) // NOT OK! console.log(foo); + + import { filter } from 'lodash' + var bar = filter([1,2,4], x => { equals(x, 3) } ) // NOT OK! + console.log(bar); })(); \ No newline at end of file From b29f88450b7dc062a6ca77572f54a95050020668 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 17 Oct 2019 12:10:23 -0700 Subject: [PATCH 013/148] C++: buffer read side effects on unmodeled funcs --- .../raw/internal/TranslatedCall.qll | 22 ++- .../test/library-tests/ir/ir/raw_ir.expected | 154 +++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 6 +- .../ir/ssa/unaliased_ssa_ir.expected | 6 +- 4 files changed, 96 insertions(+), 92 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 4a7aa607f57..fbe4910a0dd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -460,14 +460,18 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff } override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { - tag instanceof OnlyInstructionTag and - result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and - operandTag instanceof SideEffectOperandTag - or - tag instanceof OnlyInstructionTag and - result = arg.getType().getUnspecifiedType() and - not result instanceof DerivedType and - operandTag instanceof SideEffectOperandTag + if hasSpecificReadSideEffect(any(Opcode::BufferReadSideEffect op)) + then result instanceof UnknownType + else ( + tag instanceof OnlyInstructionTag and + result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and + operandTag instanceof SideEffectOperandTag + or + tag instanceof OnlyInstructionTag and + result = arg.getType().getUnspecifiedType() and + not result instanceof DerivedType and + operandTag instanceof SideEffectOperandTag + ) } predicate hasSpecificWriteSideEffect(Opcode op) { @@ -517,7 +521,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff ) or not call.getTarget() instanceof SideEffectFunction and - op instanceof Opcode::IndirectReadSideEffect + op instanceof Opcode::BufferReadSideEffect } final override int getInstructionIndex(InstructionTag tag) { diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 3bff2bff690..b2556c8616b 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -14,7 +14,7 @@ bad_asts.cpp: # 16| r0_10(int) = Constant[1] : # 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10 # 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 16| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +# 16| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu0_2 # 16| mu0_14(S) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 17| v0_15(void) = NoOp : # 14| v0_16(void) = ReturnVoid : @@ -2675,8 +2675,8 @@ ir.cpp: # 585| r0_8(char *) = Convert : r0_7 # 585| v0_9(void) = Call : func:r0_3, 0:r0_5, 1:r0_6, 2:r0_8 # 585| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 585| v0_11(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 -# 585| v0_12(void) = ^IndirectReadSideEffect[2] : &:r0_8, ~mu0_2 +# 585| v0_11(void) = ^BufferReadSideEffect[0] : &:r0_5, ~mu0_2 +# 585| v0_12(void) = ^BufferReadSideEffect[2] : &:r0_8, ~mu0_2 # 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5 # 585| mu0_14(unknown) = ^BufferMayWriteSideEffect[2] : &:r0_8 # 586| v0_15(void) = NoOp : @@ -2721,7 +2721,7 @@ ir.cpp: # 617| r0_10(char *) = Convert : r0_9 # 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 # 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 617| v0_13(void) = ^IndirectReadSideEffect[0] : &:r0_10, ~mu0_2 +# 617| v0_13(void) = ^BufferReadSideEffect[0] : &:r0_10, ~mu0_2 # 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_10 # 618| r0_15(glval) = VariableAddress[s3] : # 618| r0_16(glval) = FunctionAddress[ReturnObject] : @@ -2734,7 +2734,7 @@ ir.cpp: # 619| r0_23(char *) = Convert : r0_22 # 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 # 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 619| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +# 619| v0_26(void) = ^BufferReadSideEffect[0] : &:r0_23, ~mu0_2 # 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 # 620| v0_28(void) = NoOp : # 615| v0_29(void) = ReturnVoid : @@ -2758,7 +2758,7 @@ ir.cpp: # 623| r0_12(glval) = FunctionAddress[c_str] : # 623| r0_13(char *) = Call : func:r0_12, this:r0_11 # 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 623| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +# 623| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_11, ~mu0_2 # 623| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 # 624| r0_17(glval) = VariableAddress[p] : # 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 @@ -2766,14 +2766,14 @@ ir.cpp: # 624| r0_20(glval) = FunctionAddress[c_str] : # 624| r0_21(char *) = Call : func:r0_20, this:r0_19 # 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 624| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 +# 624| v0_23(void) = ^BufferReadSideEffect[-1] : &:r0_19, ~mu0_2 # 624| mu0_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 # 625| r0_25(glval) = VariableAddress[s] : # 625| r0_26(glval) = Convert : r0_25 # 625| r0_27(glval) = FunctionAddress[c_str] : # 625| r0_28(char *) = Call : func:r0_27, this:r0_26 # 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 625| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 +# 625| v0_30(void) = ^BufferReadSideEffect[-1] : &:r0_26, ~mu0_2 # 625| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_26 # 626| v0_32(void) = NoOp : # 622| v0_33(void) = ReturnVoid : @@ -2881,21 +2881,21 @@ ir.cpp: # 653| r0_6(int) = Constant[0] : # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 653| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_4, ~mu0_2 +# 653| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_4, ~mu0_2 # 653| mu0_10(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 654| r0_11(C *) = CopyValue : r0_3 # 654| r0_12(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r0_13(int) = Constant[1] : # 654| r0_14(int) = Call : func:r0_12, this:r0_11, 0:r0_13 # 654| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 -# 654| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +# 654| v0_16(void) = ^BufferReadSideEffect[-1] : &:r0_11, ~mu0_2 # 654| mu0_17(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 #-----| r0_18(C *) = CopyValue : r0_3 # 655| r0_19(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r0_20(int) = Constant[2] : # 655| r0_21(int) = Call : func:r0_19, this:r0_18, 0:r0_20 # 655| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_18, ~mu0_2 +#-----| v0_23(void) = ^BufferReadSideEffect[-1] : &:r0_18, ~mu0_2 #-----| mu0_24(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_18 # 656| v0_25(void) = NoOp : # 652| v0_26(void) = ReturnVoid : @@ -2927,7 +2927,7 @@ ir.cpp: # 662| r0_20(char *) = Convert : r0_19 # 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 # 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 662| v0_23(void) = ^IndirectReadSideEffect[0] : &:r0_20, ~mu0_2 +# 662| v0_23(void) = ^BufferReadSideEffect[0] : &:r0_20, ~mu0_2 # 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_20 # 664| v0_25(void) = NoOp : # 658| v0_26(void) = ReturnVoid : @@ -3127,7 +3127,7 @@ ir.cpp: # 721| r0_6(char) = Constant[111] : # 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 # 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 721| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 +# 721| v0_9(void) = ^BufferReadSideEffect[0] : &:r0_5, ~mu0_2 # 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5 # 721| r0_11(double) = Convert : r0_7 # 721| mu0_12(double) = Store : &:r0_3, r0_11 @@ -3201,7 +3201,7 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 731| v7_6(void) = ^BufferReadSideEffect[0] : &:r7_3, ~mu0_2 # 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -3226,7 +3226,7 @@ ir.cpp: # 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 736| v10_8(void) = ^BufferReadSideEffect[0] : &:r10_5, ~mu0_2 # 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 @@ -3268,8 +3268,8 @@ ir.cpp: #-----| r0_11(glval) = FieldAddress[base_s] : r0_10 # 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_11, ~mu0_2 #-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(glval) = VariableAddress[#return] : @@ -3343,8 +3343,8 @@ ir.cpp: #-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 # 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_11, ~mu0_2 #-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(Middle *) = CopyValue : r0_3 @@ -3355,8 +3355,8 @@ ir.cpp: #-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 # 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 # 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +#-----| v0_26(void) = ^BufferReadSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^BufferReadSideEffect[0] : &:r0_23, ~mu0_2 #-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 #-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 #-----| r0_30(glval) = VariableAddress[#return] : @@ -3421,8 +3421,8 @@ ir.cpp: #-----| r0_11(Middle *) = ConvertToBase[Derived : Middle] : r0_10 # 763| r0_12(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_11, ~mu0_2 #-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(Derived *) = CopyValue : r0_3 @@ -3433,8 +3433,8 @@ ir.cpp: #-----| r0_23(glval) = FieldAddress[derived_s] : r0_22 # 763| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 # 763| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +#-----| v0_26(void) = ^BufferReadSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^BufferReadSideEffect[0] : &:r0_23, ~mu0_2 #-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 #-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 #-----| r0_30(glval) = VariableAddress[#return] : @@ -3645,8 +3645,8 @@ ir.cpp: # 808| r0_27(glval) = ConvertToBase[Middle : Base] : r0_26 # 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 # 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 808| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_24, ~mu0_2 -# 808| v0_31(void) = ^IndirectReadSideEffect[0] : &:r0_27, ~mu0_2 +# 808| v0_30(void) = ^BufferReadSideEffect[-1] : &:r0_24, ~mu0_2 +# 808| v0_31(void) = ^BufferReadSideEffect[0] : &:r0_27, ~mu0_2 # 808| mu0_32(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 # 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27 # 809| r0_34(glval) = VariableAddress[b] : @@ -3656,13 +3656,13 @@ ir.cpp: # 809| r0_38(glval) = ConvertToBase[Middle : Base] : r0_37 # 809| v0_39(void) = Call : func:r0_36, 0:r0_38 # 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_41(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 +# 809| v0_41(void) = ^BufferReadSideEffect[0] : &:r0_38, ~mu0_2 # 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 # 809| r0_43(glval) = Convert : v0_39 # 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 # 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_34, ~mu0_2 -# 809| v0_47(void) = ^IndirectReadSideEffect[0] : &:r0_43, ~mu0_2 +# 809| v0_46(void) = ^BufferReadSideEffect[-1] : &:r0_34, ~mu0_2 +# 809| v0_47(void) = ^BufferReadSideEffect[0] : &:r0_43, ~mu0_2 # 809| mu0_48(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 # 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_43 # 810| r0_50(glval) = VariableAddress[b] : @@ -3672,13 +3672,13 @@ ir.cpp: # 810| r0_54(glval) = ConvertToBase[Middle : Base] : r0_53 # 810| v0_55(void) = Call : func:r0_52, 0:r0_54 # 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_57(void) = ^IndirectReadSideEffect[0] : &:r0_54, ~mu0_2 +# 810| v0_57(void) = ^BufferReadSideEffect[0] : &:r0_54, ~mu0_2 # 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_54 # 810| r0_59(glval) = Convert : v0_55 # 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 # 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_50, ~mu0_2 -# 810| v0_63(void) = ^IndirectReadSideEffect[0] : &:r0_59, ~mu0_2 +# 810| v0_62(void) = ^BufferReadSideEffect[-1] : &:r0_50, ~mu0_2 +# 810| v0_63(void) = ^BufferReadSideEffect[0] : &:r0_59, ~mu0_2 # 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_50 # 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_59 # 811| r0_66(glval) = VariableAddress[pm] : @@ -3708,8 +3708,8 @@ ir.cpp: # 816| r0_90(glval) = Convert : r0_89 # 816| r0_91(Middle &) = Call : func:r0_87, this:r0_86, 0:r0_90 # 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 -# 816| v0_93(void) = ^IndirectReadSideEffect[-1] : &:r0_86, ~mu0_2 -# 816| v0_94(void) = ^IndirectReadSideEffect[0] : &:r0_90, ~mu0_2 +# 816| v0_93(void) = ^BufferReadSideEffect[-1] : &:r0_86, ~mu0_2 +# 816| v0_94(void) = ^BufferReadSideEffect[0] : &:r0_90, ~mu0_2 # 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_86 # 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_90 # 817| r0_97(glval) = VariableAddress[m] : @@ -3719,8 +3719,8 @@ ir.cpp: # 817| r0_101(glval) = Convert : r0_100 # 817| r0_102(Middle &) = Call : func:r0_98, this:r0_97, 0:r0_101 # 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 -# 817| v0_104(void) = ^IndirectReadSideEffect[-1] : &:r0_97, ~mu0_2 -# 817| v0_105(void) = ^IndirectReadSideEffect[0] : &:r0_101, ~mu0_2 +# 817| v0_104(void) = ^BufferReadSideEffect[-1] : &:r0_97, ~mu0_2 +# 817| v0_105(void) = ^BufferReadSideEffect[0] : &:r0_101, ~mu0_2 # 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_97 # 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_101 # 818| r0_108(glval) = VariableAddress[pb] : @@ -3745,8 +3745,8 @@ ir.cpp: # 822| r0_127(glval) = ConvertToBase[Middle : Base] : r0_126 # 822| r0_128(Base &) = Call : func:r0_124, this:r0_123, 0:r0_127 # 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 -# 822| v0_130(void) = ^IndirectReadSideEffect[-1] : &:r0_123, ~mu0_2 -# 822| v0_131(void) = ^IndirectReadSideEffect[0] : &:r0_127, ~mu0_2 +# 822| v0_130(void) = ^BufferReadSideEffect[-1] : &:r0_123, ~mu0_2 +# 822| v0_131(void) = ^BufferReadSideEffect[0] : &:r0_127, ~mu0_2 # 822| mu0_132(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_123 # 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_127 # 823| r0_134(glval) = VariableAddress[b] : @@ -3757,13 +3757,13 @@ ir.cpp: # 823| r0_139(glval) = ConvertToBase[Middle : Base] : r0_138 # 823| v0_140(void) = Call : func:r0_136, 0:r0_139 # 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_142(void) = ^IndirectReadSideEffect[0] : &:r0_139, ~mu0_2 +# 823| v0_142(void) = ^BufferReadSideEffect[0] : &:r0_139, ~mu0_2 # 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_139 # 823| r0_144(glval) = Convert : v0_140 # 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_147(void) = ^IndirectReadSideEffect[-1] : &:r0_134, ~mu0_2 -# 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 +# 823| v0_147(void) = ^BufferReadSideEffect[-1] : &:r0_134, ~mu0_2 +# 823| v0_148(void) = ^BufferReadSideEffect[0] : &:r0_144, ~mu0_2 # 823| mu0_149(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_134 # 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 # 824| r0_151(glval) = VariableAddress[b] : @@ -3774,13 +3774,13 @@ ir.cpp: # 824| r0_156(glval) = ConvertToBase[Middle : Base] : r0_155 # 824| v0_157(void) = Call : func:r0_153, 0:r0_156 # 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_159(void) = ^IndirectReadSideEffect[0] : &:r0_156, ~mu0_2 +# 824| v0_159(void) = ^BufferReadSideEffect[0] : &:r0_156, ~mu0_2 # 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_156 # 824| r0_161(glval) = Convert : v0_157 # 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 # 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_164(void) = ^IndirectReadSideEffect[-1] : &:r0_151, ~mu0_2 -# 824| v0_165(void) = ^IndirectReadSideEffect[0] : &:r0_161, ~mu0_2 +# 824| v0_164(void) = ^BufferReadSideEffect[-1] : &:r0_151, ~mu0_2 +# 824| v0_165(void) = ^BufferReadSideEffect[0] : &:r0_161, ~mu0_2 # 824| mu0_166(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_151 # 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_161 # 825| r0_168(glval) = VariableAddress[pd] : @@ -3814,8 +3814,8 @@ ir.cpp: # 830| r0_196(glval) = Convert : r0_195 # 830| r0_197(Derived &) = Call : func:r0_192, this:r0_191, 0:r0_196 # 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 -# 830| v0_199(void) = ^IndirectReadSideEffect[-1] : &:r0_191, ~mu0_2 -# 830| v0_200(void) = ^IndirectReadSideEffect[0] : &:r0_196, ~mu0_2 +# 830| v0_199(void) = ^BufferReadSideEffect[-1] : &:r0_191, ~mu0_2 +# 830| v0_200(void) = ^BufferReadSideEffect[0] : &:r0_196, ~mu0_2 # 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_191 # 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_196 # 831| r0_203(glval) = VariableAddress[d] : @@ -3826,8 +3826,8 @@ ir.cpp: # 831| r0_208(glval) = Convert : r0_207 # 831| r0_209(Derived &) = Call : func:r0_204, this:r0_203, 0:r0_208 # 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 -# 831| v0_211(void) = ^IndirectReadSideEffect[-1] : &:r0_203, ~mu0_2 -# 831| v0_212(void) = ^IndirectReadSideEffect[0] : &:r0_208, ~mu0_2 +# 831| v0_211(void) = ^BufferReadSideEffect[-1] : &:r0_203, ~mu0_2 +# 831| v0_212(void) = ^BufferReadSideEffect[0] : &:r0_208, ~mu0_2 # 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_203 # 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_208 # 832| r0_215(glval) = VariableAddress[pb] : @@ -3972,7 +3972,7 @@ ir.cpp: # 868| r0_6(char *) = Convert : r0_5 # 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 # 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 +# 868| v0_9(void) = ^BufferReadSideEffect[0] : &:r0_6, ~mu0_2 # 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 # 869| v0_11(void) = NoOp : # 867| v0_12(void) = ReturnVoid : @@ -4189,7 +4189,7 @@ ir.cpp: # 945| r0_37(char *) = Convert : r0_36 # 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 # 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 945| v0_40(void) = ^IndirectReadSideEffect[0] : &:r0_37, ~mu0_2 +# 945| v0_40(void) = ^BufferReadSideEffect[0] : &:r0_37, ~mu0_2 # 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_37 # 946| r0_42(glval) = FunctionAddress[operator new] : # 946| r0_43(unsigned long) = Constant[256] : @@ -4677,7 +4677,7 @@ ir.cpp: # 1035| r0_28(float) = Constant[1.0] : # 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 # 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 -# 1035| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 +# 1035| v0_31(void) = ^BufferReadSideEffect[-1] : &:r0_26, ~mu0_2 # 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_26 # 1036| r0_33(glval) = VariableAddress[lambda_val] : # 1036| r0_34(glval) = FunctionAddress[(constructor)] : @@ -4694,7 +4694,7 @@ ir.cpp: # 1036| r0_45(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 # 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 # 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| v0_48(void) = ^IndirectReadSideEffect[0] : &:r0_45, ~mu0_2 +# 1036| v0_48(void) = ^BufferReadSideEffect[0] : &:r0_45, ~mu0_2 # 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_45 # 1037| r0_50(glval) = VariableAddress[lambda_val] : # 1037| r0_51(glval) = Convert : r0_50 @@ -4702,7 +4702,7 @@ ir.cpp: # 1037| r0_53(float) = Constant[2.0] : # 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 # 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| v0_56(void) = ^IndirectReadSideEffect[-1] : &:r0_51, ~mu0_2 +# 1037| v0_56(void) = ^BufferReadSideEffect[-1] : &:r0_51, ~mu0_2 # 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_51 # 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : # 1038| r0_59(glval) = VariableAddress[#temp1038:30] : @@ -4719,7 +4719,7 @@ ir.cpp: # 1039| r0_70(float) = Constant[3.0] : # 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 # 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 -# 1039| v0_73(void) = ^IndirectReadSideEffect[-1] : &:r0_68, ~mu0_2 +# 1039| v0_73(void) = ^BufferReadSideEffect[-1] : &:r0_68, ~mu0_2 # 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_68 # 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : # 1040| r0_76(glval) = FunctionAddress[(constructor)] : @@ -4732,7 +4732,7 @@ ir.cpp: # 1040| r0_83(decltype([...](...){...})) = Load : &:r0_77, ~mu0_2 # 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 # 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| v0_86(void) = ^IndirectReadSideEffect[0] : &:r0_83, ~mu0_2 +# 1040| v0_86(void) = ^BufferReadSideEffect[0] : &:r0_83, ~mu0_2 # 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_83 # 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : # 1041| r0_89(glval) = Convert : r0_88 @@ -4740,7 +4740,7 @@ ir.cpp: # 1041| r0_91(float) = Constant[4.0] : # 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 # 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| v0_94(void) = ^IndirectReadSideEffect[-1] : &:r0_89, ~mu0_2 +# 1041| v0_94(void) = ^BufferReadSideEffect[-1] : &:r0_89, ~mu0_2 # 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_89 # 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : # 1042| r0_97(glval) = VariableAddress[#temp1042:32] : @@ -4761,7 +4761,7 @@ ir.cpp: # 1043| r0_112(float) = Constant[5.0] : # 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 # 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 -# 1043| v0_115(void) = ^IndirectReadSideEffect[-1] : &:r0_110, ~mu0_2 +# 1043| v0_115(void) = ^BufferReadSideEffect[-1] : &:r0_110, ~mu0_2 # 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_110 # 1044| r0_117(glval) = VariableAddress[r] : # 1044| r0_118(glval) = VariableAddress[x] : @@ -4797,7 +4797,7 @@ ir.cpp: # 1046| r0_148(float) = Constant[6.0] : # 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 # 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 -# 1046| v0_151(void) = ^IndirectReadSideEffect[-1] : &:r0_146, ~mu0_2 +# 1046| v0_151(void) = ^BufferReadSideEffect[-1] : &:r0_146, ~mu0_2 # 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_146 # 1047| v0_153(void) = NoOp : # 1031| v0_154(void) = ReturnVoid : @@ -4862,7 +4862,7 @@ ir.cpp: # 1034| r0_10(glval) = FunctionAddress[c_str] : # 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1034| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1034| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_9, ~mu0_2 # 1034| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 @@ -4905,7 +4905,7 @@ ir.cpp: # 1036| r0_9(glval) = FunctionAddress[c_str] : # 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| v0_12(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu0_2 #-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 #-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 #-----| r0_15(glval) = FieldAddress[x] : r0_14 @@ -4933,7 +4933,7 @@ ir.cpp: # 1038| r0_10(glval) = FunctionAddress[c_str] : # 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1038| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_9, ~mu0_2 # 1038| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 1038| r0_15(int) = Constant[0] : # 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 @@ -4990,7 +4990,7 @@ ir.cpp: # 1040| r0_9(glval) = FunctionAddress[c_str] : # 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| v0_12(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu0_2 #-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 1040| r0_14(int) = Constant[0] : # 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 @@ -5016,7 +5016,7 @@ ir.cpp: # 1042| r0_10(glval) = FunctionAddress[c_str] : # 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1042| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1042| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_9, ~mu0_2 # 1042| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 @@ -5044,7 +5044,7 @@ ir.cpp: # 1045| r0_10(glval) = FunctionAddress[c_str] : # 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1045| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1045| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_9, ~mu0_2 # 1045| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 @@ -5083,7 +5083,7 @@ ir.cpp: # 1069| r0_12(glval) = FunctionAddress[begin] : # 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 # 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_11, ~mu0_2 #-----| mu0_16(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 # 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 # 1069| r0_18(glval) = VariableAddress[(__end)] : @@ -5092,7 +5092,7 @@ ir.cpp: # 1069| r0_21(glval) = FunctionAddress[end] : # 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 # 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_24(void) = ^IndirectReadSideEffect[-1] : &:r0_20, ~mu0_2 +#-----| v0_24(void) = ^BufferReadSideEffect[-1] : &:r0_20, ~mu0_2 #-----| mu0_25(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_20 # 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 #-----| Goto -> Block 4 @@ -5104,7 +5104,7 @@ ir.cpp: # 1075| r1_3(glval) = FunctionAddress[operator*] : # 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 # 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v1_6(void) = ^IndirectReadSideEffect[-1] : &:r1_2, ~mu0_2 +#-----| v1_6(void) = ^BufferReadSideEffect[-1] : &:r1_2, ~mu0_2 #-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1_2 # 1075| r1_8(glval) = Convert : r1_4 # 1075| mu1_9(int &) = Store : &:r1_0, r1_8 @@ -5136,7 +5136,7 @@ ir.cpp: #-----| r4_4(iterator) = Load : &:r4_3, ~mu0_2 # 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 # 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v4_7(void) = ^IndirectReadSideEffect[-1] : &:r4_1, ~mu0_2 +#-----| v4_7(void) = ^BufferReadSideEffect[-1] : &:r4_1, ~mu0_2 #-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r4_1 # 1069| v4_9(void) = ConditionalBranch : r4_5 #-----| False -> Block 8 @@ -5149,7 +5149,7 @@ ir.cpp: # 1069| r5_3(glval) = FunctionAddress[operator*] : # 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 # 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v5_6(void) = ^IndirectReadSideEffect[-1] : &:r5_2, ~mu0_2 +#-----| v5_6(void) = ^BufferReadSideEffect[-1] : &:r5_2, ~mu0_2 #-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r5_2 # 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 # 1069| mu5_9(int) = Store : &:r5_0, r5_8 @@ -5171,7 +5171,7 @@ ir.cpp: # 1069| r7_2(glval) = FunctionAddress[operator++] : # 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 # 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v7_5(void) = ^IndirectReadSideEffect[-1] : &:r7_1, ~mu0_2 +#-----| v7_5(void) = ^BufferReadSideEffect[-1] : &:r7_1, ~mu0_2 #-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r7_1 #-----| Goto (back edge) -> Block 4 @@ -5186,7 +5186,7 @@ ir.cpp: # 1075| r8_7(glval) = FunctionAddress[begin] : # 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 # 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v8_10(void) = ^IndirectReadSideEffect[-1] : &:r8_6, ~mu0_2 +#-----| v8_10(void) = ^BufferReadSideEffect[-1] : &:r8_6, ~mu0_2 #-----| mu8_11(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_6 # 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 # 1075| r8_13(glval) = VariableAddress[(__end)] : @@ -5195,7 +5195,7 @@ ir.cpp: # 1075| r8_16(glval) = FunctionAddress[end] : # 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 # 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v8_19(void) = ^IndirectReadSideEffect[-1] : &:r8_15, ~mu0_2 +#-----| v8_19(void) = ^BufferReadSideEffect[-1] : &:r8_15, ~mu0_2 #-----| mu8_20(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_15 # 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 #-----| Goto -> Block 9 @@ -5208,7 +5208,7 @@ ir.cpp: #-----| r9_4(iterator) = Load : &:r9_3, ~mu0_2 # 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 # 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v9_7(void) = ^IndirectReadSideEffect[-1] : &:r9_1, ~mu0_2 +#-----| v9_7(void) = ^BufferReadSideEffect[-1] : &:r9_1, ~mu0_2 #-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r9_1 # 1075| v9_9(void) = ConditionalBranch : r9_5 #-----| False -> Block 3 @@ -5219,7 +5219,7 @@ ir.cpp: # 1075| r10_1(glval) = FunctionAddress[operator++] : # 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 # 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v10_4(void) = ^IndirectReadSideEffect[-1] : &:r10_0, ~mu0_2 +#-----| v10_4(void) = ^BufferReadSideEffect[-1] : &:r10_0, ~mu0_2 #-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r10_0 #-----| Goto (back edge) -> Block 9 @@ -5378,7 +5378,7 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 1140| v7_6(void) = ^BufferReadSideEffect[0] : &:r7_3, ~mu0_2 # 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -5403,7 +5403,7 @@ ir.cpp: # 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 1145| v10_8(void) = ^BufferReadSideEffect[0] : &:r10_5, ~mu0_2 # 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 9d005c57ca8..9e32c962fb7 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -327,7 +327,7 @@ ssa.cpp: # 97| v0_13(void) = Call : func:r0_10, 0:r0_12 # 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 # 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 -# 97| v0_16(void) = ^IndirectReadSideEffect[0] : &:r0_12, ~m0_15 +# 97| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m0_15 # 97| m0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 # 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 # 98| v0_19(void) = NoOp : @@ -381,7 +381,7 @@ ssa.cpp: # 108| v0_19(void) = Call : func:r0_16, 0:r0_18 # 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 # 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 -# 108| v0_22(void) = ^IndirectReadSideEffect[0] : &:r0_18, ~m0_21 +# 108| v0_22(void) = ^BufferReadSideEffect[0] : &:r0_18, ~m0_21 # 108| m0_23(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18 # 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 # 109| v0_25(void) = NoOp : @@ -451,7 +451,7 @@ ssa.cpp: # 119| v0_27(void) = Call : func:r0_24, 0:r0_26 # 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 # 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 -# 119| v0_30(void) = ^IndirectReadSideEffect[0] : &:r0_26, ~m0_29 +# 119| v0_30(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m0_29 # 119| m0_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 # 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 # 120| v0_33(void) = NoOp : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index a68690c7055..0a203453a72 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -326,7 +326,7 @@ ssa.cpp: # 97| r0_11(void *) = Convert : r0_10 # 97| v0_12(void) = Call : func:r0_9, 0:r0_11 # 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 97| v0_14(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +# 97| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_11, ~mu0_2 # 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 # 98| v0_16(void) = NoOp : # 95| v0_17(void) = ReturnVoid : @@ -377,7 +377,7 @@ ssa.cpp: # 108| r0_17(void *) = Convert : r0_16 # 108| v0_18(void) = Call : func:r0_15, 0:r0_17 # 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 108| v0_20(void) = ^IndirectReadSideEffect[0] : &:r0_17, ~mu0_2 +# 108| v0_20(void) = ^BufferReadSideEffect[0] : &:r0_17, ~mu0_2 # 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_17 # 109| v0_22(void) = NoOp : # 105| v0_23(void) = ReturnVoid : @@ -440,7 +440,7 @@ ssa.cpp: # 119| r0_23(void *) = Convert : r0_22 # 119| v0_24(void) = Call : func:r0_21, 0:r0_23 # 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 119| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +# 119| v0_26(void) = ^BufferReadSideEffect[0] : &:r0_23, ~mu0_2 # 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 # 120| v0_28(void) = NoOp : # 116| v0_29(void) = ReturnVoid : From e57fef093b6f4d7a6202a031270bbf2e2361dad2 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 18 Oct 2019 10:08:53 -0700 Subject: [PATCH 014/148] C++: accept syntax-zoo changes --- .../library-tests/syntax-zoo/aliased_ssa_sanity.expected | 8 ++++---- .../syntax-zoo/unaliased_ssa_sanity.expected | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 5fb356f5701..8512c3dc732 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -1,9 +1,9 @@ missingOperand | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | BufferReadSideEffect: my_c | Instruction 'BufferReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | BufferReadSideEffect: my_c | Instruction 'BufferReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | BufferReadSideEffect: my_c | Instruction 'BufferReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | BufferReadSideEffect: my_c | Instruction 'BufferReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | | try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index 22a395b3f89..d68395fe136 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -1,9 +1,5 @@ missingOperand | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | | try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand From 8a1d1e7b7a119f1b39db0d424ff34f7a7140e88d Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 21 Oct 2019 16:07:48 +0200 Subject: [PATCH 015/148] Python: Modernise and false positive in `py/undefined-export`. --- python/ql/src/Variables/UndefinedExport.ql | 14 +++++++------- python/ql/src/semmle/python/Module.qll | 7 +++++++ python/ql/src/semmle/python/objects/ObjectAPI.qll | 6 ++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 6bf128def79..cbe43475afa 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -22,10 +22,10 @@ predicate declaredInAll(Module m, StrConst name) ) } -predicate mutates_globals(PythonModuleObject m) { +predicate mutates_globals(ModuleValue m) { exists(CallNode globals | globals = Object::builtin("globals").(FunctionObject).getACall() and - globals.getScope() = m.getModule() | + globals.getScope() = m.getScope() | exists(AttrNode attr | attr.getObject() = globals) or exists(SubscriptNode sub | sub.getValue() = globals and sub.isStore()) @@ -34,7 +34,7 @@ predicate mutates_globals(PythonModuleObject m) { exists(Object enum_convert | enum_convert.hasLongName("enum.Enum._convert") and exists(CallNode call | - call.getScope() = m.getModule() + call.getScope() = m.getScope() | enum_convert.(FunctionObject).getACall() = call or call.getFunction().refersTo(enum_convert) @@ -42,11 +42,11 @@ predicate mutates_globals(PythonModuleObject m) { ) } -from PythonModuleObject m, StrConst name, string exported_name -where declaredInAll(m.getModule(), name) and +from ModuleValue m, StrConst name, string exported_name +where declaredInAll(m.getScope(), name) and exported_name = name.strValue() and not m.hasAttribute(exported_name) and -not (m.getShortName() = "__init__" and exists(m.getPackage().getModule().getSubModule(exported_name))) and -not exists(ImportStarNode imp | imp.getEnclosingModule() = m.getModule() | not imp.getModule().refersTo(_)) and +not (m.getScope().getShortName() = "__init__" and exists(m.getScope().getPackage().getSubModule(exported_name))) and +not exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() | imp.getModule().pointsTo().isAbsent()) and not mutates_globals(m) select name, "The name '" + exported_name + "' is exported by __all__ but is not defined." \ No newline at end of file diff --git a/python/ql/src/semmle/python/Module.qll b/python/ql/src/semmle/python/Module.qll index a3bf174897f..68361d1b12c 100644 --- a/python/ql/src/semmle/python/Module.qll +++ b/python/ql/src/semmle/python/Module.qll @@ -52,6 +52,13 @@ class Module extends Module_, Scope, AstNode { result = moduleNameFromFile(this.getPath()) } + /** Gets the short name of the module. For example the short name of module x.y.z is 'z' */ + string getShortName() { + result = this.getName().suffix(this.getPackage().getName().length()+1) + or + result = this.getName() and not exists(this.getPackage()) + } + /** Gets this module */ override Module getEnclosingModule() { result = this diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index dd6b856875a..3fc003b86e5 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -99,6 +99,12 @@ class Value extends TObject { this.(ObjectInternal).hasAttribute(name) } + /** Whether this value is absent from the database, but has been inferred to likely exist */ + predicate isAbsent() { + this instanceof AbsentModuleObjectInternal + or + this instanceof AbsentModuleAttributeObjectInternal + } } /** Class representing modules in the Python program From 4fe1ba0ea401477995f1c1ab1b494461cf576ac1 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 21 Oct 2019 16:15:13 +0200 Subject: [PATCH 016/148] Python: Refactor `py/undefined-export` for more clarity. --- python/ql/src/Variables/UndefinedExport.ql | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index cbe43475afa..5e739030f2a 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -42,11 +42,25 @@ predicate mutates_globals(ModuleValue m) { ) } +predicate is_exported_submodule_name(ModuleValue m, string exported_name) { + m.getScope().getShortName() = "__init__" and + exists(m.getScope().getPackage().getSubModule(exported_name)) +} + +predicate contains_unknown_import_star(ModuleValue m) { + exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() | + imp.getModule().pointsTo().isAbsent() + or + not exists(imp.getModule().pointsTo()) + ) +} + from ModuleValue m, StrConst name, string exported_name -where declaredInAll(m.getScope(), name) and -exported_name = name.strValue() and -not m.hasAttribute(exported_name) and -not (m.getScope().getShortName() = "__init__" and exists(m.getScope().getPackage().getSubModule(exported_name))) and -not exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() | imp.getModule().pointsTo().isAbsent()) and -not mutates_globals(m) -select name, "The name '" + exported_name + "' is exported by __all__ but is not defined." \ No newline at end of file +where + declaredInAll(m.getScope(), name) and + exported_name = name.strValue() and + not m.hasAttribute(exported_name) and + not is_exported_submodule_name(m, exported_name) and + not contains_unknown_import_star(m) and + not mutates_globals(m) +select name, "The name '" + exported_name + "' is exported by __all__ but is not defined." From ab2c8f312cc67ceeb28bd3a4e3e6132e9617726a Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 21 Oct 2019 16:15:48 +0200 Subject: [PATCH 017/148] Python: Apply autoformat. --- python/ql/src/Variables/UndefinedExport.ql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 5e739030f2a..b7a835b42d6 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -14,18 +14,20 @@ import python /** Whether name is declared in the __all__ list of this module */ -predicate declaredInAll(Module m, StrConst name) -{ - exists(Assign a, GlobalVariable all | - a.defines(all) and a.getScope() = m and - all.getId() = "__all__" and ((List)a.getValue()).getAnElt() = name +predicate declaredInAll(Module m, StrConst name) { + exists(Assign a, GlobalVariable all | + a.defines(all) and + a.getScope() = m and + all.getId() = "__all__" and + a.getValue().(List).getAnElt() = name ) } predicate mutates_globals(ModuleValue m) { exists(CallNode globals | globals = Object::builtin("globals").(FunctionObject).getACall() and - globals.getScope() = m.getScope() | + globals.getScope() = m.getScope() + | exists(AttrNode attr | attr.getObject() = globals) or exists(SubscriptNode sub | sub.getValue() = globals and sub.isStore()) @@ -33,9 +35,7 @@ predicate mutates_globals(ModuleValue m) { or exists(Object enum_convert | enum_convert.hasLongName("enum.Enum._convert") and - exists(CallNode call | - call.getScope() = m.getScope() - | + exists(CallNode call | call.getScope() = m.getScope() | enum_convert.(FunctionObject).getACall() = call or call.getFunction().refersTo(enum_convert) ) From 2e0244cda62deea17afe438c30e289d5c97913ca Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 21 Oct 2019 20:21:41 +0200 Subject: [PATCH 018/148] address review feedback --- .../ql/src/Expressions/ExprHasNoEffect.ql | 1 + .../ql/src/Expressions/ExprHasNoEffect.qll | 1 - .../src/Statements/UseOfReturnlessFunction.ql | 25 +++++++++++++++---- .../UseOfReturnlessFunction.expected | 8 +++--- .../Statements/UseOfReturnlessFunction/tst.js | 3 +++ 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.ql b/javascript/ql/src/Expressions/ExprHasNoEffect.ql index 929e84616f0..917ab81a3e7 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.ql +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.ql @@ -14,6 +14,7 @@ import javascript import ExprHasNoEffect +import semmle.javascript.RestrictedLocations from Expr e diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.qll b/javascript/ql/src/Expressions/ExprHasNoEffect.qll index 822bcbb26fa..bee980e5fd8 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.qll +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.qll @@ -5,7 +5,6 @@ import javascript import DOMProperties import semmle.javascript.frameworks.xUnit -import semmle.javascript.RestrictedLocations /** * Holds if `e` appears in a syntactic context where its value is discarded. diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 2d70cecb0d3..fe03c66cf4a 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -82,8 +82,19 @@ predicate alwaysThrows(Function f) { ) } +/** + * Holds if the last statement in the function is flagged by the js/useless-expression query. + */ +predicate alwaysHasNoEffect(Function f) { + exists(ReachableBasicBlock entry, DataFlow::Node noEffect | + entry = f.getEntryBB() and + hasNoEffect(noEffect.asExpr()) and + entry.dominates(noEffect.getBasicBlock()) + ) +} + predicate callToVoidFunction(DataFlow::CallNode call, Function func) { - not call.isIndefinite(_) and + not call.isIncomplete() and func = call.getACallee() and forall(Function f | f = call.getACallee() | returnsVoid(f) and not isStub(f) and not alwaysThrows(f) @@ -113,6 +124,11 @@ DataFlow::SourceNode array(DataFlow::TypeTracker t) { DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } +/** + * Holds if `call` is an Array or Lodash method accepting a callback `func`, + * where the `call` expects a callback that returns an expression, + * but `func` does return a value. + */ predicate voidArrayCallback(DataFlow::CallNode call, Function func) { hasNonVoidCallbackMethod(call.getCalleeName()) and func = call.getAnArgument().getALocalSource().asExpr() and @@ -132,15 +148,14 @@ where ( callToVoidFunction(call, func) and msg = "the $@ does not return anything, yet the return value is used." and - name = "function " + call.getCalleeName() + name = func.describe() or voidArrayCallback(call, func) and - msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + "() is used." and + msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + " is used." and name = "callback function" ) and not benignContext(call.asExpr()) and - // Avoid double reporting from js/useless-expression - not hasNoEffect(func.getBodyStmt(func.getNumBodyStmt() - 1).(ExprStmt).getExpr()) and + not alwaysHasNoEffect(func) and // anonymous one-shot closure. Those are used in weird ways and we ignore them. not oneshotClosure(call.asExpr()) select diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected index 98ae4e3696c..f23b702bf20 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected @@ -1,7 +1,7 @@ | tst.js:20:17:20:33 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | | tst.js:24:13:24:29 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | | tst.js:30:20:30:36 | onlySideEffects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | -| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | -| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function bothOnlyHaveSideEffects | -| tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter() is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function | -| tst.js:80:12:80:50 | filter( ... 3) } ) | the $@ does not return anything, yet the return value from the call to filter() is used. | tst.js:80:28:80:48 | x => { ... x, 3) } | callback function | +| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:11:5:13:5 | functio ... )\\n } | function onlySideEffects | +| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function onlySideEffects2 | +| tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function | +| tst.js:80:12:80:50 | filter( ... 3) } ) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:80:28:80:48 | x => { ... x, 3) } | callback function | diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js index 2b523223e91..8a6a44707ed 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js @@ -79,4 +79,7 @@ import { filter } from 'lodash' var bar = filter([1,2,4], x => { equals(x, 3) } ) // NOT OK! console.log(bar); + + var baz = [1,2,3].filter(n => {n === 3}) // OK + console.log(baz); })(); \ No newline at end of file From db22916850202d1e159fc21e651670f501d29bc2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 22 Oct 2019 09:37:19 +0200 Subject: [PATCH 019/148] fix the alwaysHasNoEffect predicate, and rename it to lastStatementHasNoEffect --- .../ql/src/Statements/UseOfReturnlessFunction.ql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index fe03c66cf4a..0f168e263dd 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -85,11 +85,11 @@ predicate alwaysThrows(Function f) { /** * Holds if the last statement in the function is flagged by the js/useless-expression query. */ -predicate alwaysHasNoEffect(Function f) { - exists(ReachableBasicBlock entry, DataFlow::Node noEffect | - entry = f.getEntryBB() and - hasNoEffect(noEffect.asExpr()) and - entry.dominates(noEffect.getBasicBlock()) +predicate lastStatementHasNoEffect(Function f) { + exists(DataFlow::Node noEffect | + noEffect.getContainer() = f and + hasNoEffect(noEffect.asExpr()) and + not exists(noEffect.getASuccessor()) ) } @@ -155,7 +155,7 @@ where name = "callback function" ) and not benignContext(call.asExpr()) and - not alwaysHasNoEffect(func) and + not lastStatementHasNoEffect(func) and // anonymous one-shot closure. Those are used in weird ways and we ignore them. not oneshotClosure(call.asExpr()) select From ad3185c5586efc622cea59956868e729a545ae4a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 22 Oct 2019 10:33:05 +0200 Subject: [PATCH 020/148] simplify lastStatementHasNoEffect and use the control-flow to determine which statement is the last --- javascript/ql/src/Statements/UseOfReturnlessFunction.ql | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 0f168e263dd..2fc3f01a560 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -86,11 +86,7 @@ predicate alwaysThrows(Function f) { * Holds if the last statement in the function is flagged by the js/useless-expression query. */ predicate lastStatementHasNoEffect(Function f) { - exists(DataFlow::Node noEffect | - noEffect.getContainer() = f and - hasNoEffect(noEffect.asExpr()) and - not exists(noEffect.getASuccessor()) - ) + hasNoEffect(f.getExit().getAPredecessor()) } predicate callToVoidFunction(DataFlow::CallNode call, Function func) { From ee7cf17b1567028914db80b26ba33aec54290251 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 23 Oct 2019 11:22:52 +0100 Subject: [PATCH 021/148] C#: Add test case for local disposal. --- .../NoDisposeCallOnLocalIDisposable.cs | 5 +++++ .../NoDisposeCallOnLocalIDisposable.expected | 1 + 2 files changed, 6 insertions(+) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index 45caec0022d..c5336b72ab3 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -83,6 +83,11 @@ class Test // GOOD: Disposed automatically. using var c2 = new Timer(TimerProc); + // GOOD: ownership taken via ?? (false positive) + StringReader source = null; + using(XmlReader.Create(source ?? new StringReader("xml"), null)) + ; + return null; } diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index aa70ad5a1cd..128686a7b63 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -2,4 +2,5 @@ | NoDisposeCallOnLocalIDisposable.cs:53:18:53:73 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:54:9:54:64 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:76:25:76:71 | call to method Create | Disposable 'XmlReader' is created here but is not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:88:42:88:64 | object creation of type StringReader | Disposable 'StringReader' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | From 01ad93d199d8d5bdfb3aebd5e3d0bc251e28eabb Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 23 Oct 2019 12:26:01 +0100 Subject: [PATCH 022/148] C#: Fix for false positive. --- .../src/API Abuse/NoDisposeCallOnLocalIDisposable.ql | 11 ++++++++++- .../NoDisposeCallOnLocalIDisposable.expected | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index 646ab04ac1f..d8de5242fcc 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -54,7 +54,16 @@ private class Conf extends DataFlow::Configuration { ) or // A disposing method - exists(Call c, Parameter p | e = c.getArgumentForParameter(p) | mayBeDisposed(p)) + exists(Call c, Parameter p | + e = c.getArgumentForParameter(p) + or + // e.g `Stream.Create(input ?? new TextReader())` + exists(NullCoalescingExpr nce | + nce = c.getArgumentForParameter(p) and e = nce.getRightOperand() + ) + | + mayBeDisposed(p) + ) or // Things that are assigned to fields, properties, or indexers may be disposed exists(AssignableDefinition def, Assignable a | diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 128686a7b63..aa70ad5a1cd 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -2,5 +2,4 @@ | NoDisposeCallOnLocalIDisposable.cs:53:18:53:73 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:54:9:54:64 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:76:25:76:71 | call to method Create | Disposable 'XmlReader' is created here but is not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:88:42:88:64 | object creation of type StringReader | Disposable 'StringReader' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | From 6b15bf62fd65bc63448365c0aabe045adb50fa75 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 23 Oct 2019 13:49:22 +0100 Subject: [PATCH 023/148] C#: Rewrite null-coalsecing logic --- .../API Abuse/NoDisposeCallOnLocalIDisposable.ql | 13 +++---------- .../NoDisposeCallOnLocalIDisposable.cs | 2 +- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index d8de5242fcc..3a50d474577 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -54,16 +54,7 @@ private class Conf extends DataFlow::Configuration { ) or // A disposing method - exists(Call c, Parameter p | - e = c.getArgumentForParameter(p) - or - // e.g `Stream.Create(input ?? new TextReader())` - exists(NullCoalescingExpr nce | - nce = c.getArgumentForParameter(p) and e = nce.getRightOperand() - ) - | - mayBeDisposed(p) - ) + exists(Call c, Parameter p | e = c.getArgumentForParameter(p) | mayBeDisposed(p)) or // Things that are assigned to fields, properties, or indexers may be disposed exists(AssignableDefinition def, Assignable a | @@ -90,6 +81,8 @@ private class Conf extends DataFlow::Configuration { override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { node2.asExpr() = any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr()) + or + exists(NullCoalescingExpr nce | node1.asExpr() = nce.getRightOperand() and node2.asExpr() = nce) } override predicate isBarrierOut(DataFlow::Node node) { diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index c5336b72ab3..82a33086144 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -83,7 +83,7 @@ class Test // GOOD: Disposed automatically. using var c2 = new Timer(TimerProc); - // GOOD: ownership taken via ?? (false positive) + // GOOD: ownership taken via ?? StringReader source = null; using(XmlReader.Create(source ?? new StringReader("xml"), null)) ; From 60226801aa2f92e14c7299a3e6dd1a7b78047a7d Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 23 Oct 2019 14:54:02 +0100 Subject: [PATCH 024/148] Docs: Update terminology A more in-depth attempt at changing terminology for GHU. I've only updated the non-language specific topics so far. --- docs/language/learn-ql/about-ql.rst | 4 +- .../learn-ql/advanced/abstract-classes.rst | 4 +- .../learn-ql/advanced/advanced-ql.rst | 2 +- .../learn-ql/advanced/constraining-types.rst | 2 +- .../determining-specific-types-variables.rst | 8 ++-- .../learn-ql/advanced/equivalence.rst | 2 +- .../advanced/monotonic-aggregates.rst | 2 +- .../learn-ql/beginner/find-thief-3.rst | 2 +- docs/language/learn-ql/beginner/fire-2.rst | 2 +- docs/language/learn-ql/beginner/heir.rst | 2 +- .../learn-ql/beginner/ql-tutorials.rst | 13 +++--- docs/language/learn-ql/database.rst | 33 +++++++++++++++ docs/language/learn-ql/index.rst | 35 ++++++++-------- docs/language/learn-ql/intro-to-data-flow.rst | 24 +++++------ docs/language/learn-ql/introduction-to-ql.rst | 33 +++++++++------ docs/language/learn-ql/locations.rst | 10 +++-- .../learn-ql/python/pointsto-type-infer.rst | 4 +- .../learn-ql/ql-etudes/river-crossing.rst | 4 +- docs/language/learn-ql/snapshot.rst | 33 --------------- docs/language/learn-ql/technical-info.rst | 4 +- .../introduction-to-queries.rst | 42 ++++++++++--------- .../learn-ql/writing-queries/path-queries.rst | 28 ++++++------- .../learn-ql/writing-queries/query-help.rst | 12 +++--- .../writing-queries/select-statement.rst | 2 +- .../writing-queries/writing-queries.rst | 23 +++++----- docs/language/ql-handbook/annotations.rst | 2 +- docs/language/ql-handbook/index.rst | 2 +- docs/language/ql-handbook/types.rst | 6 +-- .../ql-training/slide-snippets/info.rst | 2 +- 29 files changed, 179 insertions(+), 163 deletions(-) create mode 100644 docs/language/learn-ql/database.rst delete mode 100644 docs/language/learn-ql/snapshot.rst diff --git a/docs/language/learn-ql/about-ql.rst b/docs/language/learn-ql/about-ql.rst index 145f98ad600..8f2f26018a4 100644 --- a/docs/language/learn-ql/about-ql.rst +++ b/docs/language/learn-ql/about-ql.rst @@ -1,11 +1,11 @@ About QL ======== -This section is aimed at users with a background in general purpose programming as well as in databases. For a basic introduction and information on how to get started, see :doc:`Introduction to the QL language ` and :doc:`Learning QL <../index>`. +This section is aimed at users with a background in general purpose programming as well as in databases. For a basic introduction and information on how to get started, see :doc:`Introduction to QL ` and :doc:`Learning CodeQL <../index>`. QL is a declarative, object-oriented query language that is optimized to enable efficient analysis of hierarchical data structures, in particular, databases representing software artifacts. -The queries and metrics used in LGTM are implemented using QL. This ensures that they can be extended or revised easily to keep up with changes in definitions of best coding practice. We continually improve existing queries as we work towards the ultimate goal of 100% precision. +The queries and metrics used in LGTM are implemented using CodeQL, which uses QL to analyze code. This ensures that they can be extended or revised easily to keep up with changes in definitions of best coding practice. We continually improve existing queries as we work towards the ultimate goal of 100% precision. You can write queries to identify security vulnerabilities, find coding errors and bugs, or find code that breaks your team's guidelines for best practice. You can also create customized versions of the default queries to accommodate a new framework. diff --git a/docs/language/learn-ql/advanced/abstract-classes.rst b/docs/language/learn-ql/advanced/abstract-classes.rst index d616a31395b..32441b35996 100644 --- a/docs/language/learn-ql/advanced/abstract-classes.rst +++ b/docs/language/learn-ql/advanced/abstract-classes.rst @@ -4,7 +4,7 @@ Semantics of abstract classes Concrete classes ---------------- -Concrete QL classes, as described in the QL language handbook topic on `Classes `__, lend themselves well to top-down modeling. We start from general superclasses representing large sets of values, and carve out individual subclasses representing more restricted sets of values. +Concrete classes, as described in the QL language handbook topic on `Classes `__, lend themselves well to top-down modeling. We start from general superclasses representing large sets of values, and carve out individual subclasses representing more restricted sets of values. A classic example where this approach is useful is when modeling ASTs (Abstract Syntax Trees): the node types of an AST form a natural inheritance hierarchy, where, for example, there is a class ``Expr`` representing all expression nodes, with many different subclasses for different categories of expressions. There might be a class ``ArithmeticExpr`` representing arithmetic expressions, which in turn could have subclasses ``AddExpr`` and ``SubExpr``. @@ -57,7 +57,7 @@ Like a concrete class, an abstract class has one or more superclasses and a char Example ~~~~~~~ -The following example is taken from the standard QL library for Java: +The following example is taken from the CodeQL library for Java: .. code-block:: ql diff --git a/docs/language/learn-ql/advanced/advanced-ql.rst b/docs/language/learn-ql/advanced/advanced-ql.rst index e9397bd5ab2..67af5a6fb26 100644 --- a/docs/language/learn-ql/advanced/advanced-ql.rst +++ b/docs/language/learn-ql/advanced/advanced-ql.rst @@ -8,7 +8,7 @@ Advanced QL ./* -Topics on advanced uses of QL. These topics assume that you are familiar with the QL language and the basics of query writing. +Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing. - :doc:`Semantics of abstract classes ` - :doc:`Choosing appropriate ways to constrain types ` diff --git a/docs/language/learn-ql/advanced/constraining-types.rst b/docs/language/learn-ql/advanced/constraining-types.rst index e150c8ba380..8c00f86fe50 100644 --- a/docs/language/learn-ql/advanced/constraining-types.rst +++ b/docs/language/learn-ql/advanced/constraining-types.rst @@ -8,7 +8,7 @@ Type constraint methods Note - The examples below use the Java QL library. All QL libraries support using these methods to constrain variables, the only difference is in the names of the classes used. + The examples below use the CodeQL library for Java. All CodeQL libraries support using these methods to constrain variables, the only difference is in the names of the classes used. There are several ways of imposing type constraints on variables: diff --git a/docs/language/learn-ql/advanced/determining-specific-types-variables.rst b/docs/language/learn-ql/advanced/determining-specific-types-variables.rst index ce3c5a9e211..7deadde39c9 100644 --- a/docs/language/learn-ql/advanced/determining-specific-types-variables.rst +++ b/docs/language/learn-ql/advanced/determining-specific-types-variables.rst @@ -1,14 +1,14 @@ Determining the most specific types of a variable ================================================= -It is sometimes useful to be able to determine what QL types an entity has -- especially when you are unfamiliar with the QL library used by a query. To help with this, QL provides a predicate called ``getAQlClass()``, which returns the most specific QL types of the entity that it is called on. +It is sometimes useful to be able to determine what types an entity has -- especially when you are unfamiliar with the library used by a query. To help with this, there is a predicate called ``getAQlClass()``, which returns the most specific QL types of the entity that it is called on. This can be useful when you are not sure of the most precise class of a value. Discovering a more precise class can allow you to cast to it and use predicates that are not available on the more general class. Example ------- -If you were working with a Java snapshot database, you might use ``getAQlClass()`` on every ``Expr`` in a callable called ``c``: +If you were working with a Java database, you might use ``getAQlClass()`` on every ``Expr`` in a callable called ``c``: **Java example** @@ -23,6 +23,6 @@ If you were working with a Java snapshot database, you might use ``getAQlClass() and e.getEnclosingCallable() = c select e, e.getAQlClass() -The result of this query is a list of the most specific types of every ``Expr`` in that function. You will see multiple results for some expressions because that expression is represented by more than one QL type. +The result of this query is a list of the most specific types of every ``Expr`` in that function. You will see multiple results for some expressions because that expression is represented by more than one type. -For example, ``StringLiteral``\ s like ``"Hello"`` in Java belong to both the ``StringLiteral`` QL class (a specialization of the ``Literal`` QL class) and the ``CompileTimeConstantExpr`` QL class. So any instances of ``StringLiteral``\ s in the results will produce more than one result, one for each of the QL classes to which they belong. +For example, ``StringLiteral``\ s like ``"Hello"`` in Java belong to both the ``StringLiteral`` class (a specialization of the ``Literal`` class) and the ``CompileTimeConstantExpr`` class. So any instances of ``StringLiteral``\ s in the results will produce more than one result, one for each of the classes to which they belong. diff --git a/docs/language/learn-ql/advanced/equivalence.rst b/docs/language/learn-ql/advanced/equivalence.rst index 40f00cde00f..bf5efb595d0 100644 --- a/docs/language/learn-ql/advanced/equivalence.rst +++ b/docs/language/learn-ql/advanced/equivalence.rst @@ -6,7 +6,7 @@ The two expressions: #. ``a() != b()`` #. ``not(a() = b())`` -look equivalent - so much so that inexperienced (and even experienced) QL programmers have been known to rewrite one as the other. However, they are not equivalent due to the quantifiers involved. +look equivalent - so much so that inexperienced (and even experienced) programmers have been known to rewrite one as the other. However, they are not equivalent due to the quantifiers involved. Thinking of ``a()`` and ``b()`` as sets of values, the first expression says that there is a pair of values (one from each side of the inequality) which are different. diff --git a/docs/language/learn-ql/advanced/monotonic-aggregates.rst b/docs/language/learn-ql/advanced/monotonic-aggregates.rst index 515dec6dff0..161776dbcf6 100644 --- a/docs/language/learn-ql/advanced/monotonic-aggregates.rst +++ b/docs/language/learn-ql/advanced/monotonic-aggregates.rst @@ -1,7 +1,7 @@ Monotonic aggregates in QL ========================== -In addition to standard QL aggregates, QL also supports *monotonic* aggregates. These are a slightly different way of computing aggregates which have some advantages, notably the ability to be used recursively, which normal aggregates do not have. You can enable them in a scope by adding the \ ``language[monotonicAggregates]`` pragma on a predicate, class, or module. +In addition to standard aggregates, QL also supports *monotonic* aggregates. These are a slightly different way of computing aggregates which have some advantages, notably the ability to be used recursively, which normal aggregates do not have. You can enable them in a scope by adding the \ ``language[monotonicAggregates]`` pragma on a predicate, class, or module. Syntax ------ diff --git a/docs/language/learn-ql/beginner/find-thief-3.rst b/docs/language/learn-ql/beginner/find-thief-3.rst index 03f7c866230..f8323147cf1 100644 --- a/docs/language/learn-ql/beginner/find-thief-3.rst +++ b/docs/language/learn-ql/beginner/find-thief-3.rst @@ -77,4 +77,4 @@ What next? - Help the villagers track down another criminal in the :doc:`next tutorial `. - Find out more about the concepts you discovered in this tutorial in the `QL language handbook `__. -- Explore the libraries that help you get data about code in :doc:`Learning QL <../../index>`. +- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. diff --git a/docs/language/learn-ql/beginner/fire-2.rst b/docs/language/learn-ql/beginner/fire-2.rst index c5380fb0b6b..0c7e4852ae7 100644 --- a/docs/language/learn-ql/beginner/fire-2.rst +++ b/docs/language/learn-ql/beginner/fire-2.rst @@ -40,4 +40,4 @@ What next? - Find out who will be the new ruler of the village in the :doc:`next tutorial `. - Learn more about predicates and classes in the `QL language handbook `__. -- Explore the libraries that help you get data about code in :doc:`Learning QL <../../index>`. +- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. diff --git a/docs/language/learn-ql/beginner/heir.rst b/docs/language/learn-ql/beginner/heir.rst index b5efd73fc40..f0f0c315025 100644 --- a/docs/language/learn-ql/beginner/heir.rst +++ b/docs/language/learn-ql/beginner/heir.rst @@ -161,4 +161,4 @@ What next? - Learn more about recursion in the `QL language handbook `__. - Put your QL skills to the test and solve the :doc:`River crossing puzzle <../ql-etudes/river-crossing>`. -- Start using QL to analyze projects. See :doc:`Learning QL <../../index>` for a summary of the available languages and resources. +- Start using QL to analyze projects. See :doc:`Learning CodeQL <../../index>` for a summary of the available languages and resources. diff --git a/docs/language/learn-ql/beginner/ql-tutorials.rst b/docs/language/learn-ql/beginner/ql-tutorials.rst index 2ba6e449b86..d97c4d6688e 100644 --- a/docs/language/learn-ql/beginner/ql-tutorials.rst +++ b/docs/language/learn-ql/beginner/ql-tutorials.rst @@ -7,18 +7,21 @@ QL detective tutorials ./* -Welcome to QL! These tutorials are aimed at complete beginners. They teach you how to write QL queries and introduce you to key logic concepts along the way. +Welcome to the detective tutorials! These are aimed at complete beginners who would like to learn the basics of QL, +before analyzing code with CodeQL. +The tutorials teach you how to write queries and introduce you to key logic concepts along the way. -We recommend you first read the :doc:`Introduction to the QL language <../introduction-to-ql>` page for a basic description of QL. +We recommend you first read the :doc:`Introduction to QL <../introduction-to-ql>` page for a description of the language and +some simple examples. -Currently the following tutorials are available: +Currently the following detective tutorials are available: -- :doc:`Find the thief ` - a three part mystery that introduces logical connectives, quantifiers and aggregates +- :doc:`Find the thief ` - a three part mystery that introduces logical connectives, quantifiers, and aggregates - :doc:`Catch the fire starter ` - an intriguing search that introduces predicates and classes - :doc:`Crown the rightful heir ` - a detective puzzle that introduces recursion Further resources ----------------- -- For a summary of available learning resources, see :doc:`Learning QL <../../index>`. +- For a summary of available learning resources, see :doc:`Learning CodeQL <../../index>`. - For an overview of the important concepts in QL, see the `QL language handbook `__. diff --git a/docs/language/learn-ql/database.rst b/docs/language/learn-ql/database.rst new file mode 100644 index 00000000000..70ba0091853 --- /dev/null +++ b/docs/language/learn-ql/database.rst @@ -0,0 +1,33 @@ +What's in a CodeQL database? +============================ + +A CodeQL database contains a variety of data related to a particular code base at a particular point in time. For details of how the database is generated see `Database generation `__. + +The database contains a full, hierarchical representation of the program defined by the code base. The database schema varies according to the language analyzed. The schema provides an interface between the initial lexical analysis during the extraction process, and the actual complex analysis using CodeQL. When the source code languages being analyzed change (such as Java 7 evolving into Java 8), this interface between the analysis phases can also change. + +For each language, a CodeQL library defines classes to provide a layer of abstraction over the database tables. This provides an object-oriented view of the data which makes it easier to write queries. This is easiest to explain using an example. + +Example +------- + +For a Java program, two key tables are: + +- The ``expressions`` table containing a row for every single expression in the source code that was analyzed during the build process. +- The ``statements`` table containing a row for every single statement in the source code that was analyzed during the build process. + +The CodeQL library defines classes to provide a layer of abstraction over each of these tables (and the related auxiliary tables): ``Expr`` and ``Stmt``. + +Most classes in the CodeQL library are similar: they are abstractions over one or more database tables. Looking at one of the CodeQL libraries illustrates this: + +.. code-block:: ql + + class Expr extends StmtParent, @expr { + ... + + /** the location of this expression */ + Location getLocation() { exprs(this,_,_,result) } + + ... + } + +The ``Expr`` class, shown here, extends from the database type ``@expr``. Member predicates of the ``Expr`` class are implemented in terms of the database-provided ``exprs`` table. diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index 3fc348be096..76649890131 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -1,14 +1,13 @@ -Learning QL -########### +Learning CodeQL +############### +CodeQL is the code analysis platform used by security researchers to automate `variant analysis `__. +You can use CodeQL queries to explore code and quickly find variants of security vulnerabilities and bugs. +These queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. +You can also try out CodeQL in the `query console `__ on `LGTM.com `__. +Here, you can query open source projects directly, without having to download CodeQL databases and libraries. -`QL `__ is the query language used in Semmle's `variant analysis `__ engine. -You can use queries written in QL to explore code and quickly find variants of security vulnerabilities and bugs. -The QL language is also part of the technology behind `LGTM `__, Semmle's analysis platform that combines deep semantic code search with data science insights to help developers ship secure code. - -QL queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. -You can also try out QL in the `query console `__ on `LGTM.com `__. -Here, you can write QL code to query open source projects directly, without having to download snapshots and libraries. +CodeQL is based on a powerful query language called QL. The following topics help you understand QL in general, as well as how to use it when analyzing code with CodeQL. .. _getting-started: @@ -25,10 +24,10 @@ If you are new to QL, start by looking at the following topics: beginner/ql-tutorials ql-etudes/river-crossing -QL training and variant analysis examples -****************************************** +CodeQL training and variant analysis examples +********************************************* -To start learning how to use QL in variant analysis for a specific language, see: +To start learning how to use CodeQL for variant analysis for code written in a specific language, see: .. toctree:: :maxdepth: -1 @@ -37,8 +36,8 @@ To start learning how to use QL in variant analysis for a specific language, see .. _writing-ql-queries: -Writing QL queries -****************** +Writing CodeQL queries +********************** To learn more about writing your own queries, see: @@ -48,7 +47,7 @@ To learn more about writing your own queries, see: writing-queries/writing-queries -For more information on writing QL to query code written in a specific language see: +For more information on using CodeQL to query code written in a specific language, see: .. toctree:: :maxdepth: 2 @@ -77,10 +76,10 @@ For more technical information see: Reference topics **************** -For a more comprehensive guide to QL see the following reference topics: +For a more comprehensive guide to the query language itself, see the following reference topics: -- `QL language handbook `__—a description of important concepts in QL -- `QL language specification `__—a formal specification of the QL language. +- `QL language handbook `__—a description of important concepts in QL. +- `QL language specification `__—a formal specification of QL. Search ****** diff --git a/docs/language/learn-ql/intro-to-data-flow.rst b/docs/language/learn-ql/intro-to-data-flow.rst index 024df3525e8..4868c3e952d 100644 --- a/docs/language/learn-ql/intro-to-data-flow.rst +++ b/docs/language/learn-ql/intro-to-data-flow.rst @@ -1,15 +1,15 @@ -Introduction to data flow analysis in QL -######################################## +Introduction to data flow analysis with CodeQL +############################################## Overview ******** Data flow analysis computes the possible values that a variable can hold at various points in a program, determining how those values propagate through the program and where they are used. -Many of Semmle's built-in security queries implement data flow analysis, which can highlight the fate of potentially malicious or insecure data that can cause vulnerabilities in your code base. +Many CodeQL security queries implement data flow analysis, which can highlight the fate of potentially malicious or insecure data that can cause vulnerabilities in your code base. These queries help you understand if data is used in an insecure way, whether dangerous arguments are passed to functions, or whether sensitive data can leak. -As well as highlighting potential security issues, you can also use data flow analysis to understand other aspects of how a program behaves, by finding, for example, uses of unititialized variables and resource leaks. +As well as highlighting potential security issues, you can also use data flow analysis to understand other aspects of how a program behaves, by finding, for example, uses of uninitialized variables and resource leaks. -The following sections provide a brief introduction to data flow analysis in QL. +The following sections provide a brief introduction to data flow analysis with CodeQL. See the following tutorials for more information about analyzing data flow in specific languages: @@ -30,7 +30,7 @@ See the following tutorials for more information about analyzing data flow in sp Data flow graph *************** -The QL data flow libraries implement data flow analysis on a program or function by modeling its data flow graph. +The CodeQL data flow libraries implement data flow analysis on a program or function by modeling its data flow graph. Unlike the `abstract syntax tree `__, the data flow graph does not reflect the syntactic structure of the program, but models the way data flows through the program at runtime. Nodes in the abstract syntax tree represent syntactic elements such as statements or expressions. Nodes in the data flow graph, on the other hand, represent semantic elements that carry values at runtime. @@ -58,18 +58,18 @@ Computing an accurate and complete data flow graph presents several challenges: - Aliasing between variables can result in a single write changing the value that multiple pointers point to. - The data flow graph can be very large and slow to compute. -To overcome these potential problems, two kinds of data flow are modeled in the QL libraries: +To overcome these potential problems, two kinds of data flow are modeled in the CodeQL libraries: -- Local data flow, concerning the data flow within a single function. When reasoning about local, you only considers edges between data flow nodes belonging to the same function.It is generally sufficiently fast, efficient and precise for many queries, and it is usually possible to compute the local data flow for all functions in a snapshot. +- Local data flow, concerning the data flow within a single function. When reasoning about local, you only considers edges between data flow nodes belonging to the same function.It is generally sufficiently fast, efficient and precise for many queries, and it is usually possible to compute the local data flow for all functions in a CodeQL database. - Global data flow, effectively considers the data flow within an entire program, by calculating data flow between functions and through object properties. Computing global data flow is typically more time and energy intensive than local data flow, therefore queries should be refined to look for more specific sources and sinks. -Many of the built-in queries included in the latest Semmle release contain examples of both local and global data flow analysis. See `the built-in queries `__ for details. +Many CodeQL queries contain examples of both local and global data flow analysis. See `the built-in queries `__ for details. Normal data flow vs taint tracking ********************************** -In the QL standard libraries, we make a distinction between 'normal' data flow and taint tracking. +In the standard CodeQL libraries, we make a distinction between 'normal' data flow and taint tracking. The normal data flow libraries are used to analyze the information flow in which data values are preserved at each step. For example, if you are tracking an insecure object ``x`` (which might be some untrusted or potentially malicious data), a step in the program may 'change' its value. So, in a simple process such as ``y = x + 1``, a normal data flow analysis will highlight the use of ``x``, but not ``y``. @@ -81,5 +81,5 @@ These flow steps are modeled in the taint-tracking library using predicates that What next? ********** -- Search for ``DataFlow`` and ``TaintTracking`` in the `QL standard libraries `__ to learn more about the technical implementation of data flow analysis in QL for specific programming languages. -- Visit `Learning QL `__ to find language-specific QL tutorials on data flow and other topics. +- Search for ``DataFlow`` and ``TaintTracking`` in the `standard CodeQL libraries `__ to learn more about the technical implementation of data flow analysis for specific programming languages. +- Visit `Learning CodeQL `__ to find language-specific tutorials on data flow and other topics. diff --git a/docs/language/learn-ql/introduction-to-ql.rst b/docs/language/learn-ql/introduction-to-ql.rst index 737c593fb4a..a06b80839ac 100644 --- a/docs/language/learn-ql/introduction-to-ql.rst +++ b/docs/language/learn-ql/introduction-to-ql.rst @@ -1,18 +1,22 @@ -Introduction to the QL language -=============================== +Introduction to QL +================== -QL is a powerful query language that is used to analyze code. Queries written in QL can be used to find errors and uncover variants of important security vulnerabilities. Visit Semmle's `security research page `__ to read about examples of vulnerabilities that we have recently found in open source projects using QL queries. +QL is a powerful query language that underlies CodeQL, which is used to analyze code. +Queries written with CodeQL can find errors and uncover variants of important security vulnerabilities. +Visit Semmle's `security research page `__ to read about examples of vulnerabilities that we have recently found in open source projects. + +Before diving into code analysis with CodeQL, it can be helpful to learn about the underlying language more generally. QL is a logic programming language, so it is built up of logical formulas. QL uses common logical connectives (such as ``and``, ``or``, and ``not``), quantifiers (such as ``forall`` and ``exists``), and other important logical concepts such as predicates. -QL also supports recursion and aggregates. This allows you to write complex recursive queries using simple QL syntax and directly use aggregates such as ``count``, ``sum`` and ``average``. +QL also supports recursion and aggregates. This allows you to write complex recursive queries using simple QL syntax and directly use aggregates such as ``count``, ``sum``, and ``average``. Basic syntax ------------ -The basic syntax will look familiar to anyone who has used SQL, but it is used somewhat differently. +The basic syntax of QL will look familiar to anyone who has used SQL, but it is used somewhat differently. -A QL query is defined by a **select** clause, which specifies what the result of the query should be. You can try out the examples and exercises in this topic directly in LGTM. Open the `query console `__. Before you can run a query, you need to select a language and project to query (for these logic examples, any language and project will do). +A query is defined by a **select** clause, which specifies what the result of the query should be. You can try out the examples and exercises in this topic directly in LGTM. Open the `query console `__. Before you can run a query, you need to select a language and project to query (for these logic examples, any language and project will do). Once you have selected a language, the query console is populated with the query: @@ -110,9 +114,12 @@ To simplify the query, we can introduce a class ``SmallInt`` representing the in ➤ `See this in the query console `__ -Now that you've seen some general examples, let's use QL queries to analyze projects. In particular, LGTM generates a database representing the code and then QL is used to query this database. See `Database generation `__ for more details on how the database is built. +Now that you've seen some general examples, let's use the CodeQL libraries to analyze projects. +In particular, LGTM generates a database representing the code and then CodeQL is used to query this database. See `Database generation `__ for more details on how the database is built. -The previous exercises just used the primitive types built in to QL. Although we chose a project to query, they did not use the project-specific database. The following example queries *do* use these databases and give you an idea of what QL can be used for. There are more details about how to write QL `below <#learning-ql>`__, so don't worry if you don't fully understand these examples yet! +.. XX: Perhaps a link to the "CodeQL libraries for X"? + +The previous exercises just used the primitive types built in to QL. Although we chose a project to query, they did not use the project-specific database. The following example queries *do* use these databases and give you an idea of what CodeQL can be used for. There are more details about how to use CodeQL `below <#learning-ql>`__, so don't worry if you don't fully understand these examples yet! Python ~~~~~~ @@ -153,9 +160,9 @@ Java ➤ `See this in the query console `__. The ``from`` clause defines a variable ``p`` representing a parameter. The ``where`` clause finds unused parameters by limiting the parameters ``p`` to those which are not accessed. Finally, the ``select`` clause lists these parameters. -Learning QL ------------ +Learning CodeQL +--------------- -- To find out more about how to write your own QL queries, try working through the :doc:`QL detective tutorials `. -- For an overview of the other available resources, see :doc:`Learning QL <../index>`. -- For a more technical description of QL, see :doc:`About QL `. +- To find out more about how to write your own queries, try working through the :doc:`QL detective tutorials `. +- For an overview of the other available resources, see :doc:`Learning CodeQL <../index>`. +- For a more technical description of the underlying language, see :doc:`About QL `. diff --git a/docs/language/learn-ql/locations.rst b/docs/language/learn-ql/locations.rst index eebb6fec68e..df210819ef2 100644 --- a/docs/language/learn-ql/locations.rst +++ b/docs/language/learn-ql/locations.rst @@ -1,6 +1,8 @@ Locations and strings for QL entities ===================================== +.. Not sure how much of this topic needs to change, and what the title should be + Providing locations ------------------- @@ -55,18 +57,18 @@ By convention, the location of an entire file may also be denoted by a ``file:// Other types of URL ^^^^^^^^^^^^^^^^^^ -The following, less-common types of URL are valid QL but are not supported by LGTM and will be omitted from any results: +The following, less-common types of URL are valid but are not supported by LGTM and will be omitted from any results: - **HTTP URLs** are supported in some client applications. For an example, see the code snippet above. - **Folder URLs** can be useful, for example to provide folder-level metrics. They may use a file URL, for example ``file:///opt/src:0:0:0:0``, but they may also start with a scheme of ``folder://``, and no trailing numbers, for example ``folder:///opt/src``. -- **Relative file URLs** are like normal file URLs, but start with the scheme ``relative://``. They are typically only meaningful in the context of a particular snapshot, and are taken to be implicitly prefixed by the snapshot's source location. Note that, in particular, the relative URL of a file will stay constant regardless of where the snapshot is analyzed. It is often most convenient to produce these URLs as input when importing external information; selecting one from a QL class would be unusual, and client applications may not handle it appropriately. +- **Relative file URLs** are like normal file URLs, but start with the scheme ``relative://``. They are typically only meaningful in the context of a particular database, and are taken to be implicitly prefixed by the database's source location. Note that, in particular, the relative URL of a file will stay constant regardless of where the database is analyzed. It is often most convenient to produce these URLs as input when importing external information; selecting one from a QL class would be unusual, and client applications may not handle it appropriately. Providing location information ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If no ``getURL()`` member predicate is defined, a QL class is checked for the presence of a member predicate called ``hasLocationInfo(..)``. This can be understood as a convenient way of providing file URLs (see above) without constructing the long URL string in QL. ``hasLocationInfo(..)`` should be a predicate, its first column must be ``string``-typed (it corresponds to the "path" portion of a file URL), and it must have an additional 3 or 4 ``int``-typed columns, which are interpreted like a trailing group of three or four numbers on a file URL. -For example, let us imagine that the locations for methods provided by the extractor extend from the first character of the method name to the closing curly brace of the method body, and we want to "fix" them in QL to ensure that only the method name is selected. The following code shows two ways of achieving this: +For example, let us imagine that the locations for methods provided by the extractor extend from the first character of the method name to the closing curly brace of the method body, and we want to "fix" them to ensure that only the method name is selected. The following code shows two ways of achieving this: .. code-block:: ql @@ -104,7 +106,7 @@ Using extracted location information Finally, if the above two predicates fail, client applications will attempt to call a predicate called ``getLocation()`` with no parameters, and try to apply one of the above two predicates to the result. This allows certain locations to be put into the database, assigned identifiers, and picked up. -By convention, the return value of the ``getLocation()`` predicate should be a QL class called ``Location``, and it should define a version of ``hasLocationInfo(..)`` (or ``getURL()``, though the former is preferable). If the ``Location`` class does not provide either of these member predicates, then no location information will be available. +By convention, the return value of the ``getLocation()`` predicate should be a class called ``Location``, and it should define a version of ``hasLocationInfo(..)`` (or ``getURL()``, though the former is preferable). If the ``Location`` class does not provide either of these member predicates, then no location information will be available. The ``toString()`` predicate ---------------------------- diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index bcbab520477..a50e0776a83 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -231,5 +231,5 @@ For more information on writing QL, see: - `QL language handbook `__ - an introduction to the concepts of QL. - :doc:`Learning QL <../../index>` - an overview of the resources for learning how to write your own QL queries. -- `Database generation `__ - an overview of the process that creates a snapshot from source code. -- :doc:`What's in a snapshot? <../snapshot>` - a description of the snapshot database. +- `Database generation `__ - an overview of the process that creates a database from source code. +- :doc:`What's in a CodeQL database? <../database>` - a description of the CodeQL database. diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index e6fb0024612..fef3363a08b 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -1,7 +1,7 @@ River crossing puzzle ##################### -The aim of this tutorial is to write a QL query that finds a solution to the following classical logic puzzle: +The aim of this tutorial is to write a query that finds a solution to the following classical logic puzzle: .. pull-quote:: @@ -243,7 +243,7 @@ You could tweak the predicate and the select clause to make the solution clearer Alternative solutions --------------------- -Here are some more example QL queries that solve the river crossing puzzle: +Here are some more example queries that solve the river crossing puzzle: #. This query uses a modified ``path`` variable to describe the resulting path in more detail. diff --git a/docs/language/learn-ql/snapshot.rst b/docs/language/learn-ql/snapshot.rst deleted file mode 100644 index f89229b8b27..00000000000 --- a/docs/language/learn-ql/snapshot.rst +++ /dev/null @@ -1,33 +0,0 @@ -What's in a snapshot database? -=============================== - -A snapshot database contains a variety of data related to a particular code base at a particular point in time. For details of how the database is generated see `Database generation `__. - -The database contains a full, hierarchical representation of the program defined by the code base. The database schema varies according to the language analyzed. The schema provides an interface between the initial lexical analysis during the extraction process, and the actual complex analysis using QL. When the source code languages being analyzed change (such as Java 7 evolving into Java 8), this interface between the analysis phases can also change. - -For each language, a QL library defines classes to provide a layer of abstraction over the database tables. This provides an object-oriented view of the data which makes it easier to write queries. This is easiest to explain using an example. - -Example -------- - -For a Java program, two key tables are: - -- The ``expressions`` table containing a row for every single expression in the source code that was analyzed during the build process. -- The ``statements`` table containing a row for every single statement in the source code that was analyzed during the build process. - -The QL library defines classes to provide a layer of abstraction over each of these tables (and the related auxiliary tables): ``Expr`` and ``Stmt``. - -Most classes in the QL library are similar: they are abstractions over one or more database tables. Looking at one of the QL libraries illustrates this: - -.. code-block:: ql - - class Expr extends StmtParent, @expr { - ... - - /** the location of this expression */ - Location getLocation() { exprs(this,_,_,result) } - - ... - } - -The ``Expr`` class, shown here, extends from the database type ``@expr``. Member predicates of the ``Expr`` class are implemented in terms of the database-provided ``exprs`` table. diff --git a/docs/language/learn-ql/technical-info.rst b/docs/language/learn-ql/technical-info.rst index 777cc2f1041..7494011f7c6 100644 --- a/docs/language/learn-ql/technical-info.rst +++ b/docs/language/learn-ql/technical-info.rst @@ -4,6 +4,6 @@ Technical information .. toctree:: :hidden: - snapshot + database -- :doc:`What's in a snapshot database ` \ No newline at end of file +- :doc:`What's in a CodeQL database? ` \ No newline at end of file diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index c36c8c47de7..de75db30742 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -4,13 +4,15 @@ Introduction to query files Overview ******** -Queries are programs written in QL. The QL queries included in the Semmle tools are designed to highlight issues related to the security, correctness, maintainability, and readability of a code base. You can also write custom queries to find specific issues relevant to your own project. Three important types of query are: +Queries are programs written with CodeQL. They are designed to highlight issues related to the security, correctness, maintainability, and readability of a code base. You can also write custom queries to find specific issues relevant to your own project. Three important types of query are: - **Alert queries**: queries that highlight issues in specific locations in your code. - **Path queries**: queries that describe the flow of information between a source and a sink in your code. - **Metric queries**: queries that compute statistics for your code. -You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a project using the `QL command-line tools `__, or you can contribute to Semmle's built-in queries in our `open source repository on GitHub `__. +You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a project using the `command-line tools `__, or you can contribute to the standard CodeQL queries in our `open source repository on GitHub `__. + +.. TODO: Change "command-line tools" to a link to the CodeQL CLI? Similarly, change "QL for Eclipse". .. pull-quote:: @@ -22,13 +24,13 @@ You can add custom queries to `custom query packs `__, and detailed technical information about QL in the `QL language handbook `__ and the `QL language specification `__. -For information on how to format QL code when contributing queries to the GitHub repository, see the `QL style guide `__. +For information on how to format your code when contributing queries to the GitHub repository, see the `QL style guide `__. Basic query structure ********************* -`Queries `__ written in QL have the file extension ``.ql``, and contain a ``select`` clause. Many of the built-in Semmle queries include additional optional information, and have the following structure:: +`Queries `__ written with CodeQL have the file extension ``.ql``, and contain a ``select`` clause. Many of the existing CodeQL queries include additional optional information, and have the following structure:: /** * @@ -36,9 +38,9 @@ Basic query structure * */ - import /* ... QL libraries or modules ... */ + import /* ... CodeQL libraries or modules ... */ - /* ... Optional, define QL classes and predicates ... */ + /* ... Optional, define CodeQL classes and predicates ... */ from /* ... variable declarations ... */ where /* ... logical formula ... */ @@ -49,9 +51,9 @@ The following sections describe the information that is typically included in a Query metadata ============== -Query metadata is used to identify your custom queries when they are added to the Semmle repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see the :doc:`query metadata reference `. The exact metadata requirement depends on how you are going to run your query: +Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see the :doc:`query metadata reference `. The exact metadata requirement depends on how you are going to run your query: -- If you are contributing a query to the Semmle open source repository for inclusion in the standard queries, please read the `query metadata style guide `__. +- If you are contributing a query to the GitHub repository, please read the `query metadata style guide `__. - If you are adding a custom query to a query pack for analysis using LGTM , see `Writing custom queries to include in LGTM analysis `__. - If you are analyzing a project using the `QL command-line tools `__, see `Preparing custom queries `__. - If you are running a query in the query console on LGTM or in the Quick query window in QL for Eclipse, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct `@kind` property, as explained below. See `Using the query console `__ and `Running a quick query `__ for further information. @@ -60,7 +62,7 @@ Query metadata is used to identify your custom queries when they are added to th Note - Queries that are contributed to the Semmle open source repository, added to a query pack in LGTM, or used to analyze a project with the QL command-line tools must have a query type (``@kind``) specified. The ``@kind`` property indicates how to interpret and display the results of the query analysis: + Queries that are contributed to the open source repository, added to a query pack in LGTM, or used to analyze a project with the QL command-line tools must have a query type (``@kind``) specified. The ``@kind`` property indicates how to interpret and display the results of the query analysis: - Alert query metadata must contain ``@kind problem``. - Path query metadata must contain ``@kind path-problem``. @@ -71,8 +73,8 @@ Query metadata is used to identify your custom queries when they are added to th Import statements ================= -Each query generally contains one or more ``import`` statements, which define the `QL libraries `__ or `modules `__ to import into the query. QL libraries and modules provide a way of grouping together related `types `__, `predicates `__, and other modules. The contents of each library or module that you import can then be accessed by the query. -`Semmle's open source repository on GitHub `__ contains all of the standard QL libraries for each supported language. +Each query generally contains one or more ``import`` statements, which define the `libraries `__ or `modules `__ to import into the query. Libraries and modules provide a way of grouping together related `types `__, `predicates `__, and other modules. The contents of each library or module that you import can then be accessed by the query. +Our `open source repository on GitHub `__ contains the standard CodeQL libraries for each supported language. When writing your own alert queries, you would typically import the standard library for the language of the project that you are querying, using ``import`` followed by a language: @@ -83,13 +85,13 @@ When writing your own alert queries, you would typically import the standard lib - JavaScript/TypeScript: ``javascript`` - Python: ``python`` -There are also QL libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. See :doc:`Constructing path queries ` for further information. +There are also CodeQL libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. See :doc:`Constructing path queries ` for further information. -You can explore the contents of all the standard QL libraries in the `QL library reference documentation `__, using `QL for Eclipse `__, or in the `GitHub repository `__. +You can explore the contents of all the standard CodeQL libraries in the `CodeQL library reference documentation `__, using `QL for Eclipse `__, or in the `GitHub repository `__. -Optional QL classes and predicates ----------------------------------- +Optional CodeQL classes and predicates +-------------------------------------- You can customize your analysis by defining your own predicates and classes in the query. See `Defining a predicate `__ and `Defining a class `__ for further details. @@ -97,13 +99,13 @@ From clause =========== The ``from`` clause declares the variables that are used in the query. Each declaration must be of the form `` ``. -For more information on the `types `__ available in QL, and to learn how to define your own types using `classes `__, see the `QL language handbook `__. +For more information on the available `types `__, and to learn how to define your own types using `classes `__, see the `QL language handbook `__. Where clause ============ The ``where`` clause defines the logical conditions to apply to the variables declared in the ``from`` clause to generate your results. This clause uses `aggregations `__, `predicates `__, and logical `formulas `_ to limit the variables of interest to a smaller set, which meet the defined conditions. -The QL libraries group commonly used predicates for specific languages and frameworks. You can also define your own predicates in the body of the query file or in your own custom modules, as described above. +The CodeQL libraries group commonly used predicates for specific languages and frameworks. You can also define your own predicates in the body of the query file or in your own custom modules, as described above. Select clause ============= @@ -138,6 +140,6 @@ What next? - See the queries used in real-life variant analysis on the `Semmle blog `__. - To learn more about writing path queries, see :doc:`Constructing path queries `. -- Take a look at the `built-in queries `__ to see examples of the queries included in the Semmle tools. -- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the QL libraries. -- For a full list of resources to help you learn QL, including beginner tutorials and language-specific examples, visit `Learning QL `__. \ No newline at end of file +- Take a look at the `built-in queries `__ to see examples of the queries included in CodeQL. +- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. +- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. \ No newline at end of file diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 50de68dbe55..8b793a63181 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -5,8 +5,8 @@ Overview ======== Security researchers are particularly interested in the way that information flows in a program. Many vulnerabilities are caused by seemingly benign data flowing to unexpected locations, and being used in a malicious way. -Path queries written in QL are particularly useful for analyzing data flow as they can be used to track the path taken by a variable from its possible starting points (``source``) to its possible end points (``sink``). -To model paths in QL, your query must provide information about the ``source`` and the ``sink``, as well as the data flow steps that link them. +Path queries written with CodeQL are particularly useful for analyzing data flow as they can be used to track the path taken by a variable from its possible starting points (``source``) to its possible end points (``sink``). +To model paths with CodeQL, your query must provide information about the ``source`` and the ``sink``, as well as the data flow steps that link them. This topic provides information on how to structure a path query file so you can explore the paths associated with the results of data flow analysis. @@ -17,8 +17,8 @@ This topic provides information on how to structure a path query file so you can The alerts generated by path queries are displayed by default in `LGTM `__ and included in the results generated using the `QL command-line tools `__. You can also view the paths explanations generated by your path query `directly in LGTM `__, or using the `Path explorer view `__ in `QL for Eclipse `__. -To learn more about modeling data flow in QL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. -For more language-specific information on analyzing data flow with QL see: +To learn more about modeling data flow with CodeQL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. +For more language-specific information on analyzing data flow see: - :doc:`Analyzing data flow in C/C++ <../cpp/dataflow>` - :doc:`Analyzing data flow in C# <../csharp/dataflow>` @@ -29,7 +29,7 @@ For more language-specific information on analyzing data flow with QL see: Path query examples ******************* -The easiest way to get started writing your own path query is to modify one of the existing queries. Visit the links below to see all of the built-in path queries: +The easiest way to get started writing your own path query is to modify one of the existing queries. Visit the links below to see all the built-in path queries: - `C/C++ path queries `__ - `C# path queries `__ @@ -43,7 +43,7 @@ Constructing a path query ========================= Path queries require certain metadata, query predicates, and ``select`` statement structures. -Many of the built-in path queries included in the Semmle tools follow a simple structure, which depends on how the language you are analyzing is modeled in QL. +Many of the built-in path queries included in CodeQL follow a simple structure, which depends on how the language you are analyzing is modeled with CodeQL. For C/C++, C#, Java, and JavaScript you should use the following template:: @@ -63,7 +63,7 @@ For C/C++, C#, Java, and JavaScript you should use the following template:: Where: -- ``DataFlow::Pathgraph`` is the path graph module you need to import from the standard QL libraries. +- ``DataFlow::Pathgraph`` is the path graph module you need to import from the standard CodeQL libraries. - ``source`` and ``sink`` are nodes on the `path graph `__, and ``DataFlow::PathNode`` is their type. - ``Configuration`` is a class containing the predicates which define how data may flow between the ``source`` and the ``sink``. @@ -85,7 +85,7 @@ For Python you should use a slightly different template:: Where: -- ``semmle.python.security.Paths`` is the path graph module imported from the standard QL libraries. +- ``semmle.python.security.Paths`` is the path graph module imported from the standard CodeQL libraries. - ``source`` and ``sink`` are nodes on the path graph, ``TaintedPathSource source`` and ``TaintedPathSink`` are their respective types. Note, you do not need to declare a configuration class to define the data flow from the ``source`` to the ``sink`` in a Python path query. @@ -103,7 +103,7 @@ Generating path explanations In order to generate path explanations, your query needs to compute a `path graph `__. To do this you need to define a `query predicate `__ called ``edges`` in your query. This predicate defines the edge relations of the graph you are computing, and it is used to compute the paths related to each result that your query generates. -You can import a predefined ``edges`` predicate from a path graph module in one of the standard QL data flow libraries. In addition to the path graph module, the data flow libraries contain the other ``classes``, ``predicates``, and ``modules`` that are commonly used in data flow analysis. The import statement to use depends on the language that you are analyzing. +You can import a predefined ``edges`` predicate from a path graph module in one of the standard CodeQL data flow libraries. In addition to the path graph module, the data flow libraries contain the other ``classes``, ``predicates``, and ``modules`` that are commonly used in data flow analysis. The import statement to use depends on the language that you are analyzing. For C/C++, C#. Java, and JavaScript you would use:: @@ -115,7 +115,7 @@ For Python, the ``Paths`` module contains the ``edges`` predicate:: import semmle.python.security.Paths -You can also import libraries specifically designed to implement data flow analysis in various common frameworks and environments, and many additional libraries are included with the Semmle tools. To see examples of the different libraries used in data flow analysis, see the links to the built-in queries above or browse the `standard QL libraries `__. +You can also import libraries specifically designed to implement data flow analysis in various common frameworks and environments, and many additional libraries are included with CodeQL. To see examples of the different libraries used in data flow analysis, see the links to the built-in queries above or browse the `standard CodeQL libraries `__. For all languages, you can also optionally define a ``nodes`` query predicate, which specifies the nodes of the path graph that you are interested in. If ``nodes`` is defined, only edges with endpoints defined by these nodes are selected. If ``nodes`` is not defined, you select all possible endpoints of ``edges``. @@ -128,7 +128,7 @@ You can also define your own ``edges`` predicate in the body of your query. It s /** Logical conditions which hold if `(a,b)` is an edge in the data flow graph */ } -For more examples of how to define an ``edges`` predicate, visit the `standard QL libraries `__ and search for ``edges``. +For more examples of how to define an ``edges`` predicate, visit the `standard CodeQL libraries `__ and search for ``edges``. Declaring sources and sinks *************************** @@ -136,7 +136,7 @@ Declaring sources and sinks You must provide information about the ``source`` and ``sink`` in your path query. These are objects that correspond to the nodes of the paths that you are exploring. The name and the type of the ``source`` and the ``sink`` must be declared in the ``from`` statement of the query, and the types must be compatible with the nodes of the graph computed by the ``edges`` predicate. -If you are querying C/C++, C#, Java or JavaScript code (and you have used ``import DataFlow::PathGraph`` in your query), the definitions of the ``source`` and ``sink`` are accessed via the ``Configuration`` class in the data flow library. You should declare all three of these objects in the ``from`` statement. +If you are querying C/C++, C#, Java, or JavaScript code (and you have used ``import DataFlow::PathGraph`` in your query), the definitions of the ``source`` and ``sink`` are accessed via the ``Configuration`` class in the data flow library. You should declare all three of these objects in the ``from`` statement. For example:: from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink @@ -191,5 +191,5 @@ What next? ********** - Take a look at the path queries for `C/C++ `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of the queries included in the Semmle tools. -- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the QL libraries. -- For a full list of resources to help you learn QL, including beginner tutorials and language-specific examples, visit `Learning QL `__. +- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. +- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst index 9e295df7620..c3692b7fac0 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -2,16 +2,16 @@ Query help reference ******************** This topic provides detailed information on the structure of query help files. -For more information about how to write useful query help in a style that is consistent with Semmle's built-in queries, see the `Query help style guide `__ on GitHub. +For more information about how to write useful query help in a style that is consistent with the standard CodeQL queries, see the `Query help style guide `__ on GitHub. .. pull-quote:: Note - You can access the query help for Semmle's built-in queries by visiting the `Built-in query pages `__. - You can also access the raw query help files in the `Semmle/ql GitHub repository `__. - For example, the `JavaScript security queries `__ and `C/C++ critical queries `__. + You can access the query help for CodeQL queries by visiting the `Built-in query pages `__. + You can also access the raw query help files in the `GitHub repository `__. + For example, see the `JavaScript security queries `__ and `C/C++ critical queries `__. For queries run by default on LGTM, there are several different ways to access the query help. For further information, see `Where do I see the query help for a query on LGTM? `__ in the LGTM user help. @@ -207,5 +207,5 @@ The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `__ on GitHub. -- To learn more about writing custom queries, and how to format your QL for clarity and consistency, see `Writing QL queries `__. +- To learn more about contributing to the standard CodeQL queries and libraries, see our `Contributing guidelines `__ on GitHub. +- To learn more about writing custom queries, and how to format your code for clarity and consistency, see `Writing CodeQL queries `__. diff --git a/docs/language/learn-ql/writing-queries/select-statement.rst b/docs/language/learn-ql/writing-queries/select-statement.rst index ea2b256e421..86e0770d426 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -27,7 +27,7 @@ If you look at some of the LGTM queries, you'll see that they can select extra e Developing a select statement ----------------------------- -Here's a simple query that uses the standard QL ``CodeDuplication.qll`` library to identify similar files. +Here's a simple query that uses the standard CodeQL ``CodeDuplication.qll`` library to identify similar files. Basic select statement ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/language/learn-ql/writing-queries/writing-queries.rst b/docs/language/learn-ql/writing-queries/writing-queries.rst index 1c3877e1a77..caedde2b0a0 100644 --- a/docs/language/learn-ql/writing-queries/writing-queries.rst +++ b/docs/language/learn-ql/writing-queries/writing-queries.rst @@ -1,8 +1,7 @@ -Writing QL queries -################## +Writing CodeQL queries +###################### - -If you are familiar with QL, you can modify the existing Semmle queries or write custom queries to analyze, improve, and secure your own projects. Get started by reading the information for query writers and viewing the examples provided below. +If you are familiar with CodeQL, you can modify the existing queries or write custom queries to analyze, improve, and secure your own projects. Get started by reading the information for query writers and viewing the examples provided below. Information for query writers ***************************** @@ -18,19 +17,21 @@ Information for query writers ../locations -Visit `Learning QL `__ to find basic information about QL, as well as help and advice on writing QL for specific programming languages. To learn more about the structure of query files, the key information to include when writing your own QL queries, and how to format your QL for clarity and consistency, see the following topics: +Visit `Learning CodeQL `__ to find basic information about CodeQL. This includes information about the underlying query language QL, as well as help and advice on writing queries for specific programming languages. +To learn more about the structure of query files, the key information to include when writing your own queries, and how to format them for clarity and consistency, see the following topics: - :doc:`Introduction to query files `–an introduction to the information contained in a basic query file. - :doc:`Constructing path queries `–a quick guide to structuring path queries to use in security research. -- :doc:`Introduction to data flow analysis in QL <../intro-to-data-flow>`–a brief introduction to modeling data flow using QL. +- :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`–a brief introduction to modeling data flow using CodeQL. - :doc:`Defining 'select' statements `–further detail on developing query alert messages to provide extra information in your query results. -- :doc:`Locations and strings for QL entities <../locations>`–further detail on providing location information in query results. +- :doc:`Locations and strings for CodeQL entities <../locations>`–further detail on providing location information in query results. - `QL style guide on GitHub `__–a guide to formatting QL for consistency and clarity. -Viewing the built-in QL queries +Viewing existing CodeQL queries ******************************* -The easiest way to get started writing your own queries is to modify an existing query. To view examples of the queries included in the latest release of the Semmle tools, or to try out the QL query cookbooks, visit `Exploring QL queries `__. You can also find all of the Semmle queries in our `open source repository on GitHub `__. +The easiest way to get started writing your own queries is to modify an existing query. To see these queries, or to try out the CodeQL query cookbooks, visit `Exploring CodeQL queries `__. +SYou can also find all the CodeQL queries in our `open source repository on GitHub `__. You can also find examples of queries developed to find security vulnerabilities and bugs in open-source software projects in the `Semmle demos GitHub repository `__ and the `Semmle blog `__. @@ -45,7 +46,9 @@ Contributing queries query-help Contributions to the standard queries and libraries are very welcome–see our `contributing guidelines `__ for further information. -If you are contributing a query to the open source GitHub repository, writing a custom query for LGTM, or using a custom query in an analysis with the QL command-line tools, then you need to include extra metadata in your query to ensure that the query results are interpreted and displayed correctly. See the following topics for more information on query metadata: +If you are contributing a query to the open source GitHub repository, writing a custom query for LGTM, or using a custom query in an analysis with our command-line tools, then you need to include extra metadata in your query to ensure that the query results are interpreted and displayed correctly. See the following topics for more information on query metadata: + +.. TODO: Change "command-line tools" to a link to the CodeQL CLI? - :doc:`Query metadata reference ` - `Query metadata style guide on GitHub `__ diff --git a/docs/language/ql-handbook/annotations.rst b/docs/language/ql-handbook/annotations.rst index e4f4b0c40cd..8673b8194f6 100644 --- a/docs/language/ql-handbook/annotations.rst +++ b/docs/language/ql-handbook/annotations.rst @@ -245,7 +245,7 @@ Compiler pragmas **Available for**: |characteristic predicates|, |member predicates|, |non-member predicates| -The following compiler pragmas affect the compilation and optimization of QL queries. You +The following compiler pragmas affect the compilation and optimization of queries. You should avoid using these annotations unless you experience significant performance issues. Before adding pragmas to your code, contact Semmle to describe the performance problems. diff --git a/docs/language/ql-handbook/index.rst b/docs/language/ql-handbook/index.rst index 2bd22a3a628..701d7d02237 100644 --- a/docs/language/ql-handbook/index.rst +++ b/docs/language/ql-handbook/index.rst @@ -9,7 +9,7 @@ help you understand how the language works, and how to write more advanced QL co Each section describes an important concept or syntactic construct of QL. For an overview, see the table of contents below. -If you are just getting started with QL, see `Learning QL `_ +If you are just getting started with QL, see `Learning CodeQL `_ for a list of the available resources. .. index:: specification diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 999ec5ca51f..6aa9043bd62 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -230,7 +230,7 @@ abstract class, you can add more subclasses to it. **Example** -If you are writing a security query in QL, you may be interested in identifying +If you are writing a security query, you may be interested in identifying all expressions that can be interpreted as SQL queries. You can use the following abstract class to describe these expressions:: @@ -438,7 +438,7 @@ In the standard QL language libraries, this is usually done as follows: and provide a definition for any abstract predicates from ``A``. - Annotate the algebraic datatype with :ref:`private`, and leave the classes public. -For example, the following code snippet from the QL for C# data flow library defines classes +For example, the following code snippet from the CodeQL data-flow library for C# defines classes for dealing with tainted or untainted values. In this case, it doesn't make sense for ``TaintType`` to extend a database type. It is part of the taint analysis, not the underlying program, so it's helpful to extend a new type (namely ``TTaintType``):: @@ -473,7 +473,7 @@ Database types Database types are defined in the database schema. This means that they depend on the database that you are querying, and vary according to the data you are analyzing. -For example, if you are querying a QL database for a Java project, the database types may +For example, if you are querying a CodeQL database for a Java project, the database types may include ``@ifstmt``, representing an if statement in the Java code, and ``@variable``, representing a variable. diff --git a/docs/language/ql-training/slide-snippets/info.rst b/docs/language/ql-training/slide-snippets/info.rst index d093559eaba..583a456207b 100644 --- a/docs/language/ql-training/slide-snippets/info.rst +++ b/docs/language/ql-training/slide-snippets/info.rst @@ -5,7 +5,7 @@ To try the examples in this presentation we recommend you download `QL for Eclip **QL language resources** -- If you are new to QL, try the QL language tutorials at `Learning QL `__. +- If you are new to QL, try the QL language tutorials at `Learning CodeQL `__. - To learn more about the main features of QL, try looking at the `QL language handbook `__. - For further information about writing queries in QL, see `Writing QL queries `__. From 48c0d9ecca4e3ec3592611a7284adb3df1de4c09 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 23 Oct 2019 15:17:26 +0100 Subject: [PATCH 025/148] C#: Add qltests for ?? dataflow. --- .../dataflow/local/DataFlow.expected | 2 +- .../dataflow/local/DataFlowStep.expected | 20 +++++++++---- .../dataflow/local/LocalDataFlow.cs | 6 ++++ .../dataflow/local/TaintTracking.expected | 4 ++- .../dataflow/local/TaintTrackingStep.expected | 30 ++++++++++++++----- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index 63462bbad86..d1801f1833a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -8,7 +8,7 @@ | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index d38e1f02215..ba8398610a1 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -545,7 +545,10 @@ | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | | LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | +| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | +| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | +| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | | LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | @@ -562,12 +565,19 @@ | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:458:28:458:30 | this | LocalDataFlow.cs:458:41:458:45 | this access | -| LocalDataFlow.cs:458:50:458:52 | this | LocalDataFlow.cs:458:56:458:60 | this access | -| LocalDataFlow.cs:458:50:458:52 | value | LocalDataFlow.cs:458:64:458:68 | access to parameter value | -| LocalDataFlow.cs:464:41:464:47 | tainted | LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | -| LocalDataFlow.cs:469:44:469:53 | nonTainted | LocalDataFlow.cs:471:15:471:24 | access to parameter nonTainted | +| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | +| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | +| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | +| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | +| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | +| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | +| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | +| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | +| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index 154b4d5fcb9..65de9fc65fe 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -438,6 +438,12 @@ public class LocalDataFlow Check(nonSink17); break; } + + // Null-coalescing expressions + var sink73 = nonSink0 ?? sink0; + var sink74 = sink0 ?? nonSink0; + Check(sink73); + Check(sink74); } static void Check(T x) { } diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index ba3d91130f2..756d79333c1 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -62,7 +62,9 @@ | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | +| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | +| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index f9511969108..f320c87cb8b 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -690,7 +690,10 @@ | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | | LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | +| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | +| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | +| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | | LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | @@ -707,15 +710,26 @@ | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:458:28:458:30 | this | LocalDataFlow.cs:458:41:458:45 | this access | -| LocalDataFlow.cs:458:50:458:52 | this | LocalDataFlow.cs:458:56:458:60 | this access | -| LocalDataFlow.cs:458:50:458:52 | value | LocalDataFlow.cs:458:50:458:52 | value | -| LocalDataFlow.cs:458:50:458:52 | value | LocalDataFlow.cs:458:64:458:68 | access to parameter value | -| LocalDataFlow.cs:464:41:464:47 | tainted | LocalDataFlow.cs:464:41:464:47 | tainted | -| LocalDataFlow.cs:464:41:464:47 | tainted | LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | -| LocalDataFlow.cs:469:44:469:53 | nonTainted | LocalDataFlow.cs:469:44:469:53 | nonTainted | -| LocalDataFlow.cs:469:44:469:53 | nonTainted | LocalDataFlow.cs:471:15:471:24 | access to parameter nonTainted | +| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | +| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | +| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | +| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | +| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | +| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | +| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | +| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | +| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | +| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | +| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | +| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:50:464:52 | value | +| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | +| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:470:41:470:47 | tainted | +| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:475:44:475:53 | nonTainted | +| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:5:26:5:32 | tainted | From 9b8516cbd67083c82e197abbde4dfd2267936593 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 23 Oct 2019 17:40:48 +0100 Subject: [PATCH 026/148] Remove some mentions of "CodeQL" and fix typos --- docs/language/learn-ql/advanced/constraining-types.rst | 2 +- docs/language/learn-ql/database.rst | 2 +- docs/language/learn-ql/intro-to-data-flow.rst | 6 +++--- docs/language/learn-ql/introduction-to-ql.rst | 2 +- .../learn-ql/writing-queries/introduction-to-queries.rst | 6 +++--- docs/language/learn-ql/writing-queries/path-queries.rst | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/language/learn-ql/advanced/constraining-types.rst b/docs/language/learn-ql/advanced/constraining-types.rst index 8c00f86fe50..3a8d2e76637 100644 --- a/docs/language/learn-ql/advanced/constraining-types.rst +++ b/docs/language/learn-ql/advanced/constraining-types.rst @@ -8,7 +8,7 @@ Type constraint methods Note - The examples below use the CodeQL library for Java. All CodeQL libraries support using these methods to constrain variables, the only difference is in the names of the classes used. + The examples below use the CodeQL library for Java. All libraries support using these methods to constrain variables, the only difference is in the names of the classes used. There are several ways of imposing type constraints on variables: diff --git a/docs/language/learn-ql/database.rst b/docs/language/learn-ql/database.rst index 70ba0091853..fe8e2e273ef 100644 --- a/docs/language/learn-ql/database.rst +++ b/docs/language/learn-ql/database.rst @@ -17,7 +17,7 @@ For a Java program, two key tables are: The CodeQL library defines classes to provide a layer of abstraction over each of these tables (and the related auxiliary tables): ``Expr`` and ``Stmt``. -Most classes in the CodeQL library are similar: they are abstractions over one or more database tables. Looking at one of the CodeQL libraries illustrates this: +Most classes in the library are similar: they are abstractions over one or more database tables. Looking at one of the libraries illustrates this: .. code-block:: ql diff --git a/docs/language/learn-ql/intro-to-data-flow.rst b/docs/language/learn-ql/intro-to-data-flow.rst index 4868c3e952d..fcd907af947 100644 --- a/docs/language/learn-ql/intro-to-data-flow.rst +++ b/docs/language/learn-ql/intro-to-data-flow.rst @@ -58,9 +58,9 @@ Computing an accurate and complete data flow graph presents several challenges: - Aliasing between variables can result in a single write changing the value that multiple pointers point to. - The data flow graph can be very large and slow to compute. -To overcome these potential problems, two kinds of data flow are modeled in the CodeQL libraries: +To overcome these potential problems, two kinds of data flow are modeled in the libraries: -- Local data flow, concerning the data flow within a single function. When reasoning about local, you only considers edges between data flow nodes belonging to the same function.It is generally sufficiently fast, efficient and precise for many queries, and it is usually possible to compute the local data flow for all functions in a CodeQL database. +- Local data flow, concerning the data flow within a single function. When reasoning about local data flow, you only consider edges between data flow nodes belonging to the same function. It is generally sufficiently fast, efficient and precise for many queries, and it is usually possible to compute the local data flow for all functions in a CodeQL database. - Global data flow, effectively considers the data flow within an entire program, by calculating data flow between functions and through object properties. Computing global data flow is typically more time and energy intensive than local data flow, therefore queries should be refined to look for more specific sources and sinks. @@ -69,7 +69,7 @@ Many CodeQL queries contain examples of both local and global data flow analysis Normal data flow vs taint tracking ********************************** -In the standard CodeQL libraries, we make a distinction between 'normal' data flow and taint tracking. +In the standard libraries, we make a distinction between 'normal' data flow and taint tracking. The normal data flow libraries are used to analyze the information flow in which data values are preserved at each step. For example, if you are tracking an insecure object ``x`` (which might be some untrusted or potentially malicious data), a step in the program may 'change' its value. So, in a simple process such as ``y = x + 1``, a normal data flow analysis will highlight the use of ``x``, but not ``y``. diff --git a/docs/language/learn-ql/introduction-to-ql.rst b/docs/language/learn-ql/introduction-to-ql.rst index a06b80839ac..e54fd9b3c69 100644 --- a/docs/language/learn-ql/introduction-to-ql.rst +++ b/docs/language/learn-ql/introduction-to-ql.rst @@ -1,7 +1,7 @@ Introduction to QL ================== -QL is a powerful query language that underlies CodeQL, which is used to analyze code. +QL is the powerful query language that underlies CodeQL, which is used to analyze code. Queries written with CodeQL can find errors and uncover variants of important security vulnerabilities. Visit Semmle's `security research page `__ to read about examples of vulnerabilities that we have recently found in open source projects. diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index de75db30742..4dca736817c 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -30,7 +30,7 @@ For information on how to format your code when contributing queries to the GitH Basic query structure ********************* -`Queries `__ written with CodeQL have the file extension ``.ql``, and contain a ``select`` clause. Many of the existing CodeQL queries include additional optional information, and have the following structure:: +`Queries `__ written with CodeQL have the file extension ``.ql``, and contain a ``select`` clause. Many of the existing queries include additional optional information, and have the following structure:: /** * @@ -85,9 +85,9 @@ When writing your own alert queries, you would typically import the standard lib - JavaScript/TypeScript: ``javascript`` - Python: ``python`` -There are also CodeQL libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. See :doc:`Constructing path queries ` for further information. +There are also libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. See :doc:`Constructing path queries ` for further information. -You can explore the contents of all the standard CodeQL libraries in the `CodeQL library reference documentation `__, using `QL for Eclipse `__, or in the `GitHub repository `__. +You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__, using `QL for Eclipse `__, or in the `GitHub repository `__. Optional CodeQL classes and predicates diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 8b793a63181..73708b17eed 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -6,7 +6,7 @@ Overview Security researchers are particularly interested in the way that information flows in a program. Many vulnerabilities are caused by seemingly benign data flowing to unexpected locations, and being used in a malicious way. Path queries written with CodeQL are particularly useful for analyzing data flow as they can be used to track the path taken by a variable from its possible starting points (``source``) to its possible end points (``sink``). -To model paths with CodeQL, your query must provide information about the ``source`` and the ``sink``, as well as the data flow steps that link them. +To model paths, your query must provide information about the ``source`` and the ``sink``, as well as the data flow steps that link them. This topic provides information on how to structure a path query file so you can explore the paths associated with the results of data flow analysis. @@ -18,7 +18,7 @@ This topic provides information on how to structure a path query file so you can To learn more about modeling data flow with CodeQL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. -For more language-specific information on analyzing data flow see: +For more language-specific information on analyzing data flow, see: - :doc:`Analyzing data flow in C/C++ <../cpp/dataflow>` - :doc:`Analyzing data flow in C# <../csharp/dataflow>` @@ -103,7 +103,7 @@ Generating path explanations In order to generate path explanations, your query needs to compute a `path graph `__. To do this you need to define a `query predicate `__ called ``edges`` in your query. This predicate defines the edge relations of the graph you are computing, and it is used to compute the paths related to each result that your query generates. -You can import a predefined ``edges`` predicate from a path graph module in one of the standard CodeQL data flow libraries. In addition to the path graph module, the data flow libraries contain the other ``classes``, ``predicates``, and ``modules`` that are commonly used in data flow analysis. The import statement to use depends on the language that you are analyzing. +You can import a predefined ``edges`` predicate from a path graph module in one of the standard data flow libraries. In addition to the path graph module, the data flow libraries contain the other ``classes``, ``predicates``, and ``modules`` that are commonly used in data flow analysis. The import statement to use depends on the language that you are analyzing. For C/C++, C#. Java, and JavaScript you would use:: @@ -115,7 +115,7 @@ For Python, the ``Paths`` module contains the ``edges`` predicate:: import semmle.python.security.Paths -You can also import libraries specifically designed to implement data flow analysis in various common frameworks and environments, and many additional libraries are included with CodeQL. To see examples of the different libraries used in data flow analysis, see the links to the built-in queries above or browse the `standard CodeQL libraries `__. +You can also import libraries specifically designed to implement data flow analysis in various common frameworks and environments, and many additional libraries are included with CodeQL. To see examples of the different libraries used in data flow analysis, see the links to the built-in queries above or browse the `standard libraries `__. For all languages, you can also optionally define a ``nodes`` query predicate, which specifies the nodes of the path graph that you are interested in. If ``nodes`` is defined, only edges with endpoints defined by these nodes are selected. If ``nodes`` is not defined, you select all possible endpoints of ``edges``. From 6cf8f06191b0288da7c6f7beca4dc2e1d1258f3b Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 23 Oct 2019 17:48:35 +0100 Subject: [PATCH 027/148] Docs: Update COBOL --- .../cobol/introduce-libraries-cobol.rst | 24 +++++++++---------- docs/language/learn-ql/cobol/ql-for-cobol.rst | 12 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/language/learn-ql/cobol/introduce-libraries-cobol.rst b/docs/language/learn-ql/cobol/introduce-libraries-cobol.rst index 8ab24df1edd..2d01200484d 100644 --- a/docs/language/learn-ql/cobol/introduce-libraries-cobol.rst +++ b/docs/language/learn-ql/cobol/introduce-libraries-cobol.rst @@ -1,10 +1,10 @@ -Introducing the QL libraries for COBOL -====================================== +Introducing the CodeQL libraries for COBOL +========================================== Overview -------- -There is an extensive QL library for analyzing COBOL code. The classes in this library present the data from a snapshot database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. +There is an extensive library for analyzing COBOL code. The classes in this library present the data from a CodeQL database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules–that is, files with the extension ``.qll``. The module ``cobol.qll`` imports most other standard library modules, so you can include the complete library by beginning your query with: @@ -12,12 +12,12 @@ The library is implemented as a set of QL modules–that is, files with the exte import cobol -The rest of this tutorial briefly summarizes the most important QL classes and predicates provided by this library, including references to the `detailed API documentation `__ where applicable. +The rest of this tutorial briefly summarizes the most important classes and predicates provided by this library, including references to the `detailed API documentation `__ where applicable. Introducing the library ----------------------- -The QL COBOL library presents information about COBOL source code at different levels: +The CodeQL library for COBOL presents information about COBOL source code at different levels: - **Textual** — classes that represent source code as unstructured text files - **Lexical** — classes that represent comments and other tokens of interest @@ -36,7 +36,7 @@ At its most basic level, a COBOL code base can simply be viewed as a collection Files and folders ^^^^^^^^^^^^^^^^^ -In QL, files are represented as entities of class `File `__, and folders as entities of class `Folder `__, both of which are subclasses of class `Container `__. +Files are represented as entities of class `File `__, and folders as entities of class `Folder `__, both of which are subclasses of class `Container `__. Class `Container `__ provides the following member predicates: @@ -48,7 +48,7 @@ Note that while ``getAFile`` and ``getAFolder`` are declared on class `Container Both files and folders have paths, which can be accessed by the predicate ``Container.getAbsolutePath()``. For example, if ``f`` represents a file with the path ``/home/user/project/src/main.cbl``, then ``f.getAbsolutePath()`` evaluates to the string ``"/home/user/project/src/main.cbl"``, while ``f.getParentContainer().getAbsolutePath()`` returns ``"/home/user/project/src"``. -These paths are absolute file system paths. If you want to obtain the path of a file relative to the snapshot source location, use ``Container.getRelativePath()`` instead. Note, however, that a snapshot may contain files that are not located underneath the snapshot source location; for such files, ``getRelativePath()`` will not return anything. +These paths are absolute file system paths. If you want to obtain the path of a file relative to the source location in the CodeQL database, use ``Container.getRelativePath()`` instead. Note, however, that a database may contain files that are not located underneath the source location; for such files, ``getRelativePath()`` will not return anything. The following member predicates of class `Container `__ provide more information about the name of a file or folder: @@ -68,9 +68,9 @@ For example, the following query computes, for each folder, the number of COBOL Locations ^^^^^^^^^ -Most entities in a snapshot database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive. +Most entities in a CodeQL database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive. -All entities associated with a source location belong to the QL class `Locatable `__. The location itself is modeled by the QL class `Location `__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location `__ class provides the following member predicates: +All entities associated with a source location belong to the class `Locatable `__. The location itself is modeled by the class `Location `__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location `__ class provides the following member predicates: - ``Location.getFile()``, ``Location.getStartLine()``, ``Location.getStartColumn()``, ``Location.getEndLine()``, ``Location.getEndColumn()`` return detailed information about the location. - ``Location.getNumLines()`` returns the number of (whole or partial) lines covered by the location. @@ -104,13 +104,13 @@ The most important member predicates are as follows: Syntactic level ~~~~~~~~~~~~~~~ -The majority of classes in the QL COBOL library is concerned with representing a COBOL program as a collection of `abstract syntax trees `__ (ASTs). +The majority of classes in the CodeQL library for COBOL are concerned with representing a COBOL program as a collection of `abstract syntax trees `__ (ASTs). -The QL class `ASTNode `__ contains all entities representing nodes in the abstract syntax trees and defines generic tree traversal predicates: +The class `ASTNode `__ contains all entities representing nodes in the abstract syntax trees and defines generic tree traversal predicates: - ``ASTNode.getParent()``: returns the parent node of this AST node, if any. -Please note that the QL libraries for COBOL do not currently represent all possible parts of a COBOL program. Due to the complexity of the language, and its many dialects, this is an ongoing task. We prioritize elements that are of interest to queries, and expand this selection over time. Please check the `detailed API documentation `__ to see what is currently available. +Please note that the libraries for COBOL do not currently represent all possible parts of a COBOL program. Due to the complexity of the language, and its many dialects, this is an ongoing task. We prioritize elements that are of interest to queries, and expand this selection over time. Please check the `detailed API documentation `__ to see what is currently available. The main structure of any COBOL program is represented by the `Unit `__ class and its subclasses. For example, each program definition has a `ProgramDefinition `__ counterpart. For each ``PROCEDURE DIVISION`` in the program, there will be a `ProcedureDivision `__ class. diff --git a/docs/language/learn-ql/cobol/ql-for-cobol.rst b/docs/language/learn-ql/cobol/ql-for-cobol.rst index 12ba25e69f4..f85ff62649e 100644 --- a/docs/language/learn-ql/cobol/ql-for-cobol.rst +++ b/docs/language/learn-ql/cobol/ql-for-cobol.rst @@ -1,5 +1,5 @@ -QL for COBOL -============ +CodeQL for COBOL +================ .. toctree:: :glob: @@ -7,14 +7,14 @@ QL for COBOL introduce-libraries-cobol -This page provides an overview of the QL for COBOL documentation that is currently available. +This page provides an overview of the CodeQL for COBOL documentation that is currently available. - `Basic COBOL query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the QL libraries for COBOL ` introduces the standard libraries used to write queries for COBOL code. +- :doc:`Introducing the CodeQL libraries for COBOL ` introduces the standard libraries used to write queries for COBOL code. Other resources --------------- -- For the queries used in LGTM, display a `COBOL query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the COBOL QL library see the `QL library for COBOL `__. +- For the queries used in LGTM, display a `COBOL query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for COBOL see the `CodeQL library for COBOL `__. From 2aefcbd42c69a55e29813f592b87c64bd2375dd5 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 23 Oct 2019 18:16:20 +0100 Subject: [PATCH 028/148] Docs: Update C/C++ --- .../learn-ql/cpp/conversions-classes.rst | 18 ++++++------- docs/language/learn-ql/cpp/dataflow.rst | 6 ++--- .../learn-ql/cpp/expressions-types.rst | 8 +++--- .../learn-ql/cpp/function-classes.rst | 10 +++---- .../learn-ql/cpp/introduce-libraries-cpp.rst | 24 ++++++++--------- .../cpp/private-field-initialization.rst | 6 ++--- docs/language/learn-ql/cpp/ql-for-cpp.rst | 26 ++++++++++--------- .../cpp/value-numbering-hash-cons.rst | 2 +- .../learn-ql/cpp/zero-space-terminator.rst | 8 +++--- 9 files changed, 55 insertions(+), 53 deletions(-) diff --git a/docs/language/learn-ql/cpp/conversions-classes.rst b/docs/language/learn-ql/cpp/conversions-classes.rst index 716991f96b2..016efa50d67 100644 --- a/docs/language/learn-ql/cpp/conversions-classes.rst +++ b/docs/language/learn-ql/cpp/conversions-classes.rst @@ -4,12 +4,12 @@ Tutorial: Conversions and classes Overview -------- -This topic contains worked examples of how to write queries using the standard QL library classes for C/C++ conversions and classes. +This topic contains worked examples of how to write queries using the CodeQL library classes for C/C++ conversions and classes. Conversions ----------- -Let us take a look at the QL ``Conversion`` class in the standard library: +Let us take a look at the ``Conversion`` class in the standard library: - ``Expr`` @@ -128,26 +128,26 @@ Unlike the earlier versions of the query, this query would return each side of t Note - In general, QL predicates named ``getAXxx`` exploit the ability to return multiple results (multiple instances of ``Xxx``) whereas plain ``getXxx`` predicates usually return at most one specific instance of ``Xxx``. + In general, predicates named ``getAXxx`` exploit the ability to return multiple results (multiple instances of ``Xxx``) whereas plain ``getXxx`` predicates usually return at most one specific instance of ``Xxx``. Classes ------- -Next we're going to look at C++ classes, using the following QL classes: +Next we're going to look at C++ classes, using the following CodeQL classes: - ``Type`` - - ``UserType``—includes classes, typedefs and enums + - ``UserType``—includes classes, typedefs, and enums - ``Class``—a class or struct - - ``Struct``—a struct, which is treated as a subtype of Class in QL. + - ``Struct``—a struct, which is treated as a subtype of ``Class`` - ``TemplateClass``—a C++ class template Finding derived classes ~~~~~~~~~~~~~~~~~~~~~~~ -We want to create a query that checks for destructors that should be ``virtual``. Specifically, when a class and a class derived from it both have destructors, the base class destructor should generally be virtual. This ensures that the derived class destructor is always invoked. A ``Destructor`` in QL is a subtype of ``MemberFunction``: +We want to create a query that checks for destructors that should be ``virtual``. Specifically, when a class and a class derived from it both have destructors, the base class destructor should generally be virtual. This ensures that the derived class destructor is always invoked. In the CodeQL library, ``Destructor`` is a subtype of ``MemberFunction``: - ``Function`` @@ -221,13 +221,13 @@ Our last change is to use ``Function.isVirtual()`` to find cases where the base That completes the query. -There is a similar built-in LGTM `query `__ that finds classes in a C/C++ project with virtual functions but no virtual destructor. You can take a look at the QL code for this query by clicking **Open in query console** at the top of that page. +There is a similar built-in LGTM `query `__ that finds classes in a C/C++ project with virtual functions but no virtual destructor. You can take a look at the code for this query by clicking **Open in query console** at the top of that page. What next? ---------- - Explore other ways of querying classes using examples from the `C/C++ cookbook `__. - Take a look at the :doc:`Analyzing data flow in C/C++ ` tutorial. -- Try the worked examples in the following topics: :doc:`Example: Checking that constructors initialize all private fields ` and :doc:`Example: Checking for allocations equal to 'strlen(string)' without space for a null terminator `. +- Try the worked examples in the following topics: :doc:`Example: Checking that constructors initialize all private fields `, and :doc:`Example: Checking for allocations equal to 'strlen(string)' without space for a null terminator `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. diff --git a/docs/language/learn-ql/cpp/dataflow.rst b/docs/language/learn-ql/cpp/dataflow.rst index 4867f3daf47..0b28c71445f 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -4,10 +4,10 @@ Analyzing data flow in C/C++ Overview -------- -This topic describes how data flow analysis is implemented in the QL for C/C++ library and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the QL libraries for local data flow, global data flow and taint tracking. +This topic describes how data flow analysis is implemented in the CodeQL libraries for C/C++ and includes examples to help you write your own data flow queries. +The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. -For a more general introduction to modeling data flow in QL, see :doc:`Introduction to data flow analysis in QL <../intro-to-data-flow>`. +For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. Local data flow --------------- diff --git a/docs/language/learn-ql/cpp/expressions-types.rst b/docs/language/learn-ql/cpp/expressions-types.rst index d6bd0b2c740..1595d594683 100644 --- a/docs/language/learn-ql/cpp/expressions-types.rst +++ b/docs/language/learn-ql/cpp/expressions-types.rst @@ -4,12 +4,12 @@ Tutorial: Expressions, types and statements Overview -------- -This topic contains worked examples of how to write queries using the standard QL library classes for C/C++ expressions, types, and statements. +This topic contains worked examples of how to write queries using the standard CodeQL library classes for C/C++ expressions, types, and statements. Expressions and types --------------------- -Each part of an expression in C becomes an instance of the QL ``Expr`` class. For example, the C code ``x = x + 1`` becomes an ``AssignExpr``, an ``AddExpr``, two instances of ``VariableAccess`` and a ``Literal``. All of these QL classes extend ``Expr``. +Each part of an expression in C becomes an instance of the ``Expr`` class. For example, the C code ``x = x + 1`` becomes an ``AssignExpr``, an ``AddExpr``, two instances of ``VariableAccess`` and a ``Literal``. All of these CodeQL classes extend ``Expr``. Finding assignments to zero ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -26,7 +26,7 @@ In the following example we find instances of ``AssignExpr`` which assign the co ➤ `See this in the query console `__ -The ``where`` clause in this example gets the expression on the right side of the assignment, ``getRValue()``, and compares it with zero. Notice that there are no checks to make sure that the right side of the assignment is an integer or that it has a value (that is, it is compile-time constant, rather than a variable). For expressions where either of these assumptions is wrong, the associated QL predicate simply does not return anything and the ``where`` clause will not produce a result. You could think of it as if there is an implicit ``exists(e.getRValue().getValue().toInt())`` at the beginning of this line. +The ``where`` clause in this example gets the expression on the right side of the assignment, ``getRValue()``, and compares it with zero. Notice that there are no checks to make sure that the right side of the assignment is an integer or that it has a value (that is, it is compile-time constant, rather than a variable). For expressions where either of these assumptions is wrong, the associated predicate simply does not return anything and the ``where`` clause will not produce a result. You could think of it as if there is an implicit ``exists(e.getRValue().getValue().toInt())`` at the beginning of this line. It is also worth noting that the query above would find this C code: @@ -34,7 +34,7 @@ It is also worth noting that the query above would find this C code: yPtr = NULL; -This is because the snapshot contains a representation of the code base after the preprocessor transforms have run (for more information, see `Database generation `__). This means that any macro invocations, such as the ``NULL`` define used here, are expanded during the creation of the snapshot. If you want to write queries about macros then there are some special library classes that have been designed specifically for this purpose (for example, the ``Macro``, ``MacroInvocation`` classes and predicates like ``Element.isInMacroExpansion()``). In this case, it is good that macros are expanded, but we do not want to find assignments to pointers. +This is because the database contains a representation of the code base after the preprocessor transforms have run (for more information, see `Database generation `__). This means that any macro invocations, such as the ``NULL`` define used here, are expanded during the creation of the database. If you want to write queries about macros then there are some special library classes that have been designed specifically for this purpose (for example, the ``Macro``, ``MacroInvocation`` classes and predicates like ``Element.isInMacroExpansion()``). In this case, it is good that macros are expanded, but we do not want to find assignments to pointers. Finding assignments of 0 to an integer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/language/learn-ql/cpp/function-classes.rst b/docs/language/learn-ql/cpp/function-classes.rst index e8f0f743722..51f07a8d0f0 100644 --- a/docs/language/learn-ql/cpp/function-classes.rst +++ b/docs/language/learn-ql/cpp/function-classes.rst @@ -4,14 +4,14 @@ Tutorial: Function classes Overview -------- -The standard QL library for C and C++ represents functions using the ``Function`` class (see :doc:`Introducing the C/C++ libraries `). +The standard CodeQL library for C and C++ represents functions using the ``Function`` class (see :doc:`Introducing the C/C++ libraries `). The example queries in this topic explore some of the most useful library predicates for querying functions. Finding all static functions ---------------------------- -Using the member predicate ``Function.isStatic()`` we can list all of the static functions in a snapshot: +Using the member predicate ``Function.isStatic()`` we can list all the static functions in a database: .. code-block:: ql @@ -26,7 +26,7 @@ This query is very general, so there are probably too many results to be interes Finding functions that are not called ------------------------------------- -It might be more interesting to find functions that are not called, using the standard QL ``FunctionCall`` class from the **abstract syntax tree** category (see :doc:`Introducing the C/C++ libraries `). The ``FunctionCall`` class can be used to identify places where a function is actually used, and it is related to ``Function`` through the ``FunctionCall.getTarget()`` predicate. +It might be more interesting to find functions that are not called, using the standard CodeQL ``FunctionCall`` class from the **abstract syntax tree** category (see :doc:`Introducing the C/C++ libraries `). The ``FunctionCall`` class can be used to identify places where a function is actually used, and it is related to ``Function`` through the ``FunctionCall.getTarget()`` predicate. .. code-block:: ql @@ -58,9 +58,9 @@ You can modify the query to remove functions where a function pointer is used to This query returns fewer results. However, if you examine the results then you can probably still find potential refinements. -For example, there is a more complicated LGTM `query `__ that finds unused static functions. To see the QL code for this query, click **Open in query console** at the top of the page. +For example, there is a more complicated LGTM `query `__ that finds unused static functions. To see the code for this query, click **Open in query console** at the top of the page. - You can explore the definition of an element in the standard QL libraries and see what predicates are available. Use the keyboard **F3** button to open the definition of any element. Alternatively, hover over the element and click **Jump to definition** in the tooltip displayed. The library file is opened in a new tab with the definition highlighted. + You can explore the definition of an element in the standard libraries and see what predicates are available. Use the keyboard **F3** button to open the definition of any element. Alternatively, hover over the element and click **Jump to definition** in the tooltip displayed. The library file is opened in a new tab with the definition highlighted. Finding a specific function --------------------------- diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index 1ab7cdd1498..6bea8d40c2c 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -1,23 +1,23 @@ -Introducing the C/C++ libraries -=============================== +Introducing the CodeQL libraries for C/C++ +========================================== Overview -------- -There is an extensive QL library for analyzing snapshots extracted from C/C++ projects. The QL classes in this library present the data from a snapshot database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``cpp.qll`` imports all of the core C/C++ library modules, so you can include the complete library by beginning your query with: +There is an extensive library for analyzing CodeQL databases extracted from C/C++ projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``cpp.qll`` imports all the core C/C++ library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import cpp -The rest of this topic summarizes available QL classes and corresponding C/C++ constructs. +The rest of this topic summarizes the available CodeQL classes and corresponding C/C++ constructs. -NOTE: You can find related classes and features using the query console's auto-complete feature. You can also press *F3* to jump to the definition of any element; QL library files are opened in new tabs in the console. +NOTE: You can find related classes and features using the query console's auto-complete feature. You can also press *F3* to jump to the definition of any element; library files are opened in new tabs in the console. Summary of the library classes ------------------------------ -The most commonly used standard QL library classes are listed below. The listing is broken down by functionality. Each QL library class is annotated with a C/C++ construct it corresponds to. +The most commonly used standard library classes are listed below. The listing is broken down by functionality. Each library class is annotated with a C/C++ construct it corresponds to. Declaration classes ~~~~~~~~~~~~~~~~~~~ @@ -25,7 +25,7 @@ Declaration classes This table lists `Declaration `__ classes representing C/C++ declarations. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Example syntax | QL class | Remarks | +| Example syntax | CodeQL class | Remarks | +=================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+=======================================================================================================================================================================+====================================================================================================================================================================================================+ | ``int`` *var* ``;`` | `GlobalVariable `__ | | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -154,7 +154,7 @@ Statement classes This table lists subclasses of `Stmt `__ representing C/C++ statements. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Example syntax | QL class | Remarks | +| Example syntax | CodeQL class | Remarks | +===============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+==================================================================================================================================================================+===================================================================================================================================================================================================================================================================================================+ | ``__asm__ ("`` *movb %bh, (%eax)* ``");`` | `AsmStmt `__ | Specific to a given CPU instruction set | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -215,7 +215,7 @@ Expression classes This table lists subclasses of `Expr `__ representing C/C++ expressions. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Example syntax | QL class(es) | Remarks | +| Example syntax | CodeQL class(es) | Remarks | +========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+==========================================================================================================================================================================================================+=============================================================================================================================================================================================================================================================================================================+ | ``{`` `Expr `__... ``}`` | | `ArrayAggregateLiteral `__ | | | | | `ClassAggregateLiteral `__ | | @@ -417,7 +417,7 @@ Type classes This table lists subclasses of `Type `__ representing C/C++ types. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Example syntax | QL class | Remarks | +| Example syntax | CodeQL class | Remarks | +=============================================================================================================================================================================================================================================================================================================================================================================================================================================+==================================================================================================================================================================+==================================================================================================================================================================================================================================================================================+ | ``void`` | `VoidType `__ | | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -485,7 +485,7 @@ Preprocessor classes This table lists `Preprocessor `__ classes representing C/C++ preprocessing directives. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Example syntax | QL class | Remarks | +| Example syntax | CodeQL class | Remarks | +=============================================================================================================================================================================================================================================================================================================================================================================================================================================+==================================================================================================================================================================+===================================================================================================================================================================================================================================================================================+ | ``#elif`` *condition* | `PreprocessorElif `__ | | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -522,6 +522,6 @@ This table lists `Preprocessor `, :doc:`Expressions, types and statements `, :doc:`Conversions and classes `, and :doc:`Analyzing data flow in C/C++ `. +- Experiment with the worked examples in the CodeQL for C/C++ topics: :doc:`Function classes `, :doc:`Expressions, types and statements `, :doc:`Conversions and classes `, and :doc:`Analyzing data flow in C/C++ `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. diff --git a/docs/language/learn-ql/cpp/private-field-initialization.rst b/docs/language/learn-ql/cpp/private-field-initialization.rst index 4aa155adeb0..26b57660142 100644 --- a/docs/language/learn-ql/cpp/private-field-initialization.rst +++ b/docs/language/learn-ql/cpp/private-field-initialization.rst @@ -4,7 +4,7 @@ Example: Checking that constructors initialize all private fields Overview -------- -This topic describes how a C++ query was developed. The example introduces recursive predicates and demonstrates the typical workflow used to refine a query. For a full overview of the topics available for learning to write QL queries for C/C++ code, see :doc:`QL for C/C++ `. +This topic describes how a C++ query was developed. The example introduces recursive predicates and demonstrates the typical workflow used to refine a query. For a full overview of the topics available for learning to write queries for C/C++ code, see :doc:`CodeQL for C/C++ `. Problem—finding every private field and checking for initialization ------------------------------------------------------------------- @@ -29,7 +29,7 @@ We can start by looking at every private field in a class and checking that ever #. ``f.isPrivate()`` checks if the field is private. #. ``not exists(Assignment a | a = f.getAnAssignment() and a.getEnclosingFunction() = c)`` checks that there is no assignment to the field in the constructor. -This QL code looks fairly complete, but when you test it on a project, there are several results that contain examples that we have overlooked. +This code looks fairly complete, but when you test it on a project, there are several results that contain examples that we have overlooked. Refinement 1—excluding fields initialized by lists -------------------------------------------------- @@ -62,7 +62,7 @@ These can be excluded by adding an extra condition to check for this special con Refinement 2—excluding fields initialized by external libraries --------------------------------------------------------------- -When you test the revised query, you may discover that fields from classes in external libraries are over-reported. This is often because a header file declares a constructor that is defined in a source file that is not analyzed (external libraries are often excluded from analysis). When the source code is analyzed, the snapshot is populated with a ``Constructor`` entry with no body. This ``constructor`` therefore contains no assignments and consequently the query reports that any fields initialized by the constructor are "uninitialized." There is no particular reason to be suspicious of these cases, and we can exclude them from the results by defining a condition to exclude constructors that have no body: +When you test the revised query, you may discover that fields from classes in external libraries are over-reported. This is often because a header file declares a constructor that is defined in a source file that is not analyzed (external libraries are often excluded from analysis). When the source code is analyzed, the CodeQL database is populated with a ``Constructor`` entry with no body. This ``constructor`` therefore contains no assignments and consequently the query reports that any fields initialized by the constructor are "uninitialized." There is no particular reason to be suspicious of these cases, and we can exclude them from the results by defining a condition to exclude constructors that have no body: .. code-block:: ql diff --git a/docs/language/learn-ql/cpp/ql-for-cpp.rst b/docs/language/learn-ql/cpp/ql-for-cpp.rst index 909d0e2e323..b1596c7de92 100644 --- a/docs/language/learn-ql/cpp/ql-for-cpp.rst +++ b/docs/language/learn-ql/cpp/ql-for-cpp.rst @@ -1,5 +1,5 @@ -QL for C/C++ -============ +CodeQL for C/C++ +================ .. toctree:: :glob: @@ -13,19 +13,19 @@ QL for C/C++ private-field-initialization zero-space-terminator -These topics provide an overview of the QL C/C++ standard libraries and show examples of how to write queries that use them. +These topics provide an overview of the CodeQL libraries for C/C++ and show examples of how to write queries that use them. -- `Basic C/C++ QL query `__ describes how to write and run queries using LGTM. +- `Basic C/C++ query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the QL libraries for C/C++ ` introduces the standard libraries used to write queries for C and C++ code. +- :doc:`Introducing the CodeQL libraries for C/C++ ` introduces the standard libraries used to write queries for C and C++ code. -- :doc:`Tutorial: Function classes ` demonstrates how to write queries using the standard QL library classes for C/C++ functions. +- :doc:`Tutorial: Function classes ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ functions. -- :doc:`Tutorial: Expressions, types and statements ` demonstrates how to write queries using the standard QL library classes for C/C++ expressions, types and statements. +- :doc:`Tutorial: Expressions, types and statements ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ expressions, types and statements. -- :doc:`Tutorial: Conversions and classes ` demonstrates how to write queries using the standard QL library classes for C/C++ conversions and classes. +- :doc:`Tutorial: Conversions and classes ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ conversions and classes. -- :doc:`Tutorial: Analyzing data flow in C/C++ ` demonstrates how to write queries using the standard QL for C/C++ data flow and taint tracking libraries. +- :doc:`Tutorial: Analyzing data flow in C/C++ ` demonstrates how to write queries using the standard data flow and taint tracking libraries for C/C++. - :doc:`Example: Checking that constructors initialize all private fields ` works through the development of a query. It introduces recursive predicates and shows the typical workflow used to refine a query. @@ -51,6 +51,8 @@ Advanced libraries Other resources --------------- -- For examples of how to query common C/C++ elements, see the `C/C++ QL cookbook `__. -- For the queries used in LGTM, display a `C/C++ query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the C/C++ QL library see the `QL library for C/C++ `__. +.. TODO: Rename the cookbooks: C/C++ cookbook, or C/C++ CodeQL cookbook, or CodeQL cookbook for C/C++, or...? + +- For examples of how to query common C/C++ elements, see the `C/C++ cookbook `__. +- For the queries used in LGTM, display a `C/C++ query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for C/C++ see the `CodeQL library for C/C++ `__. diff --git a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst index 7a1bbd2888b..e05f93dbae1 100644 --- a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst +++ b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst @@ -4,7 +4,7 @@ Hash consing and value numbering Overview -------- -In C and C++ QL databases, each node in the abstract syntax tree is represented by a separate object. This allows both analysis and results display to refer to specific appearances of a piece of syntax. However, it is frequently useful to determine whether two expressions are equivalent, either syntactically or semantically. +In C and C++ databases, each node in the abstract syntax tree is represented by a separate object. This allows both analysis and results display to refer to specific appearances of a piece of syntax. However, it is frequently useful to determine whether two expressions are equivalent, either syntactically or semantically. The `hash consing `__ library (defined in ``semmle.code.cpp.valuenumbering.HashCons``) provides a mechanism for identifying expressions that have the same syntactic structure. The `global value numbering `__ library (defined in ``semmle.code.cpp.valuenumbering.GlobalValueNumbering``) provides a mechanism for identifying expressions that compute the same value at runtime. diff --git a/docs/language/learn-ql/cpp/zero-space-terminator.rst b/docs/language/learn-ql/cpp/zero-space-terminator.rst index e977470ea6f..7026d9fa9ae 100644 --- a/docs/language/learn-ql/cpp/zero-space-terminator.rst +++ b/docs/language/learn-ql/cpp/zero-space-terminator.rst @@ -4,7 +4,7 @@ Example: Checking for allocations equal to ``strlen(string)`` without space for Overview -------- -This topic describes how a C/C++ query for detecting a potential buffer overflow was developed. For a full overview of the topics available for learning to write QL queries for C/C++ code, see :doc:`QL for C/C++ `. +This topic describes how a C/C++ query for detecting a potential buffer overflow was developed. For a full overview of the topics available for learning to write queries for C/C++ code, see :doc:`CodeQL for C/C++ `. Problem—detecting memory allocation that omits space for a null termination character ------------------------------------------------------------------------------------- @@ -32,7 +32,7 @@ Defining the entities of interest You could approach this problem either by searching for code similar to the call to ``malloc`` in line 3 or the call to ``strcpy`` in line 5 (see example above). For our basic query, we start with a simple assumption: any call to ``malloc`` with only a ``strlen`` to define the memory size is likely to cause an error when the memory is populated. -Calls to ``strlen`` can be identified using the library `StrlenCall `__ class, but we need to define a new class to identify calls to ``malloc``. Both the library class and the new class need to extend the standard QL class ``FunctionCall``, with the added restriction of the function name that they apply to: +Calls to ``strlen`` can be identified using the library `StrlenCall `__ class, but we need to define a new class to identify calls to ``malloc``. Both the library class and the new class need to extend the standard class ``FunctionCall``, with the added restriction of the function name that they apply to: .. code-block:: ql @@ -52,7 +52,7 @@ Calls to ``strlen`` can be identified using the library `StrlenCall Date: Wed, 23 Oct 2019 21:23:00 +0100 Subject: [PATCH 029/148] C#: Add ?? as a local dataflow step. --- csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql | 2 -- .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 4 ++++ csharp/ql/test/library-tests/dataflow/local/DataFlow.expected | 2 ++ .../test/library-tests/dataflow/local/DataFlowStep.expected | 4 ++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index 3a50d474577..646ab04ac1f 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -81,8 +81,6 @@ private class Conf extends DataFlow::Configuration { override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { node2.asExpr() = any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr()) - or - exists(NullCoalescingExpr nce | node1.asExpr() = nce.getRightOperand() and node2.asExpr() = nce) } override predicate isBarrierOut(DataFlow::Node node) { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index d1ca7596f30..e69d5d93bf5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -86,6 +86,10 @@ module LocalFlow { scope = e2 and isSuccessor = true or + e1 = e2.(NullCoalescingExpr).getAnOperand() and + scope = e2 and + isSuccessor = false + or e1 = e2.(SuppressNullableWarningExpr).getExpr() and scope = e2 and isSuccessor = true diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index d1801f1833a..78c0204ed20 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -8,6 +8,8 @@ | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | +| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | +| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index ba8398610a1..1b93aded791 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -568,11 +568,15 @@ | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | +| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | +| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | +| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | +| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | | LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | | LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | | LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | From 6ac163abace5021bfae1deb3e1b018e5ed0e831a Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 23 Oct 2019 21:54:49 +0100 Subject: [PATCH 030/148] C#: Add change note --- change-notes/1.23/analysis-csharp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index 7ec412a0eb2..59d9903fffb 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -43,5 +43,6 @@ The following changes in version 1.23 affect C# analysis in all applications. * There is now a `DataFlow::localExprFlow` predicate and a `TaintTracking::localExprTaint` predicate to make it easy to use the most common case of local data flow and taint: from one `Expr` to another. +* Data is now tracked through null-coalescing expressions (`??`). ## Changes to autobuilder From b9ba534bcbe071405a94c0b192c3b1aa3472beb5 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 24 Oct 2019 11:06:34 +0100 Subject: [PATCH 031/148] C#: Update qltest output. --- csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected b/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected index 65e04f8d48c..d82ff134b35 100644 --- a/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected +++ b/csharp/ql/test/library-tests/cil/dataflow/DataFlow.expected @@ -12,6 +12,8 @@ | dataflow.cs:46:35:46:39 | "t1b" | dataflow.cs:46:18:46:40 | call to method Taint1 | | dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect | | dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect | +| dataflow.cs:102:30:102:33 | null | dataflow.cs:74:21:74:52 | ... ?? ... | | dataflow.cs:102:30:102:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... | | dataflow.cs:102:30:102:33 | null | dataflow.cs:108:20:108:33 | call to method IndirectNull | +| dataflow.cs:109:23:109:26 | null | dataflow.cs:74:21:74:52 | ... ?? ... | | dataflow.cs:109:23:109:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... | From 8e31b8167afe6c19c3381ea439b959286ce10a11 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 24 Oct 2019 14:46:10 +0200 Subject: [PATCH 032/148] C++: Add a sample class in PrintAST.ql I've found myself typing out this class whenever I want to print the AST of one function. I hope it will be useful to others too. --- cpp/ql/src/semmle/code/cpp/PrintAST.ql | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.ql b/cpp/ql/src/semmle/code/cpp/PrintAST.ql index 6fc40dd0525..23f249585b9 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.ql +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.ql @@ -7,3 +7,12 @@ import cpp import PrintAST + +/** + * Temporarily tweak this class or make a copy to control which functions are + * printed. + */ +class Cfg extends PrintASTConfiguration { + /** Holds if the AST for `func` should be printed. */ + override predicate shouldPrintFunction(Function func) { any() } +} From 5c07750286a2bfa2c4bdffc35f4267e488d1f7f6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 24 Oct 2019 11:28:42 +0200 Subject: [PATCH 033/148] simplify the heuristic for Deferred promises --- .../ql/src/semmle/javascript/Promises.qll | 48 ++++--------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 13eb1e8114e..ae8554c1a0a 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -36,35 +36,9 @@ module Bluebird { * Provides classes for working with various Deferred implementations */ module Deferred { - class DeferredClass extends DataFlow::SourceNode { - DeferredClass() { - exists(Variable var | - var.getName() = "Deferred" and - ( - var.getADeclaration() instanceof LocalNamespaceDecl or - var.getScope() instanceof GlobalScope - ) and - this = DataFlow::valueNode(var.getADefinition()) - ) - or - this.(DataFlow::ParameterNode).getName() = "Deferred" - or - exists(Function f | - f.getName() = "Deferred" and - this = DataFlow::valueNode(f) - ) - or - exists(ClassDefinition c | - c.getName() = "Deferred" and - this = DataFlow::valueNode(c) - ) - } - } - class DeferredInstance extends DataFlow::NewNode { - DeferredClass deferredClass; - - DeferredInstance() { this = deferredClass.getAnInstantiation() } + // Describes both `new Deferred()`, `new $.Deferred` and other variants. + DeferredInstance() { this.getCalleeName() = "Deferred" } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -72,23 +46,17 @@ module Deferred { or exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) } - - DeferredClass getDeferredClass() { result = deferredClass } - - DataFlow::CallNode getPromiseMemberCall(string methodName) { - result = ref(DataFlow::TypeTracker::end()).getAMemberCall(methodName) - } + + DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) } } /** * A promise object created by a Deferred constructor */ private class DeferredPromiseDefinition extends PromiseDefinition, DeferredInstance { - DeferredPromiseDefinition() { - this = any(DeferredClass c | - exists(any(DeferredInstance i | i.getDeferredClass() = c).getPromiseMemberCall("resolve")) and - exists(any(DeferredInstance i | i.getDeferredClass() = c).getPromiseMemberCall("reject")) - ).getAnInstantiation() + DeferredPromiseDefinition() { + // hardening of the "Deferred" heuristic: a method call to `resolve`. + exists(ref().getAMethodCall("resolve")) } override DataFlow::FunctionNode getExecutor() { result = getCallback(0) } @@ -99,7 +67,7 @@ module Deferred { */ class ResolvedDeferredPromiseDefinition extends ResolvedPromiseDefinition { ResolvedDeferredPromiseDefinition() { - this = any(DeferredPromiseDefinition def).getPromiseMemberCall("resolve") + this = any(DeferredPromiseDefinition def).ref().getAMethodCall("resolve") } override DataFlow::Node getValue() { result = getArgument(0) } From f9e76b27f5def0fbe4f210e0b548d7236bf4f5db Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Thu, 24 Oct 2019 14:26:51 +0100 Subject: [PATCH 034/148] Docs: Update C# --- docs/language/learn-ql/csharp/dataflow.rst | 8 ++--- .../csharp/introduce-libraries-csharp.rst | 34 +++++++++---------- .../learn-ql/csharp/ql-for-csharp.rst | 18 +++++----- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/docs/language/learn-ql/csharp/dataflow.rst b/docs/language/learn-ql/csharp/dataflow.rst index e9d8a63be76..3b9bb69d7da 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -4,10 +4,10 @@ Analyzing data flow in C# Overview -------- -This topic describes how data flow analysis is implemented in the QL for C# library and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the QL libraries for local data flow, global data flow and taint tracking. +This topic describes how data flow analysis is implemented in the CodeQL libraries for C# and includes examples to help you write your own data flow queries. +The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. -For a more general introduction to modeling data flow in QL, see :doc:`Introduction to data flow analysis in QL <../intro-to-data-flow>`. +For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. Local data flow --------------- @@ -548,6 +548,6 @@ This can be adapted from the ``SystemUriFlow`` class: What next? ---------- -- Learn about the QL standard libraries used to write queries for C# in :doc:`Introducing the C# libraries `. +- Learn about the standard libraries used to write queries for C# in :doc:`Introducing the C# libraries `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. diff --git a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst index 43e6c11327c..32a782d5034 100644 --- a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst +++ b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst @@ -1,25 +1,23 @@ -Introducing the C# libraries -============================ +Introducing the CodeQL libraries for C# +======================================= Overview -------- -The C# QL libraries are a data model for analysis of C# code. QL is an object-oriented language, so the data model is represented as *QL classes*, which are organized into *QL libraries*. The QL classes are a layer of logic built on top of an underlying database. - -The core library is imported at the top of each query using: +There is an extensive library for analyzing CodeQL databases extracted from C# projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``csharp.qll`` imports all the core C# library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import csharp -Since this is required for all C# queries, it is omitted from QL snippets below. +Since this is required for all C# queries, it is omitted from code snippets below. -The core library contains all the program elements, including `files <#files>`__, `types <#types>`__, methods, `variables <#variables>`__, `statements <#statements>`__, and `expressions <#expressions>`__. This is sufficient for most queries, however additional libraries can be imported for bespoke functionality such as control flow and data flow. See :doc:`QL for C# ` for information about these additional libraries. +The core library contains all the program elements, including `files <#files>`__, `types <#types>`__, methods, `variables <#variables>`__, `statements <#statements>`__, and `expressions <#expressions>`__. This is sufficient for most queries, however additional libraries can be imported for bespoke functionality such as control flow and data flow. See :doc:`CodeQL for C# ` for information about these additional libraries. Class hierarchies ~~~~~~~~~~~~~~~~~ -Each section contains a QL class hierarchy, showing the inheritance structure between QL classes. For example: +Each section contains a class hierarchy, showing the inheritance structure between CodeQL classes. For example: - ``Expr`` @@ -46,13 +44,13 @@ Each section contains a QL class hierarchy, showing the inheritance structure be This means that the class ``AddExpr`` extends class ``BinaryArithmeticOperation``, which in turn extends class ``ArithmeticOperation`` and so on. If you want to query any arithmetic operation, then use the class ``ArithmeticOperation``, but if you specifically want to limit the query to addition operations, then use the class ``AddExpr``. -QL classes can also be considered to be *sets*, and the ``extends`` relation between classes defines a subset. Every member of class ``AddExpr`` is also in the class ``BinaryArithmeticOperation``. In general, QL classes overlap and an entity can be a member of several classes. +Classes can also be considered to be *sets*, and the ``extends`` relation between classes defines a subset. Every member of class ``AddExpr`` is also in the class ``BinaryArithmeticOperation``. In general, classes overlap and an entity can be a member of several classes. This overview omits some of the less important or intermediate classes from the class hierarchy. Each class has predicates, which are logical propositions about that class. They also define navigable relationships between classes. Predicates are inherited, so for example the ``AddExpr`` class inherits the predicates ``getLeftOperand()`` and ``getRightOperand()`` from ``BinaryArithmeticOperation``, and ``getType()`` from class ``Expr``. This is similar to how methods are inherited in object-oriented programming languages. -In this overview, we present the most common and useful predicates. Consult the reference, QL source code, and autocomplete in the editor for the complete list of predicates available on each class. +In this overview, we present the most common and useful predicates. Consult the `reference `__, the CodeQL source code, and autocomplete in the editor for the complete list of predicates available on each class. Exercises ~~~~~~~~~ @@ -72,7 +70,7 @@ Exercise 1: Simplify the following query: Files ----- -Files are represented by the QL class `File `__, and directories by the QL class `Folder `__. The database contains all of the source files and assemblies used during the compilation. +Files are represented by the class `File `__, and directories by the class `Folder `__. The database contains all of the source files and assemblies used during the compilation. Class hierarchy ~~~~~~~~~~~~~~~ @@ -143,7 +141,7 @@ To list all elements in ``Main.cs``, their QL class and location: where e.getFile().getShortName() = "Main" select e, e.getAQlClass(), e.getLocation() -Note that ``getAQlClass()`` is available on all QL classes and is a useful way to figure out the QL class of something. Often the same element will have several QL classes which are all returned by ``getAQlClass()``. +Note that ``getAQlClass()`` is available on all entities and is a useful way to figure out the QL class of something. Often the same element will have several classes which are all returned by ``getAQlClass()``. Locations --------- @@ -234,7 +232,7 @@ Find declarations containing a username: Variables --------- -The QL class `Variable `__ represents C# variables, such as fields, parameters and local variables. The database contains all variables from the source code, as well as all fields and parameters from assemblies referenced by the program. +The class `Variable `__ represents C# variables, such as fields, parameters and local variables. The database contains all variables from the source code, as well as all fields and parameters from assemblies referenced by the program. Class hierarchy ~~~~~~~~~~~~~~~ @@ -283,7 +281,7 @@ Find all unused local variables: Types ----- -Types are represented by the QL class `Type `__ and consist of builtin types, interfaces, classes, structs, enums, and type parameters. The database contains types from the program and all referenced assemblies including mscorlib and the .NET framework. +Types are represented by the CodeQL class `Type `__ and consist of builtin types, interfaces, classes, structs, enums, and type parameters. The database contains types from the program and all referenced assemblies including mscorlib and the .NET framework. The builtin types (``object``, ``int``, ``double`` etc.) have corresponding types (``System.Object``, ``System.Int32`` etc.) in mscorlib. @@ -438,7 +436,7 @@ Exercise 5: Write a query to find all classes starting with the letter ``A``. (` Callables --------- -Callables are represented by the QL class `Callable `__ and are anything that can be called independently, such as methods, constructors, destructors, operators, anonymous functions, indexers, and property accessors. +Callables are represented by the class `Callable `__ and are anything that can be called independently, such as methods, constructors, destructors, operators, anonymous functions, indexers, and property accessors. The database contains all of the callables in your program and in all referenced assemblies. @@ -564,7 +562,7 @@ Find ``Main`` methods which are not ``private``: Statements ---------- -Statements are represented by the QL class `Stmt `__ and make up the body of methods (and other callables). The database contains all statements in the source code, but does not contain any statements from referenced assemblies where the source code is not available. +Statements are represented by the class `Stmt `__ and make up the body of methods (and other callables). The database contains all statements in the source code, but does not contain any statements from referenced assemblies where the source code is not available. Class hierarchy ~~~~~~~~~~~~~~~ @@ -922,7 +920,7 @@ Exercise 9: Limit the previous query to string types. Exclude empty passwords or Attributes ---------- -C# attributes are represented by the QL class `Attribute `__. They can be present on many C# elements, such as classes, methods, fields, and parameters. The database contains attributes from the source code and all assembly references. +C# attributes are represented by the class `Attribute `__. They can be present on many C# elements, such as classes, methods, fields, and parameters. The database contains attributes from the source code and all assembly references. The attribute of any ``Element`` can be obtained via ``getAnAttribute()``, whereas if you have an attribute, you can find its element via ``getTarget()``. The following two query fragments are identical: @@ -1122,6 +1120,6 @@ Here is the fixed version: What next? ---------- -- Visit :doc:`Tutorial: Analyzing data flow in C# ` to learn more about writing queries using the standard QL for C# data flow and taint tracking libraries. +- Visit :doc:`Tutorial: Analyzing data flow in C# ` to learn more about writing queries using the standard data flow and taint tracking libraries. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. \ No newline at end of file diff --git a/docs/language/learn-ql/csharp/ql-for-csharp.rst b/docs/language/learn-ql/csharp/ql-for-csharp.rst index 56d8f7ef017..013464ed036 100644 --- a/docs/language/learn-ql/csharp/ql-for-csharp.rst +++ b/docs/language/learn-ql/csharp/ql-for-csharp.rst @@ -1,5 +1,5 @@ -QL for C# -========= +CodeQL for C# +============= .. toctree:: :glob: @@ -8,17 +8,17 @@ QL for C# introduce-libraries-csharp dataflow -These topics provide an overview of the QL C# libraries and show examples of how to use them. +These topics provide an overview of the CodeQL libraries for C# and show examples of how to use them. -- `Basic C# QL query `__ describes how to write and run queries using LGTM. +- `Basic C# query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the C# libraries ` introduces the standard libraries used to write queries for C# code. +- :doc:`Introducing the CodeQL libraries for C# ` introduces the standard libraries used to write queries for C# code. .. raw:: html -- :doc:`Tutorial: Analyzing data flow in C# ` demonstrates how to write queries using the standard QL for C# data flow and taint tracking libraries. +- :doc:`Tutorial: Analyzing data flow in C# ` demonstrates how to write queries using the standard data flow and taint tracking libraries for C#. .. raw:: html @@ -35,6 +35,6 @@ These topics provide an overview of the QL C# libraries and show examples of how Other resources --------------- -- For examples of how to query common C# elements, see the `C# QL cookbook `__. -- For the queries used in LGTM, display a `C# query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the C/C++ QL library see the `QL library for C# `__. +- For examples of how to query common C# elements, see the `C# cookbook `__. +- For the queries used in LGTM, display a `C# query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for C# see the `CodeQL library for C# `__. From fbc11e505f6d779444fae33ce0abd12ffae79dc9 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Thu, 24 Oct 2019 14:27:27 +0100 Subject: [PATCH 035/148] Docs: Update Go --- docs/language/learn-ql/go/ql-for-go.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index 47080ebfe89..baa390dc7c6 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -1,7 +1,7 @@ -QL for Go -========= +CodeQL for Go +============= -This page provides an overview of the QL for Go documentation that is currently available. +This page provides an overview of the CodeQL for Go documentation that is currently available. - `Basic Go query `__ describes how to write and run queries using LGTM. @@ -9,5 +9,5 @@ This page provides an overview of the QL for Go documentation that is currently Other resources --------------- -- For the queries used in LGTM, display a `Go query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the Go QL library see the `QL library for Go `__. \ No newline at end of file +- For the queries used in LGTM, display a `Go query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for Go see the `CodeQL library for Go `__. \ No newline at end of file From 6090867542f945fd18f2fd18dd25b6508c2d681f Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Thu, 24 Oct 2019 14:58:10 +0100 Subject: [PATCH 036/148] Docs: Update Java --- docs/language/learn-ql/java/annotations.rst | 18 +++++------ .../learn-ql/java/ast-class-reference.rst | 14 ++++---- docs/language/learn-ql/java/call-graph.rst | 6 ++-- docs/language/learn-ql/java/dataflow.rst | 6 ++-- .../learn-ql/java/expressions-statements.rst | 12 +++---- .../java/introduce-libraries-java.rst | 22 ++++++------- docs/language/learn-ql/java/javadoc.rst | 8 ++--- docs/language/learn-ql/java/ql-for-java.rst | 32 +++++++++---------- .../learn-ql/java/source-locations.rst | 10 +++--- .../learn-ql/java/types-class-hierarchy.rst | 24 +++++++------- 10 files changed, 76 insertions(+), 76 deletions(-) diff --git a/docs/language/learn-ql/java/annotations.rst b/docs/language/learn-ql/java/annotations.rst index 2808633dcf1..9fbb70776c4 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -4,9 +4,9 @@ Tutorial: Annotations Overview -------- -Snapshots of Java projects contain information about all annotations attached to program elements. +CodeQL databases of Java projects contain information about all annotations attached to program elements. -In QL, annotations are represented as follows: +Annotations are represented by the following CodeQL classes: - The class ``Annotatable`` represents all entities that may have an annotation attached to them (that is, packages, reference types, fields, methods, and local variables). - The class ``AnnotationType`` represents a Java annotation type, such as ``java.lang.Override``; annotation types are interfaces. @@ -23,7 +23,7 @@ As an example, recall that the Java standard library defines an annotation ``Sup String[] value; } -In QL, ``SuppressWarnings`` is represented as an ``AnnotationType``, with ``value`` as its only ``AnnotationElement``. +``SuppressWarnings`` is represented as an ``AnnotationType``, with ``value`` as its only ``AnnotationElement``. A typical usage of ``SuppressWarnings`` would be the following annotation to prevent a warning about using raw types: @@ -35,7 +35,7 @@ A typical usage of ``SuppressWarnings`` would be the following annotation to pre } } -In QL, the expression ``@SuppressWarnings("rawtypes")`` is represented as an ``Annotation``. The string literal ``"rawtypes"`` is used to initialize the annotation element ``value``, and its value can be extracted from the annotation by means of the ``getValue`` predicate. +The expression ``@SuppressWarnings("rawtypes")`` is represented as an ``Annotation``. The string literal ``"rawtypes"`` is used to initialize the annotation element ``value``, and its value can be extracted from the annotation by means of the ``getValue`` predicate. We could then write the following query to find all ``@SuppressWarnings`` annotations attached to constructors, and return both the annotation itself and the value of its ``value`` element: @@ -101,7 +101,7 @@ As a first step, let us write a query that finds all ``@Override`` annotations. where ann.getType().hasQualifiedName("java.lang", "Override") select ann -As always, it is a good idea to try this query on a Java snapshot to make sure it actually produces some results. On the earlier example, it should find the annotation on ``Sub1.m``. Next, we encapsulate the concept of an ``@Override`` annotation as a QL class: +As always, it is a good idea to try this query on a CodeQL database for a Java project to make sure it actually produces some results. On the earlier example, it should find the annotation on ``Sub1.m``. Next, we encapsulate the concept of an ``@Override`` annotation as a CodeQL class: :: @@ -147,7 +147,7 @@ For example, consider the following example program: Here, both ``A.m`` and ``A.n`` are marked as deprecated. Methods ``n`` and ``r`` both call ``m``, but note that ``n`` itself is deprecated, so we probably should not warn about this call. -Like in the previous example, we start by defining a QL class for representing ``@Deprecated`` annotations: +Like in the previous example, we start by defining a class for representing ``@Deprecated`` annotations: .. code-block:: ql @@ -204,7 +204,7 @@ For instance, consider this slightly updated example: Here, the programmer has explicitly suppressed warnings about deprecated calls in ``A.r``, so our query should not flag the call to ``A.m`` any more. -To do so, we first introduce a QL class for representing all ``@SuppressWarnings`` annotations where the string ``deprecated`` occurs among the list of warnings to suppress: +To do so, we first introduce a class for representing all ``@SuppressWarnings`` annotations where the string ``deprecated`` occurs among the list of warnings to suppress: .. code-block:: ql @@ -238,6 +238,6 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress What next? ---------- -- Take a look at some of the other tutorials: :doc:`Tutorial: Javadoc `, :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Take a look at some of the other tutorials: :doc:`Tutorial: Javadoc ` and :doc:`Tutorial: Working with source locations `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index e9fcc4b1d6a..268b95acac5 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -15,7 +15,7 @@ Statement classes This table lists all subclasses of `Stmt`_. +------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| Statement syntax | QL class | Superclasses | Remarks | +| Statement syntax | CodeQL class | Superclasses | Remarks | +========================================================================+===========================================================================================================================================================+===================================+=============================================+ | ``;`` | `EmptyStmt `__ | | | +------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ @@ -87,7 +87,7 @@ Literals All classes in this subsection are subclasses of `Literal `__. +---------------------------+--------------------------+ -| Expression syntax example | QL class | +| Expression syntax example | CodeQL class | +===========================+==========================+ | ``true`` | ``BooleanLiteral`` | +---------------------------+--------------------------+ @@ -112,7 +112,7 @@ Unary expressions All classes in this subsection are subclasses of `UnaryExpr `__. +---------------------------+-----------------+---------------------+---------------------------------------------------+ -| Expression syntax example | QL class | Superclasses | Remarks | +| Expression syntax example | CodeQL class | Superclasses | Remarks | +===========================+=================+=====================+===================================================+ | ``x++`` | ``PostIncExpr`` | ``UnaryAssignExpr`` | | +---------------------------+-----------------+---------------------+---------------------------------------------------+ @@ -137,7 +137,7 @@ Binary expressions All classes in this subsection are subclasses of `BinaryExpr `__. +---------------------------+--------------------+--------------------+ -| Expression syntax example | QL class | Superclasses | +| Expression syntax example | CodeQL class | Superclasses | +===========================+====================+====================+ | ``x * y`` | ``MulExpr`` | | +---------------------------+--------------------+--------------------+ @@ -184,7 +184,7 @@ Assignment expressions All classes in this table are subclasses of `Assignment `__. +---------------------------+-----------------------+--------------+ -| Expression syntax example | QL class | Superclasses | +| Expression syntax example | CodeQL class | Superclasses | +===========================+=======================+==============+ | ``x = y`` | ``AssignExpr`` | | +---------------------------+-----------------------+--------------+ @@ -215,7 +215,7 @@ Accesses ~~~~~~~~ +--------------------------------------+-------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax examples | QL class | +| Expression syntax examples | CodeQL class | +======================================+=========================================================================================================================+ | ``this`` | `ThisAccess `__ | +--------------------------------------+ + @@ -250,7 +250,7 @@ Miscellaneous ~~~~~~~~~~~~~ +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ -| Expression syntax examples | QL class | Remarks | +| Expression syntax examples | CodeQL class | Remarks | +==================================================================+=======================================================================================================================+=============================================================================+ | ``(int) f`` | `CastExpr `__ | | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index 4be0153fca4..bb24c2d8550 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -4,7 +4,7 @@ Tutorial: Navigating the call graph Call graph API -------------- -The QL Java library provides two abstract classes for representing a program's call graph: ``Callable`` and ``Call``. The former is simply the common superclass of ``Method`` and ``Constructor``, the latter is a common superclass of ``MethodAccess``, ``ClassInstanceExpression``, ``ThisConstructorInvocationStmt`` and ``SuperConstructorInvocationStmt``. Simply put, a ``Callable`` is something that can be invoked, and a ``Call`` is something that invokes a ``Callable``. +The CodeQL library for Java provides two abstract classes for representing a program's call graph: ``Callable`` and ``Call``. The former is simply the common superclass of ``Method`` and ``Constructor``, the latter is a common superclass of ``MethodAccess``, ``ClassInstanceExpression``, ``ThisConstructorInvocationStmt`` and ``SuperConstructorInvocationStmt``. Simply put, a ``Callable`` is something that can be invoked, and a ``Call`` is something that invokes a ``Callable``. For example, in the following program all callables and calls have been annotated with comments: @@ -160,6 +160,6 @@ Finally, on many Java projects there are methods that are invoked indirectly by What next? ---------- -- Find out how to query metadata and white space: :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Find out how to query metadata and white space: :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/dataflow.rst b/docs/language/learn-ql/java/dataflow.rst index 39a2b6d5f50..974579e1bcc 100644 --- a/docs/language/learn-ql/java/dataflow.rst +++ b/docs/language/learn-ql/java/dataflow.rst @@ -4,10 +4,10 @@ Analyzing data flow in Java Overview -------- -This topic describes how data flow analysis is implemented in the QL for Java library and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the QL libraries for local data flow, global data flow and taint tracking. +This topic describes how data flow analysis is implemented in the CodeQL libraries for Java and includes examples to help you write your own data flow queries. +The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. -For a more general introduction to modeling data flow in QL, see :doc:`Introduction to data flow analysis in QL <../intro-to-data-flow>`. +For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. Local data flow --------------- diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index 0dfaa9f18ed..b08f2cf0b8b 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -22,12 +22,12 @@ If ``l`` is bigger than 2\ :sup:`31`\ - 1 (the largest positive value of type `` All primitive numeric types have a maximum value, beyond which they will wrap around to their lowest possible value (called an "overflow"). For ``int``, this maximum value is 2\ :sup:`31`\ - 1. Type ``long`` can accommodate larger values up to a maximum of 2\ :sup:`63`\ - 1. In this example, this means that ``l`` can take on a value that is higher than the maximum for type ``int``; ``i`` will never be able to reach this value, instead overflowing and returning to a low value. -We will develop a query that finds code that looks like it might exhibit this kind of behavior. We will be using several of the standard QL library classes for representing statements and functions, a full list of which can be found in the :doc:`AST class reference `. +We will develop a query that finds code that looks like it might exhibit this kind of behavior. We will be using several of the standard library classes for representing statements and functions, a full list of which can be found in the :doc:`AST class reference `. Initial query ------------- -We start out by writing a query that finds less-than expressions (QL class ``LTExpr``) where the left operand is of type ``int`` and the right operand is of type ``long``: +We start out by writing a query that finds less-than expressions (CodeQL class ``LTExpr``) where the left operand is of type ``int`` and the right operand is of type ``long``: .. code-block:: ql @@ -57,7 +57,7 @@ Notice that we use the predicate ``getType`` (available on all subclasses of ``E The class ``LoopStmt`` is a common superclass of all loops, including, in particular, ``for`` loops as in our example above. While different kinds of loops have different syntax, they all have a loop condition, which can be accessed through predicate ``getCondition``. We use the reflexive transitive closure operator ``*`` applied to the ``getAChildExpr`` predicate to express the requirement that ``expr`` should be nested inside the loop condition. In particular, it can be the loop condition itself. -The final conjunct in the ``where`` clause takes advantage of the fact that QL predicates can return more than one value (they are really relations). In particular, ``getAnOperand`` may return *either* operand of ``expr``, so ``expr.getAnOperand().isCompileTimeConstant()`` holds if at least one of the operands is constant. Negating this condition means that the query will only find expressions where *neither* of the operands is constant. +The final conjunct in the ``where`` clause takes advantage of the fact that `predicates `__ can return more than one value (they are really relations). In particular, ``getAnOperand`` may return *either* operand of ``expr``, so ``expr.getAnOperand().isCompileTimeConstant()`` holds if at least one of the operands is constant. Negating this condition means that the query will only find expressions where *neither* of the operands is constant. Generalizing the query ---------------------- @@ -76,7 +76,7 @@ In order to compare the ranges of types, we define a predicate that returns the (pt.hasName("long") and result=64) } -We now want to generalize our query to apply to any comparison where the width of the type on the smaller end of the comparison is less than the width of the type on the greater end. Let us call such a comparison *overflow prone*, and introduce an abstract QL class to model it: +We now want to generalize our query to apply to any comparison where the width of the type on the smaller end of the comparison is less than the width of the type on the greater end. Let us call such a comparison *overflow prone*, and introduce an abstract class to model it: .. code-block:: ql @@ -121,6 +121,6 @@ Now we rewrite our query to make use of these new classes: What next? ---------- -- Have a look at some of the other tutorials: :doc:`Tutorial: Types and the class hierarchy `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Have a look at some of the other tutorials: :doc:`Tutorial: Types and the class hierarchy `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 9f37957e5c6..377823c6f70 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -1,25 +1,25 @@ -Introducing the QL libraries for Java -===================================== +Introducing the CodeQL libraries for Java +========================================= Overview -------- -There is an extensive QL library for analyzing Java code. The QL classes in this library present the data from a snapshot database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. +There is an extensive library for analyzing CodeQL databases extracted from Java projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. -The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``java.qll`` imports all other standard library modules, so you can include the complete library by beginning your query with: +The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``java.qll`` imports all the core C/C++ library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import java -The rest of this topic briefly summarizes the most important QL classes and predicates provided by this library. +The rest of this topic briefly summarizes the most important classes and predicates provided by this library. The example queries in this topic illustrate the types of results returned by different library classes. The results themselves are not interesting but can be used as the basis for developing a more complex query. The tutorial topics show how you can take a simple query and fine-tune it to find precisely the results you're interested in. Summary of the library classes ------------------------------ -The most important classes in the standard QL Java library can be grouped into five main categories: +The most important classes in the standard Java library can be grouped into five main categories: #. Classes for representing program elements (such as classes and methods) #. Classes for representing AST nodes (such as statements and expressions) @@ -89,7 +89,7 @@ Several more specialized classes are available as well: - A ``LocalClass``, which is `a class declared inside a method or constructor `__. - An ``AnonymousClass``, which is an `anonymous class `__. -Finally, the QL library also has a number of singleton classes that wrap frequently used Java standard library classes: ``TypeObject``, ``TypeCloneable``, ``TypeRuntime``, ``TypeSerializable``, ``TypeString``, ``TypeSystem`` and ``TypeClass``. Each QL class represents the standard Java class suggested by its name. +Finally, the library also has a number of singleton classes that wrap frequently used Java standard library classes: ``TypeObject``, ``TypeCloneable``, ``TypeRuntime``, ``TypeSerializable``, ``TypeString``, ``TypeSystem`` and ``TypeClass``. Each CodeQL class represents the standard Java class suggested by its name. As an example, we can write a query that finds all nested classes that directly extend ``Object``: @@ -160,7 +160,7 @@ As an example, the following query finds all type variables with type bound ``Nu ➤ `See this in the query console `__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *gradle/gradle* and *hibernate/hibernate-orm* projects all contained examples of this pattern. -For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In QL, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``: +For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In the CodeQL libraries, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``: .. code-block:: ql @@ -342,7 +342,7 @@ For example, the following query finds methods with a `cyclomatic complexity `, :doc:`Expressions and statements `, :doc:`Navigating the call graph `, :doc:`Annotations `, :doc:`Javadoc ` and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Experiment with the worked examples in the CodeQL for Java tutorial topics: :doc:`Types and the class hierarchy `, :doc:`Expressions and statements `, :doc:`Navigating the call graph `, :doc:`Annotations `, :doc:`Javadoc ` and :doc:`Working with source locations `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/javadoc.rst b/docs/language/learn-ql/java/javadoc.rst index 4b76da9c1fa..bd0a11b9132 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -49,7 +49,7 @@ The ``JavadocTag`` has several subclasses representing specific kinds of Javadoc Example: Finding spurious @param tags ------------------------------------- -As an example of using the QL Javadoc API, let us write a query that finds ``@param`` tags that refer to a non-existent parameter. +As an example of using the CodeQL Javadoc API, let us write a query that finds ``@param`` tags that refer to a non-existent parameter. For example, consider the following program: @@ -110,7 +110,7 @@ For example, consider the following Java program: Notice that the Javadoc comment of ``A.foo`` documents two thrown exceptions: ``IOException`` and ``RuntimeException``. The former is clearly spurious: ``A.foo`` does not have a ``throws IOException`` clause, and thus cannot throw this kind of exception. On the other hand, ``RuntimeException`` is an unchecked exception, so it can be thrown even if there is no explicit ``throws`` clause listing it. Therefore, our query should flag the ``@throws`` tag for ``IOException``, but not the one for ``RuntimeException.`` -Recall from above that QL represents ``@throws`` tags using class ``ThrowsTag``. This class does not provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look as follows: +Recall from above that the CodeQL library represents ``@throws`` tags using class ``ThrowsTag``. This class does not provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look as follows: .. code-block:: ql @@ -170,7 +170,7 @@ This program defines its own class ``IOException``, which is unrelated to the cl As an example of the second problem, method ``A.foo`` from our previous example was annotated with a ``@throws RuntimeException`` tag. Our current version of ``mayThrow``, however, would think that ``A.foo`` cannot throw a ``RuntimeException``, and thus flag the tag as spurious. -We can make ``mayThrow`` less restrictive by introducing a new QL class to represent unchecked exceptions, which are just the subtypes of ``java.lang.RuntimeException`` and ``java.lang.Error``: +We can make ``mayThrow`` less restrictive by introducing a new class to represent unchecked exceptions, which are just the subtypes of ``java.lang.RuntimeException`` and ``java.lang.Error``: .. code-block:: ql @@ -220,5 +220,5 @@ What next? ---------- - Find out how you can use the location API to define queries on whitespace: :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/ql-for-java.rst b/docs/language/learn-ql/java/ql-for-java.rst index f09a5ae990d..aa26c5ba6bb 100644 --- a/docs/language/learn-ql/java/ql-for-java.rst +++ b/docs/language/learn-ql/java/ql-for-java.rst @@ -1,5 +1,5 @@ -QL for Java -=========== +CodeQL for Java +=============== .. toctree:: :glob: @@ -15,31 +15,31 @@ QL for Java source-locations ast-class-reference -These topics provide an overview of the QL Java standard library and show examples of how to use them. +These topics provide an overview of the CodeQL libraries for Java and show examples of how to use them. -- `Basic Java QL query `__ describes how to write and run queries using LGTM. +- `Basic Java query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the QL libraries for Java ` an introduction to the organization of the standard libraries used to write queries for Java code. +- :doc:`Introducing the CodeQL libraries for Java ` introduces the standard libraries used to write queries for Java code. -- :doc:`Tutorial: Analyzing data flow in Java ` demonstrates how to write queries using the standard QL for Java data flow and taint tracking libraries. +- :doc:`Tutorial: Analyzing data flow in Java ` demonstrates how to write queries using the standard data flow and taint tracking libraries for Java. -- :doc:`Tutorial: Types and the class hierarchy ` introduces the QL classes for representing a program's class hierarchy by means of examples. +- :doc:`Tutorial: Types and the class hierarchy ` introduces the classes for representing a program's class hierarchy by means of examples. -- :doc:`Tutorial: Expressions and statements ` introduces the QL classes for representing a program's syntactic structure by means of examples. +- :doc:`Tutorial: Expressions and statements ` introduces the classes for representing a program's syntactic structure by means of examples. -- :doc:`Tutorial: Navigating the call graph ` a worked example of how to write a query that navigates a program's call graph to find unused methods. +- :doc:`Tutorial: Navigating the call graph ` is a worked example of how to write a query that navigates a program's call graph to find unused methods. -- :doc:`Tutorial: Annotations ` introduces the QL classes for representing annotations by means of examples. +- :doc:`Tutorial: Annotations ` introduces the classes for representing annotations by means of examples. -- :doc:`Tutorial: Javadoc ` introduces the QL classes for representing Javadoc comments by means of examples. +- :doc:`Tutorial: Javadoc ` introduces the classes for representing Javadoc comments by means of examples. -- :doc:`Tutorial: Working with source locations ` a worked example of how to write a query that uses the location information provided in the snapshot for finding likely bugs. +- :doc:`Tutorial: Working with source locations ` is a worked example of how to write a query that uses the location information provided in the database for finding likely bugs. -- :doc:`AST class reference ` an overview of all AST classes in the QL standard library for Java. +- :doc:`AST class reference ` gives an overview of all AST classes in the standard CodeQL library for Java. Other resources --------------- -- For examples of how to query common Java elements, see the `Java QL cookbook `__. -- For the queries used in LGTM, display a `Java query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the Java QL library see the `QL library for Java `__. +- For examples of how to query common Java elements, see the `Java cookbook `__. +- For the queries used in LGTM, display a `Java query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for Java see the `CodeQL library for Java `__. diff --git a/docs/language/learn-ql/java/source-locations.rst b/docs/language/learn-ql/java/source-locations.rst index ebb40916d04..6e29777fab9 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -16,12 +16,12 @@ Note that the source layout gives a fairly clear indication of the intended mean We will now develop a query that finds this kind of suspicious nesting, where the operator of the inner expression has more white space around it than the operator of the outer expression. This pattern may not necessarily indicate a bug, but at the very least it makes the code hard to read and prone to misinterpretation. -White space is not directly represented in the snapshot database, but we can deduce its presence from the location information associated with program elements and AST nodes. So we will start by providing an overview of source location management in the QL standard library. +White space is not directly represented in the CodeQL database, but we can deduce its presence from the location information associated with program elements and AST nodes. So we will start by providing an overview of source location management in the standard library for Java. Location API ------------ -For every entity that has a representation in Java source code (including, in particular, program elements and AST nodes), the QL standard library provides the following predicates for accessing source location information: +For every entity that has a representation in Java source code (including, in particular, program elements and AST nodes), the standard CodeQL library provides the following predicates for accessing source location information: - ``getLocation`` returns a ``Location`` object describing the start and end position of the entity. - ``getFile`` returns a ``File`` object representing the file containing the entity. @@ -123,7 +123,7 @@ If we run this initial query, we might notice some false positives arising from i< start + 100 -Note that our predicate ``operatorWS`` computes the **total** amount of white space around the operator, which, in this case, is one for the ``<`` and two for the ``+``. Ideally, we would like to exclude cases where the amount of white space before and after the operator are not the same. Currently, snapshot databases do not record enough information to figure this out, but as an approximation we could require that the total number of white space characters is even: +Note that our predicate ``operatorWS`` computes the **total** amount of white space around the operator, which, in this case, is one for the ``<`` and two for the ``+``. Ideally, we would like to exclude cases where the amount of white space before and after the operator are not the same. Currently, CodeQL databases do not record enough information to figure this out, but as an approximation we could require that the total number of white space characters is even: .. code-block:: ql @@ -141,7 +141,7 @@ Note that our predicate ``operatorWS`` computes the **total** amount of white sp ➤ `See this in the query console `__. Any results will be refined by our changes to the query. -Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive.To exclude these cases, let us define a new QL class identifying binary expressions with an associative operator: +Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive.To exclude these cases, let us define a new class identifying binary expressions with an associative operator: .. code-block:: ql @@ -184,5 +184,5 @@ Whitespace suggests that the programmer meant to toggle ``i`` between zero and o What next? ---------- -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index cc7e6da4afd..7677c64965d 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -4,7 +4,7 @@ Tutorial: Types and the class hierarchy Overview -------- -The standard QL library for Java represents Java types by means of the ``Type`` class and its various subclasses. +The standard CodeQL library represents Java types by means of the ``Type`` class and its various subclasses. In particular, class ``PrimitiveType`` represents primitive types that are built into the Java language (such as ``boolean`` and ``int``), whereas ``RefType`` and its subclasses represent reference types, that is classes, interfaces, array types, and so on. This includes both types from the Java standard library (like ``java.lang.Object``) and types defined by non-library code. @@ -62,7 +62,7 @@ In this tutorial, we do not try to distinguish these two cases. Our query should - Both ``source`` and ``target`` are array types. - The element type of ``source`` is a transitive super type of the element type of ``target``. -This recipe is not too difficult to translate into a QL query: +This recipe is not too difficult to translate into a query: .. code-block:: ql @@ -93,7 +93,7 @@ In code that does not use generics, this method is often used in the following w Here, ``l`` has the raw type ``List``, so ``l.toArray`` has return type ``Object[]``, independent of the type of its argument array. Hence the cast goes from ``Object[]`` to ``A[]`` and will be flagged as problematic by our query, although at runtime this cast can never go wrong. -To identify these cases, we can create two QL classes that represent, respectively, the ``Collection.toArray`` class, and calls to this method or any method that overrides it: +To identify these cases, we can create two CodeQL classes that represent, respectively, the ``Collection.toArray`` class, and calls to this method or any method that overrides it: .. code-block:: ql @@ -160,7 +160,7 @@ Since ``zkProp`` is a map from ``Object`` to ``Object``, ``zkProp.entrySet`` ret In general, we want to find calls to ``Collection.contains`` (or any of its overriding methods in any parameterized instance of ``Collection``), such that the type ``E`` of collection elements and the type ``A`` of the argument to ``contains`` are unrelated, that is, they have no common subtype. -We start by creating a QL class that describes ``java.util.Collection``: +We start by creating a class that describes ``java.util.Collection``: .. code-block:: ql @@ -179,7 +179,7 @@ To make sure we have not mistyped anything, we can run a simple test query: This query should return precisely one result. -Next, we can create a QL class that describes ``java.util.Collection.contains``: +Next, we can create a class that describes ``java.util.Collection.contains``: .. code-block:: ql @@ -198,9 +198,9 @@ Notice that we use ``hasStringSignature`` to check that: Alternatively, we could have implemented these three checks more verbosely using ``hasName``, ``getNumberOfParameters``, and ``getParameter(0).getType() instanceof TypeObject``. -As before, it is a good idea to test the new QL class by running a simple query to select all instances of ``JavaUtilCollectionContains``; again there should only be a single result. +As before, it is a good idea to test the new class by running a simple query to select all instances of ``JavaUtilCollectionContains``; again there should only be a single result. -Now we want to identify all calls to ``Collection.contains``, including any methods that override it, and considering all parameterized instances of ``Collection`` and its subclasses. That is, we are looking for method accesses where the source declaration of the invoked method (reflexively or transitively) overrides ``Collection.contains``. We encode this in a QL class ``JavaUtilCollectionContainsCall``: +Now we want to identify all calls to ``Collection.contains``, including any methods that override it, and considering all parameterized instances of ``Collection`` and its subclasses. That is, we are looking for method accesses where the source declaration of the invoked method (reflexively or transitively) overrides ``Collection.contains``. We encode this in a CodeQL class ``JavaUtilCollectionContainsCall``: .. code-block:: ql @@ -230,7 +230,7 @@ For the latter, we proceed as follows: - Find a (reflexive or transitive) super type ``S`` of ``D`` that is a parameterized instance of ``java.util.Collection``. - Return the (only) type argument of ``S``. -We encode this in QL as follows: +We encode this as follows: .. code-block:: ql @@ -268,11 +268,11 @@ Now we are ready to write a first version of our query: Improvements ~~~~~~~~~~~~ -For many programs, this query yields a large number of false positive results due to type variables and wild cards: if the collection element type is some type variable ``E`` and the argument type is ``String``, for example, QL will consider that the two have no common subtype, and our query will flag the call. An easy way to exclude such false positive results is to simply require that neither ``collEltType`` nor ``argType`` are instances of ``TypeVariable``. +For many programs, this query yields a large number of false positive results due to type variables and wild cards: if the collection element type is some type variable ``E`` and the argument type is ``String``, for example, CodeQL will consider that the two have no common subtype, and our query will flag the call. An easy way to exclude such false positive results is to simply require that neither ``collEltType`` nor ``argType`` are instances of ``TypeVariable``. Another source of false positives is autoboxing of primitive types: if, for example, the collection's element type is ``Integer`` and the argument is of type ``int``, predicate ``haveCommonDescendant`` will fail, since ``int`` is not a ``RefType``. Thus, our query should check that ``collEltType`` is not the boxed type of ``argType``. -Finally, ``null`` is special because its type (known as ```` in QL) is compatible with every reference type, so we should exclude it from consideration. +Finally, ``null`` is special because its type (known as ```` in the CodeQL library) is compatible with every reference type, so we should exclude it from consideration. Adding these three improvements, our final query becomes: @@ -295,6 +295,6 @@ Adding these three improvements, our final query becomes: What next? ---------- -- Take a look at some of the other tutorials: :doc:`Tutorial: Expressions and statements `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the QL standard library for Java: :doc:`AST class reference `. +- Take a look at some of the other tutorials: :doc:`Tutorial: Expressions and statements `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. +- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. From 5489a80372ab2fdbf1c30f7d3a5c0625a4ed9bf1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 10 Oct 2019 16:20:27 +0200 Subject: [PATCH 037/148] add query for detecting ignored calls to Array.prototype.concat --- change-notes/1.23/analysis-javascript.md | 1 + .../src/Statements/IgnoreConcatReturn.qhelp | 44 +++++++++++++++++++ .../ql/src/Statements/IgnoreConcatReturn.ql | 42 ++++++++++++++++++ .../src/Statements/examples/IgnoreConcat.js | 5 +++ .../Statements/examples/IgnoreConcatFixed.js | 5 +++ .../IgnoreConcatReturn.expected | 2 + .../IgnoreConcatReturn.qlref | 1 + .../Statements/IgnoreConcatReturn/tst.js | 13 ++++++ 8 files changed, 113 insertions(+) create mode 100644 javascript/ql/src/Statements/IgnoreConcatReturn.qhelp create mode 100644 javascript/ql/src/Statements/IgnoreConcatReturn.ql create mode 100644 javascript/ql/src/Statements/examples/IgnoreConcat.js create mode 100644 javascript/ql/src/Statements/examples/IgnoreConcatFixed.js create mode 100644 javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected create mode 100644 javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref create mode 100644 javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 73bbf1247f7..90f46403f26 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -23,6 +23,7 @@ | Use of returnless function (`js/use-of-returnless-function`) | maintainability, correctness | Highlights calls where the return value is used, but the callee never returns a value. Results are shown on LGTM by default. | | Useless regular expression character escape (`js/useless-regexp-character-escape`) | correctness, security, external/cwe/cwe-20 | Highlights regular expression strings with useless character escapes, indicating a possible violation of [CWE-20](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default. | | Unreachable method overloads (`js/unreachable-method-overloads`) | correctness, typescript | Highlights method overloads that are impossible to use from client code. Results are shown on LGTM by default. | +| Ignoring return from concat (`js/ignore-return-from-concat`) | maintainability, correctness | Highlights calls to the concat method on array where the return value is ignored. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/ql/src/Statements/IgnoreConcatReturn.qhelp b/javascript/ql/src/Statements/IgnoreConcatReturn.qhelp new file mode 100644 index 00000000000..1b69a61b3a9 --- /dev/null +++ b/javascript/ql/src/Statements/IgnoreConcatReturn.qhelp @@ -0,0 +1,44 @@ + + + +

+The concat method on is pure and does not modify any of the input +arrays. It is therefore generally an error to ignore the return value from a +call to concat. +

+ +
+ + +

+Use the returned value from the call to concat. +

+ +
+ + +

+In the following example a function extend is defined. The +function uses the concat method to add elements to the +arr array. However, the extend function has no +effect as the return value from concat is ignored. +

+ + + +

+Assigning the returned value from the call to concat to the +arr variable fixes the error. +

+ + + +
+ + +
  • Mozilla Developer Network: Array concat.
  • + +
    +
    diff --git a/javascript/ql/src/Statements/IgnoreConcatReturn.ql b/javascript/ql/src/Statements/IgnoreConcatReturn.ql new file mode 100644 index 00000000000..65c379b3437 --- /dev/null +++ b/javascript/ql/src/Statements/IgnoreConcatReturn.ql @@ -0,0 +1,42 @@ +/** + * @name Ignoring return from concat + * @description The concat method does not modify an array, ignoring the result of a call to concat is therefore generally an error. + * @kind problem + * @problem.severity warning + * @id js/ignore-result-from-concat + * @tags maintainability, + * correctness + * @precision high + */ + +import javascript +import Expressions.ExprHasNoEffect + +DataFlow::SourceNode array(DataFlow::TypeTracker t) { + t.start() and + result instanceof DataFlow::ArrayCreationNode + or + exists (DataFlow::TypeTracker t2 | + result = array(t2).track(t2, t) + ) +} + +DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } + +predicate isArrayMethod(DataFlow::MethodCallNode call) { + call.getReceiver().getALocalSource() = array() +} + +predicate isIncomplete(DataFlow::Node node) { + any(DataFlow::Incompleteness cause | node.analyze().getAValue().isIndefinite(cause)) != "global" +} + +from DataFlow::CallNode call +where + isArrayMethod(call) and + call.getCalleeName() = "concat" and + call.getNumArgument() = 1 and + (call.getArgument(0).getALocalSource() = array() or isIncomplete(call.getArgument(0))) and + not call.getArgument(0).asExpr().(ArrayExpr).getSize() = 0 and + inVoidContext(call.asExpr()) +select call, "Return value from call to concat ignored." diff --git a/javascript/ql/src/Statements/examples/IgnoreConcat.js b/javascript/ql/src/Statements/examples/IgnoreConcat.js new file mode 100644 index 00000000000..7137d5261a6 --- /dev/null +++ b/javascript/ql/src/Statements/examples/IgnoreConcat.js @@ -0,0 +1,5 @@ +var arr = [1,2,3]; + +function extend(others) { + arr.concat(others); +} \ No newline at end of file diff --git a/javascript/ql/src/Statements/examples/IgnoreConcatFixed.js b/javascript/ql/src/Statements/examples/IgnoreConcatFixed.js new file mode 100644 index 00000000000..1c7977e9ef0 --- /dev/null +++ b/javascript/ql/src/Statements/examples/IgnoreConcatFixed.js @@ -0,0 +1,5 @@ +var arr = [1,2,3]; + +function extend(others) { + arr = arr.concat(others); +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected new file mode 100644 index 00000000000..1ae8b59226a --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected @@ -0,0 +1,2 @@ +| tst.js:3:1:3:19 | arr.concat([1,2,3]) | Return value from call to concat ignored. | +| tst.js:5:1:5:15 | arr.concat(arr) | Return value from call to concat ignored. | diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref new file mode 100644 index 00000000000..485692fff07 --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref @@ -0,0 +1 @@ +Statements/IgnoreConcatReturn.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js new file mode 100644 index 00000000000..f2c5f34cc60 --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js @@ -0,0 +1,13 @@ +var arr = [1,2,3]; + +arr.concat([1,2,3]); // NOT OK! + +arr.concat(arr); // NOT OK! + +console.log(arr.concat([1,2,3])); + +arr.concat(null); +arr.concat(); +arr.concat([]); + +({concat: Array.prototype.concat}.concat(arr)); \ No newline at end of file From 8f58e7e6c950ca6033a7b29803e32876b9c4b869 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 24 Oct 2019 17:34:01 +0200 Subject: [PATCH 038/148] C++: Clarify qldoc --- cpp/ql/src/semmle/code/cpp/PrintAST.ql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.ql b/cpp/ql/src/semmle/code/cpp/PrintAST.ql index 23f249585b9..e4c53030da5 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.ql +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.ql @@ -13,6 +13,9 @@ import PrintAST * printed. */ class Cfg extends PrintASTConfiguration { - /** Holds if the AST for `func` should be printed. */ + /** + * TWEAK THIS PREDICATE AS NEEDED. + * Holds if the AST for `func` should be printed. + */ override predicate shouldPrintFunction(Function func) { any() } } From 5b26d03f1ca2dba1a91e86f363dd855e09529230 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 25 Oct 2019 15:45:35 +0200 Subject: [PATCH 039/148] introduce backtracking, and also marking join/slice calls --- ...atReturn.qhelp => IgnoreArrayResult.qhelp} | 16 ++++--- .../ql/src/Statements/IgnoreArrayResult.ql | 45 +++++++++++++++++++ .../ql/src/Statements/IgnoreConcatReturn.ql | 42 ----------------- .../{IgnoreConcat.js => IgnoreArrayResult.js} | 0 ...ncatFixed.js => IgnoreArrayResultFixed.js} | 0 .../IgnoreArrayResult.expected} | 0 .../IgnoreArrayResult.qlref} | 0 .../tst.js | 0 8 files changed, 55 insertions(+), 48 deletions(-) rename javascript/ql/src/Statements/{IgnoreConcatReturn.qhelp => IgnoreArrayResult.qhelp} (50%) create mode 100644 javascript/ql/src/Statements/IgnoreArrayResult.ql delete mode 100644 javascript/ql/src/Statements/IgnoreConcatReturn.ql rename javascript/ql/src/Statements/examples/{IgnoreConcat.js => IgnoreArrayResult.js} (100%) rename javascript/ql/src/Statements/examples/{IgnoreConcatFixed.js => IgnoreArrayResultFixed.js} (100%) rename javascript/ql/test/query-tests/Statements/{IgnoreConcatReturn/IgnoreConcatReturn.expected => IgnoreArrayResult/IgnoreArrayResult.expected} (100%) rename javascript/ql/test/query-tests/Statements/{IgnoreConcatReturn/IgnoreConcatReturn.qlref => IgnoreArrayResult/IgnoreArrayResult.qlref} (100%) rename javascript/ql/test/query-tests/Statements/{IgnoreConcatReturn => IgnoreArrayResult}/tst.js (100%) diff --git a/javascript/ql/src/Statements/IgnoreConcatReturn.qhelp b/javascript/ql/src/Statements/IgnoreArrayResult.qhelp similarity index 50% rename from javascript/ql/src/Statements/IgnoreConcatReturn.qhelp rename to javascript/ql/src/Statements/IgnoreArrayResult.qhelp index 1b69a61b3a9..b70ff1f1b32 100644 --- a/javascript/ql/src/Statements/IgnoreConcatReturn.qhelp +++ b/javascript/ql/src/Statements/IgnoreArrayResult.qhelp @@ -4,16 +4,18 @@

    -The concat method on is pure and does not modify any of the input -arrays. It is therefore generally an error to ignore the return value from a -call to concat. +The concat, join and slice methods are +pure and does not modify any of the inputs or the array the method was called +on. It is therefore generally an error to ignore the return value from a call +to one of these methods.

    -Use the returned value from the call to concat. +Use the returned value from the calls to concat, join +or slice.

    @@ -26,19 +28,21 @@ function uses the concat method to add elements to the effect as the return value from concat is ignored.

    - +

    Assigning the returned value from the call to concat to the arr variable fixes the error.

    - +
  • Mozilla Developer Network: Array concat.
  • +
  • Mozilla Developer Network: Array slice.
  • +
  • Mozilla Developer Network: Array join.
  • diff --git a/javascript/ql/src/Statements/IgnoreArrayResult.ql b/javascript/ql/src/Statements/IgnoreArrayResult.ql new file mode 100644 index 00000000000..b3703c6992d --- /dev/null +++ b/javascript/ql/src/Statements/IgnoreArrayResult.ql @@ -0,0 +1,45 @@ +/** + * @name Ignoring result from pure array method + * @description The array methods do not modify the array, ignoring the result of such a call is therefore generally an error. + * @kind problem + * @problem.severity warning + * @id js/ignore-array-result + * @tags maintainability, + * correctness + * @precision high + */ + +import javascript +import Expressions.ExprHasNoEffect + +DataFlow::SourceNode callsArray(DataFlow::TypeBackTracker t, DataFlow::MethodCallNode call) { + isIgnoredPureArrayCall(call) and + ( + t.start() and + result = call.getReceiver() + or + exists(DataFlow::TypeBackTracker t2 | result = callsArray(t2, call).backtrack(t2, t)) + ) +} + +DataFlow::SourceNode callsArray(DataFlow::MethodCallNode call) { + result = callsArray(DataFlow::TypeBackTracker::end(), call) +} + +predicate isIgnoredPureArrayCall(DataFlow::MethodCallNode call) { + inVoidContext(call.asExpr()) and + ( + call.getMethodName() = "concat" and + call.getNumArgument() = 1 + or + call.getMethodName() = "join" and + call.getNumArgument() < 2 + or + call.getMethodName() = "slice" and + call.getNumArgument() < 3 + ) +} + +from DataFlow::MethodCallNode call +where callsArray(call) instanceof DataFlow::ArrayCreationNode +select call, "Result from call to " + call.getMethodName() + " ignored." diff --git a/javascript/ql/src/Statements/IgnoreConcatReturn.ql b/javascript/ql/src/Statements/IgnoreConcatReturn.ql deleted file mode 100644 index 65c379b3437..00000000000 --- a/javascript/ql/src/Statements/IgnoreConcatReturn.ql +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @name Ignoring return from concat - * @description The concat method does not modify an array, ignoring the result of a call to concat is therefore generally an error. - * @kind problem - * @problem.severity warning - * @id js/ignore-result-from-concat - * @tags maintainability, - * correctness - * @precision high - */ - -import javascript -import Expressions.ExprHasNoEffect - -DataFlow::SourceNode array(DataFlow::TypeTracker t) { - t.start() and - result instanceof DataFlow::ArrayCreationNode - or - exists (DataFlow::TypeTracker t2 | - result = array(t2).track(t2, t) - ) -} - -DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } - -predicate isArrayMethod(DataFlow::MethodCallNode call) { - call.getReceiver().getALocalSource() = array() -} - -predicate isIncomplete(DataFlow::Node node) { - any(DataFlow::Incompleteness cause | node.analyze().getAValue().isIndefinite(cause)) != "global" -} - -from DataFlow::CallNode call -where - isArrayMethod(call) and - call.getCalleeName() = "concat" and - call.getNumArgument() = 1 and - (call.getArgument(0).getALocalSource() = array() or isIncomplete(call.getArgument(0))) and - not call.getArgument(0).asExpr().(ArrayExpr).getSize() = 0 and - inVoidContext(call.asExpr()) -select call, "Return value from call to concat ignored." diff --git a/javascript/ql/src/Statements/examples/IgnoreConcat.js b/javascript/ql/src/Statements/examples/IgnoreArrayResult.js similarity index 100% rename from javascript/ql/src/Statements/examples/IgnoreConcat.js rename to javascript/ql/src/Statements/examples/IgnoreArrayResult.js diff --git a/javascript/ql/src/Statements/examples/IgnoreConcatFixed.js b/javascript/ql/src/Statements/examples/IgnoreArrayResultFixed.js similarity index 100% rename from javascript/ql/src/Statements/examples/IgnoreConcatFixed.js rename to javascript/ql/src/Statements/examples/IgnoreArrayResultFixed.js diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected similarity index 100% rename from javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.expected rename to javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref similarity index 100% rename from javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/IgnoreConcatReturn.qlref rename to javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref diff --git a/javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js similarity index 100% rename from javascript/ql/test/query-tests/Statements/IgnoreConcatReturn/tst.js rename to javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js From 841dac1abad86183a0c590fbe45eb486efd81039 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 25 Oct 2019 17:46:55 +0200 Subject: [PATCH 040/148] address review feedback --- javascript/ql/src/Statements/UseOfReturnlessFunction.ql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 2fc3f01a560..c01c6b5e3eb 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -127,8 +127,10 @@ DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) } */ predicate voidArrayCallback(DataFlow::CallNode call, Function func) { hasNonVoidCallbackMethod(call.getCalleeName()) and - func = call.getAnArgument().getALocalSource().asExpr() and - 1 = count(DataFlow::Node arg | arg = call.getAnArgument() and arg.getALocalSource().asExpr() instanceof Function) and + exists(int index | + index = min(int i | exists(call.getCallback(i))) and + func = call.getCallback(index).getFunction() + ) and returnsVoid(func) and not isStub(func) and not alwaysThrows(func) and From da23898ebae5e0701ba1aa40783401e232619c16 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sat, 26 Oct 2019 23:26:45 +0200 Subject: [PATCH 041/148] update tests --- .../Statements/IgnoreArrayResult/IgnoreArrayResult.expected | 4 ++-- .../Statements/IgnoreArrayResult/IgnoreArrayResult.qlref | 2 +- .../ql/test/query-tests/Statements/IgnoreArrayResult/tst.js | 4 ---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected index 1ae8b59226a..9f5c5a0b082 100644 --- a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected +++ b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.expected @@ -1,2 +1,2 @@ -| tst.js:3:1:3:19 | arr.concat([1,2,3]) | Return value from call to concat ignored. | -| tst.js:5:1:5:15 | arr.concat(arr) | Return value from call to concat ignored. | +| tst.js:3:1:3:19 | arr.concat([1,2,3]) | Result from call to concat ignored. | +| tst.js:5:1:5:15 | arr.concat(arr) | Result from call to concat ignored. | diff --git a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref index 485692fff07..2cbc7e722a5 100644 --- a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref +++ b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/IgnoreArrayResult.qlref @@ -1 +1 @@ -Statements/IgnoreConcatReturn.ql \ No newline at end of file +Statements/IgnoreArrayResult.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js index f2c5f34cc60..fc00470c8e1 100644 --- a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js +++ b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js @@ -6,8 +6,4 @@ arr.concat(arr); // NOT OK! console.log(arr.concat([1,2,3])); -arr.concat(null); -arr.concat(); -arr.concat([]); - ({concat: Array.prototype.concat}.concat(arr)); \ No newline at end of file From c6f53199d400c11c4ad71f75e44484bef81a6e18 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sun, 27 Oct 2019 00:24:38 +0200 Subject: [PATCH 042/148] ignore when the reciever is the empty array --- javascript/ql/src/Statements/IgnoreArrayResult.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Statements/IgnoreArrayResult.ql b/javascript/ql/src/Statements/IgnoreArrayResult.ql index b3703c6992d..b6137e664d7 100644 --- a/javascript/ql/src/Statements/IgnoreArrayResult.ql +++ b/javascript/ql/src/Statements/IgnoreArrayResult.ql @@ -41,5 +41,7 @@ predicate isIgnoredPureArrayCall(DataFlow::MethodCallNode call) { } from DataFlow::MethodCallNode call -where callsArray(call) instanceof DataFlow::ArrayCreationNode +where + callsArray(call) instanceof DataFlow::ArrayCreationNode and + not call.getReceiver().asExpr().(ArrayExpr).getSize() = 0 select call, "Result from call to " + call.getMethodName() + " ignored." From 92cebea235d6906a18e818c5234696fae2e58965 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sun, 27 Oct 2019 00:25:59 +0200 Subject: [PATCH 043/148] update tests to include empty reciever case --- .../ql/test/query-tests/Statements/IgnoreArrayResult/tst.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js index fc00470c8e1..47efe8c1cb6 100644 --- a/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js +++ b/javascript/ql/test/query-tests/Statements/IgnoreArrayResult/tst.js @@ -6,4 +6,6 @@ arr.concat(arr); // NOT OK! console.log(arr.concat([1,2,3])); -({concat: Array.prototype.concat}.concat(arr)); \ No newline at end of file +({concat: Array.prototype.concat}.concat(arr)); + +[].concat([1,2,3]); \ No newline at end of file From b2c31701f3cf6dfdfb900fdaeba38b5e0ced2444 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sun, 27 Oct 2019 09:07:45 +0100 Subject: [PATCH 044/148] add documentation to two predicates --- javascript/ql/src/Statements/UseOfReturnlessFunction.ql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index c01c6b5e3eb..77ec29ba9ee 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -89,6 +89,9 @@ predicate lastStatementHasNoEffect(Function f) { hasNoEffect(f.getExit().getAPredecessor()) } +/** + * Holds if `func` is a callee of `call`, and all possible callees of `call` never return a value. + */ predicate callToVoidFunction(DataFlow::CallNode call, Function func) { not call.isIncomplete() and func = call.getACallee() and @@ -97,6 +100,11 @@ predicate callToVoidFunction(DataFlow::CallNode call, Function func) { ) } +/** + * Holds if `name` is the name of a method from `Array.prototype` or Lodash, + * where that method takes a callback as parameter, + * and the callback is expected to return a value. + */ predicate hasNonVoidCallbackMethod(string name) { name = "every" or name = "filter" or From d94b0cab29b83be4759c58b4fa3ddf935127e964 Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 28 Oct 2019 12:05:51 +0000 Subject: [PATCH 045/148] Update docs/language/learn-ql/java/introduce-libraries-java.rst Co-Authored-By: Felicity Chapman --- docs/language/learn-ql/java/introduce-libraries-java.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 377823c6f70..b3d5987ab41 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -6,7 +6,7 @@ Overview There is an extensive library for analyzing CodeQL databases extracted from Java projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. -The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``java.qll`` imports all the core C/C++ library modules, so you can include the complete library by beginning your query with: +The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``java.qll`` imports all the core Java library modules, so you can include the complete library by beginning your query with: .. code-block:: ql From 1fc786bea7f6b3a05f7ba91ef1c4cba75483650d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 28 Oct 2019 13:11:10 +0100 Subject: [PATCH 046/148] C#: Add `precision` tag to `cs/deserialized-delegate` --- .../ql/src/Security Features/CWE-502/DeserializedDelegate.ql | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql index 1c68f01e78b..31d28311908 100644 --- a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql +++ b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql @@ -5,14 +5,11 @@ * @kind problem * @id cs/deserialized-delegate * @problem.severity warning + * @precision high * @tags security * external/cwe/cwe-502 */ -/* - * consider: @precision high - */ - import csharp import semmle.code.csharp.frameworks.system.linq.Expressions import semmle.code.csharp.serialization.Deserializers From c3f23f542ae4108f1773a6da76fc484d47fa1c1d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 28 Oct 2019 13:15:20 +0100 Subject: [PATCH 047/148] C#: Add change note --- change-notes/1.23/analysis-csharp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index 7ec412a0eb2..4f1cb268468 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -8,6 +8,7 @@ The following changes in version 1.23 affect C# analysis in all applications. | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| +| Deserialized delegate (`cs/deserialized-delegate`) | security | Finds unsafe deserialization of delegate types. | | Unsafe year argument for 'DateTime' constructor (`cs/unsafe-year-construction`) | reliability, date-time | Finds incorrect manipulation of `DateTime` values, which could lead to invalid dates. | | Mishandling the Japanese era start date (`cs/mishandling-japanese-era`) | reliability, date-time | Finds hard-coded Japanese era start dates that could be invalid. | From b13535ac7d2c673f0aa7f941e20e82b283edfeca Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 28 Oct 2019 15:58:20 +0100 Subject: [PATCH 048/148] C++: Implement DataFlow::BarrierGuard for AST+IR The change note is copied from the Java change note. --- change-notes/1.23/analysis-cpp.md | 4 ++ .../cpp/dataflow/internal/DataFlowUtil.qll | 16 +++-- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 13 ++-- .../dataflow/dataflow-tests/BarrierGuard.cpp | 68 +++++++++++++++++++ .../dataflow-tests/DataflowTestCommon.qll | 16 +++++ .../dataflow-tests/IRDataflowTestCommon.qll | 17 +++++ .../dataflow/dataflow-tests/test.expected | 10 +++ .../dataflow-tests/test_diff.expected | 3 + .../dataflow/dataflow-tests/test_ir.expected | 7 ++ docs/language/learn-ql/cpp/dataflow.rst | 2 + 10 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/BarrierGuard.cpp diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index 64e9b98fcfb..f22436f55cb 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -39,6 +39,10 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. definition of `x` when `x` is a variable of pointer type. It no longer considers deep paths such as `f(&x.myField)` to be definitions of `x`. These changes are in line with the user expectations we've observed. +* The data-flow library now makes it easier to specify barriers/sanitizers + arising from guards by overriding the predicate + `isBarrierGuard`/`isSanitizerGuard` on data-flow and taint-tracking + configurations respectively. * There is now a `DataFlow::localExprFlow` predicate and a `TaintTracking::localExprTaint` predicate to make it easy to use the most common case of local data flow and taint: from one `Expr` to another. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 0caa2ab05df..cd1fbd487e0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -5,6 +5,8 @@ private import cpp private import semmle.code.cpp.dataflow.internal.FlowVar private import semmle.code.cpp.models.interfaces.DataFlow +private import semmle.code.cpp.controlflow.Guards +private import semmle.code.cpp.valuenumbering.GlobalValueNumbering cached private newtype TNode = @@ -680,12 +682,16 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) { * * It is important that all extending classes in scope are disjoint. */ -class BarrierGuard extends Expr { - /** NOT YET SUPPORTED. Holds if this guard validates `e` upon evaluating to `branch`. */ - abstract deprecated predicate checks(Expr e, boolean branch); +class BarrierGuard extends GuardCondition { + /** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */ + abstract predicate checks(Expr e, boolean branch); /** Gets a node guarded by this guard. */ - final Node getAGuardedNode() { - none() // stub + final ExprNode getAGuardedNode() { + exists(GVN value, boolean branch | + result.getExpr() = value.getAnExpr() and + this.checks(value.getAnExpr(), branch) and + this.controls(result.getExpr().getBasicBlock(), branch) + ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 0476ea3c30a..f824e0b6bf2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -5,6 +5,7 @@ private import cpp private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards +private import semmle.code.cpp.ir.ValueNumbering /** * A newtype wrapper to prevent accidental casts between `Node` and @@ -220,7 +221,7 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) } /** - * A guard that validates some expression. + * A guard that validates some instruction. * * To use this in a configuration, extend the class and provide a * characteristic predicate precisely specifying the guard, and override @@ -229,11 +230,15 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2) * It is important that all extending classes in scope are disjoint. */ class BarrierGuard extends IRGuardCondition { - /** NOT YET SUPPORTED. Holds if this guard validates `e` upon evaluating to `b`. */ - abstract deprecated predicate checks(Instruction e, boolean b); + /** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */ + abstract predicate checks(Instruction instr, boolean b); /** Gets a node guarded by this guard. */ final Node getAGuardedNode() { - none() // stub + exists(ValueNumber value, boolean edge | + result.asInstruction() = value.getAnInstruction() and + this.checks(value.getAnInstruction(), edge) and + this.controls(result.asInstruction().getBlock(), edge) + ) } } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/BarrierGuard.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/BarrierGuard.cpp new file mode 100644 index 00000000000..9c3c8bc4569 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/BarrierGuard.cpp @@ -0,0 +1,68 @@ +int source(); +void sink(int); +bool guarded(int); + +void bg_basic(int source) { + if (guarded(source)) { + sink(source); // no flow + } else { + sink(source); // flow + } +} + +void bg_not(int source) { + if (!guarded(source)) { + sink(source); // flow + } else { + sink(source); // no flow + } +} + +void bg_and(int source, bool arbitrary) { + if (guarded(source) && arbitrary) { + sink(source); // no flow + } else { + sink(source); // flow + } +} + +void bg_or(int source, bool arbitrary) { + if (guarded(source) || arbitrary) { + sink(source); // flow + } else { + sink(source); // flow + } +} + +void bg_return(int source) { + if (!guarded(source)) { + return; + } + sink(source); // no flow +} + +struct XY { + int x, y; +}; + +void bg_stackstruct(XY s1, XY s2) { + s1.x = source(); + if (guarded(s1.x)) { + sink(s1.x); // no flow + } else if (guarded(s1.y)) { + sink(s1.x); // flow + } else if (guarded(s2.y)) { + sink(s1.x); // flow + } +} + +void bg_structptr(XY *p1, XY *p2) { + p1->x = source(); + if (guarded(p1->x)) { + sink(p1->x); // no flow [FALSE POSITIVE in AST] + } else if (guarded(p1->y)) { + sink(p1->x); // flow [NOT DETECTED in IR] + } else if (guarded(p2->x)) { + sink(p1->x); // flow [NOT DETECTED in IR] + } +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/DataflowTestCommon.qll b/cpp/ql/test/library-tests/dataflow/dataflow-tests/DataflowTestCommon.qll index 02ee4d45380..a81394640ee 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/DataflowTestCommon.qll +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/DataflowTestCommon.qll @@ -1,6 +1,20 @@ import cpp import semmle.code.cpp.dataflow.DataFlow +/** + * A `BarrierGuard` that stops flow to all occurrences of `x` within statement + * S in `if (guarded(x)) S`. + */ +// This is tested in `BarrierGuard.cpp`. +class TestBarrierGuard extends DataFlow::BarrierGuard { + TestBarrierGuard() { this.(FunctionCall).getTarget().getName() = "guarded" } + + override predicate checks(Expr checked, boolean isTrue) { + checked = this.(FunctionCall).getArgument(0) and + isTrue = true + } +} + /** Common data flow configuration to be used by tests. */ class TestAllocationConfig extends DataFlow::Configuration { TestAllocationConfig() { this = "TestAllocationConfig" } @@ -26,4 +40,6 @@ class TestAllocationConfig extends DataFlow::Configuration { override predicate isBarrier(DataFlow::Node barrier) { barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") } + + override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard } } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll b/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll index eb5fa14e2e0..490f7e4290a 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/IRDataflowTestCommon.qll @@ -1,5 +1,20 @@ import cpp import semmle.code.cpp.ir.dataflow.DataFlow +import semmle.code.cpp.ir.IR + +/** + * A `BarrierGuard` that stops flow to all occurrences of `x` within statement + * S in `if (guarded(x)) S`. + */ +// This is tested in `BarrierGuard.cpp`. +class TestBarrierGuard extends DataFlow::BarrierGuard { + TestBarrierGuard() { this.(CallInstruction).getStaticCallTarget().getName() = "guarded" } + + override predicate checks(Instruction checked, boolean isTrue) { + checked = this.(CallInstruction).getPositionalArgument(0) and + isTrue = true + } +} /** Common data flow configuration to be used by tests. */ class TestAllocationConfig extends DataFlow::Configuration { @@ -24,4 +39,6 @@ class TestAllocationConfig extends DataFlow::Configuration { override predicate isBarrier(DataFlow::Node barrier) { barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") } + + override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard } } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected index b9fca1f678f..6527db4b77e 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected @@ -1,3 +1,13 @@ +| BarrierGuard.cpp:9:10:9:15 | source | BarrierGuard.cpp:5:19:5:24 | source | +| BarrierGuard.cpp:15:10:15:15 | source | BarrierGuard.cpp:13:17:13:22 | source | +| BarrierGuard.cpp:25:10:25:15 | source | BarrierGuard.cpp:21:17:21:22 | source | +| BarrierGuard.cpp:31:10:31:15 | source | BarrierGuard.cpp:29:16:29:21 | source | +| BarrierGuard.cpp:33:10:33:15 | source | BarrierGuard.cpp:29:16:29:21 | source | +| BarrierGuard.cpp:53:13:53:13 | x | BarrierGuard.cpp:49:10:49:15 | call to source | +| BarrierGuard.cpp:55:13:55:13 | x | BarrierGuard.cpp:49:10:49:15 | call to source | +| BarrierGuard.cpp:62:14:62:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source | +| BarrierGuard.cpp:64:14:64:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source | +| BarrierGuard.cpp:66:14:66:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source | | acrossLinkTargets.cpp:12:8:12:8 | x | acrossLinkTargets.cpp:19:27:19:32 | call to source | | clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 | | clang.cpp:22:8:22:20 | & ... | clang.cpp:12:9:12:20 | sourceArray1 | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index cd7e3dac785..7d0d4e7d72e 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -1,3 +1,6 @@ +| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only | +| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:64:14:64:14 | AST only | +| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:66:14:66:14 | AST only | | clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only | | clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only | | clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 83ba546480f..9b67a013a58 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -1,3 +1,10 @@ +| BarrierGuard.cpp:9:10:9:15 | Load: source | BarrierGuard.cpp:5:19:5:24 | InitializeParameter: source | +| BarrierGuard.cpp:15:10:15:15 | Load: source | BarrierGuard.cpp:13:17:13:22 | InitializeParameter: source | +| BarrierGuard.cpp:25:10:25:15 | Load: source | BarrierGuard.cpp:21:17:21:22 | InitializeParameter: source | +| BarrierGuard.cpp:31:10:31:15 | Load: source | BarrierGuard.cpp:29:16:29:21 | InitializeParameter: source | +| BarrierGuard.cpp:33:10:33:15 | Load: source | BarrierGuard.cpp:29:16:29:21 | InitializeParameter: source | +| BarrierGuard.cpp:53:13:53:13 | Load: x | BarrierGuard.cpp:49:10:49:15 | Call: call to source | +| BarrierGuard.cpp:55:13:55:13 | Load: x | BarrierGuard.cpp:49:10:49:15 | Call: call to source | | acrossLinkTargets.cpp:12:8:12:8 | Convert: (int)... | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source | | acrossLinkTargets.cpp:12:8:12:8 | Load: x | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source | | clang.cpp:18:8:18:19 | Convert: (const int *)... | clang.cpp:12:9:12:20 | InitializeParameter: sourceArray1 | diff --git a/docs/language/learn-ql/cpp/dataflow.rst b/docs/language/learn-ql/cpp/dataflow.rst index 4867f3daf47..50fccdc5cc4 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -166,6 +166,7 @@ The following predicates are defined in the configuration: - ``isSource``—defines where data may flow from - ``isSink``—defines where data may flow to - ``isBarrier``—optional, restricts the data flow +- ``isBarrierGuard``—optional, restricts the data flow - ``isAdditionalFlowStep``—optional, adds additional flow steps The characteristic predicate ``MyDataFlowConfiguration()`` defines the name of the configuration, so ``"MyDataFlowConfiguration"`` should be replaced by the name of your class. @@ -204,6 +205,7 @@ The following predicates are defined in the configuration: - ``isSource``—defines where taint may flow from - ``isSink``—defines where taint may flow to - ``isSanitizer``—optional, restricts the taint flow +- ``isSanitizerGuard``—optional, restricts the taint flow - ``isAdditionalTaintStep``—optional, adds additional taint steps Similar to global data flow, the characteristic predicate ``MyTaintTrackingConfiguration()`` defines the unique name of the configuration, so ``"MyTaintTrackingConfiguration"`` should be replaced by the name of your class. From d693eb8c20a147a927ae2e5dda179d9233cde6b9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 28 Oct 2019 17:39:45 +0000 Subject: [PATCH 049/148] CPP: Correct the ConditionallyUninitializedVariable examples. --- .../CWE/CWE-457/ConditionallyUninitializedVariableBad.c | 6 +++--- .../CWE/CWE-457/ConditionallyUninitializedVariableGood.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableBad.c b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableBad.c index 1f281f3cfd9..73a01c2d900 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableBad.c +++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableBad.c @@ -19,7 +19,7 @@ int notify(int deviceNumber) { DeviceConfig config; initDeviceConfig(&config, deviceNumber); // BAD: Using config without checking the status code that is returned - if (config->isEnabled) { - notifyChannel(config->channel); + if (config.isEnabled) { + notifyChannel(config.channel); } -} \ No newline at end of file +} diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableGood.c b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableGood.c index a9dcc06c9a5..ced43a66cfc 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableGood.c +++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariableGood.c @@ -20,8 +20,8 @@ void notify(int deviceNumber) { int statusCode = initDeviceConfig(&config, deviceNumber); if (statusCode == 0) { // GOOD: Status code returned by initialization function is checked, so this is safe - if (config->isEnabled) { - notifyChannel(config->channel); + if (config.isEnabled) { + notifyChannel(config.channel); } } -} \ No newline at end of file +} From c40c88ec4bfd2ddd5e79ed48fb1c955e23bf2a7b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 28 Oct 2019 18:43:00 +0000 Subject: [PATCH 050/148] CPP: Add test cases for ConditionallyUninitializedVariables.ql. --- ...onditionallyUninitializedVariable.expected | 3 + .../ConditionallyUninitializedVariable.qlref | 1 + .../examples.cpp | 43 +++++++++ .../test.cpp | 96 +++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.expected create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.qlref create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/examples.cpp create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/test.cpp diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.expected new file mode 100644 index 00000000000..60964c8f178 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.expected @@ -0,0 +1,3 @@ +| examples.cpp:38:3:38:18 | call to initDeviceConfig | The status of this call to $@ is not checked, potentially leaving $@ uninitialized. | examples.cpp:13:5:13:20 | initDeviceConfig | initDeviceConfig | examples.cpp:37:16:37:21 | config | config | +| test.cpp:22:2:22:17 | call to maybeInitialize1 | The status of this call to $@ is not checked, potentially leaving $@ uninitialized. | test.cpp:4:5:4:20 | maybeInitialize1 | maybeInitialize1 | test.cpp:19:6:19:6 | a | a | +| test.cpp:68:2:68:17 | call to maybeInitialize2 | The status of this call to $@ is not checked, potentially leaving $@ uninitialized. | test.cpp:51:6:51:21 | maybeInitialize2 | maybeInitialize2 | test.cpp:66:6:66:6 | a | a | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.qlref new file mode 100644 index 00000000000..5150d627257 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/ConditionallyUninitializedVariable.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/examples.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/examples.cpp new file mode 100644 index 00000000000..ccb15904d02 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/examples.cpp @@ -0,0 +1,43 @@ +// based on the qhelp + +int getMaxDevices(); +bool fetchIsDeviceEnabled(int deviceNumber); +int fetchDeviceChannel(int deviceNumber); +void notifyChannel(int channel); + +struct DeviceConfig { + bool isEnabled; + int channel; +}; + +int initDeviceConfig(DeviceConfig *ref, int deviceNumber) { + if (deviceNumber >= getMaxDevices()) { + // No device with that number, return -1 to indicate failure + return -1; + } + // Device with that number, fetch parameters and initialize struct + ref->isEnabled = fetchIsDeviceEnabled(deviceNumber); + ref->channel = fetchDeviceChannel(deviceNumber); + // Return 0 to indicate success + return 0; +} + +void notifyGood(int deviceNumber) { + DeviceConfig config; + int statusCode = initDeviceConfig(&config, deviceNumber); + if (statusCode == 0) { + // GOOD: Status code returned by initialization function is checked, so this is safe + if (config.isEnabled) { + notifyChannel(config.channel); + } + } +} + +int notifyBad(int deviceNumber) { + DeviceConfig config; + initDeviceConfig(&config, deviceNumber); + // BAD: Using config without checking the status code that is returned + if (config.isEnabled) { + notifyChannel(config.channel); + } +} \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/test.cpp new file mode 100644 index 00000000000..a3c9b0a24aa --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-457/semmle/ConditionallyUninitializedVariable/test.cpp @@ -0,0 +1,96 @@ + +void use(int i); + +int maybeInitialize1(int *v) +{ + static int resources = 100; + + if (resources == 0) + { + return 0; // FAIL + } + + *v = resources--; + return 1; // SUCCESS +} + +void test1() +{ + int a, b, c, d, e, f; + int result1, result2; + + maybeInitialize1(&a); // BAD (initialization not checked) + use(a); + + if (maybeInitialize1(&b) == 1) // GOOD + { + use(b); + } + + if (maybeInitialize1(&c) == 0) // BAD (initialization check is wrong) [NOT DETECTED] + { + use(c); + } + + result1 = maybeInitialize1(&d); // BAD (initialization stored but not checked) [NOT DETECTED] + use(d); + + result2 = maybeInitialize1(&e); // GOOD + if (result2 == 1) + { + use(e); + } + + if (maybeInitialize1(&f) == 0) // GOOD + { + return; + } + use(f); +} + +bool maybeInitialize2(int *v) +{ + static int resources = 100; + + if (resources > 0) + { + *v = resources--; + return true; // SUCCESS + } + + return false; // FAIL +} + +void test2() +{ + int a, b; + + maybeInitialize2(&a); // BAD (initialization not checked) + use(a); + + if (maybeInitialize2(&b)) // GOOD + { + use(b); + } +} + +int alwaysInitialize(int *v) +{ + static int resources = 0; + + *v = resources++; + return 1; // SUCCESS +} + +void test3() +{ + int a, b; + + alwaysInitialize(&a); // GOOD (initialization never fails) + use(a); + + if (alwaysInitialize(&b) == 1) // GOOD + { + use(b); + } +} From 2d64fedeb021db7fa0a919bad6f189ae4805907f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 25 Oct 2019 11:19:31 +0100 Subject: [PATCH 051/148] CPP: Speed up VirtualDispatch.qll's getAViableTarget. --- .../code/cpp/dispatch/VirtualDispatch.qll | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll b/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll index 2fa9322843e..1113fc430e7 100644 --- a/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll @@ -28,6 +28,19 @@ module VirtualDispatch { not result.hasName("IUnknown") } + /** + * Helper predicate for `getAViableTarget`, which computes the viable targets for + * virtual calls based on the qualifier type. + */ + private Function getAViableVirtualCallTarget(Class qualifierType, MemberFunction staticTarget) { + exists(Class qualifierSubType | + result = getAPossibleImplementation(staticTarget) and + qualifierType = qualifierSubType.getABaseClass*() and + mayInherit(qualifierSubType, result) and + not cannotInherit(qualifierSubType, result) + ) + } + /** * Gets a viable target for the given function call. * @@ -42,18 +55,9 @@ module VirtualDispatch { * If `c` is not a virtual call, the result will be `c.getTarget()`. */ Function getAViableTarget(Call c) { - exists(Function staticTarget | staticTarget = c.getTarget() | - if c.(FunctionCall).isVirtual() and staticTarget instanceof MemberFunction - then - exists(Class qualifierType, Class qualifierSubType | - result = getAPossibleImplementation(staticTarget) and - qualifierType = getCallQualifierType(c) and - qualifierType = qualifierSubType.getABaseClass*() and - mayInherit(qualifierSubType, result) and - not cannotInherit(qualifierSubType, result) - ) - else result = staticTarget - ) + if c.(FunctionCall).isVirtual() and c.getTarget() instanceof MemberFunction + then result = getAViableVirtualCallTarget(getCallQualifierType(c), c.getTarget()) + else result = c.getTarget() } /** Holds if `f` is declared in `c` or a transitive base class of `c`. */ From 3584c0b2e5ae646b0e4c53d4d80810e84ed5c780 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 25 Oct 2019 11:22:42 +0100 Subject: [PATCH 052/148] CPP: Speed up InitializationFunctions.qll's getTarget. --- .../CWE/CWE-457/InitializationFunctions.qll | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 240bd7aa25e..720cf11950b 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -618,6 +618,33 @@ Function getAPossibleDefinition(Function undefinedFunction) { ) and result.isDefined() } + +private Function getTarget1(Call c) { + /* + * If there is at least one defined target after performing some simple virtual dispatch + * resolution, then the result is all the defined targets. + */ + + result = VirtualDispatch::getAViableTarget(c) and + result.isDefined() +} + +private Function getTarget2(Call c) { + /* + * If we can use the heuristic matching of functions to find definitions for some of the viable + * targets, return those. + */ + + not exists(getTarget1(c)) and + result = getAPossibleDefinition(VirtualDispatch::getAViableTarget(c)) +} + +private Function getTarget3(Call c) { + not exists(getTarget1(c)) and + not exists(getTarget2(c)) and + // Otherwise, the result is the undefined `Function` instances. + result = VirtualDispatch::getAViableTarget(c) +} /** * Gets a possible target for the Call, using the name and parameter matching if we did not associate @@ -625,27 +652,9 @@ Function getAPossibleDefinition(Function undefinedFunction) { * dispatch resolution. */ Function getTarget(Call c) { - if VirtualDispatch::getAViableTarget(c).isDefined() - then - /* - * If there is at least one defined target after performing some simple virtual dispatch - * resolution, then the result is all the defined targets. - */ - - result = VirtualDispatch::getAViableTarget(c) and - result.isDefined() - else - if exists(getAPossibleDefinition(VirtualDispatch::getAViableTarget(c))) - then - /* - * If we can use the heuristic matching of functions to find definitions for some of the viable - * targets, return those. - */ - - result = getAPossibleDefinition(VirtualDispatch::getAViableTarget(c)) - else - // Otherwise, the result is the undefined `Function` instances - result = VirtualDispatch::getAViableTarget(c) + result = getTarget1(c) or + result = getTarget2(c) or + result = getTarget3(c) } /** From ff62afb575e242cdc01586491d40908e18a65f23 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 29 Oct 2019 10:38:23 +0100 Subject: [PATCH 053/148] C++: Rename parameter to `b` to match QLDoc --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index cd1fbd487e0..fc0b5a90882 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -684,7 +684,7 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) { */ class BarrierGuard extends GuardCondition { /** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */ - abstract predicate checks(Expr e, boolean branch); + abstract predicate checks(Expr e, boolean b); /** Gets a node guarded by this guard. */ final ExprNode getAGuardedNode() { From 563f32193cfbb747c19c0b28884be70264a6296c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 29 Oct 2019 12:10:12 +0100 Subject: [PATCH 054/148] suggestions from @max-schaefer Co-Authored-By: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> --- javascript/ql/src/Statements/IgnoreArrayResult.qhelp | 2 +- javascript/ql/src/Statements/IgnoreArrayResult.ql | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/Statements/IgnoreArrayResult.qhelp b/javascript/ql/src/Statements/IgnoreArrayResult.qhelp index b70ff1f1b32..2232784d881 100644 --- a/javascript/ql/src/Statements/IgnoreArrayResult.qhelp +++ b/javascript/ql/src/Statements/IgnoreArrayResult.qhelp @@ -5,7 +5,7 @@

    The concat, join and slice methods are -pure and does not modify any of the inputs or the array the method was called +pure and do not modify any of the inputs or the array the method was called on. It is therefore generally an error to ignore the return value from a call to one of these methods.

    diff --git a/javascript/ql/src/Statements/IgnoreArrayResult.ql b/javascript/ql/src/Statements/IgnoreArrayResult.ql index b6137e664d7..5ab778ed95b 100644 --- a/javascript/ql/src/Statements/IgnoreArrayResult.ql +++ b/javascript/ql/src/Statements/IgnoreArrayResult.ql @@ -1,10 +1,10 @@ /** * @name Ignoring result from pure array method - * @description The array methods do not modify the array, ignoring the result of such a call is therefore generally an error. + * @description Ignoring the result of an array method that does not modify its receiver is generally an error. * @kind problem * @problem.severity warning * @id js/ignore-array-result - * @tags maintainability, + * @tags maintainability * correctness * @precision high */ @@ -16,7 +16,7 @@ DataFlow::SourceNode callsArray(DataFlow::TypeBackTracker t, DataFlow::MethodCal isIgnoredPureArrayCall(call) and ( t.start() and - result = call.getReceiver() + result = call.getReceiver().getALocalSource() or exists(DataFlow::TypeBackTracker t2 | result = callsArray(t2, call).backtrack(t2, t)) ) From 2d01e7c5ed97392e55db948755d445dc8337a68a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 29 Oct 2019 12:13:01 +0100 Subject: [PATCH 055/148] simplify the callsArray predicate --- javascript/ql/src/Statements/IgnoreArrayResult.ql | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/Statements/IgnoreArrayResult.ql b/javascript/ql/src/Statements/IgnoreArrayResult.ql index 5ab778ed95b..6f6698797f1 100644 --- a/javascript/ql/src/Statements/IgnoreArrayResult.ql +++ b/javascript/ql/src/Statements/IgnoreArrayResult.ql @@ -13,13 +13,11 @@ import javascript import Expressions.ExprHasNoEffect DataFlow::SourceNode callsArray(DataFlow::TypeBackTracker t, DataFlow::MethodCallNode call) { - isIgnoredPureArrayCall(call) and - ( - t.start() and - result = call.getReceiver().getALocalSource() - or - exists(DataFlow::TypeBackTracker t2 | result = callsArray(t2, call).backtrack(t2, t)) - ) + isIgnoredPureArrayCall(call) and + t.start() and + result = call.getReceiver().getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = callsArray(t2, call).backtrack(t2, t)) } DataFlow::SourceNode callsArray(DataFlow::MethodCallNode call) { From 3337eaf0f9ec2b9de5bf1f58bebd8e5550209509 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Tue, 29 Oct 2019 12:35:03 +0000 Subject: [PATCH 056/148] Docs: Update JavaScript/TypeScript --- .../javascript/ast-class-reference.rst | 24 +++--- .../javascript/dataflow-cheat-sheet.rst | 8 +- .../language/learn-ql/javascript/dataflow.rst | 8 +- .../learn-ql/javascript/flow-labels.rst | 2 +- .../javascript/introduce-libraries-js.rst | 78 +++++++++---------- .../javascript/introduce-libraries-ts.rst | 24 +++--- .../learn-ql/javascript/ql-for-javascript.rst | 26 +++---- .../learn-ql/javascript/type-tracking.rst | 6 +- 8 files changed, 89 insertions(+), 87 deletions(-) diff --git a/docs/language/learn-ql/javascript/ast-class-reference.rst b/docs/language/learn-ql/javascript/ast-class-reference.rst index 1231f83c4cf..1b513b2d4ec 100644 --- a/docs/language/learn-ql/javascript/ast-class-reference.rst +++ b/docs/language/learn-ql/javascript/ast-class-reference.rst @@ -7,7 +7,7 @@ Statement classes This table lists subclasses of `Stmt `__ representing ECMAScript and TypeScript statements. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Statement syntax | QL class | Superclasses | Remarks | +| Statement syntax | CodeQL class | Superclasses | Remarks | +=============================================================================================================================================================================================================================================================================================================================================================================================================================================+==================================================================================================================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================================================+===================================================================================================================================================================================================+ | `Expr `__ ``;`` | `ExprStmt `__ | | | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -105,7 +105,7 @@ Literals All classes in this subsection are subclasses of `Literal `__. +-------------------+------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | +| Expression syntax | CodeQL class | +===================+========================================================================================================================+ | ``true`` | `BooleanLiteral `__ | +-------------------+------------------------------------------------------------------------------------------------------------------------+ @@ -123,7 +123,7 @@ All classes in this subsection are subclasses of `Literal `__, which has subclasses to represent specific kinds of identifiers: +All identifiers are represented by the class `Identifier `__, which has subclasses to represent specific kinds of identifiers: - `VarAccess `__: an identifier that refers to a variable - `VarDecl `__: an identifier that declares a variable, for example ``x`` in ``var x = "hi"`` or in ``function(x) { }`` @@ -142,7 +142,7 @@ Primary expressions All classes in this subsection are subclasses of `Expr `__. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | Superclasses | Remarks | +| Expression syntax | CodeQL class | Superclasses | Remarks | +======================================================================================================================================================================================================================================================================+==========================================================================================================================================+======================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ | ``this`` | `ThisExpr `__ | | | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -167,7 +167,7 @@ Properties All classes in this subsection are subclasses of `Property `__. Note that `Property `__ is not a subclass of `Expr `__. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| Property syntax | QL class | Superclasses | +| Property syntax | CodeQL class | Superclasses | +=====================================================================================================================================================================================================================================================================================================================================================================+========================================================================================================================+============================================================================================================================+ | `Identifier `__ ``:`` `Expr `__ | `ValueProperty `__ | | +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ @@ -182,7 +182,7 @@ Property accesses All classes in this subsection are subclasses of `PropAccess `__. +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | +| Expression syntax | CodeQL class | +=========================================================================================================================================================================================================================+==============================================================================================================+ | `Expr `__ ``.`` `Identifier `__ | `DotExpr `__ | +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+ @@ -195,7 +195,7 @@ Function calls and ``new`` All classes in this subsection are subclasses of `InvokeExpr `__. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | Remarks | +| Expression syntax | CodeQL class | Remarks | +============================================================================================================================================================================================================================================================================================================================================+========================================================================================================================+==========================================================================================================================================================================================================================================================================================================================================================================+ | `Expr `__ ``(`` `Expr `__... ``)`` | `CallExpr `__ | | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -210,7 +210,7 @@ Unary expressions All classes in this subsection are subclasses of `UnaryExpr `__. +---------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | +| Expression syntax | CodeQL class | +===============================================================================================================+======================================================================================================================+ | ``~`` `Expr `__ | `BitNotExpr `__ | +---------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------+ @@ -235,7 +235,7 @@ Binary expressions All classes in this subsection are subclasses of `BinaryExpr `__. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | Superclasses | +| Expression syntax | CodeQL class | Superclasses | +======================================================================================================================================================================================================================+========================================================================================================================+====================================================================================================================================================================================================================================+ | `Expr `__ ``*`` `Expr `__ | `MulExpr `__ | | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -292,7 +292,7 @@ Assignment expressions All classes in this table are subclasses of `Assignment `__. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | Superclasses | +| Expression syntax | CodeQL class | Superclasses | +================================================================================================================================================================================================================+==============================================================================================================================+================================================================================================================================+ | `Expr `__ ``=`` `Expr `__ | `AssignExpr `__ | | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+ @@ -327,7 +327,7 @@ Update expressions All classes in this table are subclasses of `UpdateExpr `__. +-----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | +| Expression syntax | CodeQL class | +===========================================================================================================+==================================================================================================================+ | `Expr `__ ``++`` | `PostIncExpr `__ | +-----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ @@ -344,7 +344,7 @@ Miscellaneous All classes in this table are subclasses of `Expr `__. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ -| Expression syntax | QL class | +| Expression syntax | CodeQL class | +======================================================================================================================================================================================================================================================================================================================+==========================================================================================================================+ | `Expr `__ ``?`` `Expr `__ ``:`` `Expr `__ | `ConditionalExpr `__ | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index 5159c26bf19..a2ff4309ee0 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -1,14 +1,14 @@ Data flow cheat sheet ===================== -This page describes parts of the JavaScript QL libraries commonly used for variant analysis and in data flow queries. +This page describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. Taint tracking path queries --------------------------- Use the following template to create a taint tracking path query: -.. code-block:: ql +.. code-block:: ql /** * @kind path-problem @@ -134,10 +134,10 @@ Files - `File `__, `Folder `__ extends - `Container `__ -- file or folder in the snapshot + `Container `__ -- file or folder in the database - `getBaseName `__ -- the name of the file or folder - - `getRelativePath `__ -- path relative to the snapshot root + - `getRelativePath `__ -- path relative to the database root AST nodes --------- diff --git a/docs/language/learn-ql/javascript/dataflow.rst b/docs/language/learn-ql/javascript/dataflow.rst index 3cd41de6a84..15cd1ad7e46 100644 --- a/docs/language/learn-ql/javascript/dataflow.rst +++ b/docs/language/learn-ql/javascript/dataflow.rst @@ -4,13 +4,13 @@ Analyzing data flow in JavaScript and TypeScript Overview -------- -This topic describes how data flow analysis is implemented in the QL libraries for JavaScript/TypeScript and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the QL libraries for local data flow, global data flow, and taint tracking. +This topic describes how data flow analysis is implemented in the CodeQL libraries for JavaScript/TypeScript and includes examples to help you write your own data flow queries. +The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. As our running example, we will develop a query that identifies command-line arguments that are passed as a file path to the standard Node.js ``readFile`` function. While this is not a problematic pattern as such, it is typical of the kind of reasoning that is frequently used in security queries. -For a more general introduction to modeling data flow in QL, see :doc:`Introduction to data flow analysis in QL <../intro-to-data-flow>`. +For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. Data flow nodes --------------- @@ -174,7 +174,7 @@ There are two points worth making about the source node API: 2. Strings are not source nodes and cannot be tracked using this API. You can, however, use the ``mayHaveStringValue`` predicate on class ``DataFlow::Node`` to reason about the possible string values flowing into a data flow node. -For a full description of the ``DataFlow::SourceNode`` API, see the `QL JavaScript standard library `__. +For a full description of the ``DataFlow::SourceNode`` API, see the `JavaScript standard library `__. Exercises ~~~~~~~~~ diff --git a/docs/language/learn-ql/javascript/flow-labels.rst b/docs/language/learn-ql/javascript/flow-labels.rst index aa6ded8e7bc..c693319576d 100644 --- a/docs/language/learn-ql/javascript/flow-labels.rst +++ b/docs/language/learn-ql/javascript/flow-labels.rst @@ -393,6 +393,6 @@ string may be an absolute path and whether it may contain ``..`` components. What next? ---------- -- Learn about the QL standard libraries used to write queries for JavaScript in :doc:`Introducing the JavaScript libraries `. +- Learn about the standard CodeQL libraries used to write queries for JavaScript in :doc:`Introducing the JavaScript libraries `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index 0e3a7e5acdd..edac4a8c21b 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -1,10 +1,10 @@ -Introducing the QL libraries for JavaScript -=========================================== +Introducing the CodeQL libraries for JavaScript +=============================================== Overview -------- -There is an extensive QL library for analyzing JavaScript code. The classes in this library present the data from a snapshot database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. +There is an extensive CodeQL library for analyzing JavaScript code. The classes in this library present the data from a CodeQL database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``javascript.qll`` imports most other standard library modules, so you can include the complete library by beginning your query with: @@ -12,12 +12,12 @@ The library is implemented as a set of QL modules, that is, files with the exten import javascript -The rest of this tutorial briefly summarizes the most important QL classes and predicates provided by this library, including references to the `detailed API documentation `__ where applicable. +The rest of this tutorial briefly summarizes the most important classes and predicates provided by this library, including references to the `detailed API documentation `__ where applicable. Introducing the library ----------------------- -The QL JavaScript library presents information about JavaScript source code at different levels: +The CodeQL library for JavaScript presents information about JavaScript source code at different levels: - **Textual** — classes that represent source code as unstructured text files - **Lexical** — classes that represent source code as a series of tokens and comments @@ -39,12 +39,12 @@ Textual level At its most basic level, a JavaScript code base can simply be viewed as a collection of files organized into folders, where each file is composed of zero or more lines of text. -Note that the textual content of a program is not included in the snapshot database unless you specifically request it during extraction. In particular, snapshots on LGTM do not normally include textual information. +Note that the textual content of a program is not included in the CodeQL database unless you specifically request it during extraction. In particular, databases on LGTM (also known as "snapshots") do not normally include textual information. Files and folders ^^^^^^^^^^^^^^^^^ -In QL, files are represented as entities of class `File `__, and folders as entities of class `Folder `__, both of which are subclasses of class `Container `__. +In the CodeQL libraries, files are represented as entities of class `File `__, and folders as entities of class `Folder `__, both of which are subclasses of class `Container `__. Class `Container `__ provides the following member predicates: @@ -56,7 +56,7 @@ Note that while ``getAFile`` and ``getAFolder`` are declared on class `Container Both files and folders have paths, which can be accessed by the predicate ``Container.getAbsolutePath()``. For example, if ``f`` represents a file with the path ``/home/user/project/src/index.js``, then ``f.getAbsolutePath()`` evaluates to the string ``"/home/user/project/src/index.js"``, while ``f.getParentContainer().getAbsolutePath()`` returns ``"/home/user/project/src"``. -These paths are absolute file system paths. If you want to obtain the path of a file relative to the snapshot source location, use ``Container.getRelativePath()`` instead. Note, however, that a snapshot may contain files that are not located underneath the snapshot source location; for such files, ``getRelativePath()`` will not return anything. +These paths are absolute file system paths. If you want to obtain the path of a file relative to the source location in the CodeQL database, use ``Container.getRelativePath()`` instead. Note, however, that a database may contain files that are not located underneath the source location; for such files, ``getRelativePath()`` will not return anything. The following member predicates of class `Container `__ provide more information about the name of a file or folder: @@ -78,9 +78,9 @@ For example, the following query computes, for each folder, the number of JavaSc Locations ^^^^^^^^^ -Most entities in a snapshot database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive. +Most entities in a CodeQL database have an associated source location. Locations are identified by four pieces of information: a file, a start line, a start column, an end line, and an end column. Line and column counts are 1-based (so the first character of a file is at line 1, column 1), and the end position is inclusive. -All entities associated with a source location belong to the QL class `Locatable `__. The location itself is modeled by the QL class `Location `__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location `__ class provides the following member predicates: +All entities associated with a source location belong to the class `Locatable `__. The location itself is modeled by the class `Location `__ and can be accessed through the member predicate ``Locatable.getLocation()``. The `Location `__ class provides the following member predicates: - ``Location.getFile()``, ``Location.getStartLine()``, ``Location.getStartColumn()``, ``Location.getEndLine()``, ``Location.getEndColumn()`` return detailed information about the location. - ``Location.getNumLines()`` returns the number of (whole or partial) lines covered by the location. @@ -90,12 +90,12 @@ All entities associated with a source location belong to the QL class `Locatable Lines ^^^^^ -Lines of text in files are represented by the QL class `Line `__. This class offers the following member predicates: +Lines of text in files are represented by the class `Line `__. This class offers the following member predicates: - ``Line.getText()`` returns the text of the line, excluding any terminating newline characters. - ``Line.getTerminator()`` returns the terminator character(s) of the line. The last line in a file may not have any terminator characters, in which case this predicate does not return anything; otherwise it returns either the two-character string ``"\r\n"`` (carriage-return followed by newline), or one of the one-character strings ``"\n"`` (newline), ``"\r"`` (carriage-return), ``"\u2028"`` (Unicode character LINE SEPARATOR), ``"\u2029"`` (Unicode character PARAGRAPH SEPARATOR). -Note that, as mentioned above, the textual representation of the program is not included in the snapshot database by default. +Note that, as mentioned above, the textual representation of the program is not included in the CodeQL database by default. Lexical level ~~~~~~~~~~~~~ @@ -180,9 +180,9 @@ As an example of a query using only lexical information, consider the following Syntactic level ~~~~~~~~~~~~~~~ -The majority of classes in the QL JavaScript library is concerned with representing a JavaScript program as a collection of `abstract syntax trees `__ (ASTs). +The majority of classes in the JavaScript library is concerned with representing a JavaScript program as a collection of `abstract syntax trees `__ (ASTs). -The QL class `ASTNode `__ contains all entities representing nodes in the abstract syntax trees and defines generic tree traversal predicates: +The class `ASTNode `__ contains all entities representing nodes in the abstract syntax trees and defines generic tree traversal predicates: - ``ASTNode.getChild(i)``: returns the ``i``\ th child of this AST node. - ``ASTNode.getAChild()``: returns any child of this AST node. @@ -352,7 +352,7 @@ As an example of how to use expression AST nodes, here is a query that finds exp Functions ^^^^^^^^^ -JavaScript provides several ways of defining functions: in ECMAScript 5, there are function declaration statements and function expressions, and ECMAScript 2015 adds arrow function expressions. These different syntactic forms are represented by the QL classes `FunctionDeclStmt `__ (a subclass of `Stmt `__), `FunctionExpr `__ (a subclass of `Expr `__) and `ArrowFunctionExpr `__ (also a subclass of +JavaScript provides several ways of defining functions: in ECMAScript 5, there are function declaration statements and function expressions, and ECMAScript 2015 adds arrow function expressions. These different syntactic forms are represented by the classes `FunctionDeclStmt `__ (a subclass of `Stmt `__), `FunctionExpr `__ (a subclass of `Expr `__) and `ArrowFunctionExpr `__ (also a subclass of `Expr `__), respectively. All three are subclasses of `Function `__, which provides common member predicates for accessing function parameters or the function body: - ``Function.getId()`` returns the `Identifier `__ naming the function, which may not be defined for function expressions. @@ -389,7 +389,7 @@ As another example, this query finds functions that have two parameters that bin Classes ^^^^^^^ -Classes can be defined either by class declaration statements, represented by the QL class `ClassDeclStmt `__ (which is a subclass of `Stmt `__), or by class expressions, represented by the QL class `ClassExpr `__ (which is a subclass of `Expr `__). Both of these classes are also subclasses of `ClassDefinition `__, which provides common member predicates for accessing the name of a class, its superclass, and its body: +Classes can be defined either by class declaration statements, represented by the CodeQL class `ClassDeclStmt `__ (which is a subclass of `Stmt `__), or by class expressions, represented by the CodeQL class `ClassExpr `__ (which is a subclass of `Expr `__). Both of these classes are also subclasses of `ClassDefinition `__, which provides common member predicates for accessing the name of a class, its superclass, and its body: - ``ClassDefinition.getIdentifier()`` returns the `Identifier `__ naming the function, which may not be defined for class expressions. - ``ClassDefinition.getSuperClass()`` returns the `Expr `__ specifying the superclass, which may not be defined. @@ -400,14 +400,14 @@ Classes can be defined either by class declaration statements, represented by th Note that class fields are not a standard language feature yet, so details of their representation may change. -Method definitions are represented by the QL class `MethodDefinition `__, which (like its counterpart `FieldDefinition `__ for fields) is a subclass of `MemberDefinition `__. That class provides the following important member predicates: +Method definitions are represented by the class `MethodDefinition `__, which (like its counterpart `FieldDefinition `__ for fields) is a subclass of `MemberDefinition `__. That class provides the following important member predicates: - ``MemberDefinition.isStatic()``: holds if this is a static member. - ``MemberDefinition.isComputed()``: holds if the name of this member is computed at runtime. - ``MemberDefinition.getName()``: gets the name of this member if it can be determined statically. - ``MemberDefinition.getInit()``: gets the initializer of this field; for methods, the initializer is a function expressions, for fields it may be an arbitrary expression, and may be undefined. -There are three QL classes for modeling special methods: `ConstructorDefinition `__ models constructors, while `GetterMethodDefinition `__ and `SetterMethodDefinition `__ model getter and setter methods, respectively. +There are three classes for modeling special methods: `ConstructorDefinition `__ models constructors, while `GetterMethodDefinition `__ and `SetterMethodDefinition `__ model getter and setter methods, respectively. Declarations and binding patterns ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,7 +472,7 @@ As an example of a query involving properties, consider the following query that Modules ^^^^^^^ -The JavaScript library has support for working with ECMAScript 2015 modules, as well as legacy CommonJS modules (still commonly employed by Node.js code bases) and AMD-style modules. The QL classes `ES2015Module `__, `NodeModule `__, and `AMDModule `__ represent these three types of modules, and all three extend the common superclass `Module `__. +The JavaScript library has support for working with ECMAScript 2015 modules, as well as legacy CommonJS modules (still commonly employed by Node.js code bases) and AMD-style modules. The classes `ES2015Module `__, `NodeModule `__, and `AMDModule `__ represent these three types of modules, and all three extend the common superclass `Module `__. The most important member predicates defined by `Module `__ are: @@ -485,12 +485,12 @@ Moreover, there is a class `Import `__, `Variable `__, `VarDecl `__ and `VarAccess `__, respectively. +Name binding is modeled in the JavaScript libraries using four concepts: *scopes*, *variables*, *variable declarations*, and *variable accesses*, represented by the classes `Scope `__, `Variable `__, `VarDecl `__ and `VarAccess `__, respectively. Scopes ^^^^^^ -In ECMAScript 5, there are three kinds of scopes: the global scope (one per program), function scopes (one per function), and catch clause scopes (one per ``catch`` clause). These three kinds of scopes are represented by the QL classes `GlobalScope `__, `FunctionScope `__ and `CatchScope `__. ECMAScript 2015 adds block scopes for ``let``-bound variables, which are also represented by QL class `Scope `__, class expression scopes (`ClassExprScope `__), +In ECMAScript 5, there are three kinds of scopes: the global scope (one per program), function scopes (one per function), and catch clause scopes (one per ``catch`` clause). These three kinds of scopes are represented by the classes `GlobalScope `__, `FunctionScope `__ and `CatchScope `__. ECMAScript 2015 adds block scopes for ``let``-bound variables, which are also represented by class `Scope `__, class expression scopes (`ClassExprScope `__), and module scopes (`ModuleScope `__). Class `Scope `__ provides the following API: @@ -510,7 +510,7 @@ It is important not to confuse variables and their declarations: local variables Variable declarations and accesses ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Variables may be declared by variable declarators, by function declaration statements and expressions, by class declaration statements or expressions, or by parameters of functions and ``catch`` clauses. While these declarations differ in their syntactic form, in each case there is an identifier naming the declared variable. We consider that identifier to be the declaration proper, and assign it the QL class `VarDecl `__. Identifiers that reference a variable, on the other hand, are given the QL class `VarAccess `__. +Variables may be declared by variable declarators, by function declaration statements and expressions, by class declaration statements or expressions, or by parameters of functions and ``catch`` clauses. While these declarations differ in their syntactic form, in each case there is an identifier naming the declared variable. We consider that identifier to be the declaration proper, and assign it the class `VarDecl `__. Identifiers that reference a variable, on the other hand, are given the class `VarAccess `__. The most important predicates involving variables, their declarations, and their accesses are as follows: @@ -538,9 +538,9 @@ As an example, consider the following query which finds distinct function declar Control flow ~~~~~~~~~~~~ -A different program representation in terms of intraprocedural control flow graphs (CFGs) is provided by the QL classes in library `CFG.qll `__. +A different program representation in terms of intraprocedural control flow graphs (CFGs) is provided by the classes in library `CFG.qll `__. -Class `ControlFlowNode `__ represents a single node in the control flow graph, which is either an expression, a statement, or a synthetic control flow node. Note that `Expr `__ and `Stmt `__ do not inherit from `ControlFlowNode `__ at the QL level, although their entity types are compatible, so you can explicitly cast from one to the other if you need to map between the AST-based and the CFG-based program representations. +Class `ControlFlowNode `__ represents a single node in the control flow graph, which is either an expression, a statement, or a synthetic control flow node. Note that `Expr `__ and `Stmt `__ do not inherit from `ControlFlowNode `__ at the CodeQL level, although their entity types are compatible, so you can explicitly cast from one to the other if you need to map between the AST-based and the CFG-based program representations. There are two kinds of synthetic control flow nodes: entry nodes (class `ControlFlowEntryNode `__), which represent the beginning of a top-level or function, and exit nodes (class `ControlFlowExitNode `__), which represent their end. They do not correspond to any AST nodes, but simply serve as the unique entry point and exit point of a control flow graph. Entry and exit nodes can be accessed through the predicates ``StmtContainer.getEntry()`` and ``StmtContainer.getExit()``. @@ -578,7 +578,7 @@ Data flow Definitions and uses ^^^^^^^^^^^^^^^^^^^^ -Library `DefUse.qll `__ provides QL classes and predicates to determine `def-use `__ relationships between definitions and uses of variables. +Library `DefUse.qll `__ provides classes and predicates to determine `def-use `__ relationships between definitions and uses of variables. Classes `VarDef `__ and `VarUse `__ contain all expressions that define and use a variable, respectively. For the former, you can use predicate ``VarDef.getAVariable()`` to find out which variables are defined by a given variable definition (recall that destructuring assignments in ECMAScript 2015 define several variables at the same time). Similarly, predicate ``VarUse.getVariable()`` returns the (single) variable being accessed by a variable use. @@ -645,7 +645,7 @@ Note that the data flow modeling in this library is intraprocedural, that is, fl Type inference ~~~~~~~~~~~~~~ -The library ``semmle.javascript.dataflow.TypeInference`` implements a simple type inference for JavaScript based on intraprocedural, heap-insensitive flow analysis. Basically, the inference algorithm approximates the possible concrete runtime values of variables and expressions as sets of abstract values (represented by QL class `AbstractValue `__), each of which stands for a set of concrete values. +The library ``semmle.javascript.dataflow.TypeInference`` implements a simple type inference for JavaScript based on intraprocedural, heap-insensitive flow analysis. Basically, the inference algorithm approximates the possible concrete runtime values of variables and expressions as sets of abstract values (represented by the class `AbstractValue `__), each of which stands for a set of concrete values. For example, there is an abstract value representing all non-zero numbers, and another representing all non-empty strings except for those that can be converted to a number. Both of these abstract values are fairly coarse approximations that represent very large sets of concrete values. @@ -657,7 +657,7 @@ Each indefinite abstract value is associated with a string value describing the To check whether an abstract value is indefinite, you can use the ``isIndefinite`` member predicate. Its single argument describes the cause of imprecision. -Each abstract value has one or more associated types (QL class `InferredType `__ corresponding roughly to the type tags computed by the ``typeof`` operator. The types are ``null``, ``undefined``, ``boolean``, ``number``, ``string``, ``function``, ``class``, ``date`` and ``object``. +Each abstract value has one or more associated types (CodeQL class `InferredType `__ corresponding roughly to the type tags computed by the ``typeof`` operator. The types are ``null``, ``undefined``, ``boolean``, ``number``, ``string``, ``function``, ``class``, ``date`` and ``object``. To access the results of the type inference, use class `DataFlow::AnalyzedNode `__: any `DataFlow::Node `__ can be cast to this class, and additionally there is a convenience predicate ``Expr::analyze`` that maps expressions directly to their corresponding ``AnalyzedNode``\ s. @@ -820,12 +820,12 @@ The most important classes include (all in module ``HTTP``): - ``CookieDefinition``: an expression that sets a cookie in an HTTP response. - ``RequestInputAccess``: an expression that accesses user-controlled request data. -For each framework library, there is a corresponding QL library (for example ``semmle.javacript.frameworks.Express``) that instantiates the above classes for that framework and adds framework-specific classes. +For each framework library, there is a corresponding CodeQL library (for example ``semmle.javacript.frameworks.Express``) that instantiates the above classes for that framework and adds framework-specific classes. Node.js ^^^^^^^ -The ``semmle.javascript.NodeJS`` library provides support for working with `Node.js `__ modules through the following QL classes: +The ``semmle.javascript.NodeJS`` library provides support for working with `Node.js `__ modules through the following classes: - `NodeModule `__: a top-level that defines a Node.js module; see the section on `Modules <#modules>`__ for more information. - `Require `__: a call to the special ``require`` function that imports a module. @@ -844,7 +844,7 @@ As an example of the use of these classes, here is a query that counts for every NPM ^^^ -The ``semmle.javascript.NPM`` library provides support for working with `NPM `__ packages through the following QL classes: +The ``semmle.javascript.NPM`` library provides support for working with `NPM `__ packages through the following classes: - `PackageJSON `__: a ``package.json`` file describing an NPM package; various getter predicates are available for accessing detailed information about the package, which are described in the `online API documentation `__. - `BugTrackerInfo `__, `ContributorInfo `__, `RepositoryInfo `__: these classes model parts of the ``package.json`` file providing information on bug tracking systems, contributors and repositories. @@ -903,7 +903,7 @@ Miscellaneous Externs ^^^^^^^ -The ``semmle.javascript.Externs`` library provides support for working with `externs `__ through the following QL classes: +The ``semmle.javascript.Externs`` library provides support for working with `externs `__ through the following classes: - `ExternalDecl `__: common superclass modeling all different kinds of externs declarations; it defines two member predicates: @@ -938,7 +938,7 @@ JSDoc The ``semmle.javascript.JSDoc`` library provides support for working with `JSDoc comments `__. Documentation comments are parsed into an abstract syntax tree representation closely following the format employed by the `Doctrine `__ JSDoc parser. -A JSDoc comment as a whole is represented by an entity of QL class `JSDoc `__, while individual tags are represented by QL class `JSDocTag `__. Important member predicates of these two classes include: +A JSDoc comment as a whole is represented by an entity of class `JSDoc `__, while individual tags are represented by class `JSDocTag `__. Important member predicates of these two classes include: - ``JSDoc.getDescription()`` returns the descriptive header of the JSDoc comment, if any. - ``JSDoc.getComment()`` maps the `JSDoc `__ entity to its underlying `Comment `__ entity. @@ -948,7 +948,7 @@ A JSDoc comment as a whole is represented by an entity of QL class `JSDoc `__ and its subclasses, which again represent type expressions as abstract syntax trees. Examples of type expressions are `JSDocAnyTypeExpr `__, representing the "any" type ``*``, or `JSDocNullTypeExpr `__, representing the null type. +Types in JSDoc comments are represented by the class `JSDocTypeExpr `__ and its subclasses, which again represent type expressions as abstract syntax trees. Examples of type expressions are `JSDocAnyTypeExpr `__, representing the "any" type ``*``, or `JSDocNullTypeExpr `__, representing the null type. As an example, here is a query that finds ``@param`` tags that do not specify the name of the documented parameter: @@ -979,9 +979,9 @@ However, unlike HTML, JSX is interleaved with JavaScript, hence `JSXElement `__ files that were processed by the JavaScript extractor when building the snapshot database. +The ``semmle.javascript.JSON`` library provides support for working with `JSON `__ files that were processed by the JavaScript extractor when building the CodeQL database. -JSON files are modeled as trees of JSON values. Each JSON value is represented by an entity of QL class `JSONValue `__, which provides the following member predicates: +JSON files are modeled as trees of JSON values. Each JSON value is represented by an entity of class `JSONValue `__, which provides the following member predicates: - ``JSONValue.getParent()`` returns the JSON object or array in which this value occurs. - ``JSONValue.getChild(i)`` returns the ``i``\ th child of this JSON object or array. @@ -1000,16 +1000,16 @@ Class `JSONValue `__. Similar to `ASTNode `__, class `RegExpTerm `__ provides member predicates ``getParent()`` and ``getChild(i)`` to navigate the structure of the syntax tree. +The ``semmle.javascript.Regexp`` library provides support for working with regular expression literals. The syntactic structure of regular expression literals is represented as an abstract syntax tree of regular expression terms, modeled by the class `RegExpTerm `__. Similar to `ASTNode `__, class `RegExpTerm `__ provides member predicates ``getParent()`` and ``getChild(i)`` to navigate the structure of the syntax tree. Various subclasses of `RegExpTerm `__ model different kinds of regular expression constructs and operators; see `the API documentation `__ for details. YAML ^^^^ -The ``semmle.javascript.YAML`` library provides support for working with `YAML `__ files that were processed by the JavaScript extractor when building the snapshot database. +The ``semmle.javascript.YAML`` library provides support for working with `YAML `__ files that were processed by the JavaScript extractor when building the CodeQL database. -YAML files are modeled as trees of YAML nodes. Each YAML node is represented by an entity of QL class `YAMLNode `__, which provides, among others, the following member predicates: +YAML files are modeled as trees of YAML nodes. Each YAML node is represented by an entity of class `YAMLNode `__, which provides, among others, the following member predicates: - ``YAMLNode.getParentNode()`` returns the YAML collection in which this node is syntactically nested. - ``YAMLNode.getChildNode(i)`` returns the ``i``\ th child node of this node, ``YAMLNode.getAChildNode()`` returns any child node of this node. @@ -1029,6 +1029,6 @@ Predicate ``YAMLMapping.maps(key, value)`` models the key-value relation represe What next? ---------- -- Learn about the QL standard libraries used to write queries for TypeScript in :doc:`Introducing the TypeScript libraries `. +- Learn about the standard CodeQL libraries used to write queries for TypeScript in :doc:`Introducing the TypeScript libraries `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst index a31bf9ffad6..4884cc8ce09 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst @@ -1,16 +1,16 @@ -Introducing the QL libraries for TypeScript -=========================================== +Introducing the CodeQL libraries for TypeScript +=============================================== Overview -------- -Support for analyzing TypeScript code is bundled with the JavaScript QL libraries, so you can include the full TypeScript library by importing the ``javascript.qll`` module: +Support for analyzing TypeScript code is bundled with the CodeQL libraries for JavaScript, so you can include the full TypeScript library by importing the ``javascript.qll`` module: .. code-block:: ql import javascript -The :doc:`QL library introduction for JavaScript ` covers most of this library, and is also relevant for TypeScript analysis. This document supplements the JavaScript QL documentation with the TypeScript-specific classes and predicates. +The :doc:`CodeQL library introduction for JavaScript ` covers most of this library, and is also relevant for TypeScript analysis. This document supplements the JavaScript documentation with the TypeScript-specific classes and predicates. Syntax ------ @@ -124,7 +124,7 @@ Select expressions that cast a value to a type parameter: Classes and interfaces ~~~~~~~~~~~~~~~~~~~~~~ -The QL class `ClassOrInterface `__ is a common supertype of classes and interfaces, and provides some TypeScript-specific member predicates: +The CodeQL class `ClassOrInterface `__ is a common supertype of classes and interfaces, and provides some TypeScript-specific member predicates: - ``ClassOrInterface.isAbstract()`` holds if this is an interface or a class with the ``abstract`` modifier. - ``ClassOrInterface.getASuperInterface()`` gets a type from the ``implements`` clause of a class or from the ``extends`` clause of an interface. @@ -134,7 +134,7 @@ The QL class `ClassOrInterface `__. -Also see the documentation for classes in the `Introduction to the QL libraries for JavaScript `__. +Also see the documentation for classes in the `Introduction to the CodeQL libraries for JavaScript `__. To select the type references to a class or an interface, use ``getTypeName()``. @@ -175,6 +175,8 @@ Ambient nodes are mostly ignored by control flow and data flow analysis. The out Static type information ----------------------- +.. TODO: Remove link to QL command-line tools below? + Static type information and global name binding is available for projects with "full" TypeScript extraction enabled. This option is enabled by default for projects on LGTM.com. If you are using the `QL command-line tools `__, you must enable it by passing ``--typescript-full`` to the JavaScript extractor. For further information on customizing calls to the extractor, see `Customizing JavaScript extraction `__. **Note:** Without full extraction, the classes and predicates described in this section are empty. @@ -262,7 +264,7 @@ Additionally, ``Type`` has the following subclasses which overlap partially with Canonical names and named types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``CanonicalName`` is a QL class representing a qualified name relative to a root scope, such as a module or the global scope. It typically represents an entity such as a type, namespace, variable, or function. ``TypeName`` and ``Namespace`` are subclasses of this class. +``CanonicalName`` is a CodeQL class representing a qualified name relative to a root scope, such as a module or the global scope. It typically represents an entity such as a type, namespace, variable, or function. ``TypeName`` and ``Namespace`` are subclasses of this class. Canonical names can be recognized using the ``hasQualifiedName`` predicate: @@ -274,7 +276,7 @@ For convenience, this predicate is also available on other classes, such as ``Ty Function types ~~~~~~~~~~~~~~ -There is no QL class for function types, as any type with a call or construct signature is usable as a function. The type ``CallSignatureType`` represents such a signature (with or without the ``new`` keyword). +There is no CodeQL class for function types, as any type with a call or construct signature is usable as a function. The type ``CallSignatureType`` represents such a signature (with or without the ``new`` keyword). Signatures can be obtained in several ways: @@ -353,7 +355,7 @@ TypeScript also allows you to import types and namespaces, and give them local n The local name ``B`` is represented as a `LocalTypeName `__ named ``B``, restricted to just the file containing the import. An import statement can also introduce a `Variable `__ and a `LocalNamespaceName `__. -The following table shows the relevant QL classes for working with each kind of name. The classes are described in more detail below. +The following table shows the relevant classes for working with each kind of name. The classes are described in more detail below. +-----------+------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | Kind | Local alias | Canonical name | Definition | Access | @@ -419,7 +421,7 @@ Find imported names that are used as both a type and a value: Namespace names ~~~~~~~~~~~~~~~ -Namespaces are represented by the QL classes `Namespace `__ and `LocalNamespaceName `__. The `NamespaceDefinition `__ class represents a syntactic definition of a namespace, which includes ordinary namespace declarations as well as enum declarations. +Namespaces are represented by the classes `Namespace `__ and `LocalNamespaceName `__. The `NamespaceDefinition `__ class represents a syntactic definition of a namespace, which includes ordinary namespace declarations as well as enum declarations. Note that these classes deal exclusively with namespaces referenced from inside type annotations, not through expressions. @@ -443,6 +445,6 @@ A `LocalNamespaceName `. +- Learn about the standard CodeQL libraries used to write queries for JavaScript in :doc:`Introducing the JavaScript libraries `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/ql-for-javascript.rst b/docs/language/learn-ql/javascript/ql-for-javascript.rst index 5df6e2581e5..d2d864cc072 100644 --- a/docs/language/learn-ql/javascript/ql-for-javascript.rst +++ b/docs/language/learn-ql/javascript/ql-for-javascript.rst @@ -1,5 +1,5 @@ -QL for JavaScript -================= +CodeQL for JavaScript +===================== .. toctree:: :glob: @@ -13,25 +13,25 @@ QL for JavaScript ast-class-reference dataflow-cheat-sheet -These documents provide an overview of the QL JavaScript and TypeScript standard libraries and show examples of how to use them. +These documents provide an overview of the CodeQL libraries for JavaScript and TypeScript and show examples of how to use them. -- `Basic JavaScript QL query `__ describes how to write and run queries using LGTM. +- `Basic JavaScript query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the QL libraries for JavaScript `: an overview of the standard libraries used to write queries for JavaScript code. There is an extensive QL library for analyzing JavaScript code. This tutorial briefly summarizes the most important QL classes and predicates provided by this library. +- :doc:`Introducing the CodeQL libraries for JavaScript ` introduces the standard libraries used to write queries for JavaScript code. There is an extensive CodeQL library for analyzing JavaScript code. This tutorial briefly summarizes the most important classes and predicates provided by this library. -- :doc:`Introducing the QL libraries for TypeScript `: an overview of the standard libraries used to write queries for TypeScript code. +- :doc:`Introducing the CodeQL libraries for TypeScript ` introduces the standard libraries used to write queries for TypeScript code. -- :doc:`Analyzing data flow in JavaScript/TypeScript `: demonstrates how to write queries using the standard QL for JavaScript/TypeScript data flow and taint tracking libraries. +- :doc:`Analyzing data flow in JavaScript/TypeScript ` demonstrates how to write queries using the standard data flow and taint tracking libraries for JavaScript/TypeScript. -- :doc:`Advanced data-flow analysis using flow labels `: shows a more advanced example of data flow analysis using flow labels. +- :doc:`Advanced data-flow analysis using flow labels ` shows a more advanced example of data flow analysis using flow labels. -- :doc:`AST class reference `: an overview of all AST classes in the QL standard library for JavaScript. +- :doc:`AST class reference ` gives an overview of all AST classes in the standard CodeQL library for JavaScript. -- :doc:`Data flow cheat sheet `: bits of QL commonly used for variant analysis and in data flow queries. +- :doc:`Data flow cheat sheet ` lists parts of the CodeQL libraries that are commonly used for variant analysis and in data flow queries. Other resources --------------- -- For examples of how to query common JavaScript elements, see the `JavaScript QL cookbook `__ -- For the queries used in LGTM, display a `JavaScript query `__ and click **Open in query console** to see the QL code used to find alerts. -- For more information about the JavaScript QL library see the `QL library for JavaScript `__. +- For examples of how to query common JavaScript elements, see the `JavaScript cookbook `__. +- For the queries used in LGTM, display a `JavaScript query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for JavaScript see the `CodeQL library for JavaScript `__. diff --git a/docs/language/learn-ql/javascript/type-tracking.rst b/docs/language/learn-ql/javascript/type-tracking.rst index d6bcb9e7a7c..f0dadd9ef70 100644 --- a/docs/language/learn-ql/javascript/type-tracking.rst +++ b/docs/language/learn-ql/javascript/type-tracking.rst @@ -1,8 +1,8 @@ Tutorial: API modelling using type tracking =========================================== -This tutorial demonstrates how to build a simple model of the Firebase API in QL -using the JavaScript type-tracking library. +This tutorial demonstrates how to build a simple model of the Firebase API +using the CodeQL type-tracking library for JavaScript. The type-tracking library makes it possible to track values through properties and function calls, usually to recognize method calls and properties accessed on a specific type of object. @@ -89,7 +89,7 @@ For instance, ``firebaseSetterCall()`` fails to find anything in this example: var ref = getDatabase().ref("forecast"); ref.set("Rain"); -Notice that the QL predicate ``firebaseDatabase()`` still finds the call to ``firebase.database()``, +Notice that the predicate ``firebaseDatabase()`` still finds the call to ``firebase.database()``, but not the ``getDatabase()`` call. This means ``firebaseRef()`` has no result, which in turn means ``firebaseSetterCall()`` has no result. From e2b446db199d66105ec71a4c5fcb4276bdcac99a Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 28 Oct 2019 17:23:31 +0000 Subject: [PATCH 057/148] Docs: Update Python --- .../language/learn-ql/python/control-flow.rst | 8 ++-- docs/language/learn-ql/python/functions.rst | 6 +-- .../python/introduce-libraries-python.rst | 40 +++++++++---------- .../learn-ql/python/pointsto-type-infer.rst | 14 +++---- .../learn-ql/python/ql-for-python.rst | 26 ++++++------ .../python/statements-expressions.rst | 6 +-- .../learn-ql/python/taint-tracking.rst | 8 ++-- 7 files changed, 50 insertions(+), 58 deletions(-) diff --git a/docs/language/learn-ql/python/control-flow.rst b/docs/language/learn-ql/python/control-flow.rst index 45b30f51f21..fc41f59c933 100644 --- a/docs/language/learn-ql/python/control-flow.rst +++ b/docs/language/learn-ql/python/control-flow.rst @@ -1,12 +1,12 @@ Tutorial: Control flow analysis =============================== -In order to analyze the `Control-flow graph `__ of a ``Scope`` we can use the two QL classes ``ControlFlowNode`` and ``BasicBlock``. These classes allow you to ask such questions as "can you reach point A from point B?" or "Is it possible to reach point B *without* going through point A?". To report results we use the class ``AstNode``, which represents a syntactic element and corresponds to the source code - allowing the results of the query to be more easily understood. +To analyze the `Control-flow graph `__ of a ``Scope`` we can use the two CodeQL classes ``ControlFlowNode`` and ``BasicBlock``. These classes allow you to ask such questions as "can you reach point A from point B?" or "Is it possible to reach point B *without* going through point A?". To report results we use the class ``AstNode``, which represents a syntactic element and corresponds to the source code - allowing the results of the query to be more easily understood. The ``ControlFlowNode`` class ----------------------------- -The ``ControlFlowNode`` class represents nodes in the control flow graph. There is a one-to-many relation between AST nodes and control flow nodes. Each syntactic element, the ``AstNode,`` maps to zero, one or many ``ControlFlowNode`` classes, but each ControlFlowNode maps to exactly one ``AstNode``. +The ``ControlFlowNode`` class represents nodes in the control flow graph. There is a one-to-many relation between AST nodes and control flow nodes. Each syntactic element, the ``AstNode,`` maps to zero, one, or many ``ControlFlowNode`` classes, but each ``ControlFlowNode`` maps to exactly one ``AstNode``. To show why this complex relation is required consider the following Python code: @@ -21,7 +21,7 @@ To show why this complex relation is required consider the following Python code There are many paths through the above code. There are three different paths through the call to ``close_resource();`` one normal path, one path that breaks out of the loop, and one path where an exception is raised by ``might_raise()``. (An annotated flow graph can be seen :doc:`here `.) -The simplest use of the ``ControlFlowNode`` and ``AstNode`` classes is to find unreachable code. There is one ``ControlFlowNode`` per path through any ``AstNode`` and any ``AstNode`` that is unreachable has no paths flowing through it; therefore any ``AstNode`` without a corresponding ``ControlFlowNode`` is unreachable. +The simplest use of the ``ControlFlowNode`` and ``AstNode`` classes is to find unreachable code. There is one ``ControlFlowNode`` per path through any ``AstNode`` and any ``AstNode`` that is unreachable has no paths flowing through it. Therefore, any ``AstNode`` without a corresponding ``ControlFlowNode`` is unreachable. **Unreachable AST nodes** @@ -103,5 +103,5 @@ Combining these conditions we get: What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topic: :doc:`Taint tracking and data flow analysis in Python `. +- Experiment with the worked examples in the tutorial topic :doc:`Taint tracking and data flow analysis in Python `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/python/functions.rst b/docs/language/learn-ql/python/functions.rst index 7e33b77f5fc..79fcfa270d9 100644 --- a/docs/language/learn-ql/python/functions.rst +++ b/docs/language/learn-ql/python/functions.rst @@ -1,14 +1,14 @@ Tutorial: Functions =================== -This example uses the standard QL class ``Function`` (see :doc:`Introducing the Python libraries `). +This example uses the standard CodeQL class ``Function`` (see :doc:`Introducing the Python libraries `). Finding all functions called "get..." ------------------------------------- In this example we look for all the "getters" in a program. Programmers moving to Python from Java are often tempted to write lots of getter and setter methods, rather than use properties. We might want to find those methods. -Using the member predicate ``Function.getName()``, we can list all of the getter functions in a snapshot: +Using the member predicate ``Function.getName()``, we can list all of the getter functions in a database: Tip @@ -77,5 +77,5 @@ In a later tutorial we will see how to use the type-inference library to find ca What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Statements and expressions `, :doc:`Control flow `, :doc:`Points-to analysis and type inference `. +- Experiment with the worked examples in the following tutorial topics: :doc:`Statements and expressions `, :doc:`Control flow `, and :doc:`Points-to analysis and type inference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index 4314cf36913..60d965a461b 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -1,39 +1,35 @@ -Introducing the QL libraries for Python -======================================= +Introducing the CodeQL libraries for Python +=========================================== -These libraries have been created to help you analyze Python code, providing an object-oriented layer on top of the raw data in the snapshot database. They are written in standard QL. - -The QL libraries all have a ``.qll`` extension, to signify that they contain QL library code but no actual queries. Each file contains a QL class or hierarchy of classes. - -You can include all of the standard libraries by beginning each query with this statement: +There is an extensive library for analyzing CodeQL databases extracted from Python projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``python.qll`` imports all the core Python library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import python -The rest of this tutorial summarizes the contents of the standard QL libraries. We recommend that you read this and then work through the practical examples in the Python tutorials shown at the end of the page. +The rest of this tutorial summarizes the contents of the standard libraries for Python. We recommend that you read this and then work through the practical examples in the tutorials shown at the end of the page. Overview of the library ----------------------- -The QL Python library incorporates a large number of classes, each class corresponding either to one kind of entity in Python source code or to an entity that can be derived form the source code using static analysis. These classes can be divided into four categories: +The CodeQL library for Python incorporates a large number of classes. Each class corresponds either to one kind of entity in Python source code or to an entity that can be derived form the source code using static analysis. These classes can be divided into four categories: - **Syntactic** - classes that represent entities in the Python source code. - **Control flow** - classes that represent entities from the control flow graphs. - **Type inference** - classes that represent the inferred values and types of entities in the Python source code. -- **Taint tracking** - classes that represent the source, sinks and kinds of taint used to implement taint-tracking queries. +- **Taint tracking** - classes that represent the source, sinks and kinds of taint used to implement taint-tracking queries. Syntactic classes ~~~~~~~~~~~~~~~~~ -This part of the library represents the Python source code. The ``Module``, ``Class`` and ``Function`` classes correspond to Python modules, classes and functions respectively, collectively these are known as ``Scope`` classes. Each ``Scope`` contains a list of statements each of which is represented by a subclass of the class ``Stmt``. Statements themselves can contain other statements or expressions which are represented by subclasses of ``Expr``. Finally, there are a few additional classes for the parts of more complex expressions such as list comprehensions. Collectively these classes are subclasses of ``AstNode`` and form an `Abstract syntax tree `__ (AST). The root of each AST is a ``Module``. +This part of the library represents the Python source code. The ``Module``, ``Class``, and ``Function`` classes correspond to Python modules, classes, and functions respectively, collectively these are known as ``Scope`` classes. Each ``Scope`` contains a list of statements each of which is represented by a subclass of the class ``Stmt``. Statements themselves can contain other statements or expressions which are represented by subclasses of ``Expr``. Finally, there are a few additional classes for the parts of more complex expressions such as list comprehensions. Collectively these classes are subclasses of ``AstNode`` and form an `Abstract syntax tree `__ (AST). The root of each AST is a ``Module``. `Symbolic information `__ is attached to the AST in the form of variables (represented by the class ``Variable``). Scope ^^^^^ -A Python program is a group of modules. Technically a module is just a list of statements, but we often think of it as composed of classes and functions. These top-level entities, the module, class and function are represented by the three classes (`Module `__, `Class `__ and `Function `__ which are all subclasses of ``Scope``. +A Python program is a group of modules. Technically a module is just a list of statements, but we often think of it as composed of classes and functions. These top-level entities, the module, class, and function are represented by the three CodeQL classes (`Module `__, `Class `__ and `Function `__ which are all subclasses of ``Scope``. - ``Scope`` @@ -65,7 +61,7 @@ A statement is represented by the `Stmt `__ class representing the ``for`` statement has a number of member predicates to access its parts: +The `For `__ class representing the ``for`` statement has a number of member predicates to access its parts: - ``getTarget()`` returns the ``Expr`` representing the variable ``var``. - ``getIter()`` returns the ``Expr`` resenting the variable ``seq``. @@ -98,7 +94,7 @@ As an example, to find expressions of the form ``a+2`` where the left is a simpl Variable ^^^^^^^^ -Variables are represented by the `Variable `__ class in the Python QL library. There are two subclasses, ``LocalVariable`` for function-level and class-level variables and ``GlobalVariable`` for module-level variables. +Variables are represented by the `Variable `__ class in the CodeQL library. There are two subclasses, ``LocalVariable`` for function-level and class-level variables and ``GlobalVariable`` for module-level variables. Other source code elements ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +104,7 @@ Although the meaning of the program is encoded by the syntactic elements, ``Scop Examples ^^^^^^^^ -Each syntactic element in Python source is recorded in the snapshot. These can be queried via the corresponding class. Let us start with a couple of simple examples. +Each syntactic element in Python source is recorded in the CodeQL database. These can be queried via the corresponding class. Let us start with a couple of simple examples. 1. Finding all finally blocks ''''''''''''''''''''''''''''' @@ -137,13 +133,13 @@ A block that does nothing is one that contains no statements except ``pass`` sta not exists(Stmt s | s = ex.getAStmt() | not s instanceof Pass) -where ``ex`` is an ``ExceptStmt`` and ``Pass`` is the class representing ``pass`` statements. Instead of using the double negative, **"no**\ *statements that are*\ **not**\ *pass statements"*, this can also be expressed positively, "all statements must be pass statements." The positive form is expressed in QL using the ``forall`` quantifier: +where ``ex`` is an ``ExceptStmt`` and ``Pass`` is the class representing ``pass`` statements. Instead of using the double negative, "**no** \ *statements that are* \ **not** \ *pass statements"*, this can also be expressed positively, *"all statements must be pass statements."* The positive form is expressed using the ``forall`` quantifier: .. code-block:: ql forall(Stmt s | s = ex.getAStmt() | s instanceof Pass) -Both forms are equivalent. Using the positive QL expression, the whole query looks like this: +Both forms are equivalent. Using the positive expression, the whole query looks like this: **Find pass-only ``except`` blocks** @@ -160,9 +156,9 @@ Both forms are equivalent. Using the positive QL expression, the whole query loo Summary ^^^^^^^ -The most commonly used standard QL library classes in the syntactic part of the library are organized as follows: +The most commonly used standard classes in the syntactic part of the library are organized as follows: -``Module``, ``Class``, ``Function``, ``Stmt`` and ``Expr`` - they are all subclasses of `AstNode `__. +``Module``, ``Class``, ``Function``, ``Stmt``, and ``Expr`` - they are all subclasses of `AstNode `__. Abstract syntax tree '''''''''''''''''''' @@ -293,7 +289,7 @@ The classes in the control-flow part of the library are: Type-inference classes ---------------------- -The QL library for Python also supplies some classes for accessing the inferred types of values. The classes ``Value`` and ``ClassValue`` allow you to query the possible classes that an expression may have at runtime. For example, which ``ClassValue``\ s are iterable can be determined using the query: +The CodeQL library for Python also supplies some classes for accessing the inferred types of values. The classes ``Value`` and ``ClassValue`` allow you to query the possible classes that an expression may have at runtime. For example, which ``ClassValue``\ s are iterable can be determined using the query: **Find iterable "ClassValue"s** @@ -321,7 +317,7 @@ These classes are explained in more detail in :doc:`Tutorial: Points-to analysis Taint-tracking classes ---------------------- -The QL library for Python also supplies classes to specify taint-tracking analyses. The ``Configuration`` class can be overrridden to specify a taint-tracking analysis, by specifying source, sinks, sanitizers and additional flow steps. For those analyses that require additional types of taint to be tracked the ``TaintKind`` class can be overridden. +The CodeQL library for Python also supplies classes to specify taint-tracking analyses. The ``Configuration`` class can be overridden to specify a taint-tracking analysis, by specifying source, sinks, sanitizers and additional flow steps. For those analyses that require additional types of taint to be tracked the ``TaintKind`` class can be overridden. Summary @@ -336,5 +332,5 @@ These classes are explained in more detail in :doc:`Tutorial: Taint tracking and What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Functions `, :doc:`Statements and expressions `, :doc:`Control flow `, :doc:`Points-to analysis and type inference ` and :doc:`Taint tracking and data flow analysis in Python `. +- Experiment with the worked examples in the following tutorial topics: :doc:`Functions `, :doc:`Statements and expressions `, :doc:`Control flow `, :doc:`Points-to analysis and type inference `, and :doc:`Taint tracking and data flow analysis in Python `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index a50e0776a83..eb80efe815f 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -1,12 +1,12 @@ Tutorial: Points-to analysis and type inference =============================================== -This topic contains worked examples of how to write queries using the standard QL library classes for Python type inference. +This topic contains worked examples of how to write queries using the standard CodeQL library classes for Python type inference. The ``Value`` class -------------------- -The ``Value`` class and its subclasses ``FunctionValue``, ``ClassValue`` and ``ModuleValue`` represent the values an expression may hold at runtime. +The ``Value`` class and its subclasses ``FunctionValue``, ``ClassValue``, and ``ModuleValue`` represent the values an expression may hold at runtime. Summary ~~~~~~~ @@ -201,7 +201,7 @@ There are two problems with this query: - It assumes that any call to something named "eval" is a call to the builtin ``eval`` function, which may result in some false positive results. - It assumes that ``eval`` cannot be referred to by any other name, which may result in some false negative results. -We can get much more accurate results using call-graph analysis. First, we can precisely identify the ``FunctionValue`` for the ``eval`` function, by using the ``Value::named`` QL predicate as follows: +We can get much more accurate results using call-graph analysis. First, we can precisely identify the ``FunctionValue`` for the ``eval`` function, by using the ``Value::named`` predicate as follows: .. code-block:: ql @@ -227,9 +227,5 @@ Then we can use ``Value.getACall()`` to identify calls to the ``eval`` function, What next? ---------- -For more information on writing QL, see: - -- `QL language handbook `__ - an introduction to the concepts of QL. -- :doc:`Learning QL <../../index>` - an overview of the resources for learning how to write your own QL queries. -- `Database generation `__ - an overview of the process that creates a database from source code. -- :doc:`What's in a CodeQL database? <../database>` - a description of the CodeQL database. +- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- Read a description of the CodeQL database in :doc:`What's in a CodeQL database? <../database>` diff --git a/docs/language/learn-ql/python/ql-for-python.rst b/docs/language/learn-ql/python/ql-for-python.rst index 479a30dccb5..680c0c374b5 100644 --- a/docs/language/learn-ql/python/ql-for-python.rst +++ b/docs/language/learn-ql/python/ql-for-python.rst @@ -1,5 +1,5 @@ -QL for Python -============= +CodeQL for Python +================= .. toctree:: :glob: @@ -13,25 +13,25 @@ QL for Python taint-tracking pointsto-type-infer -The following tutorials and worked examples are designed to help you learn how to write effective and efficient QL queries for Python projects. You should work through these topics in the order displayed. +The following tutorials and worked examples are designed to help you learn how to write effective and efficient queries for Python projects. You should work through these topics in the order displayed. -- `Basic Python QL query `__ describes how to write and run queries using LGTM. +- `Basic Python query `__ describes how to write and run queries using LGTM. -- :doc:`Introducing the QL libraries for Python ` an introduction to the standard QL libraries used to write queries for Python code. +- :doc:`Introducing the CodeQL libraries for Python ` introduces the standard libraries used to write queries for Python code. -- :doc:`Tutorial: Functions ` worked examples of how to write queries using the standard QL library classes for Python functions. +- :doc:`Tutorial: Functions ` demonstrates how to write queries using the standard CodeQL library classes for Python functions. -- :doc:`Tutorial: Statements and expressions ` worked examples of how to write queries using the standard QL library classes for Python statements and expressions. +- :doc:`Tutorial: Statements and expressions ` demonstrates how to write queries using the standard CodeQL library classes for Python statements and expressions. -- :doc:`Tutorial: Control flow ` worked examples of how to write queries using the standard QL library classes for Python control flow. +- :doc:`Tutorial: Control flow ` demonstrates how to write queries using the standard CodeQL library classes for Python control flow. -- :doc:`Tutorial: Points-to analysis and type inference ` worked examples of how to write queries using the standard QL library classes for Python type inference. +- :doc:`Tutorial: Points-to analysis and type inference ` demonstrates how to write queries using the standard CodeQL library classes for Python type inference. -- :doc:`Taint tracking and data flow analysis in Python ` worked examples of how to write queries using the standard taint tracking and data flow QL libraries for Python. +- :doc:`Taint tracking and data flow analysis in Python ` demonstrates how to write queries using the standard taint tracking and data flow libraries for Python. Other resources --------------- -- For examples of how to query common Python elements, see the `Python QL cookbook `__ -- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the QL code used to find alerts -- For more information about the Python QL library see the `QL library for Python `__. +- For examples of how to query common Python elements, see the `Python cookbook `__. +- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for Python see the `CodeQL library for Python `__. diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 8aa1bea96f4..9a0a2484fc7 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -4,7 +4,7 @@ Tutorial: Statements and expressions Statements ---------- -The bulk of Python code takes the form of statements. Each different type of statement in Python is represented by a separate class in QL. +The bulk of Python code takes the form of statements. Each different type of statement in Python is represented by a separate CodeQL class. Here is the full class hierarchy: @@ -165,7 +165,7 @@ The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` che Example: Duplicates in dictionary literals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If there are duplicate keys in a Python dictionary, then the second key will overwrite the first, which is almost certainly a mistake. We can find these duplicates in QL, but the query is more complex than previous examples and will require us to write a ``predicate`` as a helper. +If there are duplicate keys in a Python dictionary, then the second key will overwrite the first, which is almost certainly a mistake. We can find these duplicates with CodeQL, but the query is more complex than previous examples and will require us to write a ``predicate`` as a helper. Here is the query: @@ -274,5 +274,5 @@ Here is the relevant part of the class hierarchy: What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Control flow `, :doc:`Points-to analysis and type inference `. +- Experiment with the worked examples in the following tutorial topics: :doc:`Control flow ` and :doc:`Points-to analysis and type inference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. diff --git a/docs/language/learn-ql/python/taint-tracking.rst b/docs/language/learn-ql/python/taint-tracking.rst index 71cd000c716..7335df5af11 100644 --- a/docs/language/learn-ql/python/taint-tracking.rst +++ b/docs/language/learn-ql/python/taint-tracking.rst @@ -13,10 +13,10 @@ Taint tracking differs from basic data flow in that it considers non-value-prese For example, in the assignment ``dir = path + "/"``, if ``path`` is tainted then ``dir`` is also tainted, even though there is no data flow from ``path`` to ``path + "/"``. -Separate QL libraries have been written to handle 'normal' data flow and taint tracking in :doc:`C/C++ <../cpp/dataflow>`, :doc:`C# <../csharp/dataflow>`, :doc:`Java <../java/dataflow>`, and :doc:`JavaScript <../javascript/dataflow>`. You can access the appropriate classes and predicates that reason about these different modes of data flow by importing the appropriate QL library in your query. +Separate CodeQL libraries have been written to handle 'normal' data flow and taint tracking in :doc:`C/C++ <../cpp/dataflow>`, :doc:`C# <../csharp/dataflow>`, :doc:`Java <../java/dataflow>`, and :doc:`JavaScript <../javascript/dataflow>`. You can access the appropriate classes and predicates that reason about these different modes of data flow by importing the appropriate library in your query. In Python analysis, we can use the same taint tracking library to model both 'normal' data flow and taint flow, but we are still able make the distinction between steps that preserve value and those that don't by defining additional data flow properties. -For further information on data flow and taint tracking in QL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. +For further information on data flow and taint tracking with CodeQL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. Fundamentals of taint tracking and data flow analysis ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -222,7 +222,7 @@ The ``TaintTracking::Source`` and ``TaintTracking::Sink`` classes have predicate ... } -The ``TaintKind`` itself is just a string (a QL string, not a QL entity representing a Python string), +The ``TaintKind`` itself is just a string (a QL string, not a CodeQL entity representing a Python string), which provides methods to extend flow and allow the kind of taint to change along the path. The ``TaintKind`` class has many predicates allowing flow to be modified. This simplest ``TaintKind`` does not override any predicates, meaning that it only flows as opaque data. @@ -254,5 +254,5 @@ which defines the simplest possible taint kind class, ``HardcodedValue``, and cu What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Control flow `, and :doc:`Points-to analysis and type inference `. +- Experiment with the worked examples in the following tutorial topics: :doc:`Control flow ` and :doc:`Points-to analysis and type inference `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. From 49dd2216a65e55824bb0371d8d476eebae1c241b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 10 Oct 2019 16:14:12 +0200 Subject: [PATCH 058/148] Python: Refactor django library Use General.qll for routing, like in other web libraries --- .../src/semmle/python/web/django/General.qll | 28 +++++++++++++ .../src/semmle/python/web/django/Request.qll | 41 ++++--------------- 2 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 python/ql/src/semmle/python/web/django/General.qll diff --git a/python/ql/src/semmle/python/web/django/General.qll b/python/ql/src/semmle/python/web/django/General.qll new file mode 100644 index 00000000000..954df1892e8 --- /dev/null +++ b/python/ql/src/semmle/python/web/django/General.qll @@ -0,0 +1,28 @@ +import python +import semmle.python.regex +import semmle.python.web.Http + +predicate django_route(CallNode call, ControlFlowNode regex, FunctionValue view) { + exists(FunctionValue url | + Value::named("django.conf.urls.url") = url and + url.getArgumentForCall(call, 0) = regex and + url.getArgumentForCall(call, 1).pointsTo(view) + ) +} + +class DjangoRouteRegex extends RegexString { + DjangoRouteRegex() { django_route(_, this.getAFlowNode(), _) } +} + +class DjangoRoute extends CallNode { + DjangoRoute() { django_route(this, _, _) } + + FunctionValue getViewFunction() { django_route(this, _, result) } + + string getNamedArgument() { + exists(DjangoRouteRegex regex | + django_route(this, regex.getAFlowNode(), _) and + regex.getGroupName(_, _) = result + ) + } +} diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index d2ad2ff30d3..71da78f9b43 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -1,7 +1,7 @@ import python -import semmle.python.regex import semmle.python.security.TaintTracking import semmle.python.web.Http +import semmle.python.web.django.General /** A django.request.HttpRequest object */ class DjangoRequest extends TaintKind { @@ -52,7 +52,7 @@ abstract class DjangoRequestSource extends HttpRequestTaintSource { private class DjangoFunctionBasedViewRequestArgument extends DjangoRequestSource { DjangoFunctionBasedViewRequestArgument() { exists(FunctionValue view | - url_dispatch(_, _, view) and + django_route(_, _, view) and this = view.getScope().getArg(0).asName().getAFlowNode() ) } @@ -76,41 +76,14 @@ class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { } } -/* *********** Routing ********* */ -/* Function based views */ -predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionValue view) { - exists(FunctionValue url | - Value::named("django.conf.urls.url") = url and - url.getArgumentForCall(call, 0) = regex and - url.getArgumentForCall(call, 1).pointsTo(view) - ) -} - -class UrlRegex extends RegexString { - UrlRegex() { url_dispatch(_, this.getAFlowNode(), _) } -} - -class UrlRouting extends CallNode { - UrlRouting() { url_dispatch(this, _, _) } - - FunctionValue getViewFunction() { url_dispatch(this, _, result) } - - string getNamedArgument() { - exists(UrlRegex regex | - url_dispatch(this, regex.getAFlowNode(), _) and - regex.getGroupName(_, _) = result - ) - } -} - /** An argument specified in a url routing table */ -class HttpRequestParameter extends HttpRequestTaintSource { - HttpRequestParameter() { - exists(UrlRouting url | - this.(ControlFlowNode).getNode() = url +class DjangoRequestParameter extends HttpRequestTaintSource { + DjangoRequestParameter() { + exists(DjangoRoute route | + this.(ControlFlowNode).getNode() = route .getViewFunction() .getScope() - .getArgByName(url.getNamedArgument()) + .getArgByName(route.getNamedArgument()) ) } From afe7a0536cc0ad3cc93b396c0d3ed40bb1c5502c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 10 Oct 2019 17:25:09 +0200 Subject: [PATCH 059/148] Python: Support positional arguments in Django routes --- change-notes/1.23/analysis-python.md | 5 +++ .../src/semmle/python/web/django/General.qll | 12 +++++++ .../src/semmle/python/web/django/Request.qll | 14 +++++--- .../library-tests/web/django/Sinks.expected | 4 +++ .../library-tests/web/django/Sources.expected | 9 +++++ .../ql/test/library-tests/web/django/test.py | 33 ++++++++++++++++++- 6 files changed, 71 insertions(+), 6 deletions(-) diff --git a/change-notes/1.23/analysis-python.md b/change-notes/1.23/analysis-python.md index 00fab13e098..6cea1745284 100644 --- a/change-notes/1.23/analysis-python.md +++ b/change-notes/1.23/analysis-python.md @@ -20,3 +20,8 @@ |----------------------------|------------------------|------------| | Unreachable code | Fewer false positives | Analysis now accounts for uses of `contextlib.suppress` to suppress exceptions. | | `__iter__` method returns a non-iterator | Better alert message | Alert now highlights which class is expected to be an iterator. | + + +## Changes to QL libraries + +* Django library now recognizes positional arguments from a `django.conf.urls.url` regex (Django version 1.x) diff --git a/python/ql/src/semmle/python/web/django/General.qll b/python/ql/src/semmle/python/web/django/General.qll index 954df1892e8..423d853cdad 100644 --- a/python/ql/src/semmle/python/web/django/General.qll +++ b/python/ql/src/semmle/python/web/django/General.qll @@ -25,4 +25,16 @@ class DjangoRoute extends CallNode { regex.getGroupName(_, _) = result ) } + + /** + * Get the number of positional arguments that will be passed to the view. + * Will only return a result if there are no named arguments. + */ + int getNumPositionalArguments() { + exists(DjangoRouteRegex regex | + django_route(this, regex.getAFlowNode(), _) and + not exists(string s | s = regex.getGroupName(_, _)) and + result = count(regex.getGroupNumber(_, _)) + ) + } } diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index 71da78f9b43..15ea032e6d7 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -79,11 +79,15 @@ class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { /** An argument specified in a url routing table */ class DjangoRequestParameter extends HttpRequestTaintSource { DjangoRequestParameter() { - exists(DjangoRoute route | - this.(ControlFlowNode).getNode() = route - .getViewFunction() - .getScope() - .getArgByName(route.getNamedArgument()) + exists(DjangoRoute route, Function f | + f = route.getViewFunction().getScope() | + this.(ControlFlowNode).getNode() = f.getArgByName(route.getNamedArgument()) + or + exists(int i | i >= 0 | + i < route.getNumPositionalArguments() and + // +1 because first argument is always the request + this.(ControlFlowNode).getNode() = f.getArg(i+1) + ) ) } diff --git a/python/ql/test/library-tests/web/django/Sinks.expected b/python/ql/test/library-tests/web/django/Sinks.expected index 82d1b71e53a..7201a7a20a9 100644 --- a/python/ql/test/library-tests/web/django/Sinks.expected +++ b/python/ql/test/library-tests/web/django/Sinks.expected @@ -4,3 +4,7 @@ | test.py:25 | BinaryExpr | externally controlled string | | test.py:26 | BinaryExpr | externally controlled string | | test.py:34 | BinaryExpr | externally controlled string | +| test.py:46 | Attribute() | externally controlled string | +| test.py:57 | Attribute() | externally controlled string | +| test.py:60 | Attribute() | externally controlled string | +| test.py:63 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/Sources.expected b/python/ql/test/library-tests/web/django/Sources.expected index 8f421a2d169..7482f21cdda 100644 --- a/python/ql/test/library-tests/web/django/Sources.expected +++ b/python/ql/test/library-tests/web/django/Sources.expected @@ -1,2 +1,11 @@ | test.py:11 | request | django.request.HttpRequest | | test.py:31 | request | django.request.HttpRequest | +| test.py:56 | arg0 | externally controlled string | +| test.py:56 | request | django.request.HttpRequest | +| test.py:59 | arg0 | externally controlled string | +| test.py:59 | arg1 | externally controlled string | +| test.py:59 | arg2 | externally controlled string | +| test.py:59 | request | django.request.HttpRequest | +| test.py:62 | arg0 | externally controlled string | +| test.py:62 | arg1 | externally controlled string | +| test.py:62 | request | django.request.HttpRequest | diff --git a/python/ql/test/library-tests/web/django/test.py b/python/ql/test/library-tests/web/django/test.py index e6c39c30a32..3cabac0e5c5 100644 --- a/python/ql/test/library-tests/web/django/test.py +++ b/python/ql/test/library-tests/web/django/test.py @@ -34,7 +34,38 @@ def maybe_xss(request): resp.write("first name is " + first_name) return resp -urlpatterns2 = [ +urlpatterns = [ # Route to code_execution url(r'^maybe_xss$', maybe_xss, name='maybe_xss') ] + + +# Non capturing group (we correctly identify page_number as a request parameter) + +def show_articles(request, page_number=1): + return HttpResponse('articles page: {}'.format(page_number)) + +urlpatterns = [ + # one pattern to support `articles/page-` and ensuring that articles/ goes to page-1 + url(r'articles/^(?:page-(?P\d+)/)?$', show_articles), +] + + +# Positional arguments + +def xxs_positional_arg1(request, arg0): + return HttpResponse('xxs_positional_arg1: {}'.format(arg0)) + +def xxs_positional_arg2(request, arg0, arg1, arg2): + return HttpResponse('xxs_positional_arg2: {} {} {}'.format(arg0, arg1, arg2)) + +def xxs_positional_arg3(request, arg0, arg1): + return HttpResponse('xxs_positional_arg3: {} {}'.format(arg0, arg1)) + +urlpatterns = [ + # passing as positional argument is not the recommended way of doing things, + # but it is certainly possible + url(r'^(.+)$', xxs_positional_arg1, name='xxs_positional_arg1'), + url(r'^([^/]+)/([^/]+)/([^/]+)$', xxs_positional_arg2, name='xxs_positional_arg2'), + url(r'^([^/]+)/(?:foo|bar)/([^/]+)$', xxs_positional_arg3, name='xxs_positional_arg3'), +] From 471318369b4fee5c66239a5f33c91d9410df8f76 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 14 Oct 2019 16:51:50 +0200 Subject: [PATCH 060/148] Python: Don't quote %s in django example This is vulnerable to SQL injection because of the quotes around %s -- added some code that highlights this in test.py Since our examples did this in the safe query, I ended up rewriting them completely, causing a lot of trouble for myself :D --- .../src/Security/CWE-089/SqlInjection.qhelp | 17 +++++-- .../CWE-089/examples/sql_injection.py | 28 +++++----- .../library-tests/web/django/Sinks.expected | 21 ++++---- .../library-tests/web/django/Sources.expected | 26 ++++++---- .../ql/test/library-tests/web/django/test.py | 51 ++++++++++++------- .../Security/CWE-089/SqlInjection.expected | 27 +++++----- .../Security/CWE-089/sql_injection.py | 48 ++++++++++------- 7 files changed, 128 insertions(+), 90 deletions(-) diff --git a/python/ql/src/Security/CWE-089/SqlInjection.qhelp b/python/ql/src/Security/CWE-089/SqlInjection.qhelp index e976401a6b5..286b71a6047 100644 --- a/python/ql/src/Security/CWE-089/SqlInjection.qhelp +++ b/python/ql/src/Security/CWE-089/SqlInjection.qhelp @@ -21,20 +21,29 @@ or prepared statements.

    -In the following snippet, from an example django app, -a name is stored in the database using two different queries. +In the following snippet, a user is fetched from the database using three +different queries.

    In the first case, the query string is built by -directly using string formatting from a user-supplied request attribute. +directly using string formatting from a user-supplied request parameter. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack.

    In the second case, the user-supplied request attribute is passed -to the database using query parameters. +to the database using query parameters. The database connector library will +take care of escaping and inserting quotes as needed. +

    + +

    +In the third case, the placeholder in the SQL string has been manually quoted. Since most +databaseconnector libraries will insert their own quotes, doing so yourself will make the code +vulnerable to SQL injection attacks. In this example, if username was +; DROP ALL TABLES -- , the final SQL query would be +SELECT * FROM users WHERE username = ''; DROP ALL TABLES -- ''

    diff --git a/python/ql/src/Security/CWE-089/examples/sql_injection.py b/python/ql/src/Security/CWE-089/examples/sql_injection.py index 541c580f712..fe6dbc50c01 100644 --- a/python/ql/src/Security/CWE-089/examples/sql_injection.py +++ b/python/ql/src/Security/CWE-089/examples/sql_injection.py @@ -1,21 +1,19 @@ - -from django.conf.urls import patterns, url +from django.conf.urls import url from django.db import connection -def save_name(request): +def show_user(request, username): + with connection.cursor() as cursor: + # BAD -- Using string formatting + cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) + user = cursor.fetchone() - if request.method == 'POST': - name = request.POST.get('name') - curs = connection.cursor() - #BAD -- Using string formatting - curs.execute( - "insert into names_file ('name') values ('%s')" % name) - #GOOD -- Using parameters - curs.execute( - "insert into names_file ('name') values ('%s')", name) + # GOOD -- Using parameters + cursor.execute("SELECT * FROM users WHERE username = %s", username) + user = cursor.fetchone() + # BAD -- Manually quoting placeholder (%s) + cursor.execute("SELECT * FROM users WHERE username = '%s'", username) + user = cursor.fetchone() -urlpatterns = patterns(url(r'^save_name/$', - upload, name='save_name')) - +urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)] diff --git a/python/ql/test/library-tests/web/django/Sinks.expected b/python/ql/test/library-tests/web/django/Sinks.expected index 7201a7a20a9..31a42364762 100644 --- a/python/ql/test/library-tests/web/django/Sinks.expected +++ b/python/ql/test/library-tests/web/django/Sinks.expected @@ -1,10 +1,13 @@ -| test.py:18 | Str | externally controlled string | +| test.py:14 | Str | externally controlled string | +| test.py:15 | Str | externally controlled string | +| test.py:18 | BinaryExpr | externally controlled string | | test.py:21 | BinaryExpr | externally controlled string | -| test.py:24 | BinaryExpr | externally controlled string | -| test.py:25 | BinaryExpr | externally controlled string | -| test.py:26 | BinaryExpr | externally controlled string | -| test.py:34 | BinaryExpr | externally controlled string | -| test.py:46 | Attribute() | externally controlled string | -| test.py:57 | Attribute() | externally controlled string | -| test.py:60 | Attribute() | externally controlled string | -| test.py:63 | Attribute() | externally controlled string | +| test.py:22 | BinaryExpr | externally controlled string | +| test.py:23 | BinaryExpr | externally controlled string | +| test.py:37 | Str | externally controlled string | +| test.py:44 | BinaryExpr | externally controlled string | +| test.py:48 | Attribute() | externally controlled string | +| test.py:59 | Attribute() | externally controlled string | +| test.py:70 | Attribute() | externally controlled string | +| test.py:73 | Attribute() | externally controlled string | +| test.py:76 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/Sources.expected b/python/ql/test/library-tests/web/django/Sources.expected index 7482f21cdda..371b1e7cb6f 100644 --- a/python/ql/test/library-tests/web/django/Sources.expected +++ b/python/ql/test/library-tests/web/django/Sources.expected @@ -1,11 +1,17 @@ | test.py:11 | request | django.request.HttpRequest | -| test.py:31 | request | django.request.HttpRequest | -| test.py:56 | arg0 | externally controlled string | -| test.py:56 | request | django.request.HttpRequest | -| test.py:59 | arg0 | externally controlled string | -| test.py:59 | arg1 | externally controlled string | -| test.py:59 | arg2 | externally controlled string | -| test.py:59 | request | django.request.HttpRequest | -| test.py:62 | arg0 | externally controlled string | -| test.py:62 | arg1 | externally controlled string | -| test.py:62 | request | django.request.HttpRequest | +| test.py:11 | username | externally controlled string | +| test.py:41 | request | django.request.HttpRequest | +| test.py:47 | bar | externally controlled string | +| test.py:47 | foo | externally controlled string | +| test.py:47 | request | django.request.HttpRequest | +| test.py:58 | page_number | externally controlled string | +| test.py:58 | request | django.request.HttpRequest | +| test.py:69 | arg0 | externally controlled string | +| test.py:69 | request | django.request.HttpRequest | +| test.py:72 | arg0 | externally controlled string | +| test.py:72 | arg1 | externally controlled string | +| test.py:72 | arg2 | externally controlled string | +| test.py:72 | request | django.request.HttpRequest | +| test.py:75 | arg0 | externally controlled string | +| test.py:75 | arg1 | externally controlled string | +| test.py:75 | request | django.request.HttpRequest | diff --git a/python/ql/test/library-tests/web/django/test.py b/python/ql/test/library-tests/web/django/test.py index 3cabac0e5c5..1240b9ae5a1 100644 --- a/python/ql/test/library-tests/web/django/test.py +++ b/python/ql/test/library-tests/web/django/test.py @@ -5,28 +5,38 @@ from django.db.models.expressions import RawSQL from django.http.response import HttpResponse import base64 -class Name(models.Model): +class User(models.Model): pass -def save_name(request): +def show_user(request, username): + with connection.cursor() as cursor: + # GOOD -- Using parameters + cursor.execute("SELECT * FROM users WHERE username = %s", username) + User.objects.raw("SELECT * FROM users WHERE username = %s", (username,)) - if request.method == 'POST': - name = request.POST.get('name') - curs = connection.cursor() - #GOOD -- Using parameters - curs.execute( - "insert into names_file ('name') values ('%s')", name) - #BAD -- Using string formatting - curs.execute( - "insert into names_file ('name') values ('%s')" % name) + # BAD -- Using string formatting + cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) - #BAD -- other ways of executing raw SQL code with string interpolation - Name.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % name)) - Name.objects.raw("insert into names_file ('name') values ('%s')" % name) - Name.objects.extra("insert into names_file ('name') values ('%s')" % name) + # BAD -- other ways of executing raw SQL code with string interpolation + User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) + User.objects.raw("insert into names_file ('name') values ('%s')" % username) + User.objects.extra("insert into names_file ('name') values ('%s')" % username) -urlpatterns1 = patterns(url(r'^save_name/$', - save_name, name='save_name')) + # BAD (but currently no custom query to find this) + # + # It is exposed to SQL injection (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra) + # For example, using name = "; DROP ALL TABLES -- " + # will result in SQL: SELECT * FROM name WHERE name = ''; DROP ALL TABLES -- '' + # + # This shouldn't be very widespread, since using a normal string will result in invalid SQL + # Using name = "example", will result in SQL: SELECT * FROM name WHERE name = ''example'' + # which in MySQL will give a syntax error + # + # When testing this out locally, none of the queries worked against SQLite3, but I could use + # the SQL injection against MySQL. + User.objects.raw("SELECT * FROM users WHERE username = '%s'", (username,)) + +urlpatterns = patterns(url(r'^users/(?P[^/]+)$', show_user)) def maybe_xss(request): first_name = request.POST.get('first_name', '') @@ -34,9 +44,12 @@ def maybe_xss(request): resp.write("first name is " + first_name) return resp +def xss_kwargs(request, foo, bar, baz=None): + return HttpResponse('xss_kwargs: {} {}'.format(foo, bar)) + urlpatterns = [ - # Route to code_execution - url(r'^maybe_xss$', maybe_xss, name='maybe_xss') + url(r'^maybe_xss$', maybe_xss, name='maybe_xss'), + url(r'^bar/(?P[^/]+)/foo/(?P[^/]+)', xss_kwargs, name='xss_kwargs'), ] diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected index 9c00ffdb2db..461d42fccf1 100644 --- a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -1,17 +1,14 @@ edges -| sql_injection.py:9:15:9:21 | django.request.HttpRequest | sql_injection.py:12:16:12:22 | django.request.HttpRequest | -| sql_injection.py:12:16:12:22 | django.request.HttpRequest | sql_injection.py:12:16:12:27 | django.http.request.QueryDict | -| sql_injection.py:12:16:12:27 | django.http.request.QueryDict | sql_injection.py:12:16:12:39 | externally controlled string | -| sql_injection.py:12:16:12:39 | externally controlled string | sql_injection.py:19:63:19:66 | externally controlled string | -| sql_injection.py:12:16:12:39 | externally controlled string | sql_injection.py:22:88:22:91 | externally controlled string | -| sql_injection.py:12:16:12:39 | externally controlled string | sql_injection.py:23:76:23:79 | externally controlled string | -| sql_injection.py:12:16:12:39 | externally controlled string | sql_injection.py:24:78:24:81 | externally controlled string | -| sql_injection.py:19:63:19:66 | externally controlled string | sql_injection.py:19:13:19:66 | externally controlled string | -| sql_injection.py:22:88:22:91 | externally controlled string | sql_injection.py:22:38:22:91 | externally controlled string | -| sql_injection.py:23:76:23:79 | externally controlled string | sql_injection.py:23:26:23:79 | externally controlled string | -| sql_injection.py:24:78:24:81 | externally controlled string | sql_injection.py:24:28:24:81 | externally controlled string | +| sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:19:70:19:77 | externally controlled string | +| sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:22:88:22:95 | externally controlled string | +| sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:23:76:23:83 | externally controlled string | +| sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:24:78:24:85 | externally controlled string | +| sql_injection.py:19:70:19:77 | externally controlled string | sql_injection.py:19:24:19:77 | externally controlled string | +| sql_injection.py:22:88:22:95 | externally controlled string | sql_injection.py:22:38:22:95 | externally controlled string | +| sql_injection.py:23:76:23:83 | externally controlled string | sql_injection.py:23:26:23:83 | externally controlled string | +| sql_injection.py:24:78:24:85 | externally controlled string | sql_injection.py:24:28:24:85 | externally controlled string | #select -| sql_injection.py:19:13:19:66 | BinaryExpr | sql_injection.py:9:15:9:21 | django.request.HttpRequest | sql_injection.py:19:13:19:66 | externally controlled string | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | request | a user-provided value | -| sql_injection.py:22:38:22:91 | BinaryExpr | sql_injection.py:9:15:9:21 | django.request.HttpRequest | sql_injection.py:22:38:22:91 | externally controlled string | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | request | a user-provided value | -| sql_injection.py:23:26:23:79 | BinaryExpr | sql_injection.py:9:15:9:21 | django.request.HttpRequest | sql_injection.py:23:26:23:79 | externally controlled string | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | request | a user-provided value | -| sql_injection.py:24:28:24:81 | BinaryExpr | sql_injection.py:9:15:9:21 | django.request.HttpRequest | sql_injection.py:24:28:24:81 | externally controlled string | This SQL query depends on $@. | sql_injection.py:9:15:9:21 | request | a user-provided value | +| sql_injection.py:19:24:19:77 | BinaryExpr | sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:19:24:19:77 | externally controlled string | This SQL query depends on $@. | sql_injection.py:12:24:12:31 | username | a user-provided value | +| sql_injection.py:22:38:22:95 | BinaryExpr | sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:22:38:22:95 | externally controlled string | This SQL query depends on $@. | sql_injection.py:12:24:12:31 | username | a user-provided value | +| sql_injection.py:23:26:23:83 | BinaryExpr | sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:23:26:23:83 | externally controlled string | This SQL query depends on $@. | sql_injection.py:12:24:12:31 | username | a user-provided value | +| sql_injection.py:24:28:24:85 | BinaryExpr | sql_injection.py:12:24:12:31 | externally controlled string | sql_injection.py:24:28:24:85 | externally controlled string | This SQL query depends on $@. | sql_injection.py:12:24:12:31 | username | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-089/sql_injection.py b/python/ql/test/query-tests/Security/CWE-089/sql_injection.py index b312241b809..9ccca7503bd 100644 --- a/python/ql/test/query-tests/Security/CWE-089/sql_injection.py +++ b/python/ql/test/query-tests/Security/CWE-089/sql_injection.py @@ -1,28 +1,40 @@ +"""This is copied from ql/python/ql/test/library-tests/web/django/test.py +and a only a slight extension of ql/python/ql/src/Security/CWE-089/examples/sql_injection.py +""" -from django.conf.urls import patterns, url +from django.conf.urls import url from django.db import connection, models from django.db.models.expressions import RawSQL -class Name(models.Model): +class User(models.Model): pass -def save_name(request): +def show_user(request, username): + with connection.cursor() as cursor: + # GOOD -- Using parameters + cursor.execute("SELECT * FROM users WHERE username = %s", username) + User.objects.raw("SELECT * FROM users WHERE username = %s", (username,)) - if request.method == 'POST': - name = request.POST.get('name') - curs = connection.cursor() - #GOOD -- Using parameters - curs.execute( - "insert into names_file ('name') values ('%s')", name) - #BAD -- Using string formatting - curs.execute( - "insert into names_file ('name') values ('%s')" % name) + # BAD -- Using string formatting + cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) - #BAD -- other ways of executing raw SQL code with string interpolation - Name.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % name)) - Name.objects.raw("insert into names_file ('name') values ('%s')" % name) - Name.objects.extra("insert into names_file ('name') values ('%s')" % name) + # BAD -- other ways of executing raw SQL code with string interpolation + User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) + User.objects.raw("insert into names_file ('name') values ('%s')" % username) + User.objects.extra("insert into names_file ('name') values ('%s')" % username) -urlpatterns = patterns(url(r'^save_name/$', - save_name, name='save_name')) + # BAD (but currently no custom query to find this) + # + # It is exposed to SQL injection (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra) + # For example, using name = "; DROP ALL TABLES -- " + # will result in SQL: SELECT * FROM name WHERE name = ''; DROP ALL TABLES -- '' + # + # This shouldn't be very widespread, since using a normal string will result in invalid SQL + # Using name = "example", will result in SQL: SELECT * FROM name WHERE name = ''example'' + # which in MySQL will give a syntax error + # + # When testing this out locally, none of the queries worked against SQLite3, but I could use + # the SQL injection against MySQL. + User.objects.raw("SELECT * FROM users WHERE username = '%s'", (username,)) +urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)] From 91f269ed7b873cc7fc329f562a99552297467a0e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 15 Oct 2019 16:44:26 +0200 Subject: [PATCH 061/148] Python: Remove unused django sinks This would find instances of `thing = MyThing.objects.get(field=userinput)`, and what seems to be a query that wants to match on `thing = MyThing(); thing.field=userinput`. Both are not vulnerable to user-input, due to the build-in escaping by django. The DjangoModelFieldWrite actually matches on `MyThing.field=userinput` and not `thing.field=userinput`. I suspect this to be a mistake. Matching on `thing.field=userinput`, would require this CodeQL: attr.getObject(_).pointsTo().getClass() = model --- .../ql/src/semmle/python/web/django/Model.qll | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index 34cf5856802..b8f47b64bdf 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -54,33 +54,6 @@ class DjangoModelObjects extends TaintSource { override string toString() { result = "django.db.models.Model.objects" } } -/** A write to a field of a django model, which is a vulnerable to external data. */ -class DjangoModelFieldWrite extends SqlInjectionSink { - DjangoModelFieldWrite() { - exists(AttrNode attr, DjangoModel model | - this = attr and attr.isStore() and attr.getObject(_).pointsTo(model) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django model field write" } -} - -/** A direct reference to a django model object, which is vulnerable to external data. */ -class DjangoModelDirectObjectReference extends TaintSink { - DjangoModelDirectObjectReference() { - exists(CallNode objects_get_call, ControlFlowNode objects | this = objects_get_call.getAnArg() | - objects_get_call.getFunction().(AttrNode).getObject("get") = objects and - any(DjangoDbTableObjects objs).taints(objects) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django model object reference" } -} - /** * A call to the `raw` method on a django model. This allows a raw SQL query * to be sent to the database, which is a security risk. From fb864b7262ec63ed695edf8fd084f6eb1b124da1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Oct 2019 16:39:55 +0200 Subject: [PATCH 062/148] Python: Consolidate tests for django The tests in 3/ was not Python 3 specific anymore --- .../3/library-tests/web/django/Sinks.expected | 6 -- .../test/3/library-tests/web/django/Sinks.ql | 13 --- .../library-tests/web/django/Sources.expected | 8 -- .../3/library-tests/web/django/Sources.ql | 12 --- .../3/library-tests/web/django/Taint.expected | 24 ------ .../test/3/library-tests/web/django/Taint.ql | 14 --- .../web/django/django/__init__.py | 1 - .../web/django/django/conf/__init__.py | 1 - .../web/django/django/conf/urls.py | 3 - .../web/django/django/db/__init__.py | 1 - .../web/django/django/db/models/__init__.py | 2 - .../django/django/db/models/expressions.py | 2 - .../web/django/django/http/__init__.py | 2 - .../web/django/django/http/response.py | 5 -- .../test/3/library-tests/web/django/models.py | 10 --- .../test/3/library-tests/web/django/rawsql.py | 23 ----- .../test/3/library-tests/web/django/urls.py | 9 -- .../test/3/library-tests/web/django/views.py | 19 ---- python/ql/test/3/library-tests/web/options | 1 - .../library-tests/web/django/Sinks.expected | 28 +++--- .../library-tests/web/django/Sources.expected | 32 +++---- .../ql/test/library-tests/web/django/sql.py | 53 ++++++++++++ .../ql/test/library-tests/web/django/test.py | 86 +++---------------- .../ql/test/library-tests/web/django/views.py | 65 ++++++++++++++ .../Security/lib/django/conf/urls.py | 5 +- 25 files changed, 161 insertions(+), 264 deletions(-) delete mode 100644 python/ql/test/3/library-tests/web/django/Sinks.expected delete mode 100644 python/ql/test/3/library-tests/web/django/Sinks.ql delete mode 100644 python/ql/test/3/library-tests/web/django/Sources.expected delete mode 100644 python/ql/test/3/library-tests/web/django/Sources.ql delete mode 100644 python/ql/test/3/library-tests/web/django/Taint.expected delete mode 100644 python/ql/test/3/library-tests/web/django/Taint.ql delete mode 100644 python/ql/test/3/library-tests/web/django/django/__init__.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/conf/__init__.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/conf/urls.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/db/__init__.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/db/models/__init__.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/db/models/expressions.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/http/__init__.py delete mode 100644 python/ql/test/3/library-tests/web/django/django/http/response.py delete mode 100644 python/ql/test/3/library-tests/web/django/models.py delete mode 100644 python/ql/test/3/library-tests/web/django/rawsql.py delete mode 100644 python/ql/test/3/library-tests/web/django/urls.py delete mode 100644 python/ql/test/3/library-tests/web/django/views.py delete mode 100644 python/ql/test/3/library-tests/web/options create mode 100644 python/ql/test/library-tests/web/django/sql.py create mode 100644 python/ql/test/library-tests/web/django/views.py diff --git a/python/ql/test/3/library-tests/web/django/Sinks.expected b/python/ql/test/3/library-tests/web/django/Sinks.expected deleted file mode 100644 index b4142a2d82a..00000000000 --- a/python/ql/test/3/library-tests/web/django/Sinks.expected +++ /dev/null @@ -1,6 +0,0 @@ -| models.py:9 | key | externally controlled string | -| rawsql.py:4 | BinaryExpr | externally controlled string | -| rawsql.py:13 | BinaryExpr | externally controlled string | -| rawsql.py:18 | BinaryExpr | externally controlled string | -| rawsql.py:22 | BinaryExpr | externally controlled string | -| views.py:8 | Attribute() | externally controlled string | diff --git a/python/ql/test/3/library-tests/web/django/Sinks.ql b/python/ql/test/3/library-tests/web/django/Sinks.ql deleted file mode 100644 index db9b6a89b93..00000000000 --- a/python/ql/test/3/library-tests/web/django/Sinks.ql +++ /dev/null @@ -1,13 +0,0 @@ - -import python - - -import semmle.python.web.django.Request -import semmle.python.web.django.Model -import semmle.python.web.django.Db -import semmle.python.web.django.Response -import semmle.python.security.strings.Untrusted - -from TaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind.toString() diff --git a/python/ql/test/3/library-tests/web/django/Sources.expected b/python/ql/test/3/library-tests/web/django/Sources.expected deleted file mode 100644 index 965142343dc..00000000000 --- a/python/ql/test/3/library-tests/web/django/Sources.expected +++ /dev/null @@ -1,8 +0,0 @@ -| models.py:9 | Attribute | django.db.models.Model.objects | -| rawsql.py:13 | Attribute | django.db.models.Model.objects | -| rawsql.py:16 | Attribute | django.db.models.Model.objects | -| rawsql.py:21 | Attribute | django.db.models.Model.objects | -| views.py:6 | request | django.request.HttpRequest | -| views.py:8 | HttpResponse() | django.response.HttpResponse | -| views.py:11 | path | externally controlled string | -| views.py:11 | request | django.request.HttpRequest | diff --git a/python/ql/test/3/library-tests/web/django/Sources.ql b/python/ql/test/3/library-tests/web/django/Sources.ql deleted file mode 100644 index 60d42cb2ac1..00000000000 --- a/python/ql/test/3/library-tests/web/django/Sources.ql +++ /dev/null @@ -1,12 +0,0 @@ - -import python - - -import semmle.python.web.django.Request -import semmle.python.web.django.Model -import semmle.python.web.django.Response -import semmle.python.security.strings.Untrusted - -from TaintSource src, TaintKind kind -where src.isSourceOf(kind) -select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind.toString() diff --git a/python/ql/test/3/library-tests/web/django/Taint.expected b/python/ql/test/3/library-tests/web/django/Taint.expected deleted file mode 100644 index 3f40979c8a2..00000000000 --- a/python/ql/test/3/library-tests/web/django/Taint.expected +++ /dev/null @@ -1,24 +0,0 @@ -| models.py:9 | Attribute | django.db.models.Model.objects | -| rawsql.py:13 | Attribute | django.db.models.Model.objects | -| rawsql.py:13 | Attribute() | django.db.models.Model.objects | -| rawsql.py:16 | Attribute | django.db.models.Model.objects | -| rawsql.py:16 | Attribute() | django.db.models.Model.objects | -| rawsql.py:17 | Attribute() | django.db.models.Model.objects | -| rawsql.py:17 | m | django.db.models.Model.objects | -| rawsql.py:18 | Attribute() | django.db.models.Model.objects | -| rawsql.py:18 | m | django.db.models.Model.objects | -| rawsql.py:21 | Attribute | django.db.models.Model.objects | -| rawsql.py:21 | Attribute() | django.db.models.Model.objects | -| rawsql.py:22 | Attribute() | django.db.models.Model.objects | -| rawsql.py:22 | m | django.db.models.Model.objects | -| views.py:6 | request | django.request.HttpRequest | -| views.py:8 | Attribute | django.http.request.QueryDict | -| views.py:8 | Attribute() | externally controlled string | -| views.py:8 | HttpResponse() | django.response.HttpResponse | -| views.py:8 | request | django.request.HttpRequest | -| views.py:11 | path | externally controlled string | -| views.py:11 | request | django.request.HttpRequest | -| views.py:12 | Dict | {externally controlled string} | -| views.py:12 | path | externally controlled string | -| views.py:13 | env | {externally controlled string} | -| views.py:13 | request | django.request.HttpRequest | diff --git a/python/ql/test/3/library-tests/web/django/Taint.ql b/python/ql/test/3/library-tests/web/django/Taint.ql deleted file mode 100644 index b12a6560125..00000000000 --- a/python/ql/test/3/library-tests/web/django/Taint.ql +++ /dev/null @@ -1,14 +0,0 @@ - -import python - - -import semmle.python.web.django.Request -import semmle.python.web.django.Model -import semmle.python.web.django.Response -import semmle.python.security.strings.Untrusted - - -from TaintedNode node - -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind().toString() - diff --git a/python/ql/test/3/library-tests/web/django/django/__init__.py b/python/ql/test/3/library-tests/web/django/django/__init__.py deleted file mode 100644 index fc8d5b8c09b..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/__init__.py +++ /dev/null @@ -1 +0,0 @@ -#Fake django package \ No newline at end of file diff --git a/python/ql/test/3/library-tests/web/django/django/conf/__init__.py b/python/ql/test/3/library-tests/web/django/django/conf/__init__.py deleted file mode 100644 index fc8d5b8c09b..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/conf/__init__.py +++ /dev/null @@ -1 +0,0 @@ -#Fake django package \ No newline at end of file diff --git a/python/ql/test/3/library-tests/web/django/django/conf/urls.py b/python/ql/test/3/library-tests/web/django/django/conf/urls.py deleted file mode 100644 index 580cc063d99..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/conf/urls.py +++ /dev/null @@ -1,3 +0,0 @@ - -def url(regex, view): - pass \ No newline at end of file diff --git a/python/ql/test/3/library-tests/web/django/django/db/__init__.py b/python/ql/test/3/library-tests/web/django/django/db/__init__.py deleted file mode 100644 index fc8d5b8c09b..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/db/__init__.py +++ /dev/null @@ -1 +0,0 @@ -#Fake django package \ No newline at end of file diff --git a/python/ql/test/3/library-tests/web/django/django/db/models/__init__.py b/python/ql/test/3/library-tests/web/django/django/db/models/__init__.py deleted file mode 100644 index eb9c72adc45..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/db/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -class Model: - pass diff --git a/python/ql/test/3/library-tests/web/django/django/db/models/expressions.py b/python/ql/test/3/library-tests/web/django/django/db/models/expressions.py deleted file mode 100644 index d7e0d1c27b6..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/db/models/expressions.py +++ /dev/null @@ -1,2 +0,0 @@ -class RawSQL: - pass diff --git a/python/ql/test/3/library-tests/web/django/django/http/__init__.py b/python/ql/test/3/library-tests/web/django/django/http/__init__.py deleted file mode 100644 index e1a02f873cb..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/http/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from .response import HttpResponse diff --git a/python/ql/test/3/library-tests/web/django/django/http/response.py b/python/ql/test/3/library-tests/web/django/django/http/response.py deleted file mode 100644 index f3dd53d15b0..00000000000 --- a/python/ql/test/3/library-tests/web/django/django/http/response.py +++ /dev/null @@ -1,5 +0,0 @@ - -class HttpResponse: - - def __init__(self, *args): - pass diff --git a/python/ql/test/3/library-tests/web/django/models.py b/python/ql/test/3/library-tests/web/django/models.py deleted file mode 100644 index 571c594d055..00000000000 --- a/python/ql/test/3/library-tests/web/django/models.py +++ /dev/null @@ -1,10 +0,0 @@ - -from django.db import models - -class MyModel(models.Model): - title = models.CharField(max_length=500) - summary = models.TextField(blank=True) - -def update_my_model(key, title): - item = MyModel.objects.get(pk=key) - item.title = title diff --git a/python/ql/test/3/library-tests/web/django/rawsql.py b/python/ql/test/3/library-tests/web/django/rawsql.py deleted file mode 100644 index c6c82909c2d..00000000000 --- a/python/ql/test/3/library-tests/web/django/rawsql.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.db.models.expressions import RawSQL - -def raw1(arg): - return RawSQL("select foo from bar where baz = %s" % arg, "") - - -from django.db import models - -class MyModel(models.Model): - pass - -def raw2(arg): - MyModel.objects.raw("select foo from bar where baz = %s" % arg) - -def raw3(arg): - m = MyModel.objects.filter('foo') - m = m.filter('bar') - m.raw("select foo from bar where baz = %s" % arg) - -def raw4(arg): - m = MyModel.objects.filter('foo') - m.extra("select foo from bar where baz = %s" % arg) - diff --git a/python/ql/test/3/library-tests/web/django/urls.py b/python/ql/test/3/library-tests/web/django/urls.py deleted file mode 100644 index d5a941ae519..00000000000 --- a/python/ql/test/3/library-tests/web/django/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.conf.urls import url -import views - -urlpatterns = [ - - url(r'^route1$', views.view_func1), - url(r'^(?P.*)$', views.view_func2), - url(r'^route2$', views.ClassView.as_view()) -] diff --git a/python/ql/test/3/library-tests/web/django/views.py b/python/ql/test/3/library-tests/web/django/views.py deleted file mode 100644 index f7de60a23f6..00000000000 --- a/python/ql/test/3/library-tests/web/django/views.py +++ /dev/null @@ -1,19 +0,0 @@ - -from django.http import HttpResponse -from django.shortcuts import redirect, render -from django.views.generic import View - -def view_func1(request): - # Whether this is safe depends on template.html -- annoyingly - return HttpResponse(request.GET.get("untrusted")) - - -def view_func2(request, path='default'): - env = {'path': path} - return render(request, 'vulnerable-path.html', env) - - -class ClassView(View): - - def get(self, request): - pass diff --git a/python/ql/test/3/library-tests/web/options b/python/ql/test/3/library-tests/web/options deleted file mode 100644 index f2d60a4bc3c..00000000000 --- a/python/ql/test/3/library-tests/web/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 --lang=3 diff --git a/python/ql/test/library-tests/web/django/Sinks.expected b/python/ql/test/library-tests/web/django/Sinks.expected index 31a42364762..86e05bca6dc 100644 --- a/python/ql/test/library-tests/web/django/Sinks.expected +++ b/python/ql/test/library-tests/web/django/Sinks.expected @@ -1,13 +1,15 @@ -| test.py:14 | Str | externally controlled string | -| test.py:15 | Str | externally controlled string | -| test.py:18 | BinaryExpr | externally controlled string | -| test.py:21 | BinaryExpr | externally controlled string | -| test.py:22 | BinaryExpr | externally controlled string | -| test.py:23 | BinaryExpr | externally controlled string | -| test.py:37 | Str | externally controlled string | -| test.py:44 | BinaryExpr | externally controlled string | -| test.py:48 | Attribute() | externally controlled string | -| test.py:59 | Attribute() | externally controlled string | -| test.py:70 | Attribute() | externally controlled string | -| test.py:73 | Attribute() | externally controlled string | -| test.py:76 | Attribute() | externally controlled string | +| sql.py:13 | Str | externally controlled string | +| sql.py:14 | Str | externally controlled string | +| sql.py:17 | BinaryExpr | externally controlled string | +| sql.py:20 | BinaryExpr | externally controlled string | +| sql.py:21 | BinaryExpr | externally controlled string | +| sql.py:22 | BinaryExpr | externally controlled string | +| sql.py:36 | Str | externally controlled string | +| sql.py:42 | BinaryExpr | externally controlled string | +| sql.py:47 | BinaryExpr | externally controlled string | +| views.py:7 | Attribute() | externally controlled string | +| views.py:11 | Attribute() | externally controlled string | +| views.py:15 | Attribute() | externally controlled string | +| views.py:22 | Attribute() | externally controlled string | +| views.py:27 | Attribute() | externally controlled string | +| views.py:31 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/Sources.expected b/python/ql/test/library-tests/web/django/Sources.expected index 371b1e7cb6f..a0c253b27c5 100644 --- a/python/ql/test/library-tests/web/django/Sources.expected +++ b/python/ql/test/library-tests/web/django/Sources.expected @@ -1,17 +1,17 @@ +| test.py:5 | path | externally controlled string | +| test.py:5 | request | django.request.HttpRequest | +| test.py:11 | path | externally controlled string | | test.py:11 | request | django.request.HttpRequest | -| test.py:11 | username | externally controlled string | -| test.py:41 | request | django.request.HttpRequest | -| test.py:47 | bar | externally controlled string | -| test.py:47 | foo | externally controlled string | -| test.py:47 | request | django.request.HttpRequest | -| test.py:58 | page_number | externally controlled string | -| test.py:58 | request | django.request.HttpRequest | -| test.py:69 | arg0 | externally controlled string | -| test.py:69 | request | django.request.HttpRequest | -| test.py:72 | arg0 | externally controlled string | -| test.py:72 | arg1 | externally controlled string | -| test.py:72 | arg2 | externally controlled string | -| test.py:72 | request | django.request.HttpRequest | -| test.py:75 | arg0 | externally controlled string | -| test.py:75 | arg1 | externally controlled string | -| test.py:75 | request | django.request.HttpRequest | +| views.py:6 | bar | externally controlled string | +| views.py:6 | foo | externally controlled string | +| views.py:6 | request | django.request.HttpRequest | +| views.py:10 | request | django.request.HttpRequest | +| views.py:14 | request | django.request.HttpRequest | +| views.py:25 | page_number | externally controlled string | +| views.py:25 | request | django.request.HttpRequest | +| views.py:30 | arg0 | externally controlled string | +| views.py:30 | arg1 | externally controlled string | +| views.py:30 | request | django.request.HttpRequest | +| views.py:50 | request | django.request.HttpRequest | +| views.py:50 | username | externally controlled string | +| views.py:59 | request | django.request.HttpRequest | diff --git a/python/ql/test/library-tests/web/django/sql.py b/python/ql/test/library-tests/web/django/sql.py new file mode 100644 index 00000000000..7809c24edc1 --- /dev/null +++ b/python/ql/test/library-tests/web/django/sql.py @@ -0,0 +1,53 @@ +from django.db import connection, models +from django.db.models.expressions import RawSQL + + +class User(models.Model): + username = models.CharField(max_length=100) + description = models.TextField(blank=True) + + +def show_user(username): + with connection.cursor() as cursor: + # GOOD -- Using parameters + cursor.execute("SELECT * FROM users WHERE username = %s", username) + User.objects.raw("SELECT * FROM users WHERE username = %s", (username,)) + + # BAD -- Using string formatting + cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) + + # BAD -- other ways of executing raw SQL code with string interpolation + User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) + User.objects.raw("insert into names_file ('name') values ('%s')" % username) + User.objects.extra("insert into names_file ('name') values ('%s')" % username) + + # BAD (but currently no custom query to find this) + # + # It is exposed to SQL injection (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra) + # For example, using name = "; DROP ALL TABLES -- " + # will result in SQL: SELECT * FROM name WHERE name = ''; DROP ALL TABLES -- '' + # + # This shouldn't be very widespread, since using a normal string will result in invalid SQL + # Using name = "example", will result in SQL: SELECT * FROM name WHERE name = ''example'' + # which in MySQL will give a syntax error + # + # When testing this out locally, none of the queries worked against SQLite3, but I could use + # the SQL injection against MySQL. + User.objects.raw("SELECT * FROM users WHERE username = '%s'", (username,)) + + +def raw3(arg): + m = User.objects.filter('foo') + m = m.filter('bar') + m.raw("select foo from bar where baz = %s" % arg) + + +def raw4(arg): + m = User.objects.filter('foo') + m.extra("select foo from bar where baz = %s" % arg) + + +def update_user(key, description1): + # Neither of these are exposed to sql-injections + user = User.objects.get(pk=key) + item.description = description diff --git a/python/ql/test/library-tests/web/django/test.py b/python/ql/test/library-tests/web/django/test.py index 1240b9ae5a1..5664647c3a7 100644 --- a/python/ql/test/library-tests/web/django/test.py +++ b/python/ql/test/library-tests/web/django/test.py @@ -1,84 +1,18 @@ +from django.conf.urls import url +from django.shortcuts import redirect, render -from django.conf.urls import patterns, url -from django.db import connection, models -from django.db.models.expressions import RawSQL -from django.http.response import HttpResponse -import base64 -class User(models.Model): - pass +def with_template(request, path='default'): + env = {'path': path} + # We would need to understand django templates to know if this is safe or not + return render(request, 'possibly-vulnerable-template.html', env) -def show_user(request, username): - with connection.cursor() as cursor: - # GOOD -- Using parameters - cursor.execute("SELECT * FROM users WHERE username = %s", username) - User.objects.raw("SELECT * FROM users WHERE username = %s", (username,)) - # BAD -- Using string formatting - cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) +def vuln_redirect(request, path): + return redirect(path) - # BAD -- other ways of executing raw SQL code with string interpolation - User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) - User.objects.raw("insert into names_file ('name') values ('%s')" % username) - User.objects.extra("insert into names_file ('name') values ('%s')" % username) - - # BAD (but currently no custom query to find this) - # - # It is exposed to SQL injection (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra) - # For example, using name = "; DROP ALL TABLES -- " - # will result in SQL: SELECT * FROM name WHERE name = ''; DROP ALL TABLES -- '' - # - # This shouldn't be very widespread, since using a normal string will result in invalid SQL - # Using name = "example", will result in SQL: SELECT * FROM name WHERE name = ''example'' - # which in MySQL will give a syntax error - # - # When testing this out locally, none of the queries worked against SQLite3, but I could use - # the SQL injection against MySQL. - User.objects.raw("SELECT * FROM users WHERE username = '%s'", (username,)) - -urlpatterns = patterns(url(r'^users/(?P[^/]+)$', show_user)) - -def maybe_xss(request): - first_name = request.POST.get('first_name', '') - resp = HttpResponse() - resp.write("first name is " + first_name) - return resp - -def xss_kwargs(request, foo, bar, baz=None): - return HttpResponse('xss_kwargs: {} {}'.format(foo, bar)) urlpatterns = [ - url(r'^maybe_xss$', maybe_xss, name='maybe_xss'), - url(r'^bar/(?P[^/]+)/foo/(?P[^/]+)', xss_kwargs, name='xss_kwargs'), -] - - -# Non capturing group (we correctly identify page_number as a request parameter) - -def show_articles(request, page_number=1): - return HttpResponse('articles page: {}'.format(page_number)) - -urlpatterns = [ - # one pattern to support `articles/page-` and ensuring that articles/ goes to page-1 - url(r'articles/^(?:page-(?P\d+)/)?$', show_articles), -] - - -# Positional arguments - -def xxs_positional_arg1(request, arg0): - return HttpResponse('xxs_positional_arg1: {}'.format(arg0)) - -def xxs_positional_arg2(request, arg0, arg1, arg2): - return HttpResponse('xxs_positional_arg2: {} {} {}'.format(arg0, arg1, arg2)) - -def xxs_positional_arg3(request, arg0, arg1): - return HttpResponse('xxs_positional_arg3: {} {}'.format(arg0, arg1)) - -urlpatterns = [ - # passing as positional argument is not the recommended way of doing things, - # but it is certainly possible - url(r'^(.+)$', xxs_positional_arg1, name='xxs_positional_arg1'), - url(r'^([^/]+)/([^/]+)/([^/]+)$', xxs_positional_arg2, name='xxs_positional_arg2'), - url(r'^([^/]+)/(?:foo|bar)/([^/]+)$', xxs_positional_arg3, name='xxs_positional_arg3'), + url(r'^(?P.*)$', with_template), + url(r'^redirect/(?P.*)$', vuln_redirect), ] diff --git a/python/ql/test/library-tests/web/django/views.py b/python/ql/test/library-tests/web/django/views.py new file mode 100644 index 00000000000..ffa49118785 --- /dev/null +++ b/python/ql/test/library-tests/web/django/views.py @@ -0,0 +1,65 @@ +from django.conf.urls import patterns, url +from django.http.response import HttpResponse +from django.views.generic import View + + +def url_match_xss(request, foo, bar, no_taint=None): + return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) + + +def get_params_xss(request): + return HttpResponse(request.GET.get("untrusted")) + + +def post_params_xss(request): + return HttpResponse(request.POST.get("untrusted")) + + +class ClassView(View): + + # TODO: Currently we don't flag `untrusted` as a DjangoRequestParameter + def get(self, request, untrusted): + return HttpResponse('ClassView: {}'.format(untrusted)) + + +def show_articles(request, page_number=1): + page_number = int(page_number) + return HttpResponse('articles page: {}'.format(page_number)) + + +def xxs_positional_arg(request, arg0, arg1, no_taint=None): + return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) + + +urlpatterns = [ + url(r'^url_match/(?P[^/]+)/(?P[^/]+)$', url_match_xss), + url(r'^get_params$', get_params_xss), + url(r'^post_params$', post_params_xss), + url(r'^class_view/(?P.+)$', ClassView.as_view()), + + # one pattern to support `articles/page-` and ensuring that articles/ goes to page-1 + url(r'articles/^(?:page-(?P\d+)/)?$', show_articles), + # passing as positional argument is not the recommended way of doing things, but it is certainly + # possible + url(r'^([^/]+)/(?:foo|bar)/([^/]+)$', xxs_positional_arg, name='xxs_positional_arg'), +] + + +# Using patterns() for routing + +def show_user(request, username): + pass + + +urlpatterns = patterns(url(r'^users/(?P[^/]+)$', show_user)) + + +# Show we understand the keyword arguments to django.conf.urls.url + +def we_understand_url_kwargs(request): + pass + + +urlpatterns = [ + url(view=we_understand_url_kwargs, regex=r'^specifying-as-kwargs-is-not-a-problem$') +] diff --git a/python/ql/test/query-tests/Security/lib/django/conf/urls.py b/python/ql/test/query-tests/Security/lib/django/conf/urls.py index cf65525e893..6c1a83baf0b 100644 --- a/python/ql/test/query-tests/Security/lib/django/conf/urls.py +++ b/python/ql/test/query-tests/Security/lib/django/conf/urls.py @@ -1,7 +1,6 @@ - -def url(pattern, *args): +# https://docs.djangoproject.com/en/1.11/_modules/django/conf/urls/#url +def url(regex, view, kwargs=None, name=None): pass def patterns(*urls): pass - From fc851b46c3d41cda88ecfecd8c35821d96ac7222 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Oct 2019 16:44:35 +0200 Subject: [PATCH 063/148] Python: Fix Django class-based views --- .../src/semmle/python/web/django/Request.qll | 2 +- .../library-tests/web/django/Sinks.expected | 7 ++++--- .../library-tests/web/django/Sources.expected | 18 ++++++++++-------- .../ql/test/library-tests/web/django/views.py | 11 +++++++++-- .../Security/lib/django/views/__init__.py | 0 .../Security/lib/django/views/generic.py | 2 ++ 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 python/ql/test/query-tests/Security/lib/django/views/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/django/views/generic.py diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index 15ea032e6d7..24a29ea4542 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -67,7 +67,7 @@ private class DjangoView extends ClassValue { } private FunctionValue djangoViewHttpMethod() { - exists(DjangoView view | view.attr(httpVerbLower()) = result) + exists(DjangoView view | view.lookup(httpVerbLower()) = result) } class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { diff --git a/python/ql/test/library-tests/web/django/Sinks.expected b/python/ql/test/library-tests/web/django/Sinks.expected index 86e05bca6dc..e3d233c9990 100644 --- a/python/ql/test/library-tests/web/django/Sinks.expected +++ b/python/ql/test/library-tests/web/django/Sinks.expected @@ -10,6 +10,7 @@ | views.py:7 | Attribute() | externally controlled string | | views.py:11 | Attribute() | externally controlled string | | views.py:15 | Attribute() | externally controlled string | -| views.py:22 | Attribute() | externally controlled string | -| views.py:27 | Attribute() | externally controlled string | -| views.py:31 | Attribute() | externally controlled string | +| views.py:23 | Attribute() | externally controlled string | +| views.py:29 | Attribute() | externally controlled string | +| views.py:34 | Attribute() | externally controlled string | +| views.py:38 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/Sources.expected b/python/ql/test/library-tests/web/django/Sources.expected index a0c253b27c5..35e0d3d8ced 100644 --- a/python/ql/test/library-tests/web/django/Sources.expected +++ b/python/ql/test/library-tests/web/django/Sources.expected @@ -7,11 +7,13 @@ | views.py:6 | request | django.request.HttpRequest | | views.py:10 | request | django.request.HttpRequest | | views.py:14 | request | django.request.HttpRequest | -| views.py:25 | page_number | externally controlled string | -| views.py:25 | request | django.request.HttpRequest | -| views.py:30 | arg0 | externally controlled string | -| views.py:30 | arg1 | externally controlled string | -| views.py:30 | request | django.request.HttpRequest | -| views.py:50 | request | django.request.HttpRequest | -| views.py:50 | username | externally controlled string | -| views.py:59 | request | django.request.HttpRequest | +| views.py:22 | request | django.request.HttpRequest | +| views.py:28 | request | django.request.HttpRequest | +| views.py:32 | page_number | externally controlled string | +| views.py:32 | request | django.request.HttpRequest | +| views.py:37 | arg0 | externally controlled string | +| views.py:37 | arg1 | externally controlled string | +| views.py:37 | request | django.request.HttpRequest | +| views.py:57 | request | django.request.HttpRequest | +| views.py:57 | username | externally controlled string | +| views.py:66 | request | django.request.HttpRequest | diff --git a/python/ql/test/library-tests/web/django/views.py b/python/ql/test/library-tests/web/django/views.py index ffa49118785..57d1ea5460c 100644 --- a/python/ql/test/library-tests/web/django/views.py +++ b/python/ql/test/library-tests/web/django/views.py @@ -15,11 +15,18 @@ def post_params_xss(request): return HttpResponse(request.POST.get("untrusted")) -class ClassView(View): +class Foo(object): + # Note: since Foo is used as the super type in a class view, it will be able to handle requests. + # TODO: Currently we don't flag `untrusted` as a DjangoRequestParameter + def post(self, request, untrusted): + return HttpResponse('Foo post: {}'.format(untrusted)) + + +class ClassView(View, Foo): # TODO: Currently we don't flag `untrusted` as a DjangoRequestParameter def get(self, request, untrusted): - return HttpResponse('ClassView: {}'.format(untrusted)) + return HttpResponse('ClassView get: {}'.format(untrusted)) def show_articles(request, page_number=1): diff --git a/python/ql/test/query-tests/Security/lib/django/views/__init__.py b/python/ql/test/query-tests/Security/lib/django/views/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/django/views/generic.py b/python/ql/test/query-tests/Security/lib/django/views/generic.py new file mode 100644 index 00000000000..d924b03d062 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/django/views/generic.py @@ -0,0 +1,2 @@ +class View: + pass From 63f24476e96771b0d557d3b7c2c01c547068d511 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 08:29:10 +0000 Subject: [PATCH 064/148] JavaScript: Refactor `DoubleEscaping.ql`. --- .../ql/src/Security/CWE-116/DoubleEscaping.ql | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index a150a2d7a7a..124dcf304aa 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -62,30 +62,23 @@ predicate escapingScheme(string metachar, string regex) { } /** - * A call to `String.prototype.replace` that replaces all instances of a pattern. + * A method call that performs string replacement. */ -class Replacement extends DataFlow::Node { - RegExpLiteral pattern; - - Replacement() { - exists(DataFlow::MethodCallNode mcn | this = mcn | - mcn.getMethodName() = "replace" and - pattern.flow().(DataFlow::SourceNode).flowsTo(mcn.getArgument(0)) and - mcn.getNumArgument() = 2 and - pattern.isGlobal() - ) - } - +abstract class Replacement extends DataFlow::Node { /** * Holds if this replacement replaces the string `input` with `output`. */ - predicate replaces(string input, string output) { - exists(DataFlow::MethodCallNode mcn | - mcn = this and - input = getStringValue(pattern) and - output = mcn.getArgument(1).getStringValue() - ) - } + abstract predicate replaces(string input, string output); + + /** + * Gets the input of this replacement. + */ + abstract DataFlow::Node getInput(); + + /** + * Gets the output of this replacement. + */ + abstract DataFlow::SourceNode getOutput(); /** * Holds if this replacement escapes `char` using `metachar`. @@ -119,7 +112,7 @@ class Replacement extends DataFlow::Node { * Gets the previous replacement in this chain of replacements. */ Replacement getPreviousReplacement() { - result = getASimplePredecessor*(this.(DataFlow::MethodCallNode).getReceiver()) + result.getOutput() = getASimplePredecessor*(getInput()) } /** @@ -147,6 +140,33 @@ class Replacement extends DataFlow::Node { } } +/** + * A call to `String.prototype.replace` that replaces all instances of a pattern. + */ +class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode { + RegExpLiteral pattern; + + GlobalStringReplacement() { + this.getMethodName() = "replace" and + pattern.flow().(DataFlow::SourceNode).flowsTo(this.getArgument(0)) and + this.getNumArgument() = 2 and + pattern.isGlobal() + } + + override predicate replaces(string input, string output) { + input = getStringValue(pattern) and + output = this.getArgument(1).getStringValue() + } + + override DataFlow::Node getInput() { + result = this.getReceiver() + } + + override DataFlow::SourceNode getOutput() { + result = this + } +} + from Replacement primary, Replacement supplementary, string message, string metachar where primary.escapes(metachar, _) and From bd1c99d8a428770a12c90450ce3518854427b352 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 09:35:49 +0000 Subject: [PATCH 065/148] JavaScript: Recognise `JSON.stringify` and `JSON.parse` as escaper/unescaper. --- .../ql/src/Security/CWE-116/DoubleEscaping.ql | 46 +++++++++++++++++++ .../DoubleEscaping/DoubleEscaping.expected | 2 + .../Security/CWE-116/DoubleEscaping/tst.js | 20 ++++++++ 3 files changed, 68 insertions(+) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 124dcf304aa..589a935d5fe 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -167,6 +167,52 @@ class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode { } } +/** + * A call to `JSON.stringify`, viewed as a string replacement. + */ +class JsonStringifyReplacement extends Replacement, DataFlow::CallNode { + JsonStringifyReplacement() { + this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") + } + + override predicate replaces(string input, string output) { + input = "\\" and output = "\\\\" + // the other replacements are not relevant for this query + } + + override DataFlow::Node getInput() { + result = this.getArgument(0) + } + + override DataFlow::SourceNode getOutput() { + result = this + } +} + +/** + * A call to `JSON.parse`, viewed as a string replacement. + */ +class JsonParseReplacement extends Replacement { + JsonParserCall self; + + JsonParseReplacement() { + this = self + } + + override predicate replaces(string input, string output) { + input = "\\\\" and output = "\\" + // the other replacements are not relevant for this query + } + + override DataFlow::Node getInput() { + result = self.getInput() + } + + override DataFlow::SourceNode getOutput() { + result = self.getOutput() + } +} + from Replacement primary, Replacement supplementary, string message, string metachar where primary.escapes(metachar, _) and diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected index d4930ad07cf..e3d5a9a4252 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected @@ -5,3 +5,5 @@ | tst.js:53:10:53:33 | s.repla ... , '\\\\') | This replacement may produce '\\' characters that are double-unescaped $@. | tst.js:53:10:54:33 | s.repla ... , '\\'') | here | | tst.js:60:7:60:28 | s.repla ... '%25') | This replacement may double-escape '%' characters from $@. | tst.js:59:7:59:28 | s.repla ... '%26') | here | | tst.js:68:10:70:38 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:68:10:69:39 | s.repla ... apos;") | here | +| tst.js:74:10:77:10 | JSON.st ... ) | This replacement may double-escape '\\' characters from $@. | tst.js:75:12:76:37 | s.repla ... u003E") | here | +| tst.js:86:10:86:22 | JSON.parse(s) | This replacement may produce '\\' characters that are double-unescaped $@. | tst.js:86:10:86:47 | JSON.pa ... g, "<") | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index 19ab94d2691..ee9cd930b6f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -69,3 +69,23 @@ function badEncode(s) { .replace(indirect2, "'") .replace(indirect3, "&"); } + +function badEscape1(s) { + return JSON.stringify( + s.replace(//g, "\\u003E") + ); +} + +function goodEscape1(s) { + return JSON.stringify(s) + .replace(//g, "\\u003E"); +} + +function badUnescape2(s) { + return JSON.parse(s).replace(/\\u003C/g, "<").replace(/\\u003E/g, ">"); +} + +function goodUnescape2(s) { + return JSON.parse(s.replace(/\\u003C/g, "<").replace(/\\u003E/g, ">")); +} From 1e6c983d62ea4d96730841d5672a5277cdc378cd Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 30 Oct 2019 13:42:17 +0100 Subject: [PATCH 066/148] C++: Use getASTVariable in DefaultTaintTracking This library is not yet used in a query or test, so it broke silently when `VariableAddressInstruction.getVariable` was removed. --- cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 08556a4af39..0753dfd266e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -37,7 +37,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration { } private predicate accessesVariable(CopyInstruction copy, Variable var) { - exists(VariableAddressInstruction va | va.getVariable().getAST() = var | + exists(VariableAddressInstruction va | va.getASTVariable() = var | copy.(StoreInstruction).getDestinationAddress() = va or copy.(LoadInstruction).getSourceAddress() = va From aaeca325193deedc7ac8ea163cbe574514d44b94 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 09:55:28 +0000 Subject: [PATCH 067/148] JavaScript: Recognize string escaping using `.replace` with a callback. --- javascript/ql/src/Security/CWE-116/DoubleEscaping.ql | 8 ++++++++ .../CWE-116/DoubleEscaping/DoubleEscaping.expected | 1 + .../query-tests/Security/CWE-116/DoubleEscaping/tst.js | 9 +++++++++ 3 files changed, 18 insertions(+) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 589a935d5fe..4e6969e54c3 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -156,6 +156,14 @@ class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode { override predicate replaces(string input, string output) { input = getStringValue(pattern) and output = this.getArgument(1).getStringValue() + or + exists(DataFlow::FunctionNode replacer, DataFlow::PropRead pr, DataFlow::ObjectLiteralNode map | + replacer = getCallback(1) and + replacer.getParameter(0).flowsToExpr(pr.getPropertyNameExpr()) and + pr = map.getAPropertyRead() and + pr.flowsTo(replacer.getAReturn()) and + map.asExpr().(ObjectExpr).getPropertyByName(input).getInit().getStringValue() = output + ) } override DataFlow::Node getInput() { diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected index e3d5a9a4252..d7e2b558a06 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected @@ -7,3 +7,4 @@ | tst.js:68:10:70:38 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:68:10:69:39 | s.repla ... apos;") | here | | tst.js:74:10:77:10 | JSON.st ... ) | This replacement may double-escape '\\' characters from $@. | tst.js:75:12:76:37 | s.repla ... u003E") | here | | tst.js:86:10:86:22 | JSON.parse(s) | This replacement may produce '\\' characters that are double-unescaped $@. | tst.js:86:10:86:47 | JSON.pa ... g, "<") | here | +| tst.js:99:10:99:66 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:99:10:99:43 | s.repla ... epl[c]) | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index ee9cd930b6f..78c73ce9584 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -89,3 +89,12 @@ function badUnescape2(s) { function goodUnescape2(s) { return JSON.parse(s.replace(/\\u003C/g, "<").replace(/\\u003E/g, ">")); } + +function badEncodeWithReplacer(s) { + var repl = { + '"': """, + "'": "'", + "&": "&" + }; + return s.replace(/["']/g, (c) => repl[c]).replace(/&/g, "&"); +} From 02d16b1dc99ddbcb3b2c8148b0cb53731214b039 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 10:59:04 +0000 Subject: [PATCH 068/148] JavaScript: Recognise wrapped string replacement functions. --- .../ql/src/Security/CWE-116/DoubleEscaping.ql | 28 +++++++++++++++++++ .../DoubleEscaping/DoubleEscaping.expected | 1 + .../Security/CWE-116/DoubleEscaping/tst.js | 8 ++++++ 3 files changed, 37 insertions(+) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 4e6969e54c3..733afad0b06 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -221,6 +221,34 @@ class JsonParseReplacement extends Replacement { } } +/** + * A string replacement wrapped in a utility function. + */ +class WrappedReplacement extends Replacement, DataFlow::CallNode { + int i; + + Replacement inner; + + WrappedReplacement() { + exists(DataFlow::FunctionNode wrapped | wrapped.getFunction() = getACallee() | + wrapped.getParameter(i).flowsTo(inner.getInput()) and + inner.getOutput().flowsTo(wrapped.getAReturn()) + ) + } + + override predicate replaces(string input, string output) { + inner.replaces(input, output) + } + + override DataFlow::Node getInput() { + result = getArgument(i) + } + + override DataFlow::SourceNode getOutput() { + result = this + } +} + from Replacement primary, Replacement supplementary, string message, string metachar where primary.escapes(metachar, _) and diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected index d7e2b558a06..d0747087d12 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected @@ -8,3 +8,4 @@ | tst.js:74:10:77:10 | JSON.st ... ) | This replacement may double-escape '\\' characters from $@. | tst.js:75:12:76:37 | s.repla ... u003E") | here | | tst.js:86:10:86:22 | JSON.parse(s) | This replacement may produce '\\' characters that are double-unescaped $@. | tst.js:86:10:86:47 | JSON.pa ... g, "<") | here | | tst.js:99:10:99:66 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:99:10:99:43 | s.repla ... epl[c]) | here | +| tst.js:107:10:107:53 | encodeD ... &") | This replacement may double-escape '&' characters from $@. | tst.js:107:10:107:30 | encodeD ... otes(s) | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index 78c73ce9584..d88422e74a4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -98,3 +98,11 @@ function badEncodeWithReplacer(s) { }; return s.replace(/["']/g, (c) => repl[c]).replace(/&/g, "&"); } + +function encodeDoubleQuotes(s) { + return s.replace(/"/g, """); +} + +function badWrappedEncode(s) { + return encodeDoubleQuotes(s).replace(/&/g, "&"); +} From 5349e0f88142ae4e7a63038fa3238b5001e0972d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 13:02:59 +0000 Subject: [PATCH 069/148] JavaScript: Recognise wrapped chains of replacements. --- javascript/ql/src/Security/CWE-116/DoubleEscaping.ql | 11 +++++++++-- .../CWE-116/DoubleEscaping/DoubleEscaping.expected | 1 + .../Security/CWE-116/DoubleEscaping/tst.js | 8 ++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 733afad0b06..2fc91a9854d 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -115,6 +115,13 @@ abstract class Replacement extends DataFlow::Node { result.getOutput() = getASimplePredecessor*(getInput()) } + /** + * Gets the next replacement in this chain of replacements. + */ + Replacement getNextReplacement() { + this = result.getPreviousReplacement() + } + /** * Gets an earlier replacement in this chain of replacements that * performs an escaping. @@ -231,8 +238,8 @@ class WrappedReplacement extends Replacement, DataFlow::CallNode { WrappedReplacement() { exists(DataFlow::FunctionNode wrapped | wrapped.getFunction() = getACallee() | - wrapped.getParameter(i).flowsTo(inner.getInput()) and - inner.getOutput().flowsTo(wrapped.getAReturn()) + wrapped.getParameter(i).flowsTo(inner.getPreviousReplacement*().getInput()) and + inner.getNextReplacement*().getOutput().flowsTo(wrapped.getAReturn()) ) } diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected index d0747087d12..23e5a4a6b05 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected @@ -9,3 +9,4 @@ | tst.js:86:10:86:22 | JSON.parse(s) | This replacement may produce '\\' characters that are double-unescaped $@. | tst.js:86:10:86:47 | JSON.pa ... g, "<") | here | | tst.js:99:10:99:66 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:99:10:99:43 | s.repla ... epl[c]) | here | | tst.js:107:10:107:53 | encodeD ... &") | This replacement may double-escape '&' characters from $@. | tst.js:107:10:107:30 | encodeD ... otes(s) | here | +| tst.js:115:10:115:47 | encodeQ ... &") | This replacement may double-escape '&' characters from $@. | tst.js:115:10:115:24 | encodeQuotes(s) | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index d88422e74a4..628166ed04a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -106,3 +106,11 @@ function encodeDoubleQuotes(s) { function badWrappedEncode(s) { return encodeDoubleQuotes(s).replace(/&/g, "&"); } + +function encodeQuotes(s) { + return s.replace(/"/g, """).replace(/'/g, "'"); +} + +function badWrappedEncode2(s) { + return encodeQuotes(s).replace(/&/g, "&"); +} From a8214ce7ee070ad082430a6ea0140548ea1b0799 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 14:15:59 +0000 Subject: [PATCH 070/148] JavaScript: Fix regexes for escaping schemes. --- javascript/ql/src/Security/CWE-116/DoubleEscaping.ql | 6 +++--- .../query-tests/Security/CWE-116/DoubleEscaping/tst.js | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 2fc91a9854d..5d5157bafb3 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -54,11 +54,11 @@ DataFlow::Node getASimplePredecessor(DataFlow::Node nd) { * into a form described by regular expression `regex`. */ predicate escapingScheme(string metachar, string regex) { - metachar = "&" and regex = "&.*;" + metachar = "&" and regex = "&.+;" or - metachar = "%" and regex = "%.*" + metachar = "%" and regex = "%.+" or - metachar = "\\" and regex = "\\\\.*" + metachar = "\\" and regex = "\\\\.+" } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index 628166ed04a..e05779eeb7a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -114,3 +114,12 @@ function encodeQuotes(s) { function badWrappedEncode2(s) { return encodeQuotes(s).replace(/&/g, "&"); } + +function roundtrip(s) { + return JSON.parse(JSON.stringify(s)); +} + +// dubious, but out of scope for this query +function badRoundtrip(s) { + return s.replace(/\\\\/g, "\\").replace(/\\/g, "\\\\"); +} From 8c133ff61d873b574ff0fef778f5248f8c4b11d9 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 14:46:50 +0000 Subject: [PATCH 071/148] JavaScript: Deal with (un-)escaping on captured variables. --- javascript/ql/src/Security/CWE-116/DoubleEscaping.ql | 7 ++++++- .../query-tests/Security/CWE-116/DoubleEscaping/tst.js | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index 5d5157bafb3..b6d76956630 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -46,7 +46,12 @@ string getStringValue(RegExpLiteral rl) { */ DataFlow::Node getASimplePredecessor(DataFlow::Node nd) { result = nd.getAPredecessor() and - not nd.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() instanceof SsaPhiNode + not exists(SsaDefinition ssa | + ssa = nd.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() + | + ssa instanceof SsaPhiNode or + ssa instanceof SsaVariableCapture + ) } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index e05779eeb7a..7b840e2be08 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -123,3 +123,10 @@ function roundtrip(s) { function badRoundtrip(s) { return s.replace(/\\\\/g, "\\").replace(/\\/g, "\\\\"); } + +function testWithCapturedVar(x) { + var captured = x; + (function() { + captured = captured.replace(/\\/g, "\\\\"); + })(); +} From bb0771b36c3065c60dd4aa3f04a481b241ff9c86 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 14:49:01 +0000 Subject: [PATCH 072/148] JavaScript: Deal with escape-unescape-escape (and similar) chains. --- javascript/ql/src/Security/CWE-116/DoubleEscaping.ql | 8 ++++++-- .../query-tests/Security/CWE-116/DoubleEscaping/tst.js | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index b6d76956630..db8624458b7 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -135,7 +135,9 @@ abstract class Replacement extends DataFlow::Node { exists(Replacement pred | pred = this.getPreviousReplacement() | if pred.escapes(_, metachar) then result = pred - else result = pred.getAnEarlierEscaping(metachar) + else ( + not pred.unescapes(metachar, _) and result = pred.getAnEarlierEscaping(metachar) + ) ) } @@ -147,7 +149,9 @@ abstract class Replacement extends DataFlow::Node { exists(Replacement succ | this = succ.getPreviousReplacement() | if succ.unescapes(metachar, _) then result = succ - else result = succ.getALaterUnescaping(metachar) + else ( + not succ.escapes(_, metachar) and result = succ.getALaterUnescaping(metachar) + ) ) } } diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index 7b840e2be08..9c69c837f6b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -130,3 +130,7 @@ function testWithCapturedVar(x) { captured = captured.replace(/\\/g, "\\\\"); })(); } + +function cloneAndStringify(s) { + return JSON.stringify(JSON.parse(JSON.stringify(s))); +} From 3bbded57d3c45c1adc1056d23c3c74f0ffb38568 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 30 Oct 2019 14:49:18 +0000 Subject: [PATCH 073/148] JavaScript: Autoformat. --- .../ql/src/Security/CWE-116/DoubleEscaping.ql | 52 +++++-------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql index db8624458b7..6340a2fcedc 100644 --- a/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql +++ b/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql @@ -116,16 +116,12 @@ abstract class Replacement extends DataFlow::Node { /** * Gets the previous replacement in this chain of replacements. */ - Replacement getPreviousReplacement() { - result.getOutput() = getASimplePredecessor*(getInput()) - } + Replacement getPreviousReplacement() { result.getOutput() = getASimplePredecessor*(getInput()) } /** * Gets the next replacement in this chain of replacements. */ - Replacement getNextReplacement() { - this = result.getPreviousReplacement() - } + Replacement getNextReplacement() { this = result.getPreviousReplacement() } /** * Gets an earlier replacement in this chain of replacements that @@ -182,35 +178,25 @@ class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode { ) } - override DataFlow::Node getInput() { - result = this.getReceiver() - } + override DataFlow::Node getInput() { result = this.getReceiver() } - override DataFlow::SourceNode getOutput() { - result = this - } + override DataFlow::SourceNode getOutput() { result = this } } /** * A call to `JSON.stringify`, viewed as a string replacement. */ class JsonStringifyReplacement extends Replacement, DataFlow::CallNode { - JsonStringifyReplacement() { - this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") - } + JsonStringifyReplacement() { this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") } override predicate replaces(string input, string output) { input = "\\" and output = "\\\\" // the other replacements are not relevant for this query } - override DataFlow::Node getInput() { - result = this.getArgument(0) - } + override DataFlow::Node getInput() { result = this.getArgument(0) } - override DataFlow::SourceNode getOutput() { - result = this - } + override DataFlow::SourceNode getOutput() { result = this } } /** @@ -219,22 +205,16 @@ class JsonStringifyReplacement extends Replacement, DataFlow::CallNode { class JsonParseReplacement extends Replacement { JsonParserCall self; - JsonParseReplacement() { - this = self - } + JsonParseReplacement() { this = self } override predicate replaces(string input, string output) { input = "\\\\" and output = "\\" // the other replacements are not relevant for this query } - override DataFlow::Node getInput() { - result = self.getInput() - } + override DataFlow::Node getInput() { result = self.getInput() } - override DataFlow::SourceNode getOutput() { - result = self.getOutput() - } + override DataFlow::SourceNode getOutput() { result = self.getOutput() } } /** @@ -252,17 +232,11 @@ class WrappedReplacement extends Replacement, DataFlow::CallNode { ) } - override predicate replaces(string input, string output) { - inner.replaces(input, output) - } + override predicate replaces(string input, string output) { inner.replaces(input, output) } - override DataFlow::Node getInput() { - result = getArgument(i) - } + override DataFlow::Node getInput() { result = getArgument(i) } - override DataFlow::SourceNode getOutput() { - result = this - } + override DataFlow::SourceNode getOutput() { result = this } } from Replacement primary, Replacement supplementary, string message, string metachar From 27d0b51c6b4eabc891c71eb8952874c07932c7e3 Mon Sep 17 00:00:00 2001 From: alistair Date: Wed, 30 Oct 2019 16:10:03 +0000 Subject: [PATCH 074/148] CPP & C#: Review of qhelp PR #2151 got merged without a review of the qhelp by a technical writer. The current PR makes changes I would have suggested on that PR. --- .../NtohlArrayNoBoundOpenSource.qhelp | 2 +- .../ConditionallyUninitializedVariable.qhelp | 2 +- .../ConditionallyUninitializedVariable.ql | 2 +- .../CWE-091/XMLInjection.qhelp | 4 ++-- .../CWE-114/AssemblyPathInjection.qhelp | 6 ++--- .../CWE-321/HardcodedEncryptionKey.ql | 4 ++-- .../CWE-327/InsecureSQLConnection.qhelp | 22 +++++++++---------- .../CWE-327/InsecureSQLConnection.ql | 2 +- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBoundOpenSource.qhelp b/cpp/ql/src/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBoundOpenSource.qhelp index 522d6cde74c..fc8f309f73a 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBoundOpenSource.qhelp +++ b/cpp/ql/src/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBoundOpenSource.qhelp @@ -14,7 +14,7 @@ byte order function, such as ntohl. The use of a network-to-host byte order function is therefore a good indicator that the returned value is unvalidated data retrieved from the network, and should not be used without further validation. In particular, the returned value should not be used as an array index or array length -value without validation, which may result in a buffer overflow vulnerability. +value without validation, as this could result in a buffer overflow vulnerability.

    diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.qhelp b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.qhelp index b9118edc736..8e6a8903483 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.qhelp @@ -37,7 +37,7 @@ which is then subsequently accessed to fetch properties of the device. However, check the return value from the function call to initDeviceConfig. If the device number passed to the notify function was invalid, the initDeviceConfig function will leave the config variable uninitialized, -which would result in the notify function accessing uninitialized memory.

    +which will result in the notify function accessing uninitialized memory.

    diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql index eb00fb9ea10..f9eb2fe5400 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql +++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql @@ -2,7 +2,7 @@ * @name Conditionally uninitialized variable * @description When an initialization function is used to initialize a local variable, but the * returned status code is not checked, the variable may be left in an uninitialized - * state, and reading the variable may result in undefined behaviour. + * state, and reading the variable may result in undefined behavior. * @kind problem * @problem.severity warning * @opaque-id SM02313 diff --git a/csharp/ql/src/Security Features/CWE-091/XMLInjection.qhelp b/csharp/ql/src/Security Features/CWE-091/XMLInjection.qhelp index 4e70b06531a..3aff9901bfc 100644 --- a/csharp/ql/src/Security Features/CWE-091/XMLInjection.qhelp +++ b/csharp/ql/src/Security Features/CWE-091/XMLInjection.qhelp @@ -36,10 +36,10 @@ which ensures the content is appropriately escaped.

  • - XML Injection (The Web Application Security Consortium). + Web Application Security Consortium: XML Injection.
  • - WriteRaw (Microsoft documentation). + Microsoft Docs: WriteRaw.
  • diff --git a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.qhelp b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.qhelp index 5f95181c092..e1dbe9c1bd0 100644 --- a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.qhelp +++ b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.qhelp @@ -14,7 +14,7 @@ was not intended to be loaded, and executing arbitrary code.

    Avoid loading assemblies based on user provided input. If this is not possible, ensure that the path is validated before being used with Assembly. For example, compare the provided input -against a whitelist of known safe assemblies, or confirm that path is restricted to a single +against a whitelist of known safe assemblies, or confirm that the path is restricted to a single directory which only contains safe assemblies.

    @@ -30,8 +30,8 @@ is only loaded if the user input matches one of those options.

    -
  • - System.Reflection.Assembly (Microsoft documentation). +
  • Microsoft: + System.Reflection.Assembly.
  • diff --git a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql index c09a67d756c..cce122ffa62 100644 --- a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql +++ b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql @@ -1,6 +1,6 @@ /** - * @name Do not use hard-coded encryption keys. - * @description The .Key property or rgbKey parameter of a SymmetricAlgorithm should never be a hardcoded value. + * @name Hard-coded encryption key + * @description The .Key property or rgbKey parameter of a SymmetricAlgorithm should never be a hard-coded value. * @kind problem * @id cs/hardcoded-key * @problem.severity error diff --git a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.qhelp b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.qhelp index ae69402eb7e..c59feeed61c 100644 --- a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.qhelp +++ b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.qhelp @@ -3,7 +3,6 @@ "qhelp.dtd"> -

    Finds uses of insecure SQL Connections string by not enabling the Encrypt option.

    SQL Server connections where the client is not enforcing the encryption in transit are susceptible to multiple attacks, including a man-in-the-middle, that would potentially compromise the user credentials and/or the TDS session. @@ -29,18 +28,17 @@ - -

  • - Selectively using secure connection to SQL Server +
  • Microsoft, SQL Protocols blog: + Selectively using secure connection to SQL Server.
  • -
  • - Net SqlClient (ADO .Net) +
  • Microsoft: + SqlConnection.ConnectionString Property. +
  • +
  • Microsoft: + Using Connection String Keywords with SQL Server Native Client. +
  • +
  • Microsoft: + Setting the connection properties.
  • -
  • SQL native driver (SNAC) -
  • -
  • - JDBC driver -
  • -
    diff --git a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql index 0f855150aa9..78bcc1c19e5 100644 --- a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql +++ b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql @@ -1,6 +1,6 @@ /** * @name Insecure SQL connection - * @description TODO. + * @description Using an SQL Server connection without enforcing encryption is a security vulnerability. * @kind path-problem * @id cs/insecure-sql-connection * @problem.severity error From 24c9b8b9b14dba8b2b348790a6edb5754af31d70 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 30 Oct 2019 14:06:19 -0700 Subject: [PATCH 075/148] C++: fix unbound variables --- .../cpp/ir/implementation/raw/internal/TranslatedCall.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index fbe4910a0dd..75e0d463f2a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -461,7 +461,10 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { if hasSpecificReadSideEffect(any(Opcode::BufferReadSideEffect op)) - then result instanceof UnknownType + then + result instanceof UnknownType and + tag instanceof OnlyInstructionTag and + operandTag instanceof SideEffectOperandTag else ( tag instanceof OnlyInstructionTag and result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and From ceea96e03f0649c324ee4095f0c1033679cf2052 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 31 Oct 2019 12:00:16 +0100 Subject: [PATCH 076/148] C#: Update change note --- change-notes/1.23/analysis-csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index 4f1cb268468..cde0b4db71e 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -8,7 +8,7 @@ The following changes in version 1.23 affect C# analysis in all applications. | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| -| Deserialized delegate (`cs/deserialized-delegate`) | security | Finds unsafe deserialization of delegate types. | +| Deserialized delegate (`cs/deserialized-delegate`) | security, external/cwe/cwe-502 | Finds unsafe deserialization of delegate types. | | Unsafe year argument for 'DateTime' constructor (`cs/unsafe-year-construction`) | reliability, date-time | Finds incorrect manipulation of `DateTime` values, which could lead to invalid dates. | | Mishandling the Japanese era start date (`cs/mishandling-japanese-era`) | reliability, date-time | Finds hard-coded Japanese era start dates that could be invalid. | From 8aae1f443f7242c39c1a56974197525b9166dc59 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 22 Oct 2019 09:18:34 +0100 Subject: [PATCH 077/148] JavaScript: Use type tracking instead of auxiliary data-flow configuration to track indirect command arguments. --- .../dataflow/IndirectCommandArgument.qll | 48 +++++++------ .../CWE-078/CommandInjection.expected | 67 ------------------- .../CWE-078/IndirectCommandInjection.expected | 67 ------------------- ...llCommandInjectionFromEnvironment.expected | 67 ------------------- 4 files changed, 26 insertions(+), 223 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll index f509d9f8c6c..9f62ad7ccc8 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll @@ -10,7 +10,7 @@ import javascript * That is, either `shell` is a Unix shell (`sh` or similar) and * `arg` is `"-c"`, or `shell` is `cmd.exe` and `arg` is `"/c"`. */ -private predicate shellCmd(ConstantString shell, string arg) { +private predicate shellCmd(Expr shell, string arg) { exists(string s | s = shell.getStringValue() | (s = "sh" or s = "bash" or s = "/bin/sh" or s = "/bin/bash") and arg = "-c" @@ -23,25 +23,29 @@ private predicate shellCmd(ConstantString shell, string arg) { } /** - * Data flow configuration for tracking string literals that look like they - * may refer to an operating-system shell, and array literals that may end up being - * interpreted as argument lists for system commands. + * Gets a data-flow node whose value ends up being interpreted as the command argument in `sys` + * after a flow summarized by `t`. */ -private class ArgumentListTracking extends DataFlow::Configuration { - ArgumentListTracking() { this = "ArgumentListTracking" } +private DataFlow::Node commandArgument(SystemCommandExecution sys, DataFlow::TypeBackTracker t) { + t.start() and + result = sys.getACommandArgument() + or + exists(DataFlow::TypeBackTracker t2 | + t = t2.smallstep(result, commandArgument(sys, t2)) + ) +} - override predicate isSource(DataFlow::Node nd) { - nd instanceof DataFlow::ArrayCreationNode - or - exists(ConstantString shell | shellCmd(shell, _) | nd = DataFlow::valueNode(shell)) - } - - override predicate isSink(DataFlow::Node nd) { - exists(SystemCommandExecution sys | - nd = sys.getACommandArgument() or - nd = sys.getArgumentList() - ) - } +/** + * Gets a data-flow node whose value ends up being interpreted as the argument list in `sys` + * after a flow summarized by `t`. + */ +private DataFlow::SourceNode argumentList(SystemCommandExecution sys, DataFlow::TypeBackTracker t) { + t.start() and + result = sys.getArgumentList().getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | + result = argumentList(sys, t2).backtrack(t2, t) + ) } /** @@ -60,11 +64,11 @@ private class ArgumentListTracking extends DataFlow::Configuration { */ predicate isIndirectCommandArgument(DataFlow::Node source, SystemCommandExecution sys) { exists( - ArgumentListTracking cfg, DataFlow::ArrayCreationNode args, ConstantString shell, string dashC + DataFlow::ArrayCreationNode args, DataFlow::Node shell, string dashC | - shellCmd(shell, dashC) and - cfg.hasFlow(DataFlow::valueNode(shell), sys.getACommandArgument()) and - cfg.hasFlow(args, sys.getArgumentList()) and + shellCmd(shell.asExpr(), dashC) and + shell = commandArgument(sys, DataFlow::TypeBackTracker::end()) and + args = argumentList(sys, DataFlow::TypeBackTracker::end()) and args.getAPropertyWrite().getRhs().mayHaveStringValue(dashC) and source = args.getAPropertyWrite().getRhs() ) diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 115db66ab5a..abfab9e262d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -22,48 +22,12 @@ nodes | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:25:21:25:23 | cmd | -| child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | | child_process-test.js:39:26:39:28 | cmd | | child_process-test.js:39:26:39:28 | cmd | -| child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | -| child_process-test.js:41:16:41:17 | [] | | child_process-test.js:43:15:43:17 | cmd | | child_process-test.js:43:15:43:17 | cmd | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:15:46:18 | args | -| child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | -| child_process-test.js:48:16:48:17 | [] | | child_process-test.js:50:15:50:17 | cmd | | child_process-test.js:50:15:50:17 | cmd | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:55:19:55:22 | args | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:17:56:20 | args | -| child_process-test.js:56:17:56:20 | args | | execSeries.js:3:20:3:22 | arr | | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:21 | arr[i++] | @@ -114,9 +78,6 @@ nodes | third-party-command-injection.js:5:20:5:26 | command | | third-party-command-injection.js:6:21:6:27 | command | | third-party-command-injection.js:6:21:6:27 | command | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | edges | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:17:13:17:15 | cmd | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:17:13:17:15 | cmd | @@ -146,33 +107,6 @@ edges | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | | child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:46:15:46:18 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:44:17:44:27 | "/bin/bash" | child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:15:46:18 | args | child_process-test.js:55:19:55:22 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | | execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] | | execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command | @@ -222,7 +156,6 @@ edges | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | #select | child_process-test.js:17:13:17:15 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:17:13:17:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:18:17:18:19 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:18:17:18:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected index a16ba531410..9377069360e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected @@ -1,40 +1,4 @@ nodes -| child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | -| child_process-test.js:41:16:41:17 | [] | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:15:46:18 | args | -| child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | -| child_process-test.js:48:16:48:17 | [] | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:55:19:55:22 | args | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:17:56:20 | args | -| child_process-test.js:56:17:56:20 | args | | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | @@ -84,37 +48,7 @@ nodes | command-line-parameter-command-injection.js:27:14:27:57 | `node $ ... ption"` | | command-line-parameter-command-injection.js:27:32:27:35 | args | | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | edges -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:46:15:46:18 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:44:17:44:27 | "/bin/bash" | child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:15:46:18 | args | child_process-test.js:55:19:55:22 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:22:8:36 | process.argv[2] | | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:22:8:36 | process.argv[2] | @@ -159,7 +93,6 @@ edges | command-line-parameter-command-injection.js:27:32:27:35 | args | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | command-line-parameter-command-injection.js:27:14:27:57 | `node $ ... ption"` | | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | command-line-parameter-command-injection.js:27:14:27:57 | `node $ ... ption"` | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | #select | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line argument | | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line argument | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/ShellCommandInjectionFromEnvironment.expected b/javascript/ql/test/query-tests/Security/CWE-078/ShellCommandInjectionFromEnvironment.expected index bc0e994749e..ec3e7c99ecb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/ShellCommandInjectionFromEnvironment.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/ShellCommandInjectionFromEnvironment.expected @@ -1,77 +1,10 @@ nodes -| child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | -| child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | -| child_process-test.js:41:16:41:17 | [] | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:44:30:44:33 | args | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:9:46:12 | "sh" | -| child_process-test.js:46:15:46:18 | args | -| child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | -| child_process-test.js:48:16:48:17 | [] | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:51:35:51:38 | args | -| child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:55:19:55:22 | args | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:56:17:56:20 | args | -| child_process-test.js:56:17:56:20 | args | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | | tst_shell-command-injection-from-environment.js:5:14:5:53 | 'rm -rf ... "temp") | | tst_shell-command-injection-from-environment.js:5:14:5:53 | 'rm -rf ... "temp") | | tst_shell-command-injection-from-environment.js:5:26:5:53 | path.jo ... "temp") | | tst_shell-command-injection-from-environment.js:5:36:5:44 | __dirname | | tst_shell-command-injection-from-environment.js:5:36:5:44 | __dirname | edges -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | -| child_process-test.js:39:18:39:30 | [ flag, cmd ] | child_process-test.js:39:18:39:30 | [ flag, cmd ] | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | -| child_process-test.js:41:9:41:17 | args | child_process-test.js:46:15:46:18 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:41:16:41:17 | [] | child_process-test.js:41:9:41:17 | args | -| child_process-test.js:44:17:44:27 | "/bin/bash" | child_process-test.js:44:17:44:27 | "/bin/bash" | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:9:46:12 | "sh" | child_process-test.js:55:14:55:16 | cmd | -| child_process-test.js:46:15:46:18 | args | child_process-test.js:55:19:55:22 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:9:48:17 | args | child_process-test.js:51:35:51:38 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:48:16:48:17 | [] | child_process-test.js:48:9:48:17 | args | -| child_process-test.js:51:17:51:32 | `/bin` + "/bash" | child_process-test.js:51:17:51:32 | `/bin` + "/bash" | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | -| child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | -| tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | tst_shell-command-injection-from-environment.js:4:25:4:61 | ['-rf', ... temp")] | | tst_shell-command-injection-from-environment.js:5:26:5:53 | path.jo ... "temp") | tst_shell-command-injection-from-environment.js:5:14:5:53 | 'rm -rf ... "temp") | | tst_shell-command-injection-from-environment.js:5:26:5:53 | path.jo ... "temp") | tst_shell-command-injection-from-environment.js:5:14:5:53 | 'rm -rf ... "temp") | | tst_shell-command-injection-from-environment.js:5:36:5:44 | __dirname | tst_shell-command-injection-from-environment.js:5:26:5:53 | path.jo ... "temp") | From 03c9a40ba35db5be5e635703db8b2ab82beca909 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 22 Oct 2019 09:32:51 +0100 Subject: [PATCH 078/148] JavaScript: Add libraries for forward and backward data-flow exploration. --- .../dataflow/BackwardExploration.qll | 44 +++++++++++++++++++ .../dataflow/ForwardExploration.qll | 42 ++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll create mode 100644 javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll new file mode 100644 index 00000000000..caf67e6db7f --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll @@ -0,0 +1,44 @@ +/** + * Provides machinery for performing backward data-flow exploration. + * + * Importing this module effectively makes all data-flow and taint-tracking configurations + * ignore their `isSource` predicate. Instead, flow is tracked from any _initial node_ (that is, + * a node without incoming flow) to a sink node. All initial nodes are then treated as source + * nodes. + * + * Data-flow exploration cannot be used with configurations depending on other configurations. + * + * NOTE: This library should only be used for debugging, not in production code. Backward + * exploration in particular does not scale on non-trivial code bases and hence is of limited + * usefulness as it stands. + */ + +import javascript + +private class BackwardExploringConfiguration extends DataFlow::Configuration { + DataFlow::Configuration cfg; + + BackwardExploringConfiguration() { + this = cfg + } + + override predicate isSource(DataFlow::Node node) { any() } + + override predicate isSource(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() } + + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) | + source = src.getNode() and + sink = snk.getNode() + ) + } + + override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) { + exists(DataFlow::MidPathNode first | + source.getConfiguration() = this and + source.getASuccessor() = first and + not exists(DataFlow::MidPathNode mid | mid.getASuccessor() = first) and + first.getASuccessor*() = sink + ) + } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll new file mode 100644 index 00000000000..0e3a7ae91c2 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll @@ -0,0 +1,42 @@ +/** + * Provides machinery for performing forward data-flow exploration. + * + * Importing this module effectively makes all data-flow and taint-tracking configurations + * ignore their `isSink` predicate. Instead, flow is tracked from source nodes as far as + * possible, until a _terminal node_ (that is, a node without any outgoing flow) is reached. + * All terminal nodes are then treated as sink nodes. + * + * Data-flow exploration cannot be used with configurations depending on other configurations. + * + * NOTE: This library should only be used for debugging, not in production code. + */ + +import javascript + +private class ForwardExploringConfiguration extends DataFlow::Configuration { + DataFlow::Configuration cfg; + + ForwardExploringConfiguration() { + this = cfg + } + + override predicate isSink(DataFlow::Node node) { any() } + + override predicate isSink(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() } + + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) | + source = src.getNode() and + sink = snk.getNode() + ) + } + + override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) { + exists(DataFlow::MidPathNode last | + source.getConfiguration() = this and + source.getASuccessor*() = last and + not last.getASuccessor() instanceof DataFlow::MidPathNode and + last.getASuccessor() = sink + ) + } +} From 413f49bba546436a9a9f49df1fd004368f87efe5 Mon Sep 17 00:00:00 2001 From: Rachel Mant Date: Thu, 31 Oct 2019 22:50:44 +0000 Subject: [PATCH 079/148] Query cpp/unused-static-variable was producing incorrect results for constexpr variables --- .../src/Best Practices/Unused Entities/UnusedStaticVariables.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql index 26cf42521e5..3ad43998d18 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql @@ -21,6 +21,7 @@ from Variable v where v.isStatic() and v.hasDefinition() and + not v.isConstexpr() and not exists(VariableAccess a | a.getTarget() = v) and not v instanceof MemberVariable and not declarationHasSideEffects(v) and From d94e91b39ba6149e6d4232140375bdb0b340d0cb Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Fri, 1 Nov 2019 11:03:12 +0000 Subject: [PATCH 080/148] Apply suggestions from code review Co-Authored-By: Felicity Chapman --- docs/language/learn-ql/python/introduce-libraries-python.rst | 2 +- docs/language/learn-ql/writing-queries/path-queries.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index 60d965a461b..1594afc9679 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -12,7 +12,7 @@ The rest of this tutorial summarizes the contents of the standard libraries for Overview of the library ----------------------- -The CodeQL library for Python incorporates a large number of classes. Each class corresponds either to one kind of entity in Python source code or to an entity that can be derived form the source code using static analysis. These classes can be divided into four categories: +The CodeQL library for Python incorporates a large number of classes. Each class corresponds either to one kind of entity in Python source code or to an entity that can be derived from the source code using static analysis. These classes can be divided into four categories: - **Syntactic** - classes that represent entities in the Python source code. - **Control flow** - classes that represent entities from the control flow graphs. diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 73708b17eed..01a6e0d97ea 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -105,7 +105,7 @@ To do this you need to define a `query predicate Date: Fri, 1 Nov 2019 11:21:12 +0000 Subject: [PATCH 081/148] Docs: Rename Sphinx project to "Learning CodeQL" --- docs/language/global-sphinx-files/_templates/layout.html | 2 +- docs/language/learn-ql/conf.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/language/global-sphinx-files/_templates/layout.html b/docs/language/global-sphinx-files/_templates/layout.html index 6aa09b5fb38..de3b189e1ee 100644 --- a/docs/language/global-sphinx-files/_templates/layout.html +++ b/docs/language/global-sphinx-files/_templates/layout.html @@ -61,7 +61,7 @@