From e3b15a98c42ae0009cb8e64f2e691dd744c28d4f Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 15 Nov 2019 11:13:31 +0000 Subject: [PATCH 01/32] JS: Add prop names for array element pattern PropReads --- .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 10 ++++++---- .../ql/test/library-tests/PropWrite/tests.expected | 12 ++++++++++++ javascript/ql/test/library-tests/PropWrite/tst.js | 5 +++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 74bcc428393..26567a35172 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -840,16 +840,18 @@ module DataFlow { * An array element pattern viewed as a property read; for instance, in * `var [ x, y ] = arr`, `x` is a read of property 0 of `arr` and similar * for `y`. - * - * Note: We currently do not expose the array index as the property name, - * instead treating it as a read of an unknown property. */ private class ElementPatternAsPropRead extends PropRead, ElementPatternNode { override Node getBase() { result = TDestructuringPatternNode(pattern) } override Expr getPropertyNameExpr() { none() } - override string getPropertyName() { none() } + override string getPropertyName() { + exists (int i | + elt = pattern.getElement(i) and + result = i.toString() + ) + } } /** diff --git a/javascript/ql/test/library-tests/PropWrite/tests.expected b/javascript/ql/test/library-tests/PropWrite/tests.expected index beb4916f397..9e5872b991b 100644 --- a/javascript/ql/test/library-tests/PropWrite/tests.expected +++ b/javascript/ql/test/library-tests/PropWrite/tests.expected @@ -10,6 +10,9 @@ test_getAPropertyRead | tst.js:34:6:34:12 | vvv.ppp | tst.js:34:6:34:16 | vvv.ppp.qqq | | tst.js:44:3:44:9 | console | tst.js:44:3:44:13 | console.log | | tst.js:44:15:44:17 | obj | tst.js:44:15:44:20 | obj[p] | +| tst.js:46:17:46:21 | array | tst.js:47:10:47:10 | x | +| tst.js:46:17:46:21 | array | tst.js:47:13:47:13 | y | +| tst.js:46:17:46:21 | array | tst.js:47:16:47:16 | z | test_getAPropertyReference | classes.ts:3:21:3:20 | this | classes.ts:4:3:4:24 | instanc ... foo(); | | classes.ts:8:3:8:2 | this | classes.ts:8:15:8:35 | public ... erField | @@ -50,6 +53,9 @@ test_getAPropertyReference | tst.js:41:12:41:30 | ["a", ...arr3, "d"] | tst.js:41:27:41:29 | "d" | | tst.js:44:3:44:9 | console | tst.js:44:3:44:13 | console.log | | tst.js:44:15:44:17 | obj | tst.js:44:15:44:20 | obj[p] | +| tst.js:46:17:46:21 | array | tst.js:47:10:47:10 | x | +| tst.js:46:17:46:21 | array | tst.js:47:13:47:13 | y | +| tst.js:46:17:46:21 | array | tst.js:47:16:47:16 | z | test_getAPropertySource | classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() | | classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField | @@ -92,6 +98,9 @@ test_getAPropertyRead2 | tst.js:34:6:34:8 | vvv | ppp | tst.js:34:6:34:12 | vvv.ppp | | tst.js:34:6:34:12 | vvv.ppp | qqq | tst.js:34:6:34:16 | vvv.ppp.qqq | | tst.js:44:3:44:9 | console | log | tst.js:44:3:44:13 | console.log | +| tst.js:46:17:46:21 | array | 0 | tst.js:47:10:47:10 | x | +| tst.js:46:17:46:21 | array | 1 | tst.js:47:13:47:13 | y | +| tst.js:46:17:46:21 | array | 2 | tst.js:47:16:47:16 | z | test_getAPropertyReference2 | classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:3:4:24 | instanc ... foo(); | | classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:15:8:35 | public ... erField | @@ -116,6 +125,9 @@ test_getAPropertyReference2 | tst.js:34:6:34:8 | vvv | ppp | tst.js:34:6:34:12 | vvv.ppp | | tst.js:34:6:34:12 | vvv.ppp | qqq | tst.js:34:6:34:16 | vvv.ppp.qqq | | tst.js:44:3:44:9 | console | log | tst.js:44:3:44:13 | console.log | +| tst.js:46:17:46:21 | array | 0 | tst.js:47:10:47:10 | x | +| tst.js:46:17:46:21 | array | 1 | tst.js:47:13:47:13 | y | +| tst.js:46:17:46:21 | array | 2 | tst.js:47:16:47:16 | z | test_hasPropertyWrite | classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() | | classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField | diff --git a/javascript/ql/test/library-tests/PropWrite/tst.js b/javascript/ql/test/library-tests/PropWrite/tst.js index 99e9d5ffb1c..4f18284968d 100644 --- a/javascript/ql/test/library-tests/PropWrite/tst.js +++ b/javascript/ql/test/library-tests/PropWrite/tst.js @@ -42,3 +42,8 @@ var arr1 = ["a", "b", "c"], for (var p in obj) console.log(obj[p]); + + function test(array) { + let [x, y, z] = array; + } + \ No newline at end of file From 5a6958a1cd5e202aac72c28a96f9d3578ef91a19 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Nov 2019 21:04:24 +0100 Subject: [PATCH 02/32] add promise aggregators --- .../src/Statements/UseOfReturnlessFunction.ql | 4 ++-- .../ql/src/semmle/javascript/Promises.qll | 20 ++++++++++++++++-- .../src/semmle/javascript/StandardLibrary.qll | 21 ++++++++++++++++--- .../Statements/UseOfReturnlessFunction/tst.js | 2 ++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 0da7ba6fb1f..5771de1e922 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -67,7 +67,7 @@ predicate benignContext(Expr e) { any(InvokeExpr invoke).getCallee() = e or // arguments to Promise.resolve (and promise library variants) are benign. - e = any(ResolvedPromiseDefinition promise).getValue().asExpr() + e = any(PromiseCreationCall promise).getValue().asExpr() } predicate oneshotClosure(InvokeExpr call) { @@ -191,7 +191,7 @@ module Deferred { /** * A resolved promise created by a `new Deferred().resolve()` call. */ - class ResolvedDeferredPromiseDefinition extends ResolvedPromiseDefinition { + class ResolvedDeferredPromiseDefinition extends PromiseCreationCall { ResolvedDeferredPromiseDefinition() { this = any(DeferredPromiseDefinition def).ref().getAMethodCall("resolve") } diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 858064e85a0..c4c83eeb1a0 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -25,11 +25,27 @@ module Bluebird { /** * A resolved promise created by the bluebird `Promise.resolve` function. */ - class ResolvedBluebidPromiseDefinition extends ResolvedPromiseDefinition { + class ResolvedBluebidPromiseDefinition extends PromiseCreationCall { ResolvedBluebidPromiseDefinition() { this = bluebird().getAMemberCall("resolve") } override DataFlow::Node getValue() { result = getArgument(0) } } + + /** + * An aggregated promise produced either by `Primise.all`, `Promise.race` or `Promise.map`. + */ + class AggregateBluebirdPromiseDefinition extends PromiseCreationCall { + AggregateBluebirdPromiseDefinition() { + exists(string m | m = "all" or m = "race" or m = "map" | + this = bluebird().getAMemberCall(m) + ) + } + + override DataFlow::Node getValue() { + result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement() + } + } + } /** @@ -59,7 +75,7 @@ private module ClosurePromise { /** * A promise created by a call `goog.Promise.resolve(value)`. */ - private class ResolvedClosurePromiseDefinition extends ResolvedPromiseDefinition { + private class ResolvedClosurePromiseDefinition extends PromiseCreationCall { ResolvedClosurePromiseDefinition() { this = Closure::moduleImport("goog.Promise.resolve").getACall() } diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 13cc976725a..bf9f074d283 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -154,7 +154,7 @@ private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNo /** * A promise that is resolved with the given value. */ -abstract class ResolvedPromiseDefinition extends DataFlow::CallNode { +abstract class PromiseCreationCall extends DataFlow::CallNode { /** * Gets the value this promise is resolved with. */ @@ -164,7 +164,7 @@ abstract class ResolvedPromiseDefinition extends DataFlow::CallNode { /** * A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function. */ -class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition { +class ResolvedES2015PromiseDefinition extends PromiseCreationCall { ResolvedES2015PromiseDefinition() { this = DataFlow::globalVarRef("Promise").getAMemberCall("resolve") } @@ -172,6 +172,21 @@ class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition { override DataFlow::Node getValue() { result = getArgument(0) } } +/** + * An aggregated promise produced either by `Primise.all` or `Promise.race`. + */ +class AggregateES2015PromiseDefinition extends PromiseCreationCall { + AggregateES2015PromiseDefinition() { + exists(string m | m = "all" or m = "race" | + this = DataFlow::globalVarRef("Promise").getAMemberCall(m) + ) + } + + override DataFlow::Node getValue() { + result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement() + } +} + /** * A data flow edge from a promise reaction to the corresponding handler. */ @@ -197,7 +212,7 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) { pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0) or // from `x` to `Promise.resolve(x)` - pred = succ.(ResolvedPromiseDefinition).getValue() + pred = succ.(PromiseCreationCall).getValue() or exists(DataFlow::MethodCallNode thn, DataFlow::FunctionNode cb | thn.getMethodName() = "then" and cb = thn.getCallback(0) diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js index 90a52153dea..49097010746 100644 --- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js +++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js @@ -88,4 +88,6 @@ } new Deferred().resolve(onlySideEffects()); // OK + + Promise.all([onlySideEffects(), onlySideEffects()]) })(); \ No newline at end of file From de8ed3f508439b8257b698f108a76e8be45062fe Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 Nov 2019 09:04:30 +0100 Subject: [PATCH 03/32] update test code --- .../test/library-tests/Promises/ResolvedPromiseDefinition.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/Promises/ResolvedPromiseDefinition.qll b/javascript/ql/test/library-tests/Promises/ResolvedPromiseDefinition.qll index a7bade78412..5efd8896141 100644 --- a/javascript/ql/test/library-tests/Promises/ResolvedPromiseDefinition.qll +++ b/javascript/ql/test/library-tests/Promises/ResolvedPromiseDefinition.qll @@ -1,7 +1,7 @@ import javascript query predicate test_ResolvedPromiseDefinition( - ResolvedPromiseDefinition resolved, DataFlow::Node res + PromiseCreationCall resolved, DataFlow::Node res ) { res = resolved.getValue() } From 2f08ee9faf9ea8fe763d436b3385944386d492c1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 Nov 2019 12:53:50 +0100 Subject: [PATCH 04/32] fix typo Co-Authored-By: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> --- javascript/ql/src/semmle/javascript/Promises.qll | 2 +- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index c4c83eeb1a0..e195668ffbf 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -32,7 +32,7 @@ module Bluebird { } /** - * An aggregated promise produced either by `Primise.all`, `Promise.race` or `Promise.map`. + * An aggregated promise produced either by `Promise.all`, `Promise.race` or `Promise.map`. */ class AggregateBluebirdPromiseDefinition extends PromiseCreationCall { AggregateBluebirdPromiseDefinition() { diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index bf9f074d283..0af9e8e11ce 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -173,7 +173,7 @@ class ResolvedES2015PromiseDefinition extends PromiseCreationCall { } /** - * An aggregated promise produced either by `Primise.all` or `Promise.race`. + * An aggregated promise produced either by `Promise.all` or `Promise.race`. */ class AggregateES2015PromiseDefinition extends PromiseCreationCall { AggregateES2015PromiseDefinition() { From 3c9fe91581f8d9ed585a1a0e54d8722480a21c5d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 10:54:04 +0000 Subject: [PATCH 05/32] CPP: Add proof of zero-termination to tests. --- .../NoSpaceForZeroTerminator.expected | 8 ++++---- .../CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c | 9 +++++++++ .../CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp | 9 +++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected index a33f824484b..f2f201053d9 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected @@ -1,4 +1,4 @@ -| test.c:15:20:15:25 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.c:29:20:29:25 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.c:44:20:44:25 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:18:35:18:40 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.c:16:20:16:25 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c index a6d054874d0..2f06af7d42d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c @@ -7,18 +7,21 @@ typedef unsigned long size_t; void *malloc(size_t size); void free(void *ptr); +char *strcpy(char *s1, const char *s2); //// Test code ///// void bad0(char *str) { // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(strlen(str)); + strcpy(buffer, str); free(buffer); } void good0(char *str) { // GOOD -- Allocating extra byte for terminator char *buffer = malloc(strlen(str)+1); + strcpy(buffer, str); free(buffer); } @@ -27,6 +30,7 @@ void bad1(char *str) { int len = strlen(str); // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(len); + strcpy(buffer, str); free(buffer); } @@ -34,6 +38,7 @@ void good1(char *str) { int len = strlen(str); // GOOD -- Allocating extra byte for terminator char *buffer = malloc(len+1); + strcpy(buffer, str); free(buffer); } @@ -42,6 +47,7 @@ void bad2(char *str) { int len = strlen(str); // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(len); + strcpy(buffer, str); free(buffer); } @@ -49,18 +55,21 @@ void good2(char *str) { int len = strlen(str)+1; // GOOD -- Allocating extra byte for terminator char *buffer = malloc(len); + strcpy(buffer, str); free(buffer); } void bad3(char *str) { // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] char *buffer = malloc(strlen(str) * sizeof(char)); + strcpy(buffer, str); free(buffer); } void good3(char *str) { // GOOD -- Allocating extra byte for terminator char *buffer = malloc((strlen(str) + 1) * sizeof(char)); + strcpy(buffer, str); free(buffer); } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp index 53488c0f229..e240d391224 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp @@ -10,23 +10,32 @@ typedef unsigned long size_t; void *malloc(size_t size); void free(void *ptr); size_t wcslen(const wchar_t *s); +wchar_t* wcscpy(wchar_t* s1, const wchar_t* s2); + + + + + //// Test code ///// void bad1(wchar_t *wstr) { // BAD -- Not allocating space for '\0' terminator wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr)); + wcscpy(wbuffer, wstr); free(wbuffer); } void bad2(wchar_t *wstr) { // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t)); + wcscpy(wbuffer, wstr); free(wbuffer); } void good1(wchar_t *wstr) { // GOOD -- Allocating extra character for terminator wchar_t *wbuffer = (wchar_t *)malloc((wcslen(wstr) + 1) * sizeof(wchar_t)); + wcscpy(wbuffer, wstr); free(wbuffer); } From 57c7a87af918bb53dcd3fd6eaa57bef2a8e3431d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 11:36:12 +0000 Subject: [PATCH 06/32] CPP: Add tests with different proof of zero-termination. --- .../NoSpaceForZeroTerminator.expected | 7 ++ .../semmle/NoSpaceForZeroTerminator/test.cpp | 71 +++++++++++++++++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected index f2f201053d9..7deb5de7541 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected @@ -2,3 +2,10 @@ | test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:55:28:55:33 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:89:35:89:40 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:99:28:99:33 | call to malloc | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp index e240d391224..13196226d8d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp @@ -11,11 +11,11 @@ void *malloc(size_t size); void free(void *ptr); size_t wcslen(const wchar_t *s); wchar_t* wcscpy(wchar_t* s1, const wchar_t* s2); - - - - - +int sprintf(char *s, const char *format, ...); +int wprintf(const wchar_t *format, ...); +char *strcat(char *s1, const char *s2); +size_t strlen(const char *s); +int strcmp(const char *s1, const char *s2); //// Test code ///// @@ -39,3 +39,64 @@ void good1(wchar_t *wstr) { wcscpy(wbuffer, wstr); free(wbuffer); } + +void bad3(char *str) { + // BAD -- zero-termination proved by sprintf (as destination) + char *buffer = (char *)malloc(strlen(str)); + sprintf(buffer, "%s", str); + free(buffer); +} + +void decode(char *dest, char *src); +void wdecode(wchar_t *dest, wchar_t *src); + +void bad4(char *str) { + // BAD -- zero-termination proved by wprintf (as parameter) + char *buffer = (char *)malloc(strlen(str)); + decode(buffer, str); + wprintf(L"%s", buffer); + free(buffer); +} + +void bad5(char *str) { + // BAD -- zero-termination proved by strcat (as destination) + char *buffer = (char *)malloc(strlen(str)); + buffer[0] = 0; + strcat(buffer, str); + free(buffer); +} + +void bad6(char *str, char *dest) { + // BAD -- zero-termination proved by strcat (as source) + char *buffer = (char *)malloc(strlen(str)); + decode(buffer, str); + strcat(dest, buffer); + free(buffer); +} + +void bad7(char *str, char *str2) { + // BAD -- zero-termination proved by strcmp + char *buffer = (char *)malloc(strlen(str)); + decode(buffer, str); + if (strcmp(buffer, str2) == 0) { + // ... + } + free(buffer); +} + +void bad8(wchar_t *str) { + // BAD -- zero-termination proved by wcslen + wchar_t *wbuffer = (wchar_t *)malloc(wcslen(str)); + wdecode(wbuffer, str); + if (wcslen(wbuffer) == 0) { + // ... + } + free(wbuffer); +} + +void good2(char *str, char *dest) { + // GOOD -- zero-termination not proven [FALSE POSITIVE] + char *buffer = (char *)malloc(strlen(str)); + decode(buffer, str); + free(buffer); +} From 6fc9cc595244dbd9cc711816019966f4ac6e3f8d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 14:30:35 +0000 Subject: [PATCH 07/32] CPP: Add a test case using 'new'. --- .../CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp index 13196226d8d..30083e7811a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp @@ -100,3 +100,10 @@ void good2(char *str, char *dest) { decode(buffer, str); free(buffer); } + +void bad9(wchar_t *wstr) { + // BAD -- using new [NOT DETECTED] + wchar_t *wbuffer = new wchar_t[wcslen(wstr)]; + wcscpy(wbuffer, wstr); + delete wbuffer; +} From fbd9d9bdab4c849e689dcecad7edcf78d950a430 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 15:43:19 +0000 Subject: [PATCH 08/32] CPP: Add a test case involving the std::string constructor. --- .../NoSpaceForZeroTerminator.expected | 1 + .../semmle/NoSpaceForZeroTerminator/test2.cpp | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected index 7deb5de7541..4f8991dc564 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected @@ -1,3 +1,4 @@ +| test2.cpp:35:28:35:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:16:20:16:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp new file mode 100644 index 00000000000..e0cf225b96f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp @@ -0,0 +1,38 @@ + +///// Library functions ////// + +typedef unsigned long size_t; + +void *malloc(size_t size); +void free(void *ptr); +size_t strlen(const char *s); + +namespace std +{ + template struct char_traits; + + template class allocator { + public: + allocator() throw(); + }; + + template, class Allocator = allocator > + class basic_string { + public: + explicit basic_string(const Allocator& a = Allocator()); + basic_string(const charT* s, const Allocator& a = Allocator()); + + const charT* c_str() const; + }; + + typedef basic_string string; +} + +//// Test code ///// + +void bad1(char *str) { + // BAD -- Not allocating space for '\0' terminator + char *buffer = (char *)malloc(strlen(str)); + std::string str2(buffer); + free(buffer); +} From e6ea705ff29d3cf4add63725f1ead3f7909d90d1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 14:49:28 +0000 Subject: [PATCH 09/32] CPP: Switch from a blacklist to whitelist approach for determining null termination. --- .../CWE/CWE-131/NoSpaceForZeroTerminator.ql | 18 +++++++++++++----- .../NoSpaceForZeroTerminator.expected | 6 ------ .../semmle/NoSpaceForZeroTerminator/test.cpp | 10 +++++----- .../semmle/NoSpaceForZeroTerminator/test2.cpp | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql index ff17daca05c..6f4b8d3f392 100644 --- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql +++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql @@ -16,7 +16,7 @@ import cpp import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.models.implementations.Memcpy +import semmle.code.cpp.models.interfaces.ArrayFunction class MallocCall extends FunctionCall { MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") } @@ -33,11 +33,19 @@ class MallocCall extends FunctionCall { } predicate terminationProblem(MallocCall malloc, string msg) { + // malloc(strlen(...)) malloc.getAllocatedSize() instanceof StrlenCall and - not exists(FunctionCall fc, MemcpyFunction memcpy, int ix | - DataFlow::localExprFlow(malloc, fc.getArgument(ix)) and - fc.getTarget() = memcpy and - memcpy.hasArrayOutput(ix) + // flows into a null-terminated string function + exists(ArrayFunction af, FunctionCall fc, int arg | + DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and + fc.getTarget() = af and + ( + // null terminated string + af.hasArrayWithNullTerminator(arg) + or + // likely a null terminated string (such as `strcpy`, `strcat`) + af.hasArrayWithUnknownSize(arg) + ) ) and msg = "This allocation does not include space to null-terminate the string." } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected index 4f8991dc564..972b06af73c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected @@ -1,12 +1,6 @@ -| test2.cpp:35:28:35:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:16:20:16:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:55:28:55:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:89:35:89:40 | call to malloc | This allocation does not include space to null-terminate the string. | -| test.cpp:99:28:99:33 | call to malloc | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp index 30083e7811a..23c446b2a84 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp @@ -41,7 +41,7 @@ void good1(wchar_t *wstr) { } void bad3(char *str) { - // BAD -- zero-termination proved by sprintf (as destination) + // BAD -- zero-termination proved by sprintf (as destination) [NOT DETECTED] char *buffer = (char *)malloc(strlen(str)); sprintf(buffer, "%s", str); free(buffer); @@ -51,7 +51,7 @@ void decode(char *dest, char *src); void wdecode(wchar_t *dest, wchar_t *src); void bad4(char *str) { - // BAD -- zero-termination proved by wprintf (as parameter) + // BAD -- zero-termination proved by wprintf (as parameter) [NOT DETECTED] char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); wprintf(L"%s", buffer); @@ -75,7 +75,7 @@ void bad6(char *str, char *dest) { } void bad7(char *str, char *str2) { - // BAD -- zero-termination proved by strcmp + // BAD -- zero-termination proved by strcmp [NOT DETECTED] char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); if (strcmp(buffer, str2) == 0) { @@ -85,7 +85,7 @@ void bad7(char *str, char *str2) { } void bad8(wchar_t *str) { - // BAD -- zero-termination proved by wcslen + // BAD -- zero-termination proved by wcslen [NOT DETECTED] wchar_t *wbuffer = (wchar_t *)malloc(wcslen(str)); wdecode(wbuffer, str); if (wcslen(wbuffer) == 0) { @@ -95,7 +95,7 @@ void bad8(wchar_t *str) { } void good2(char *str, char *dest) { - // GOOD -- zero-termination not proven [FALSE POSITIVE] + // GOOD -- zero-termination not proven char *buffer = (char *)malloc(strlen(str)); decode(buffer, str); free(buffer); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp index e0cf225b96f..5fad5db1142 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp @@ -31,7 +31,7 @@ namespace std //// Test code ///// void bad1(char *str) { - // BAD -- Not allocating space for '\0' terminator + // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] char *buffer = (char *)malloc(strlen(str)); std::string str2(buffer); free(buffer); From 2212c47db24992de02c641b6e98d8e6d53359319 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 Nov 2019 17:54:04 +0000 Subject: [PATCH 10/32] CPP: Use dataflow more consistently. --- .../Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql index 6f4b8d3f392..ef983af4cb2 100644 --- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql +++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql @@ -22,19 +22,15 @@ class MallocCall extends FunctionCall { MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") } Expr getAllocatedSize() { - if this.getArgument(0) instanceof VariableAccess - then - exists(LocalScopeVariable v, ControlFlowNode def | - definitionUsePair(v, def, this.getArgument(0)) and - exprDefinition(v, def, result) - ) - else result = this.getArgument(0) + result = this.getArgument(0) } } predicate terminationProblem(MallocCall malloc, string msg) { // malloc(strlen(...)) - malloc.getAllocatedSize() instanceof StrlenCall and + exists(StrlenCall strlen | + DataFlow::localExprFlow(strlen, malloc.getAllocatedSize()) + ) and // flows into a null-terminated string function exists(ArrayFunction af, FunctionCall fc, int arg | DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and From 5c855fc92591a1dde1dc53b4aa5841f190eae33c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 20 Nov 2019 14:35:45 +0000 Subject: [PATCH 11/32] CPP: Change note. --- change-notes/1.24/analysis-cpp.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 change-notes/1.24/analysis-cpp.md diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md new file mode 100644 index 00000000000..2e7fdd422af --- /dev/null +++ b/change-notes/1.24/analysis-cpp.md @@ -0,0 +1,20 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.24 affect C/C++ analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| +| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | + +## Changes to libraries + +* From bbe6a1aa76756c2541ccb1e6e5c15fbc71224489 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:01:04 +0000 Subject: [PATCH 12/32] CPP: Additional test case. --- .../semmle/NoSpaceForZeroTerminator/test2.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp index 5fad5db1142..ec71fa5fa57 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test2.cpp @@ -14,13 +14,16 @@ namespace std template class allocator { public: allocator() throw(); + typedef size_t size_type; }; template, class Allocator = allocator > class basic_string { public: + typedef typename Allocator::size_type size_type; explicit basic_string(const Allocator& a = Allocator()); basic_string(const charT* s, const Allocator& a = Allocator()); + basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); const charT* c_str() const; }; @@ -36,3 +39,12 @@ void bad1(char *str) { std::string str2(buffer); free(buffer); } + +void good1(char *str) { + // GOOD --- copy does not overrun due to size limit + char *buffer = (char *)malloc(strlen(str)); + std::string str2(buffer, strlen(str)); + free(buffer); +} + + From d6cbc674b6f372592248d063c00f1479975245e1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:02:40 +0000 Subject: [PATCH 13/32] CPP: Autoformat. --- .../src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql index ef983af4cb2..5ed0f1bd679 100644 --- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql +++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql @@ -21,16 +21,12 @@ import semmle.code.cpp.models.interfaces.ArrayFunction class MallocCall extends FunctionCall { MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") } - Expr getAllocatedSize() { - result = this.getArgument(0) - } + Expr getAllocatedSize() { result = this.getArgument(0) } } predicate terminationProblem(MallocCall malloc, string msg) { // malloc(strlen(...)) - exists(StrlenCall strlen | - DataFlow::localExprFlow(strlen, malloc.getAllocatedSize()) - ) and + exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getAllocatedSize())) and // flows into a null-terminated string function exists(ArrayFunction af, FunctionCall fc, int arg | DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and From 12daa76b7052962a26825b0ad402e5337f5f0a34 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 14 Aug 2019 13:48:34 -0700 Subject: [PATCH 14/32] C++: Make `duplicateOperand` query report function name --- .../aliased_ssa/Instruction.qll | 20 +++++++++++++------ .../cpp/ir/implementation/raw/Instruction.qll | 20 +++++++++++++------ .../unaliased_ssa/Instruction.qll | 20 +++++++++++++------ .../ir/implementation/raw/Instruction.qll | 20 +++++++++++++------ .../unaliased_ssa/Instruction.qll | 20 +++++++++++++------ 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index e3c78f476e9..bfd04a279e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -94,12 +94,20 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, OperandTag tag) { - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) > 1 and - not tag instanceof UnmodeledUseOperandTag + query predicate duplicateOperand(Instruction instr, string message, IRFunction func, + string funcText) { + exists(OperandTag tag, int operandCount | + operandCount = strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index e3c78f476e9..bfd04a279e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -94,12 +94,20 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, OperandTag tag) { - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) > 1 and - not tag instanceof UnmodeledUseOperandTag + query predicate duplicateOperand(Instruction instr, string message, IRFunction func, + string funcText) { + exists(OperandTag tag, int operandCount | + operandCount = strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index e3c78f476e9..bfd04a279e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -94,12 +94,20 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, OperandTag tag) { - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) > 1 and - not tag instanceof UnmodeledUseOperandTag + query predicate duplicateOperand(Instruction instr, string message, IRFunction func, + string funcText) { + exists(OperandTag tag, int operandCount | + operandCount = strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index e3c78f476e9..bfd04a279e0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -94,12 +94,20 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, OperandTag tag) { - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) > 1 and - not tag instanceof UnmodeledUseOperandTag + query predicate duplicateOperand(Instruction instr, string message, IRFunction func, + string funcText) { + exists(OperandTag tag, int operandCount | + operandCount = strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index e3c78f476e9..bfd04a279e0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -94,12 +94,20 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, OperandTag tag) { - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) > 1 and - not tag instanceof UnmodeledUseOperandTag + query predicate duplicateOperand(Instruction instr, string message, IRFunction func, + string funcText) { + exists(OperandTag tag, int operandCount | + operandCount = strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) } /** From bc48c25690f98945ad6470c69877650809d6e63c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 22 Nov 2019 12:13:39 -0700 Subject: [PATCH 15/32] C++/C#: Make `IRVariable` and its derived classes non-abstract --- .../implementation/aliased_ssa/IRVariable.qll | 63 ++++++++++++++++--- .../cpp/ir/implementation/raw/IRVariable.qll | 63 ++++++++++++++++--- .../unaliased_ssa/IRVariable.qll | 63 ++++++++++++++++--- .../ir/implementation/raw/IRVariable.qll | 63 ++++++++++++++++--- .../unaliased_ssa/IRVariable.qll | 63 ++++++++++++++++--- 5 files changed, 270 insertions(+), 45 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index e10e266b2ab..349ff7cd6bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -17,10 +17,16 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var * be a user-declared variable (`IRUserVariable`) or a temporary variable * generated by the AST-to-IR translation (`IRTempVariable`). */ -abstract class IRVariable extends TIRVariable { +class IRVariable extends TIRVariable { Language::Function func; - abstract string toString(); + IRVariable() { + this = TIRUserVariable(_, _, func) or + this = TIRTempVariable(func, _, _, _) or + this = TIRStringLiteral(func, _, _, _) + } + + string toString() { none() } /** * Holds if this variable's value cannot be changed within a function. Currently used for string @@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::LanguageType getLanguageType(); + Language::LanguageType getLanguageType() { none() } /** * Gets the AST node that declared this variable, or that introduced this * variable as part of the AST-to-IR translation. */ - abstract Language::AST getAST(); + Language::AST getAST() { none() } /** * Gets an identifier string for the variable. This identifier is unique * within the function. */ - abstract string getUniqueId(); + string getUniqueId() { none() } /** * Gets the source location of this variable. @@ -101,16 +107,31 @@ class IRUserVariable extends IRVariable, TIRUserVariable { * stack. This includes all parameters, non-static local variables, and * temporary variables. */ -abstract class IRAutomaticVariable extends IRVariable { } +class IRAutomaticVariable extends IRVariable { + IRAutomaticVariable() { + exists(Language::Variable var | + this = TIRUserVariable(var, _, func) and + Language::isVariableAutomatic(var) + ) or + this = TIRTempVariable(func, _, _, _) + } +} +/** + * Represents a user-declared variable that is allocated on the stack. This + * includes all parameters and non-static local variables. + */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; - IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } - final override Language::AutomaticVariable getVariable() { result = var } } +/** + * Represents a user-declared variable that is not allocated on the stack. This + * includes all global variables, namespace-scope variables, static fields, and + * static local variables. + */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -119,10 +140,19 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } -abstract class IRGeneratedVariable extends IRVariable { +/** + * Represents a variable that is not user-declared. This includes temporary + * variables generated as part of IR construction, as well as string literals. + */ +class IRGeneratedVariable extends IRVariable { Language::AST ast; Language::LanguageType type; + IRGeneratedVariable() { + this = TIRTempVariable(func, ast, _, type) or + this = TIRStringLiteral(func, ast, type, _) + } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } @@ -144,6 +174,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getTag() = tag } +/** + * Represents a temporary variable introduced by IR construction. The most common examples are the + * variable generated to hold the return value of afunction, or the variable generated to hold the + * result of a condition operator (`a ? b : c`). + */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -158,18 +193,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa override string getBaseString() { result = "#temp" } } +/** + * The temporary variable generated to hold the return value of a function. + */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } final override string toString() { result = "#return" } } +/** + * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } override string getBaseString() { result = "#throw" } } +/** + * The variable generated to represent the contents of a string literal. This variable acts much + * like a read-only global variable. + */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index e10e266b2ab..349ff7cd6bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -17,10 +17,16 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var * be a user-declared variable (`IRUserVariable`) or a temporary variable * generated by the AST-to-IR translation (`IRTempVariable`). */ -abstract class IRVariable extends TIRVariable { +class IRVariable extends TIRVariable { Language::Function func; - abstract string toString(); + IRVariable() { + this = TIRUserVariable(_, _, func) or + this = TIRTempVariable(func, _, _, _) or + this = TIRStringLiteral(func, _, _, _) + } + + string toString() { none() } /** * Holds if this variable's value cannot be changed within a function. Currently used for string @@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::LanguageType getLanguageType(); + Language::LanguageType getLanguageType() { none() } /** * Gets the AST node that declared this variable, or that introduced this * variable as part of the AST-to-IR translation. */ - abstract Language::AST getAST(); + Language::AST getAST() { none() } /** * Gets an identifier string for the variable. This identifier is unique * within the function. */ - abstract string getUniqueId(); + string getUniqueId() { none() } /** * Gets the source location of this variable. @@ -101,16 +107,31 @@ class IRUserVariable extends IRVariable, TIRUserVariable { * stack. This includes all parameters, non-static local variables, and * temporary variables. */ -abstract class IRAutomaticVariable extends IRVariable { } +class IRAutomaticVariable extends IRVariable { + IRAutomaticVariable() { + exists(Language::Variable var | + this = TIRUserVariable(var, _, func) and + Language::isVariableAutomatic(var) + ) or + this = TIRTempVariable(func, _, _, _) + } +} +/** + * Represents a user-declared variable that is allocated on the stack. This + * includes all parameters and non-static local variables. + */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; - IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } - final override Language::AutomaticVariable getVariable() { result = var } } +/** + * Represents a user-declared variable that is not allocated on the stack. This + * includes all global variables, namespace-scope variables, static fields, and + * static local variables. + */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -119,10 +140,19 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } -abstract class IRGeneratedVariable extends IRVariable { +/** + * Represents a variable that is not user-declared. This includes temporary + * variables generated as part of IR construction, as well as string literals. + */ +class IRGeneratedVariable extends IRVariable { Language::AST ast; Language::LanguageType type; + IRGeneratedVariable() { + this = TIRTempVariable(func, ast, _, type) or + this = TIRStringLiteral(func, ast, type, _) + } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } @@ -144,6 +174,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getTag() = tag } +/** + * Represents a temporary variable introduced by IR construction. The most common examples are the + * variable generated to hold the return value of afunction, or the variable generated to hold the + * result of a condition operator (`a ? b : c`). + */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -158,18 +193,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa override string getBaseString() { result = "#temp" } } +/** + * The temporary variable generated to hold the return value of a function. + */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } final override string toString() { result = "#return" } } +/** + * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } override string getBaseString() { result = "#throw" } } +/** + * The variable generated to represent the contents of a string literal. This variable acts much + * like a read-only global variable. + */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index e10e266b2ab..349ff7cd6bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -17,10 +17,16 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var * be a user-declared variable (`IRUserVariable`) or a temporary variable * generated by the AST-to-IR translation (`IRTempVariable`). */ -abstract class IRVariable extends TIRVariable { +class IRVariable extends TIRVariable { Language::Function func; - abstract string toString(); + IRVariable() { + this = TIRUserVariable(_, _, func) or + this = TIRTempVariable(func, _, _, _) or + this = TIRStringLiteral(func, _, _, _) + } + + string toString() { none() } /** * Holds if this variable's value cannot be changed within a function. Currently used for string @@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::LanguageType getLanguageType(); + Language::LanguageType getLanguageType() { none() } /** * Gets the AST node that declared this variable, or that introduced this * variable as part of the AST-to-IR translation. */ - abstract Language::AST getAST(); + Language::AST getAST() { none() } /** * Gets an identifier string for the variable. This identifier is unique * within the function. */ - abstract string getUniqueId(); + string getUniqueId() { none() } /** * Gets the source location of this variable. @@ -101,16 +107,31 @@ class IRUserVariable extends IRVariable, TIRUserVariable { * stack. This includes all parameters, non-static local variables, and * temporary variables. */ -abstract class IRAutomaticVariable extends IRVariable { } +class IRAutomaticVariable extends IRVariable { + IRAutomaticVariable() { + exists(Language::Variable var | + this = TIRUserVariable(var, _, func) and + Language::isVariableAutomatic(var) + ) or + this = TIRTempVariable(func, _, _, _) + } +} +/** + * Represents a user-declared variable that is allocated on the stack. This + * includes all parameters and non-static local variables. + */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; - IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } - final override Language::AutomaticVariable getVariable() { result = var } } +/** + * Represents a user-declared variable that is not allocated on the stack. This + * includes all global variables, namespace-scope variables, static fields, and + * static local variables. + */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -119,10 +140,19 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } -abstract class IRGeneratedVariable extends IRVariable { +/** + * Represents a variable that is not user-declared. This includes temporary + * variables generated as part of IR construction, as well as string literals. + */ +class IRGeneratedVariable extends IRVariable { Language::AST ast; Language::LanguageType type; + IRGeneratedVariable() { + this = TIRTempVariable(func, ast, _, type) or + this = TIRStringLiteral(func, ast, type, _) + } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } @@ -144,6 +174,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getTag() = tag } +/** + * Represents a temporary variable introduced by IR construction. The most common examples are the + * variable generated to hold the return value of afunction, or the variable generated to hold the + * result of a condition operator (`a ? b : c`). + */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -158,18 +193,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa override string getBaseString() { result = "#temp" } } +/** + * The temporary variable generated to hold the return value of a function. + */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } final override string toString() { result = "#return" } } +/** + * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } override string getBaseString() { result = "#throw" } } +/** + * The variable generated to represent the contents of a string literal. This variable acts much + * like a read-only global variable. + */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index e10e266b2ab..349ff7cd6bd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -17,10 +17,16 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var * be a user-declared variable (`IRUserVariable`) or a temporary variable * generated by the AST-to-IR translation (`IRTempVariable`). */ -abstract class IRVariable extends TIRVariable { +class IRVariable extends TIRVariable { Language::Function func; - abstract string toString(); + IRVariable() { + this = TIRUserVariable(_, _, func) or + this = TIRTempVariable(func, _, _, _) or + this = TIRStringLiteral(func, _, _, _) + } + + string toString() { none() } /** * Holds if this variable's value cannot be changed within a function. Currently used for string @@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::LanguageType getLanguageType(); + Language::LanguageType getLanguageType() { none() } /** * Gets the AST node that declared this variable, or that introduced this * variable as part of the AST-to-IR translation. */ - abstract Language::AST getAST(); + Language::AST getAST() { none() } /** * Gets an identifier string for the variable. This identifier is unique * within the function. */ - abstract string getUniqueId(); + string getUniqueId() { none() } /** * Gets the source location of this variable. @@ -101,16 +107,31 @@ class IRUserVariable extends IRVariable, TIRUserVariable { * stack. This includes all parameters, non-static local variables, and * temporary variables. */ -abstract class IRAutomaticVariable extends IRVariable { } +class IRAutomaticVariable extends IRVariable { + IRAutomaticVariable() { + exists(Language::Variable var | + this = TIRUserVariable(var, _, func) and + Language::isVariableAutomatic(var) + ) or + this = TIRTempVariable(func, _, _, _) + } +} +/** + * Represents a user-declared variable that is allocated on the stack. This + * includes all parameters and non-static local variables. + */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; - IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } - final override Language::AutomaticVariable getVariable() { result = var } } +/** + * Represents a user-declared variable that is not allocated on the stack. This + * includes all global variables, namespace-scope variables, static fields, and + * static local variables. + */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -119,10 +140,19 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } -abstract class IRGeneratedVariable extends IRVariable { +/** + * Represents a variable that is not user-declared. This includes temporary + * variables generated as part of IR construction, as well as string literals. + */ +class IRGeneratedVariable extends IRVariable { Language::AST ast; Language::LanguageType type; + IRGeneratedVariable() { + this = TIRTempVariable(func, ast, _, type) or + this = TIRStringLiteral(func, ast, type, _) + } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } @@ -144,6 +174,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getTag() = tag } +/** + * Represents a temporary variable introduced by IR construction. The most common examples are the + * variable generated to hold the return value of afunction, or the variable generated to hold the + * result of a condition operator (`a ? b : c`). + */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -158,18 +193,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa override string getBaseString() { result = "#temp" } } +/** + * The temporary variable generated to hold the return value of a function. + */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } final override string toString() { result = "#return" } } +/** + * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } override string getBaseString() { result = "#throw" } } +/** + * The variable generated to represent the contents of a string literal. This variable acts much + * like a read-only global variable. + */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index e10e266b2ab..349ff7cd6bd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -17,10 +17,16 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var * be a user-declared variable (`IRUserVariable`) or a temporary variable * generated by the AST-to-IR translation (`IRTempVariable`). */ -abstract class IRVariable extends TIRVariable { +class IRVariable extends TIRVariable { Language::Function func; - abstract string toString(); + IRVariable() { + this = TIRUserVariable(_, _, func) or + this = TIRTempVariable(func, _, _, _) or + this = TIRStringLiteral(func, _, _, _) + } + + string toString() { none() } /** * Holds if this variable's value cannot be changed within a function. Currently used for string @@ -41,19 +47,19 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::LanguageType getLanguageType(); + Language::LanguageType getLanguageType() { none() } /** * Gets the AST node that declared this variable, or that introduced this * variable as part of the AST-to-IR translation. */ - abstract Language::AST getAST(); + Language::AST getAST() { none() } /** * Gets an identifier string for the variable. This identifier is unique * within the function. */ - abstract string getUniqueId(); + string getUniqueId() { none() } /** * Gets the source location of this variable. @@ -101,16 +107,31 @@ class IRUserVariable extends IRVariable, TIRUserVariable { * stack. This includes all parameters, non-static local variables, and * temporary variables. */ -abstract class IRAutomaticVariable extends IRVariable { } +class IRAutomaticVariable extends IRVariable { + IRAutomaticVariable() { + exists(Language::Variable var | + this = TIRUserVariable(var, _, func) and + Language::isVariableAutomatic(var) + ) or + this = TIRTempVariable(func, _, _, _) + } +} +/** + * Represents a user-declared variable that is allocated on the stack. This + * includes all parameters and non-static local variables. + */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; - IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } - final override Language::AutomaticVariable getVariable() { result = var } } +/** + * Represents a user-declared variable that is not allocated on the stack. This + * includes all global variables, namespace-scope variables, static fields, and + * static local variables. + */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -119,10 +140,19 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } -abstract class IRGeneratedVariable extends IRVariable { +/** + * Represents a variable that is not user-declared. This includes temporary + * variables generated as part of IR construction, as well as string literals. + */ +class IRGeneratedVariable extends IRVariable { Language::AST ast; Language::LanguageType type; + IRGeneratedVariable() { + this = TIRTempVariable(func, ast, _, type) or + this = TIRStringLiteral(func, ast, type, _) + } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } @@ -144,6 +174,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getTag() = tag } +/** + * Represents a temporary variable introduced by IR construction. The most common examples are the + * variable generated to hold the return value of afunction, or the variable generated to hold the + * result of a condition operator (`a ? b : c`). + */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -158,18 +193,28 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa override string getBaseString() { result = "#temp" } } +/** + * The temporary variable generated to hold the return value of a function. + */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } final override string toString() { result = "#return" } } +/** + * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } override string getBaseString() { result = "#throw" } } +/** + * The variable generated to represent the contents of a string literal. This variable acts much + * like a read-only global variable. + */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; From 51ff262cbc6fee9fab7a7186416649bb5b15e4ee Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 14 Aug 2019 13:53:48 -0700 Subject: [PATCH 16/32] C++/C#: Add IR SSA sanity tests --- config/identical-files.json | 5 +++++ .../aliased_ssa/internal/SSAConstruction.qll | 13 +++++++++++++ .../aliased_ssa/internal/SSASanity.ql | 8 ++++++++ .../aliased_ssa/internal/SSASanity.qll | 2 ++ .../unaliased_ssa/internal/SSAConstruction.qll | 13 +++++++++++++ .../unaliased_ssa/internal/SSASanity.ql | 8 ++++++++ .../unaliased_ssa/internal/SSASanity.qll | 2 ++ .../ir/ssa/aliased_ssa_ssa_sanity.expected | 0 .../ir/ssa/aliased_ssa_ssa_sanity.qlref | 1 + .../ir/ssa/unaliased_ssa_ssa_sanity.expected | 0 .../ir/ssa/unaliased_ssa_ssa_sanity.qlref | 1 + .../unaliased_ssa/internal/SSAConstruction.qll | 13 +++++++++++++ .../unaliased_ssa/internal/SSASanity.ql | 8 ++++++++ .../unaliased_ssa/internal/SSASanity.qll | 2 ++ .../ir/ir/unaliased_ssa_ssa_sanity.expected | 0 .../ir/ir/unaliased_ssa_ssa_sanity.qlref | 1 + 16 files changed, 77 insertions(+) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll create mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected create mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.qlref create mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected create mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.qlref create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref diff --git a/config/identical-files.json b/config/identical-files.json index 4fdac5c7fea..29601d19510 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -143,6 +143,11 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll" ], + "IR SSASanity": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll" + ], "C++ IR InstructionImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll", diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index a789edc7590..ebb111efc03 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -865,3 +865,16 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + +module SSASanity { + query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, + OldIR::IRFunction func, string funcText) { + exists(int locationCount | + locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and + locationCount > 1 and + func = operand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." + ) + } +} \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql new file mode 100644 index 00000000000..50368cdc6d9 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql @@ -0,0 +1,8 @@ +/** + * @name Aliased SSA Sanity Check + * @description Performs sanity checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/aliased-ssa-sanity-check + */ + +import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll new file mode 100644 index 00000000000..95e8443b2a3 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll @@ -0,0 +1,2 @@ +private import SSAConstruction as SSA +import SSA::SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index a789edc7590..ebb111efc03 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -865,3 +865,16 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + +module SSASanity { + query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, + OldIR::IRFunction func, string funcText) { + exists(int locationCount | + locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and + locationCount > 1 and + func = operand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." + ) + } +} \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql new file mode 100644 index 00000000000..b67f6f281be --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Sanity Check + * @description Performs sanity checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/unaliased-ssa-sanity-check + */ + +import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll new file mode 100644 index 00000000000..95e8443b2a3 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll @@ -0,0 +1,2 @@ +private import SSAConstruction as SSA +import SSA::SSASanity diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.qlref new file mode 100644 index 00000000000..8e348011785 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.qlref new file mode 100644 index 00000000000..18bf9212dbf --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index a789edc7590..ebb111efc03 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -865,3 +865,16 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + +module SSASanity { + query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, + OldIR::IRFunction func, string funcText) { + exists(int locationCount | + locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and + locationCount > 1 and + func = operand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." + ) + } +} \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql new file mode 100644 index 00000000000..11d7add514b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Sanity Check + * @description Performs sanity checks on the SSA construction. This query should have no results. + * @kind table + * @id csharp/unaliased-ssa-sanity-check + */ + +import SSASanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll new file mode 100644 index 00000000000..95e8443b2a3 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll @@ -0,0 +1,2 @@ +private import SSAConstruction as SSA +import SSA::SSASanity diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref new file mode 100644 index 00000000000..1b7d4a7996a --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file From df218357590cf1a1a9646b63481dead245f5e5dc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 14 Aug 2019 13:54:52 -0700 Subject: [PATCH 17/32] C++/C#: Refactor some integer constant code Make `bitsToBytesAndBits` omit the leftover bits if zero. --- .../code/cpp/ir/internal/IntegerConstant.qll | 33 +++++++++++++++++++ .../code/cpp/ir/internal/IntegerInterval.qll | 2 +- .../csharp/ir/internal/IntegerConstant.qll | 33 +++++++++++++++++++ .../csharp/ir/internal/IntegerInterval.qll | 2 +- 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll index 55546ba380f..0d845303c28 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll @@ -192,3 +192,36 @@ predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b } */ bindingset[a, b] predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b } + +/** + * Converts the bit count in `bits` to a byte count and a bit count in the form + * "bytes:bits". If `bits` represents an integer number of bytes, the ":bits" section is omitted. + * If `bits` does not have a known value, the result is "?". + */ +bindingset[bits] +string bitsToBytesAndBits(IntValue bits) { + exists(int bytes, int leftoverBits | + hasValue(bits) and + bytes = bits / 8 and + leftoverBits = bits % 8 and + if leftoverBits = 0 then + result = bytes.toString() + else + result = bytes + ":" + leftoverBits + ) or + not hasValue(bits) and result = "?" +} + +/** + * Gets a printable string for a bit offset with possibly unknown value. + */ +bindingset[bitOffset] +string getBitOffsetString(IntValue bitOffset) { + if hasValue(bitOffset) then + if bitOffset >= 0 then + result = "+" + bitsToBytesAndBits(bitOffset) + else + result = "-" + bitsToBytesAndBits(neg(bitOffset)) + else + result = "+?" +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll index bc09f9c2243..cd12b9b627a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll @@ -30,5 +30,5 @@ Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntVal bindingset[start, end] string getIntervalString(IntValue start, IntValue end) { // We represent an interval has half-open, so print it as "[start..end)". - result = "[" + intValueToString(start) + ".." + intValueToString(end) + ")" + result = "[" + bitsToBytesAndBits(start) + ".." + bitsToBytesAndBits(end) + ")" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll index 55546ba380f..0d845303c28 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll @@ -192,3 +192,36 @@ predicate isGT(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a > b } */ bindingset[a, b] predicate isGE(IntValue a, IntValue b) { hasValue(a) and hasValue(b) and a >= b } + +/** + * Converts the bit count in `bits` to a byte count and a bit count in the form + * "bytes:bits". If `bits` represents an integer number of bytes, the ":bits" section is omitted. + * If `bits` does not have a known value, the result is "?". + */ +bindingset[bits] +string bitsToBytesAndBits(IntValue bits) { + exists(int bytes, int leftoverBits | + hasValue(bits) and + bytes = bits / 8 and + leftoverBits = bits % 8 and + if leftoverBits = 0 then + result = bytes.toString() + else + result = bytes + ":" + leftoverBits + ) or + not hasValue(bits) and result = "?" +} + +/** + * Gets a printable string for a bit offset with possibly unknown value. + */ +bindingset[bitOffset] +string getBitOffsetString(IntValue bitOffset) { + if hasValue(bitOffset) then + if bitOffset >= 0 then + result = "+" + bitsToBytesAndBits(bitOffset) + else + result = "-" + bitsToBytesAndBits(neg(bitOffset)) + else + result = "+?" +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll index bc09f9c2243..cd12b9b627a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll @@ -30,5 +30,5 @@ Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntVal bindingset[start, end] string getIntervalString(IntValue start, IntValue end) { // We represent an interval has half-open, so print it as "[start..end)". - result = "[" + intValueToString(start) + ".." + intValueToString(end) + ")" + result = "[" + bitsToBytesAndBits(start) + ".." + bitsToBytesAndBits(end) + ")" } From bd78f689752fc34801641f293358316dec285d64 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 22 Nov 2019 16:08:49 -0700 Subject: [PATCH 18/32] C++/C#: Fix formatting --- .../ir/implementation/aliased_ssa/IRVariable.qll | 3 ++- .../ir/implementation/aliased_ssa/Instruction.qll | 13 +++++++------ .../aliased_ssa/internal/SSAConstruction.qll | 7 ++++--- .../aliased_ssa/internal/SSASanity.ql | 2 +- .../code/cpp/ir/implementation/raw/IRVariable.qll | 3 ++- .../code/cpp/ir/implementation/raw/Instruction.qll | 13 +++++++------ .../ir/implementation/unaliased_ssa/IRVariable.qll | 3 ++- .../ir/implementation/unaliased_ssa/Instruction.qll | 13 +++++++------ .../unaliased_ssa/internal/SSAConstruction.qll | 7 ++++--- .../csharp/ir/implementation/raw/IRVariable.qll | 3 ++- .../csharp/ir/implementation/raw/Instruction.qll | 13 +++++++------ .../ir/implementation/unaliased_ssa/IRVariable.qll | 3 ++- .../ir/implementation/unaliased_ssa/Instruction.qll | 13 +++++++------ .../unaliased_ssa/internal/SSAConstruction.qll | 7 ++++--- 14 files changed, 58 insertions(+), 45 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 349ff7cd6bd..1092acc0003 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -112,7 +112,8 @@ class IRAutomaticVariable extends IRVariable { exists(Language::Variable var | this = TIRUserVariable(var, _, func) and Language::isVariableAutomatic(var) - ) or + ) + or this = TIRTempVariable(func, _, _, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index bfd04a279e0..8819826d5c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -94,17 +94,18 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, string message, IRFunction func, - string funcText) { + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { exists(OperandTag tag, int operandCount | operandCount = strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and operandCount > 1 and not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and + " in function '$@'." and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index ebb111efc03..96b4c28db82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -867,8 +867,9 @@ private module CachedForDebugging { } module SSASanity { - query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, - OldIR::IRFunction func, string funcText) { + query predicate multipleOperandMemoryLocations( + OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText + ) { exists(int locationCount | locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and locationCount > 1 and @@ -877,4 +878,4 @@ module SSASanity { message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." ) } -} \ No newline at end of file +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql index 50368cdc6d9..3bd709a93dc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql @@ -1,6 +1,6 @@ /** * @name Aliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. + * @description Performs sanity checks on the SSA construction. This query should have no results. * @kind table * @id cpp/aliased-ssa-sanity-check */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 349ff7cd6bd..1092acc0003 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -112,7 +112,8 @@ class IRAutomaticVariable extends IRVariable { exists(Language::Variable var | this = TIRUserVariable(var, _, func) and Language::isVariableAutomatic(var) - ) or + ) + or this = TIRTempVariable(func, _, _, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index bfd04a279e0..8819826d5c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -94,17 +94,18 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, string message, IRFunction func, - string funcText) { + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { exists(OperandTag tag, int operandCount | operandCount = strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and operandCount > 1 and not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and + " in function '$@'." and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 349ff7cd6bd..1092acc0003 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -112,7 +112,8 @@ class IRAutomaticVariable extends IRVariable { exists(Language::Variable var | this = TIRUserVariable(var, _, func) and Language::isVariableAutomatic(var) - ) or + ) + or this = TIRTempVariable(func, _, _, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index bfd04a279e0..8819826d5c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -94,17 +94,18 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, string message, IRFunction func, - string funcText) { + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { exists(OperandTag tag, int operandCount | operandCount = strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and operandCount > 1 and not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and + " in function '$@'." and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ebb111efc03..96b4c28db82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -867,8 +867,9 @@ private module CachedForDebugging { } module SSASanity { - query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, - OldIR::IRFunction func, string funcText) { + query predicate multipleOperandMemoryLocations( + OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText + ) { exists(int locationCount | locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and locationCount > 1 and @@ -877,4 +878,4 @@ module SSASanity { message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." ) } -} \ No newline at end of file +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 349ff7cd6bd..1092acc0003 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -112,7 +112,8 @@ class IRAutomaticVariable extends IRVariable { exists(Language::Variable var | this = TIRUserVariable(var, _, func) and Language::isVariableAutomatic(var) - ) or + ) + or this = TIRTempVariable(func, _, _, _) } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index bfd04a279e0..8819826d5c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -94,17 +94,18 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, string message, IRFunction func, - string funcText) { + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { exists(OperandTag tag, int operandCount | operandCount = strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and operandCount > 1 and not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and + " in function '$@'." and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 349ff7cd6bd..1092acc0003 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -112,7 +112,8 @@ class IRAutomaticVariable extends IRVariable { exists(Language::Variable var | this = TIRUserVariable(var, _, func) and Language::isVariableAutomatic(var) - ) or + ) + or this = TIRTempVariable(func, _, _, _) } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index bfd04a279e0..8819826d5c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -94,17 +94,18 @@ module InstructionSanity { /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ - query predicate duplicateOperand(Instruction instr, string message, IRFunction func, - string funcText) { + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { exists(OperandTag tag, int operandCount | operandCount = strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and operandCount > 1 and not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and + " in function '$@'." and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ebb111efc03..96b4c28db82 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -867,8 +867,9 @@ private module CachedForDebugging { } module SSASanity { - query predicate multipleOperandMemoryLocations(OldIR::MemoryOperand operand, string message, - OldIR::IRFunction func, string funcText) { + query predicate multipleOperandMemoryLocations( + OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText + ) { exists(int locationCount | locationCount = strictcount(Alias::getOperandMemoryLocation(operand)) and locationCount > 1 and @@ -877,4 +878,4 @@ module SSASanity { message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'." ) } -} \ No newline at end of file +} From eda47bfc5175a8dfb28cf7b5b44562366e5b024f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 14 Aug 2019 13:59:41 -0700 Subject: [PATCH 19/32] C++: Add SSA sanity tests to IR tests --- cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected | 0 cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.qlref | 1 + .../test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected | 0 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref | 1 + 4 files changed, 2 insertions(+) create mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected create mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.qlref create mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected create mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.qlref new file mode 100644 index 00000000000..8e348011785 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref new file mode 100644 index 00000000000..18bf9212dbf --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file From 036e0f75c81b837f7c6bdec05317bb7f35b9210e Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 25 Nov 2019 15:32:52 +0100 Subject: [PATCH 20/32] Python: Account for non-evaluation of annotations in cyclic imports. Should fix #2426. Essentially, we disregard expressions used inside annotations, if these annotations occur in a file that has `from __future__ import annotations`, as this prevents the annotations from being evaluated. --- python/ql/src/Imports/Cyclic.qll | 27 ++++++++++++++++++- .../ModuleLevelCyclicImport.expected | 2 ++ .../ModuleLevelCyclicImport.qlref | 1 + .../cyclic-module-annotations-fp/module1.py | 10 +++++++ .../cyclic-module-annotations-fp/module2.py | 11 ++++++++ .../cyclic-module-annotations-fp/module3.py | 8 ++++++ .../cyclic-module-annotations-fp/module4.py | 9 +++++++ 7 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.expected create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.qlref create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module1.py create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module2.py create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module3.py create mode 100644 python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module4.py diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index c550c163c66..29c05b08209 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -60,7 +60,8 @@ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, exists(Expr mod | use.getEnclosingModule() = enclosing.getScope() and not use.getScope+() instanceof Function and - mod.pointsTo(m) + mod.pointsTo(m) and + not is_annotation_with_from_future_import_annotations(use) | // either 'M.foo' use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr @@ -70,6 +71,30 @@ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, ) } +/** + * Holds if `use` appears inside an annotation. + */ +predicate is_used_in_annotation(Expr use) { + exists(FunctionExpr f | + f.getReturns().getASubExpression*() = use or + f.getArgs().getAnAnnotation().getASubExpression*() = use + ) + or + exists(AnnAssign a | a.getAnnotation().getASubExpression*() = use) +} + +/** + * Holds if `use` appears as a subexpression of an annotation, _and_ if the + * postponed evaluation of annotations presented in PEP 563 is in effect. + * See https://www.python.org/dev/peps/pep-0563/ + */ +predicate is_annotation_with_from_future_import_annotations(Expr use) { + exists(ImportMember i | i.getScope() = use.getEnclosingModule() | + i.getModule().pointsTo().getName() = "__future__" and i.getName() = "annotations" + ) and + is_used_in_annotation(use) +} + /** * Whether importing module 'first' before importing module 'other' will fail at runtime, due to an * AttributeError at 'use' (in module 'other') caused by 'first.attr' not being defined as its definition can diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.expected b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.expected new file mode 100644 index 00000000000..1a5f4c8f9e8 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.expected @@ -0,0 +1,2 @@ +| module3.py:8:23:8:33 | Attribute | 'Bar' may not be defined if module $@ is imported before module $@, as the $@ of Bar occurs after the cyclic $@ of module3. | module4.py:0:0:0:0 | Module module4 | module4 | module3.py:0:0:0:0 | Module module3 | module3 | module4.py:7:7:7:9 | ControlFlowNode for Bar | definition | module4.py:4:1:4:14 | Import | import | +| module4.py:8:30:8:40 | Attribute | 'Foo' may not be defined if module $@ is imported before module $@, as the $@ of Foo occurs after the cyclic $@ of module4. | module3.py:0:0:0:0 | Module module3 | module3 | module4.py:0:0:0:0 | Module module4 | module4 | module3.py:7:7:7:9 | ControlFlowNode for Foo | definition | module3.py:4:1:4:14 | Import | import | diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.qlref b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.qlref new file mode 100644 index 00000000000..8b9bc8c123a --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/ModuleLevelCyclicImport.qlref @@ -0,0 +1 @@ +Imports/ModuleLevelCyclicImport.ql diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module1.py b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module1.py new file mode 100644 index 00000000000..66d263464e2 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module1.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +import dataclasses +import typing + +import module2 + +@dataclasses.dataclass() +class Foo: + bars: typing.List[module2.Bar] diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module2.py b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module2.py new file mode 100644 index 00000000000..1a26c3a2c52 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module2.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +import dataclasses +import typing + +import module1 + +@dataclasses.dataclass() +class Bar: + def is_in_foo(self, foo: module1.Foo): + return self in foo.bars diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module3.py b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module3.py new file mode 100644 index 00000000000..83f5eda9557 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module3.py @@ -0,0 +1,8 @@ +import dataclasses +import typing + +import module4 + +@dataclasses.dataclass() +class Foo: + bars: typing.List[module4.Bar] diff --git a/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module4.py b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module4.py new file mode 100644 index 00000000000..b6da208fbe3 --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module-annotations-fp/module4.py @@ -0,0 +1,9 @@ +import dataclasses +import typing + +import module3 + +@dataclasses.dataclass() +class Bar: + def is_in_foo(self, foo: module3.Foo): + return self in foo.bars From 82b35a116c1d75f723d7968228b810533ed35c6f Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 21 Nov 2019 21:07:12 +0000 Subject: [PATCH 21/32] JS: Handle .js import of .ts file --- javascript/ql/src/semmle/javascript/Modules.qll | 6 +++++- javascript/ql/src/semmle/javascript/Paths.qll | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index 55a8a6acd0e..97be97d8f50 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -83,9 +83,13 @@ abstract class Module extends TopLevel { result = c.(Folder).getJavaScriptFile("index") ) or - // handle the case where the import path is missing an extension + // handle the case where the import path is missing the extension exists(Folder f | f = path.resolveUpTo(path.getNumComponent() - 1) | result = f.getJavaScriptFile(path.getBaseName()) + or + // If a js file was not found look for a file that compiles to js + not exists(f.getJavaScriptFile(path.getBaseName())) and + result = f.getJavaScriptFile(path.getStem()) ) ) } diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index f15345bd94b..754b38133c8 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -205,6 +205,9 @@ abstract class PathExpr extends PathExprBase { /** Gets the base name of the folder or file this path refers to. */ string getBaseName() { result = getValue().(PathString).getBaseName() } + /** Gets the stem, that is, base name without extension, of the folder or file this path refers to. */ + string getStem() { result = getValue().(PathString).getStem() } + /** * Gets the file or folder that the first `n` components of this path refer to * when resolved relative to the root folder of the given `priority`. From e5ba80b18c3bdd3e565e9d6cd824e2398630d34a Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 25 Nov 2019 15:05:33 +0000 Subject: [PATCH 22/32] JS: Add test --- .../library-tests/Modules/import-ts-with-js-extension.ts | 3 +++ javascript/ql/test/library-tests/Modules/tests.expected | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 javascript/ql/test/library-tests/Modules/import-ts-with-js-extension.ts diff --git a/javascript/ql/test/library-tests/Modules/import-ts-with-js-extension.ts b/javascript/ql/test/library-tests/Modules/import-ts-with-js-extension.ts new file mode 100644 index 00000000000..a2b4a8a3a7f --- /dev/null +++ b/javascript/ql/test/library-tests/Modules/import-ts-with-js-extension.ts @@ -0,0 +1,3 @@ +import { foo } from "./f.js"; + +foo(); diff --git a/javascript/ql/test/library-tests/Modules/tests.expected b/javascript/ql/test/library-tests/Modules/tests.expected index 39d24b09700..6858d546fa9 100644 --- a/javascript/ql/test/library-tests/Modules/tests.expected +++ b/javascript/ql/test/library-tests/Modules/tests.expected @@ -6,6 +6,7 @@ test_ImportSpecifiers | f.ts:1:8:1:8 | g | f.ts:1:8:1:8 | g | | g.ts:1:9:1:11 | foo | g.ts:1:9:1:11 | foo | | import-in-mjs.mjs:1:8:1:24 | exported_from_mjs | import-in-mjs.mjs:1:8:1:24 | exported_from_mjs | +| import-ts-with-js-extension.ts:1:10:1:12 | foo | import-ts-with-js-extension.ts:1:10:1:12 | foo | | m/c.js:1:8:1:13 | * as b | m/c.js:1:13:1:13 | b | | tst.html:5:10:5:10 | f | tst.html:5:10:5:10 | f | | unresolved.js:1:8:1:8 | f | unresolved.js:1:8:1:8 | f | @@ -43,6 +44,7 @@ test_getImportedName | f.ts:1:8:1:8 | g | default | | g.ts:1:9:1:11 | foo | foo | | import-in-mjs.mjs:1:8:1:24 | exported_from_mjs | default | +| import-ts-with-js-extension.ts:1:10:1:12 | foo | foo | | tst.html:5:10:5:10 | f | default | | unresolved.js:1:8:1:8 | f | default | test_ExportDeclarations @@ -65,6 +67,7 @@ test_getAnImportedModule | es2015_require.js | d.js | | f.ts | e.js | | g.ts | f.ts | +| import-ts-with-js-extension.ts | f.ts | | m/c.js | b.js | test_getSourceNode | a.js:1:1:3:1 | export ... n 23;\\n} | default | a.js:1:16:3:1 | functio ... n 23;\\n} | @@ -87,6 +90,7 @@ test_Imports | f.ts:1:1:1:19 | import g from './e' | f.ts:1:15:1:19 | './e' | 1 | | g.ts:1:1:1:23 | import ... m './f' | g.ts:1:19:1:23 | './f' | 1 | | import-in-mjs.mjs:1:1:1:46 | import ... n-mjs'; | import-in-mjs.mjs:1:31:1:45 | 'export-in-mjs' | 1 | +| import-ts-with-js-extension.ts:1:1:1:29 | import ... /f.js"; | import-ts-with-js-extension.ts:1:21:1:28 | "./f.js" | 1 | | m/c.js:1:1:1:26 | import ... '../b'; | m/c.js:1:20:1:25 | '../b' | 1 | | tst.html:5:3:5:20 | import f from 'a'; | tst.html:5:17:5:19 | 'a' | 1 | | unresolved.js:1:1:1:18 | import f from 'a'; | unresolved.js:1:15:1:17 | 'a' | 1 | @@ -94,6 +98,7 @@ test_NamedImportSpecifier | d.js:1:10:1:21 | default as g | | d.js:1:24:1:29 | x as y | | g.ts:1:9:1:11 | foo | +| import-ts-with-js-extension.ts:1:10:1:12 | foo | test_GlobalVariableRef | a.js:5:31:5:31 | o | | exports.js:3:9:3:15 | exports | From 2508da7971f61618e1176ea959be1d1a5129e74f Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 25 Nov 2019 17:01:32 +0000 Subject: [PATCH 23/32] JS: Add change note --- change-notes/1.24/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 53400f537ce..a1f0ee6ea61 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -5,6 +5,8 @@ * Support for the following frameworks and libraries has been improved: - [react](https://www.npmjs.com/package/react) +- Imports with the `.js` extension can now be resolved to a TypeScript file. + ## New queries | **Query** | **Tags** | **Purpose** | From e3e15a6015b7394b4b669f6a8b93ddc8cf4e0f08 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 25 Nov 2019 17:20:42 +0000 Subject: [PATCH 24/32] JS: Rephrase change note --- change-notes/1.24/analysis-javascript.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index a1f0ee6ea61..d762962a015 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -5,7 +5,8 @@ * Support for the following frameworks and libraries has been improved: - [react](https://www.npmjs.com/package/react) -- Imports with the `.js` extension can now be resolved to a TypeScript file. +- Imports with the `.js` extension can now be resolved to a TypeScript file, + when the import refers to a file generated by TypeScript. ## New queries From 521fbb125e7466fb65d312f7c93ab4314ac2c6c7 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 25 Nov 2019 11:12:23 -0700 Subject: [PATCH 25/32] C++/C#: Fix formatting --- .../cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql | 2 +- .../ir/implementation/unaliased_ssa/internal/SSASanity.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql index b67f6f281be..1b5ee80b603 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql @@ -1,6 +1,6 @@ /** * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. + * @description Performs sanity checks on the SSA construction. This query should have no results. * @kind table * @id cpp/unaliased-ssa-sanity-check */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql index 11d7add514b..43f303dd024 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql @@ -1,6 +1,6 @@ /** * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. + * @description Performs sanity checks on the SSA construction. This query should have no results. * @kind table * @id csharp/unaliased-ssa-sanity-check */ From 44c1c5a7abb24641e18413d8ab98c067edd807e4 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 25 Nov 2019 11:13:02 -0700 Subject: [PATCH 26/32] C++: Update `points_to.ql` test to use new bit offset format --- .../aliased_ssa/internal/AliasAnalysis.qll | 26 +-- .../unaliased_ssa/internal/AliasAnalysis.qll | 26 +-- .../ir/escape/points_to.expected | 172 +++++++++--------- .../test/library-tests/ir/escape/points_to.ql | 9 +- 4 files changed, 101 insertions(+), 132 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index 6ecfd1470bb..bc67acc1be2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -6,26 +6,6 @@ private import semmle.code.cpp.models.interfaces.Alias private class IntValue = Ints::IntValue; -/** - * Converts the bit count in `bits` to a byte count and a bit count in the form - * bytes:bits. - */ -bindingset[bits] -string bitsToBytesAndBits(int bits) { result = (bits / 8).toString() + ":" + (bits % 8).toString() } - -/** - * Gets a printable string for a bit offset with possibly unknown value. - */ -bindingset[bitOffset] -string getBitOffsetString(IntValue bitOffset) { - if Ints::hasValue(bitOffset) - then - if bitOffset >= 0 - then result = "+" + bitsToBytesAndBits(bitOffset) - else result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset)) - else result = "+?" -} - /** * Gets the offset of field `field` in bits. */ @@ -137,7 +117,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { or // Adding an integer to or subtracting an integer from a pointer propagates // the address with an offset. - bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) + exists(PointerOffsetInstruction ptrOffset | + ptrOffset = instr and + operand = ptrOffset.getLeftOperand() and + bitOffset = getPointerBitOffset(ptrOffset) + ) or // Computing a field address from a pointer propagates the address plus the // offset of the field. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 6ecfd1470bb..bc67acc1be2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -6,26 +6,6 @@ private import semmle.code.cpp.models.interfaces.Alias private class IntValue = Ints::IntValue; -/** - * Converts the bit count in `bits` to a byte count and a bit count in the form - * bytes:bits. - */ -bindingset[bits] -string bitsToBytesAndBits(int bits) { result = (bits / 8).toString() + ":" + (bits % 8).toString() } - -/** - * Gets a printable string for a bit offset with possibly unknown value. - */ -bindingset[bitOffset] -string getBitOffsetString(IntValue bitOffset) { - if Ints::hasValue(bitOffset) - then - if bitOffset >= 0 - then result = "+" + bitsToBytesAndBits(bitOffset) - else result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset)) - else result = "+?" -} - /** * Gets the offset of field `field` in bits. */ @@ -137,7 +117,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { or // Adding an integer to or subtracting an integer from a pointer propagates // the address with an offset. - bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) + exists(PointerOffsetInstruction ptrOffset | + ptrOffset = instr and + operand = ptrOffset.getLeftOperand() and + bitOffset = getPointerBitOffset(ptrOffset) + ) or // Computing a field address from a pointer propagates the address plus the // offset of the field. diff --git a/cpp/ql/test/library-tests/ir/escape/points_to.expected b/cpp/ql/test/library-tests/ir/escape/points_to.expected index ac518b5dd79..6447bd81a5f 100644 --- a/cpp/ql/test/library-tests/ir/escape/points_to.expected +++ b/cpp/ql/test/library-tests/ir/escape/points_to.expected @@ -1,86 +1,86 @@ -| escape.cpp:111:18:111:21 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 | -| escape.cpp:115:20:115:23 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 | -| escape.cpp:116:20:116:23 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 | -| escape.cpp:117:23:117:26 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:118:9:118:12 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:120:12:120:15 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:123:14:123:17 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:124:15:124:18 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:127:9:127:12 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:129:12:129:15 | CopyValue | no_+0:0 | no_+0:0 | -| escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | -| escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | -| escape.cpp:136:7:136:14 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:137:17:137:24 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | -| escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | -| escape.cpp:138:19:138:26 | Convert | no_Array+0:0 | no_Array+0:0 | -| escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 | -| escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | -| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 | -| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | -| escape.cpp:143:19:143:27 | CopyValue | no_Point+0:0 | no_Point+0:0 | -| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | -| escape.cpp:144:6:144:14 | CopyValue | no_Point+0:0 | no_Point+0:0 | -| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | -| escape.cpp:145:20:145:30 | CopyValue | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:146:5:146:18 | CopyValue | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:146:7:146:17 | CopyValue | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | -| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 | -| escape.cpp:151:5:151:14 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 | -| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 | -| escape.cpp:152:19:152:28 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 | -| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 | -| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 | -| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 | -| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 | -| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 | -| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 | -| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | -| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | -| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | -| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 | -| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 | -| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0:0 | passByPtr+0:0 | -| escape.cpp:170:21:170:29 | CopyValue | passByRef+0:0 | passByRef+0:0 | -| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0:0 | no_ssa_passByPtr+0:0 | -| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0:0 | no_ssa_passByRef+0:0 | -| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0:0 | no_ssa_passByPtr_ret+0:0 | -| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0:0 | no_ssa_passByRef_ret+0:0 | -| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0:0 | passByPtr2+0:0 | -| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0:0 | passByRef2+0:0 | -| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 | -| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0:0 | passByPtr3+0:0 | -| escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 | -| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0:0 | -| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0:0 | passByRef3+0:0 | -| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0:0 | no_ssa_passByPtr4+0:0 | -| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0:0 | no_ssa_passByPtr5+0:0 | -| escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 | -| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0:0 | -| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0:0 | passByRef6+0:0 | -| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 | -| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0:0 | -| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0:0 | no_ssa_passByRef7+0:0 | -| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 | -| escape.cpp:217:14:217:16 | CopyValue | c2+0:0 | c2+0:0 | -| escape.cpp:221:8:221:19 | Call | none | c3+0:0 | -| escape.cpp:225:17:225:28 | Call | none | c4+0:0 | -| escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 | -| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0:0 | condEscape1+0:0 | -| escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 | -| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0:0 | condEscape2+0:0 | +| escape.cpp:111:18:111:21 | CopyValue | no_+0 | no_+0 | +| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0 | no_+0 | +| escape.cpp:115:20:115:23 | CopyValue | no_+0 | no_+0 | +| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0 | no_+0 | +| escape.cpp:116:20:116:23 | CopyValue | no_+0 | no_+0 | +| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0 | no_+0 | +| escape.cpp:117:23:117:26 | CopyValue | no_+0 | no_+0 | +| escape.cpp:118:9:118:12 | CopyValue | no_+0 | no_+0 | +| escape.cpp:120:12:120:15 | CopyValue | no_+0 | no_+0 | +| escape.cpp:123:14:123:17 | CopyValue | no_+0 | no_+0 | +| escape.cpp:124:15:124:18 | CopyValue | no_+0 | no_+0 | +| escape.cpp:127:9:127:12 | CopyValue | no_+0 | no_+0 | +| escape.cpp:129:12:129:15 | CopyValue | no_+0 | no_+0 | +| escape.cpp:134:5:134:18 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:134:11:134:18 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:135:5:135:12 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20 | no_Array+20 | +| escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20 | no_Array+20 | +| escape.cpp:136:7:136:14 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:137:17:137:24 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20 | no_Array+20 | +| escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20 | no_Array+20 | +| escape.cpp:138:19:138:26 | Convert | no_Array+0 | no_Array+0 | +| escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0 | no_Point+0 | +| escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4 | no_Point+4 | +| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8 | no_Point+8 | +| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0 | no_Point+0 | +| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4 | no_Point+4 | +| escape.cpp:143:19:143:27 | CopyValue | no_Point+0 | no_Point+0 | +| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4 | no_Point+4 | +| escape.cpp:144:6:144:14 | CopyValue | no_Point+0 | no_Point+0 | +| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4 | no_Point+4 | +| escape.cpp:145:20:145:30 | CopyValue | no_Point+8 | no_Point+8 | +| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8 | no_Point+8 | +| escape.cpp:146:5:146:18 | CopyValue | no_Point+8 | no_Point+8 | +| escape.cpp:146:7:146:17 | CopyValue | no_Point+8 | no_Point+8 | +| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8 | no_Point+8 | +| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0 | no_Derived+0 | +| escape.cpp:149:5:149:14 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0 | no_Derived+0 | +| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0 | no_Derived+0 | +| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Derived : Intermediate1] | no_Derived+0 | no_Derived+0 | +| escape.cpp:150:18:150:27 | ConvertToNonVirtualBase[Intermediate1 : Base] | no_Derived+0 | no_Derived+0 | +| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0 | no_Derived+0 | +| escape.cpp:151:5:151:14 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12 | no_Derived+12 | +| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16 | no_Derived+16 | +| escape.cpp:152:19:152:28 | ConvertToNonVirtualBase[Derived : Intermediate2] | no_Derived+12 | no_Derived+12 | +| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16 | no_Derived+16 | +| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0 | no_ssa_addrOf+0 | +| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0 | no_ssa_addrOf+0 | +| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0 | no_ssa_refTo+0 | +| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0 | no_ssa_refTo+0 | +| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0 | no_ssa_refToArrayElement+0 | +| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 | +| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 | +| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20 | no_ssa_refToArrayElement+20 | +| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0 | no_ssa_refToArray+0 | +| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0 | no_ssa_refToArray+0 | +| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0 | passByPtr+0 | +| escape.cpp:170:21:170:29 | CopyValue | passByRef+0 | passByRef+0 | +| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0 | no_ssa_passByPtr+0 | +| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0 | no_ssa_passByRef+0 | +| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0 | no_ssa_passByPtr_ret+0 | +| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0 | no_ssa_passByRef_ret+0 | +| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0 | passByPtr2+0 | +| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0 | passByRef2+0 | +| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0 | +| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0 | passByPtr3+0 | +| escape.cpp:194:32:194:46 | Call | none | passByRef3+0 | +| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0 | +| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0 | passByRef3+0 | +| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0 | no_ssa_passByPtr4+0 | +| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0 | no_ssa_passByPtr5+0 | +| escape.cpp:202:5:202:19 | Call | none | passByRef6+0 | +| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0 | +| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0 | passByRef6+0 | +| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0 | +| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0 | +| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0 | no_ssa_passByRef7+0 | +| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0 | +| escape.cpp:217:14:217:16 | CopyValue | c2+0 | c2+0 | +| escape.cpp:221:8:221:19 | Call | none | c3+0 | +| escape.cpp:225:17:225:28 | Call | none | c4+0 | +| escape.cpp:247:2:247:27 | Store | condEscape1+0 | condEscape1+0 | +| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0 | condEscape1+0 | +| escape.cpp:249:9:249:34 | Store | condEscape2+0 | condEscape2+0 | +| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0 | condEscape2+0 | diff --git a/cpp/ql/test/library-tests/ir/escape/points_to.ql b/cpp/ql/test/library-tests/ir/escape/points_to.ql index 04dbf0e0060..7c265974b10 100644 --- a/cpp/ql/test/library-tests/ir/escape/points_to.ql +++ b/cpp/ql/test/library-tests/ir/escape/points_to.ql @@ -4,6 +4,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as Raw import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis as UnAA import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Un import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction +import semmle.code.cpp.ir.internal.IntegerConstant from Raw::Instruction rawInstr, Un::Instruction unInstr, string rawPointsTo, string unPointsTo where @@ -12,21 +13,21 @@ where ( exists(Variable var, int rawBitOffset, int unBitOffset | RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and - rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and + rawPointsTo = var.toString() + getBitOffsetString(rawBitOffset) and UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and - unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset) + unPointsTo = var.toString() + getBitOffsetString(unBitOffset) ) or exists(Variable var, int unBitOffset | not RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), _) and rawPointsTo = "none" and UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and - unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset) + unPointsTo = var.toString() + getBitOffsetString(unBitOffset) ) or exists(Variable var, int rawBitOffset | RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and - rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and + rawPointsTo = var.toString() + getBitOffsetString(rawBitOffset) and not UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), _) and unPointsTo = "none" ) From 7d48220a76c393ecc27b67c0cf1639b252918935 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 25 Nov 2019 11:26:45 -0700 Subject: [PATCH 27/32] C++/C#: Make QLDoc conform to style guide --- .../implementation/aliased_ssa/IRVariable.qll | 40 +++++++++---------- .../cpp/ir/implementation/raw/IRVariable.qll | 40 +++++++++---------- .../unaliased_ssa/IRVariable.qll | 40 +++++++++---------- .../ir/implementation/raw/IRVariable.qll | 40 +++++++++---------- .../unaliased_ssa/IRVariable.qll | 40 +++++++++---------- 5 files changed, 95 insertions(+), 105 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 1092acc0003..f9efad42fb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -13,9 +13,9 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var } /** - * Represents a variable referenced by the IR for a function. The variable may - * be a user-declared variable (`IRUserVariable`) or a temporary variable - * generated by the AST-to-IR translation (`IRTempVariable`). + * A variable referenced by the IR for a function. The variable may be a user-declared variable + * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation + * (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -78,7 +78,7 @@ class IRVariable extends TIRVariable { } /** - * Represents a user-declared variable referenced by the IR for a function. + * A user-declared variable referenced by the IR for a function. */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; @@ -103,9 +103,8 @@ class IRUserVariable extends IRVariable, TIRUserVariable { } /** - * Represents a variable (user-declared or temporary) that is allocated on the - * stack. This includes all parameters, non-static local variables, and - * temporary variables. + * A variable (user-declared or temporary) that is allocated on the stack. This includes all + * parameters, non-static local variables, and temporary variables. */ class IRAutomaticVariable extends IRVariable { IRAutomaticVariable() { @@ -119,8 +118,8 @@ class IRAutomaticVariable extends IRVariable { } /** - * Represents a user-declared variable that is allocated on the stack. This - * includes all parameters and non-static local variables. + * A user-declared variable that is allocated on the stack. This includes all parameters and + * non-static local variables. */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; @@ -129,9 +128,8 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { } /** - * Represents a user-declared variable that is not allocated on the stack. This - * includes all global variables, namespace-scope variables, static fields, and - * static local variables. + * A user-declared variable that is not allocated on the stack. This includes all global variables, + * namespace-scope variables, static fields, and static local variables. */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -142,8 +140,8 @@ class IRStaticUserVariable extends IRUserVariable { } /** - * Represents a variable that is not user-declared. This includes temporary - * variables generated as part of IR construction, as well as string literals. + * A variable that is not user-declared. This includes temporary variables generated as part of IR + * construction, as well as string literals. */ class IRGeneratedVariable extends IRVariable { Language::AST ast; @@ -176,9 +174,9 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { } /** - * Represents a temporary variable introduced by IR construction. The most common examples are the - * variable generated to hold the return value of afunction, or the variable generated to hold the - * result of a condition operator (`a ? b : c`). + * A temporary variable introduced by IR construction. The most common examples are the variable + * generated to hold the return value of afunction, or the variable generated to hold the result of + * a condition operator (`a ? b : c`). */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -195,7 +193,7 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa } /** - * The temporary variable generated to hold the return value of a function. + * A temporary variable generated to hold the return value of a function. */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } @@ -204,7 +202,7 @@ class IRReturnVariable extends IRTempVariable { } /** - * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } @@ -213,8 +211,8 @@ class IRThrowVariable extends IRTempVariable { } /** - * The variable generated to represent the contents of a string literal. This variable acts much - * like a read-only global variable. + * A variable generated to represent the contents of a string literal. This variable acts much like + * a read-only global variable. */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 1092acc0003..f9efad42fb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -13,9 +13,9 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var } /** - * Represents a variable referenced by the IR for a function. The variable may - * be a user-declared variable (`IRUserVariable`) or a temporary variable - * generated by the AST-to-IR translation (`IRTempVariable`). + * A variable referenced by the IR for a function. The variable may be a user-declared variable + * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation + * (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -78,7 +78,7 @@ class IRVariable extends TIRVariable { } /** - * Represents a user-declared variable referenced by the IR for a function. + * A user-declared variable referenced by the IR for a function. */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; @@ -103,9 +103,8 @@ class IRUserVariable extends IRVariable, TIRUserVariable { } /** - * Represents a variable (user-declared or temporary) that is allocated on the - * stack. This includes all parameters, non-static local variables, and - * temporary variables. + * A variable (user-declared or temporary) that is allocated on the stack. This includes all + * parameters, non-static local variables, and temporary variables. */ class IRAutomaticVariable extends IRVariable { IRAutomaticVariable() { @@ -119,8 +118,8 @@ class IRAutomaticVariable extends IRVariable { } /** - * Represents a user-declared variable that is allocated on the stack. This - * includes all parameters and non-static local variables. + * A user-declared variable that is allocated on the stack. This includes all parameters and + * non-static local variables. */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; @@ -129,9 +128,8 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { } /** - * Represents a user-declared variable that is not allocated on the stack. This - * includes all global variables, namespace-scope variables, static fields, and - * static local variables. + * A user-declared variable that is not allocated on the stack. This includes all global variables, + * namespace-scope variables, static fields, and static local variables. */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -142,8 +140,8 @@ class IRStaticUserVariable extends IRUserVariable { } /** - * Represents a variable that is not user-declared. This includes temporary - * variables generated as part of IR construction, as well as string literals. + * A variable that is not user-declared. This includes temporary variables generated as part of IR + * construction, as well as string literals. */ class IRGeneratedVariable extends IRVariable { Language::AST ast; @@ -176,9 +174,9 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { } /** - * Represents a temporary variable introduced by IR construction. The most common examples are the - * variable generated to hold the return value of afunction, or the variable generated to hold the - * result of a condition operator (`a ? b : c`). + * A temporary variable introduced by IR construction. The most common examples are the variable + * generated to hold the return value of afunction, or the variable generated to hold the result of + * a condition operator (`a ? b : c`). */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -195,7 +193,7 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa } /** - * The temporary variable generated to hold the return value of a function. + * A temporary variable generated to hold the return value of a function. */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } @@ -204,7 +202,7 @@ class IRReturnVariable extends IRTempVariable { } /** - * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } @@ -213,8 +211,8 @@ class IRThrowVariable extends IRTempVariable { } /** - * The variable generated to represent the contents of a string literal. This variable acts much - * like a read-only global variable. + * A variable generated to represent the contents of a string literal. This variable acts much like + * a read-only global variable. */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 1092acc0003..f9efad42fb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -13,9 +13,9 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var } /** - * Represents a variable referenced by the IR for a function. The variable may - * be a user-declared variable (`IRUserVariable`) or a temporary variable - * generated by the AST-to-IR translation (`IRTempVariable`). + * A variable referenced by the IR for a function. The variable may be a user-declared variable + * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation + * (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -78,7 +78,7 @@ class IRVariable extends TIRVariable { } /** - * Represents a user-declared variable referenced by the IR for a function. + * A user-declared variable referenced by the IR for a function. */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; @@ -103,9 +103,8 @@ class IRUserVariable extends IRVariable, TIRUserVariable { } /** - * Represents a variable (user-declared or temporary) that is allocated on the - * stack. This includes all parameters, non-static local variables, and - * temporary variables. + * A variable (user-declared or temporary) that is allocated on the stack. This includes all + * parameters, non-static local variables, and temporary variables. */ class IRAutomaticVariable extends IRVariable { IRAutomaticVariable() { @@ -119,8 +118,8 @@ class IRAutomaticVariable extends IRVariable { } /** - * Represents a user-declared variable that is allocated on the stack. This - * includes all parameters and non-static local variables. + * A user-declared variable that is allocated on the stack. This includes all parameters and + * non-static local variables. */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; @@ -129,9 +128,8 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { } /** - * Represents a user-declared variable that is not allocated on the stack. This - * includes all global variables, namespace-scope variables, static fields, and - * static local variables. + * A user-declared variable that is not allocated on the stack. This includes all global variables, + * namespace-scope variables, static fields, and static local variables. */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -142,8 +140,8 @@ class IRStaticUserVariable extends IRUserVariable { } /** - * Represents a variable that is not user-declared. This includes temporary - * variables generated as part of IR construction, as well as string literals. + * A variable that is not user-declared. This includes temporary variables generated as part of IR + * construction, as well as string literals. */ class IRGeneratedVariable extends IRVariable { Language::AST ast; @@ -176,9 +174,9 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { } /** - * Represents a temporary variable introduced by IR construction. The most common examples are the - * variable generated to hold the return value of afunction, or the variable generated to hold the - * result of a condition operator (`a ? b : c`). + * A temporary variable introduced by IR construction. The most common examples are the variable + * generated to hold the return value of afunction, or the variable generated to hold the result of + * a condition operator (`a ? b : c`). */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -195,7 +193,7 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa } /** - * The temporary variable generated to hold the return value of a function. + * A temporary variable generated to hold the return value of a function. */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } @@ -204,7 +202,7 @@ class IRReturnVariable extends IRTempVariable { } /** - * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } @@ -213,8 +211,8 @@ class IRThrowVariable extends IRTempVariable { } /** - * The variable generated to represent the contents of a string literal. This variable acts much - * like a read-only global variable. + * A variable generated to represent the contents of a string literal. This variable acts much like + * a read-only global variable. */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 1092acc0003..f9efad42fb0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -13,9 +13,9 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var } /** - * Represents a variable referenced by the IR for a function. The variable may - * be a user-declared variable (`IRUserVariable`) or a temporary variable - * generated by the AST-to-IR translation (`IRTempVariable`). + * A variable referenced by the IR for a function. The variable may be a user-declared variable + * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation + * (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -78,7 +78,7 @@ class IRVariable extends TIRVariable { } /** - * Represents a user-declared variable referenced by the IR for a function. + * A user-declared variable referenced by the IR for a function. */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; @@ -103,9 +103,8 @@ class IRUserVariable extends IRVariable, TIRUserVariable { } /** - * Represents a variable (user-declared or temporary) that is allocated on the - * stack. This includes all parameters, non-static local variables, and - * temporary variables. + * A variable (user-declared or temporary) that is allocated on the stack. This includes all + * parameters, non-static local variables, and temporary variables. */ class IRAutomaticVariable extends IRVariable { IRAutomaticVariable() { @@ -119,8 +118,8 @@ class IRAutomaticVariable extends IRVariable { } /** - * Represents a user-declared variable that is allocated on the stack. This - * includes all parameters and non-static local variables. + * A user-declared variable that is allocated on the stack. This includes all parameters and + * non-static local variables. */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; @@ -129,9 +128,8 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { } /** - * Represents a user-declared variable that is not allocated on the stack. This - * includes all global variables, namespace-scope variables, static fields, and - * static local variables. + * A user-declared variable that is not allocated on the stack. This includes all global variables, + * namespace-scope variables, static fields, and static local variables. */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -142,8 +140,8 @@ class IRStaticUserVariable extends IRUserVariable { } /** - * Represents a variable that is not user-declared. This includes temporary - * variables generated as part of IR construction, as well as string literals. + * A variable that is not user-declared. This includes temporary variables generated as part of IR + * construction, as well as string literals. */ class IRGeneratedVariable extends IRVariable { Language::AST ast; @@ -176,9 +174,9 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { } /** - * Represents a temporary variable introduced by IR construction. The most common examples are the - * variable generated to hold the return value of afunction, or the variable generated to hold the - * result of a condition operator (`a ? b : c`). + * A temporary variable introduced by IR construction. The most common examples are the variable + * generated to hold the return value of afunction, or the variable generated to hold the result of + * a condition operator (`a ? b : c`). */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -195,7 +193,7 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa } /** - * The temporary variable generated to hold the return value of a function. + * A temporary variable generated to hold the return value of a function. */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } @@ -204,7 +202,7 @@ class IRReturnVariable extends IRTempVariable { } /** - * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } @@ -213,8 +211,8 @@ class IRThrowVariable extends IRTempVariable { } /** - * The variable generated to represent the contents of a string literal. This variable acts much - * like a read-only global variable. + * A variable generated to represent the contents of a string literal. This variable acts much like + * a read-only global variable. */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 1092acc0003..f9efad42fb0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -13,9 +13,9 @@ IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var } /** - * Represents a variable referenced by the IR for a function. The variable may - * be a user-declared variable (`IRUserVariable`) or a temporary variable - * generated by the AST-to-IR translation (`IRTempVariable`). + * A variable referenced by the IR for a function. The variable may be a user-declared variable + * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation + * (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -78,7 +78,7 @@ class IRVariable extends TIRVariable { } /** - * Represents a user-declared variable referenced by the IR for a function. + * A user-declared variable referenced by the IR for a function. */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; @@ -103,9 +103,8 @@ class IRUserVariable extends IRVariable, TIRUserVariable { } /** - * Represents a variable (user-declared or temporary) that is allocated on the - * stack. This includes all parameters, non-static local variables, and - * temporary variables. + * A variable (user-declared or temporary) that is allocated on the stack. This includes all + * parameters, non-static local variables, and temporary variables. */ class IRAutomaticVariable extends IRVariable { IRAutomaticVariable() { @@ -119,8 +118,8 @@ class IRAutomaticVariable extends IRVariable { } /** - * Represents a user-declared variable that is allocated on the stack. This - * includes all parameters and non-static local variables. + * A user-declared variable that is allocated on the stack. This includes all parameters and + * non-static local variables. */ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { override Language::AutomaticVariable var; @@ -129,9 +128,8 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { } /** - * Represents a user-declared variable that is not allocated on the stack. This - * includes all global variables, namespace-scope variables, static fields, and - * static local variables. + * A user-declared variable that is not allocated on the stack. This includes all global variables, + * namespace-scope variables, static fields, and static local variables. */ class IRStaticUserVariable extends IRUserVariable { override Language::StaticVariable var; @@ -142,8 +140,8 @@ class IRStaticUserVariable extends IRUserVariable { } /** - * Represents a variable that is not user-declared. This includes temporary - * variables generated as part of IR construction, as well as string literals. + * A variable that is not user-declared. This includes temporary variables generated as part of IR + * construction, as well as string literals. */ class IRGeneratedVariable extends IRVariable { Language::AST ast; @@ -176,9 +174,9 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { } /** - * Represents a temporary variable introduced by IR construction. The most common examples are the - * variable generated to hold the return value of afunction, or the variable generated to hold the - * result of a condition operator (`a ? b : c`). + * A temporary variable introduced by IR construction. The most common examples are the variable + * generated to hold the return value of afunction, or the variable generated to hold the result of + * a condition operator (`a ? b : c`). */ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; @@ -195,7 +193,7 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa } /** - * The temporary variable generated to hold the return value of a function. + * A temporary variable generated to hold the return value of a function. */ class IRReturnVariable extends IRTempVariable { IRReturnVariable() { tag = ReturnValueTempVar() } @@ -204,7 +202,7 @@ class IRReturnVariable extends IRTempVariable { } /** - * The temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. + * A temporary variable generated to hold the exception thrown by a `ThrowValue` instruction. */ class IRThrowVariable extends IRTempVariable { IRThrowVariable() { tag = ThrowTempVar() } @@ -213,8 +211,8 @@ class IRThrowVariable extends IRTempVariable { } /** - * The variable generated to represent the contents of a string literal. This variable acts much - * like a read-only global variable. + * A variable generated to represent the contents of a string literal. This variable acts much like + * a read-only global variable. */ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { Language::StringLiteral literal; From b6106f9638ca94df3ac7f740631919652b0f2d6e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 Nov 2019 11:16:59 +0100 Subject: [PATCH 28/32] keep the ResolvedPromiseDefinition class as a subclass of PromiseCreationCall --- javascript/ql/src/semmle/javascript/Promises.qll | 4 ++-- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index e195668ffbf..d74aafc265c 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -25,7 +25,7 @@ module Bluebird { /** * A resolved promise created by the bluebird `Promise.resolve` function. */ - class ResolvedBluebidPromiseDefinition extends PromiseCreationCall { + class ResolvedBluebidPromiseDefinition extends ResolvedPromiseDefinition { ResolvedBluebidPromiseDefinition() { this = bluebird().getAMemberCall("resolve") } override DataFlow::Node getValue() { result = getArgument(0) } @@ -75,7 +75,7 @@ private module ClosurePromise { /** * A promise created by a call `goog.Promise.resolve(value)`. */ - private class ResolvedClosurePromiseDefinition extends PromiseCreationCall { + private class ResolvedClosurePromiseDefinition extends ResolvedPromiseDefinition { ResolvedClosurePromiseDefinition() { this = Closure::moduleImport("goog.Promise.resolve").getACall() } diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 85a8f281b25..8d9df11a419 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -152,7 +152,7 @@ private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNo } /** - * A promise that is resolved with the given value. + * A promise that is created and resolved with one or more value. */ abstract class PromiseCreationCall extends DataFlow::CallNode { /** @@ -161,10 +161,15 @@ abstract class PromiseCreationCall extends DataFlow::CallNode { abstract DataFlow::Node getValue(); } +/** + * A promise that is created using a `.resolve()` call. + */ +abstract class ResolvedPromiseDefinition extends PromiseCreationCall {} + /** * A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function. */ -class ResolvedES2015PromiseDefinition extends PromiseCreationCall { +class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition { ResolvedES2015PromiseDefinition() { this = DataFlow::globalVarRef("Promise").getAMemberCall("resolve") } From deb6a6e5c69ee7ea54b97561554ed4c0cee471fe Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 26 Nov 2019 17:20:01 +0100 Subject: [PATCH 29/32] Java: Improve performance by normalizing import order to reduce cache invalidation. --- java/ql/src/Security/CWE/CWE-078/ExecTainted.ql | 2 +- java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql | 2 +- java/ql/src/Security/CWE/CWE-089/SqlTainted.ql | 2 +- java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql index 8774de339b6..353df33afed 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql @@ -11,7 +11,7 @@ * external/cwe/cwe-088 */ -import semmle.code.java.Expr +import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.ExternalProcess import ExecCommon diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql index e80afa7f6eb..a0fa793872f 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql @@ -11,7 +11,7 @@ * external/cwe/cwe-088 */ -import semmle.code.java.Expr +import java import semmle.code.java.security.ExternalProcess import ExecCommon diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql index 5b79c56a83c..5750829d7d6 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -10,7 +10,7 @@ * external/cwe/cwe-089 */ -import semmle.code.java.Expr +import java import semmle.code.java.dataflow.FlowSources import SqlInjectionLib import DataFlow::PathGraph diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql index 83eaa50ea2c..e721cb7fba6 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql @@ -10,6 +10,7 @@ * external/cwe/cwe-089 */ +import java import semmle.code.java.security.SqlUnescapedLib import SqlInjectionLib From 4e1ee7a998b52b2654f2e9d3901155050b2fd577 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 26 Nov 2019 10:48:24 -0700 Subject: [PATCH 30/32] C++/C#: Fix formatting --- .../code/cpp/ir/internal/IntegerConstant.qll | 21 ++++++++----------- .../csharp/ir/internal/IntegerConstant.qll | 21 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll index 0d845303c28..6034ebc5674 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll @@ -204,11 +204,9 @@ string bitsToBytesAndBits(IntValue bits) { hasValue(bits) and bytes = bits / 8 and leftoverBits = bits % 8 and - if leftoverBits = 0 then - result = bytes.toString() - else - result = bytes + ":" + leftoverBits - ) or + if leftoverBits = 0 then result = bytes.toString() else result = bytes + ":" + leftoverBits + ) + or not hasValue(bits) and result = "?" } @@ -217,11 +215,10 @@ string bitsToBytesAndBits(IntValue bits) { */ bindingset[bitOffset] string getBitOffsetString(IntValue bitOffset) { - if hasValue(bitOffset) then - if bitOffset >= 0 then - result = "+" + bitsToBytesAndBits(bitOffset) - else - result = "-" + bitsToBytesAndBits(neg(bitOffset)) - else - result = "+?" + if hasValue(bitOffset) + then + if bitOffset >= 0 + then result = "+" + bitsToBytesAndBits(bitOffset) + else result = "-" + bitsToBytesAndBits(neg(bitOffset)) + else result = "+?" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll index 0d845303c28..6034ebc5674 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll @@ -204,11 +204,9 @@ string bitsToBytesAndBits(IntValue bits) { hasValue(bits) and bytes = bits / 8 and leftoverBits = bits % 8 and - if leftoverBits = 0 then - result = bytes.toString() - else - result = bytes + ":" + leftoverBits - ) or + if leftoverBits = 0 then result = bytes.toString() else result = bytes + ":" + leftoverBits + ) + or not hasValue(bits) and result = "?" } @@ -217,11 +215,10 @@ string bitsToBytesAndBits(IntValue bits) { */ bindingset[bitOffset] string getBitOffsetString(IntValue bitOffset) { - if hasValue(bitOffset) then - if bitOffset >= 0 then - result = "+" + bitsToBytesAndBits(bitOffset) - else - result = "-" + bitsToBytesAndBits(neg(bitOffset)) - else - result = "+?" + if hasValue(bitOffset) + then + if bitOffset >= 0 + then result = "+" + bitsToBytesAndBits(bitOffset) + else result = "-" + bitsToBytesAndBits(neg(bitOffset)) + else result = "+?" } From 2eea94c3dc7c4c93b4e9b61b384063c9416a8246 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Tue, 26 Nov 2019 14:11:54 -0500 Subject: [PATCH 31/32] Documentation: fix invalid `@precision` value --- docs/query-metadata-style-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index d5f5606002c..70cb083cb1a 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -113,7 +113,7 @@ Alert queries (`@kind problem` or `path-problem`) support two further properties * `low ` * `medium ` * `high ` - * `very high` + * `very-high` * `@problem.severity`–defines the level of severity of the alert: * `error`–an issue that is likely to cause incorrect program behavior, for example a crash or vulnerability. * `warning`–an issue that indicates a potential problem in the code, or makes the code fragile if another (unrelated) part of code is changed. From 605c8834c63d7105951000bd59193dcb41f84734 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Nov 2019 15:05:09 +0000 Subject: [PATCH 32/32] JS: Avoid redundant window.name sources --- .../ql/src/semmle/javascript/security/dataflow/DOM.qll | 2 +- .../ql/test/query-tests/Security/CWE-079/Xss.expected | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll index 299042cc281..5b639abfa11 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll @@ -211,7 +211,7 @@ private class WindowNameAccess extends RemoteFlowSource { this = DataFlow::globalObjectRef().getAPropertyRead("name") or // Reference to `name` on a container that does not assign to it. - this.accessesGlobal("name") and + this.asExpr().(GlobalVarAccess).getName() = "name" and not exists(VarDef def | def.getAVariable().(GlobalVariable).getName() = "name" and def.getContainer() = this.asExpr().getContainer() diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 2e986a06dea..bf891339cdc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -309,12 +309,10 @@ nodes | tst.js:277:22:277:29 | location | | tst.js:277:22:277:29 | location | | tst.js:282:9:282:29 | tainted | -| tst.js:282:9:282:29 | tainted | | tst.js:282:19:282:29 | window.name | | tst.js:282:19:282:29 | window.name | | tst.js:285:59:285:65 | tainted | | tst.js:285:59:285:65 | tainted | -| tst.js:285:59:285:65 | tainted | | tst.js:297:35:297:42 | location | | tst.js:297:35:297:42 | location | | tst.js:297:35:297:42 | location | @@ -602,11 +600,8 @@ edges | tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | | tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | | tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | -| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | -| tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | | tst.js:282:19:282:29 | window.name | tst.js:282:9:282:29 | tainted | | tst.js:282:19:282:29 | window.name | tst.js:282:9:282:29 | tainted | -| tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted | | tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | @@ -694,9 +689,7 @@ edges | tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | tst.js:257:7:257:10 | name | Cross-site scripting vulnerability due to $@. | tst.js:257:7:257:10 | name | user-provided value | | tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | Cross-site scripting vulnerability due to $@. | tst.js:261:11:261:21 | window.name | user-provided value | | tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | Cross-site scripting vulnerability due to $@. | tst.js:277:22:277:29 | location | user-provided value | -| tst.js:285:59:285:65 | tainted | tst.js:282:9:282:29 | tainted | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:282:9:282:29 | tainted | user-provided value | | tst.js:285:59:285:65 | tainted | tst.js:282:19:282:29 | window.name | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:282:19:282:29 | window.name | user-provided value | -| tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:285:59:285:65 | tainted | user-provided value | | tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | Cross-site scripting vulnerability due to $@. | tst.js:297:35:297:42 | location | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value |