This rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer). Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything -from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave +from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manager to behave erratically, to a possible security vulnerability.
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index 6f3f4d43e9a..218a54b36c5 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -51,5 +51,7 @@ predicate tooFewArguments(FunctionCall fc, Function f) { hasDefiniteNumberOfParameters(fde) | fde.getNumberOfParameters() > fc.getNumberOfArguments() - ) + ) and + // Don't report on implicit function declarations, as these are likely extraction errors. + not f.getADeclarationEntry().isImplicit() } diff --git a/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md b/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md new file mode 100644 index 00000000000..116df08838a --- /dev/null +++ b/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared. diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.ql b/cpp/ql/src/experimental/Best Practices/GuardedFree.ql index 2d504d9bc05..66c7a31111b 100644 --- a/cpp/ql/src/experimental/Best Practices/GuardedFree.ql +++ b/cpp/ql/src/experimental/Best Practices/GuardedFree.ql @@ -18,9 +18,31 @@ class FreeCall extends FunctionCall { FreeCall() { this.getTarget().hasGlobalName("free") } } +predicate blockContainsPreprocessorBranches(BasicBlock bb) { + exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc | + bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation() + | + bbLoc.getFile() = ppb.getFile() and + bbLoc.getStartLine() < ppbLoc.getStartLine() and + ppbLoc.getEndLine() < bbLoc.getEndLine() + ) +} + from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb where gc.ensuresEq(v.getAnAccess(), 0, bb, false) and fc.getArgument(0) = v.getAnAccess() and - bb = fc.getEnclosingStmt() + bb = fc.getBasicBlock() and + ( + // No block statement: if (x) free(x); + bb = fc.getEnclosingStmt() + or + // Block statement with a single nested statement: if (x) { free(x); } + strictcount(bb.(BlockStmt).getAStmt()) = 1 + ) and + strictcount(BasicBlock bb2 | gc.ensuresEq(_, 0, bb2, _) | bb2) = 1 and + not fc.isInMacroExpansion() and + not blockContainsPreprocessorBranches(bb) and + not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and + not exists(CommaExpr c | c.getAChild*() = fc) select gc, "unnecessary NULL check before call to $@", fc, "free" diff --git a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected index 209bae407b8..a9a189218c6 100644 --- a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected +++ b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected @@ -1,10 +1,5 @@ | test.cpp:5:7:5:7 | x | unnecessary NULL check before call to $@ | test.cpp:6:5:6:8 | call to free | free | -| test.cpp:23:7:23:7 | x | unnecessary NULL check before call to $@ | test.cpp:26:5:26:8 | call to free | free | -| test.cpp:31:7:31:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:31:7:31:24 | ... \|\| ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:31:8:31:8 | x | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:94:12:94:12 | x | unnecessary NULL check before call to $@ | test.cpp:94:3:94:13 | call to free | free | -| test.cpp:98:7:98:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free | -| test.cpp:98:8:98:8 | x | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free | +| test.cpp:10:7:10:7 | x | unnecessary NULL check before call to $@ | test.cpp:11:5:11:8 | call to free | free | +| test.cpp:42:7:42:7 | x | unnecessary NULL check before call to $@ | test.cpp:43:5:43:8 | call to free | free | +| test.cpp:49:7:49:7 | x | unnecessary NULL check before call to $@ | test.cpp:50:5:50:8 | call to free | free | | test.cpp:106:7:106:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:107:5:107:8 | call to free | free | -| test.cpp:113:7:113:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:114:17:114:20 | call to free | free | diff --git a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp index 12b1fb2364e..d52bcef72d1 100644 --- a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp @@ -20,7 +20,7 @@ void test2(int *x) { } void test3(int *x, bool b) { - if (x) { // GOOD [FALSE POSITIVE]: x is being accessed in the body of the if + if (x) { // GOOD: x is being accessed in the body of the if if (b) *x = 42; free(x); @@ -28,7 +28,7 @@ void test3(int *x, bool b) { } bool test4(char *x, char *y) { - if (!x || strcmp(x, y)) { // GOOD [FALSE POSITIVE]: x is being accessed in the guard and return value depends on x + if (!x || strcmp(x, y)) { // GOOD: x is being accessed in the guard and return value depends on x free(x); return true; } @@ -91,11 +91,11 @@ void test10(char *x) { if (x) free(x); void test11(char *x) { - TRY_FREE(x) // BAD + TRY_FREE(x) // BAD [NOT DETECTED] } bool test12(char *x) { - if (!x) // GOOD [FALSE POSITIVE]: return value depends on x + if (!x) // GOOD: return value depends on x return false; free(x); @@ -110,6 +110,6 @@ void test13(char *x) { void inspect(char *x); void test14(char *x) { - if (x != nullptr) // GOOD [FALSE POSITIVE]: x might be accessed in the first operand of the comma operator + if (x != nullptr) // GOOD: x might be accessed in the first operand of the comma operator inspect(x), free(x); } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected index 8547894e769..d3e0ecbd591 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected @@ -1,9 +1,9 @@ | test.c:28:3:28:12 | call to undeclared | Function call implicitly declares 'undeclared'. | | test.c:31:3:31:19 | call to not_yet_declared1 | Function call implicitly declares 'not_yet_declared1'. | | test.c:32:3:32:19 | call to not_yet_declared2 | Function call implicitly declares 'not_yet_declared2'. | -| test.c:43:3:43:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. | -| test.c:54:3:54:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. | -| test.c:66:3:66:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. | -| test.c:68:3:68:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. | -| test.c:132:3:132:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. | -| test.c:133:3:133:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. | +| test.c:44:3:44:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. | +| test.c:55:3:55:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. | +| test.c:67:3:67:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. | +| test.c:69:3:69:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. | +| test.c:133:3:133:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. | +| test.c:134:3:134:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index b6015dad456..d067430aba9 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,18 +1,18 @@ -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | (unnamed parameter 0) | int (unnamed parameter 0) | -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | (unnamed parameter 0) | int (unnamed parameter 0) | -| test.c:40:3:40:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:40:31:40:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:77:38:77:38 | x | int x | -| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:29:44:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:80:36:80:36 | x | int x | -| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:37:44:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:80:50:80:50 | z | int z | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | -| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | -| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | -| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:95:32:95:32 | f | float f | -| test.c:52:3:52:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:52:22:52:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:95:32:95:32 | f | float f | -| test.c:55:3:55:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:55:23:55:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:99:35:99:35 | d | double d | -| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | -| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | -| test.c:60:3:60:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:60:23:60:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:99:35:99:35 | d | double d | -| test.c:61:3:61:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:61:26:61:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:103:44:103:45 | ll | long long ll | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) | +| test.c:41:3:41:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:41:31:41:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:78:38:78:38 | x | int x | +| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:29:45:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:81:36:81:36 | x | int x | +| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | +| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | +| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:94:6:94:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | +| test.c:52:3:52:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:96:7:96:24 | defined_with_float | defined_with_float | test.c:52:22:52:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:96:32:96:32 | f | float f | +| test.c:53:3:53:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:96:7:96:24 | defined_with_float | defined_with_float | test.c:53:22:53:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:96:32:96:32 | f | float f | +| test.c:56:3:56:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:56:23:56:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:100:35:100:35 | d | double d | +| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | +| test.c:59:3:59:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:59:26:59:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | +| test.c:61:3:61:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:61:23:61:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:100:35:100:35 | d | double d | +| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 42c4f7f9455..90468d3a9bf 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,2 @@ -| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:36:3:36:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:87:10:87:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:90:5:90:15 | dereference | dereference | +| test.c:37:3:37:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:88:10:88:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:91:5:91:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index bc64434578b..6eff27c3adb 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,2 +1,2 @@ -| test.c:41:3:41:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:72:3:72:28 | call to declared_and_defined_empty | This call has more arguments than required by $@. | test.c:114:6:114:31 | declared_and_defined_empty | declared_and_defined_empty | +| test.c:42:3:42:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:73:3:73:28 | call to declared_and_defined_empty | This call has more arguments than required by $@. | test.c:115:6:115:31 | declared_and_defined_empty | declared_and_defined_empty | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index 86e940a8e28..d77c16683ed 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -30,8 +30,9 @@ void test(int *argv[]) { not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration) not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration) - not_yet_declared2(ca); // BAD - not_yet_declared2(); // BAD + not_yet_declared2(ca); // BAD (GOOD for everything except for cpp/mistyped-function-arguments + // and cpp/too-few-arguments. Not detected in the case of cpp/too-few-arguments.) + not_yet_declared2(); // BAD [NOT DETECTED] (GOOD for everything except for cpp/too-few-arguments) declared_empty_defined_with(); // BAD declared_empty_defined_with(1); // GOOD diff --git a/csharp/.vscode/launch.json b/csharp/.vscode/launch.json index 46858861047..1f598f5e44f 100644 --- a/csharp/.vscode/launch.json +++ b/csharp/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net8.0/Semmle.Extraction.CSharp.Standalone.dll", + "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net9.0/Semmle.Extraction.CSharp.Standalone.dll", "args": [], // Set the path to the folder that should be extracted: "cwd": "${workspaceFolder}/ql/test/library-tests/standalone/standalonemode", @@ -35,7 +35,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net8.0/Semmle.Autobuild.CSharp.dll", + "program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net9.0/Semmle.Autobuild.CSharp.dll", // Set the path to the folder that should be extracted: "cwd": "${workspaceFolder}/ql/integration-tests/all-platforms/autobuild", "stopAtEntry": true, @@ -53,7 +53,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net8.0/Semmle.Extraction.CSharp.Driver.dll", + "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net9.0/Semmle.Extraction.CSharp.Driver.dll", "stopAtEntry": true, "args": [ "--binlog", diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs index e58c8ddccd9..b3efe64b7e9 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs @@ -49,11 +49,9 @@ namespace Semmle.Autobuild.CSharp tryCleanExtractorArgsLogs & BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); - ///int? or
- /// System.Nullable.
+ /// System.Nullable<int>.
/// System.Nullable.
+ /// Holds if this type is System.Nullable<T>.
/// System.Span.
+ /// Holds if this type is System.Span<T>.
/// System.Span.
+ /// Holds if this type is of the form System.Span<byte>.
/// System.ReadOnlySpan.
+ /// Holds if this type is System.ReadOnlySpan<T>.
/// System.ReadOnlySpan.
+ /// Holds if this type is of the form System.ReadOnlySpan<byte>.
/// expressions and expr_location are populated by the constructor
/// (should not fail), so even if expression-type specific population fails (e.g., in
/// standalone extraction), the expression created via
- ///
- /// IEnumerable<string?> // false
- /// IEnumerable<string?>? // true
+ /// IEnumerable<string?> // false
+ /// IEnumerable<string?>? // true
/// string? // true
/// string[] // true
/// string?[] // false
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
index f2fc4b85d7f..141bded87ac 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
@@ -86,7 +86,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// Logs an error if the name is not found.
///
/// Extractor context.
- /// The method name.
+ /// The method symbol.
/// The converted name.
private static string OperatorSymbol(Context cx, IMethodSymbol method)
{
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs
index 8d819d715f9..67bb2808ae6 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs
@@ -152,7 +152,7 @@ namespace Semmle.Extraction.CSharp
///
/// Enqueue the given action to be performed later.
///
- /// The action to run.
+ /// The action to run.
public void PopulateLater(Action a, bool preserveDuplicationKey = true)
{
var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null;
@@ -598,7 +598,6 @@ namespace Semmle.Extraction.CSharp
///
/// Register a program entity which can be bound to comments.
///
- /// Extractor context.
/// Program entity.
/// Location of the entity.
public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location? l)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs
index 4830c3209c2..42e933c8eaf 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs
@@ -171,7 +171,7 @@ namespace Semmle.Extraction.CSharp
///
/// Close the trap file, and move it to the right place in the trap directory.
/// If the file exists already, rename it to allow the new file (ending .trap.gz)
- /// to sit alongside the old file (except if is true,
+ /// to sit alongside the old file (except if is true,
/// in which case only the existing file is kept).
///
public void Dispose()
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs
index 63f5e81c358..28e1d0bf146 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs
@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp
{
///
/// A `TextWriter` object that wraps another `TextWriter` object, and which
- /// HTML escapes the characters `&`, `{`, `}`, `"`, `@`, and `#`, before
+ /// HTML escapes the characters &, {, }, ", @, and #, before
/// writing to the underlying object.
///
public sealed class EscapingTextWriter : TextWriter
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs
index 787ba62e3e8..22e38bac51c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs
@@ -226,7 +226,7 @@ namespace Semmle.Extraction.CSharp
///
/// Builds a trap builder using a separator and an action for each item in the list.
///
- /// The type of the items.
+ /// The type of the items.
/// The trap builder to append to.
/// The separator string (e.g. ",")
/// The list of items.
@@ -251,7 +251,7 @@ namespace Semmle.Extraction.CSharp
///
/// Builds a trap builder using a separator and an action for each item in the list.
///
- /// The type of the items.
+ /// The type of the items.
/// The trap builder to append to.
/// The separator string (e.g. ",")
/// The list of items.
diff --git a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs
index a79854333ac..d3cbf41fa10 100644
--- a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs
+++ b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs
@@ -208,7 +208,7 @@ namespace Semmle.Util
/// Create cache with a given capacity.
///
/// The algorithm for determining the canonical path.
- /// The size of the cache.
+ /// The size of the cache.
public CanonicalPathCache(int maxCapacity, PathStrategy pathStrategy)
{
if (maxCapacity <= 0)
@@ -230,7 +230,6 @@ namespace Semmle.Util
///
///
/// Size of the cache.
- /// Policy for following symlinks.
/// A new CanonicalPathCache.
public static CanonicalPathCache Create(ILogger logger, int maxCapacity)
{
diff --git a/csharp/extractor/Semmle.Util/CommandBuilder.cs b/csharp/extractor/Semmle.Util/CommandBuilder.cs
index 3d8f907f866..1b6cd3176c4 100644
--- a/csharp/extractor/Semmle.Util/CommandBuilder.cs
+++ b/csharp/extractor/Semmle.Util/CommandBuilder.cs
@@ -62,7 +62,6 @@ namespace Semmle.Util
///
/// The argument to append.
/// Whether to always quote the argument.
- /// Whether to escape for cmd.exe
///
///
/// This implementation is copied from
diff --git a/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py
index c32d966acb4..75ba09477fa 100644
--- a/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py
+++ b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py
@@ -1,7 +1,6 @@
import os
def check_build_out(msg, s):
- lines = s.splitlines()
lines = s.splitlines()
assert (
any (("[build-stdout]" in line) and (msg in line) for line in lines)
diff --git a/csharp/ql/test/resources/stubs/System.Web.cs b/csharp/ql/test/resources/stubs/System.Web.cs
index d876a83e318..d1942c07dc1 100644
--- a/csharp/ql/test/resources/stubs/System.Web.cs
+++ b/csharp/ql/test/resources/stubs/System.Web.cs
@@ -390,6 +390,8 @@ namespace System.Web.Script.Serialization
public JavaScriptSerializer() => throw null;
public JavaScriptSerializer(System.Web.Script.Serialization.JavaScriptTypeResolver resolver) => throw null;
public object DeserializeObject(string input) => throw null;
+ public T Deserialize (string input) => throw null;
+ public object Deserialize(string input, Type targetType) => throw null;
}
// Generated from `System.Web.Script.Serialization.JavaScriptTypeResolver` in `System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35`
diff --git a/docs/codeql/ql-language-reference/modules.rst b/docs/codeql/ql-language-reference/modules.rst
index 75b61667246..d0cbdd39e36 100644
--- a/docs/codeql/ql-language-reference/modules.rst
+++ b/docs/codeql/ql-language-reference/modules.rst
@@ -431,10 +431,7 @@ The above query therefore evalutes to:
BigInt
======
-The built-in ``QlBuiltins`` module provides an **experimental** type ``BigInt`` of arbitrary-precision integers.
-
-This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint``
-option to the CodeQL CLI. Consequently, BigInts are currently disallowed in query results and dbscheme columns.
+The built-in ``QlBuiltins`` module provides a type ``BigInt`` of arbitrary-range integers.
Unlike ``int`` and ``float``, there is no automatic conversion between ``BigInt`` and other numeric types.
Instead, big integers can be constructed using the ``.toBigInt()`` methods of ``int`` and ``string``.
@@ -451,3 +448,5 @@ The other built-in operations are:
``rank``, ``unique``, ``any``.
* other: ``.pow(int)``, ``.abs()``, ``.gcd(BigInt)``, ``.minimum(BigInt)``,
``.maximum(BigInt)``.
+
+Note: big integers are currently disallowed in query results and dbscheme columns.
diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst
index 60e5ece7330..4c8fd30076a 100644
--- a/docs/codeql/ql-language-reference/ql-language-specification.rst
+++ b/docs/codeql/ql-language-reference/ql-language-specification.rst
@@ -445,7 +445,7 @@ An integer value is of type ``int``. Each value is a 32-bit two's complement int
A string is a finite sequence of 16-bit characters. The characters are interpreted as Unicode code points.
-A :ref:`big integer ` value is of type ``QlBuiltins::BigInt``. Each value is a signed arbitrary-precision integer.
+A :ref:`big integer ` value is of type ``QlBuiltins::BigInt``. Each value is a signed arbitrary-range integer.
The database includes a number of opaque entity values. Each such value has a type that is one of the database types, and an identifying integer. An entity value is written as the name of its database type followed by its identifying integer in parentheses. For example, ``@tree(12)``, ``@person(16)``, and ``@location(38132)`` are entity values. The identifying integers are left opaque to programmers in this specification, so an implementation of QL is free to use some other set of countable labels to identify its entities.
diff --git a/docs/codeql/ql-language-reference/types.rst b/docs/codeql/ql-language-reference/types.rst
index e14f542dcf8..d2d79fe8409 100644
--- a/docs/codeql/ql-language-reference/types.rst
+++ b/docs/codeql/ql-language-reference/types.rst
@@ -52,7 +52,7 @@ independent of the database that you are querying.
QL has a range of built-in operations defined on primitive types. These are available by using dispatch on expressions of the appropriate type. For example, ``1.toString()`` is the string representation of the integer constant ``1``. For a full list of built-in operations available in QL, see the
section on `built-ins `__ in the QL language specification.
-Additionally, there is an experimental arbitrary-precision integer primitive type at :ref:`QlBuiltins::BigInt `. This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint`` option to the CodeQL CLI.
+Additionally, there is an arbitrary-range integer primitive type at :ref:`QlBuiltins::BigInt `.
.. index:: class
.. _classes:
diff --git a/go/documentation/library-coverage/coverage.csv b/go/documentation/library-coverage/coverage.csv
index 364e17aa94b..21127e396a2 100644
--- a/go/documentation/library-coverage/coverage.csv
+++ b/go/documentation/library-coverage/coverage.csv
@@ -1,121 +1,141 @@
-package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,summary:taint,summary:value
-,,,8,,,,,,,,,,,,,,,,,3,5
-archive/tar,,,5,,,,,,,,,,,,,,,,,5,
-archive/zip,,,6,,,,,,,,,,,,,,,,,6,
-bufio,,,17,,,,,,,,,,,,,,,,,17,
-bytes,,,43,,,,,,,,,,,,,,,,,43,
-clevergo.tech/clevergo,1,,,,,,,,,,,,,,1,,,,,,
-compress/bzip2,,,1,,,,,,,,,,,,,,,,,1,
-compress/flate,,,4,,,,,,,,,,,,,,,,,4,
-compress/gzip,,,3,,,,,,,,,,,,,,,,,3,
-compress/lzw,,,1,,,,,,,,,,,,,,,,,1,
-compress/zlib,,,4,,,,,,,,,,,,,,,,,4,
-container/heap,,,5,,,,,,,,,,,,,,,,,5,
-container/list,,,20,,,,,,,,,,,,,,,,,20,
-container/ring,,,5,,,,,,,,,,,,,,,,,5,
-context,,,5,,,,,,,,,,,,,,,,,5,
-crypto,,,10,,,,,,,,,,,,,,,,,10,
-database/sql,,,11,,,,,,,,,,,,,,,,,11,
-encoding,,,77,,,,,,,,,,,,,,,,,77,
-errors,,,3,,,,,,,,,,,,,,,,,3,
-expvar,,,6,,,,,,,,,,,,,,,,,6,
-fmt,,,16,,,,,,,,,,,,,,,,,16,
-github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,3,,,,,
-github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,4,,,,,
-github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,4,,,,,
-github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,8,,,,,
-github.com/antchfx/xpath,4,,,,,,,,,,,,,,,4,,,,,
-github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,
-github.com/astaxie/beego,7,21,21,,,,5,,,,,,2,,,,,,21,21,
-github.com/beego/beego,14,42,42,,,,10,,,,,,4,,,,,,42,42,
-github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,5,,,1,1
-github.com/clevergo/clevergo,1,,,,,,,,,,,,,,1,,,,,,
-github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,
-github.com/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,18,
-github.com/couchbaselabs/gocb,,,18,,,,,,,,,,,,,,,,,18,
-github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,
-github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,9,
-github.com/elazarl/goproxy,,2,2,,,,,,,,,,,,,,,,2,2,
-github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,7,,
-github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,12,
-github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,
-github.com/gin-gonic/gin,3,46,2,,,,3,,,,,,,,,,,,46,2,
-github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,3,,
-github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,
-github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4,
-github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,
-github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,6,
-github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,7,,,,
-github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,2,,
-github.com/gofiber/fiber,5,,,,,,4,,,,,,,,1,,,,,,
-github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,
-github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,11,
-github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,4,
-github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,1,,
-github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,3,,
-github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,1,,,,
-github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,,
-github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,,
-github.com/joho/godotenv,,4,,,,,,,,,,,,,,,4,,,,
-github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,4,
-github.com/kataras/iris/context,6,,,,,,6,,,,,,,,,,,,,,
-github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,
-github.com/kataras/iris/server/web/context,6,,,,,,6,,,,,,,,,,,,,,
-github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,
-github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,6,,,,
-github.com/labstack/echo,3,12,2,,,,2,,,,,,1,,,,,,12,2,
-github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,
-github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,3,,,,,
-github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,
-github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,,
-github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,,
-github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,
-github.com/revel/revel,2,23,10,,,,1,,,,,,1,,,,,,23,10,
-github.com/robfig/revel,2,23,10,,,,1,,,,,,1,,,,,,23,10,
-github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,2,,,,,
-github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,1,
-github.com/spf13/afero,34,,,,,,34,,,,,,,,,,,,,,
-github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4,
-github.com/valyala/fasthttp,35,50,5,,,,8,,,,17,8,2,,,,,,50,5,
-go.uber.org/zap,,,11,,,,,,,,,,,,,,,,,11,
-golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,
-golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,5,
-golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,16,
-golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,2,,
-google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,1,
-google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,2,
-google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,8,
-google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,1,
-gopkg.in/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,18,
-gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4,
-gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-gopkg.in/macaron,1,12,1,,,,,,,,,,,,1,,,,12,1,
-gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4,
-gopkg.in/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,9,
-html,,,8,,,,,,,,,,,,,,,,,8,
-io,5,4,34,,,,5,,,,,,,,,,,4,,34,
-k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,10,
-k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,47,
-launchpad.net/xmlpath,2,,,,,,,,,,,,,,,2,,,,,
-log,,,3,,,,,,,,,,,,,,,,,3,
-math/big,,,1,,,,,,,,,,,,,,,,,1,
-mime,,,14,,,,,,,,,,,,,,,,,14,
-net,2,16,100,,,,1,,,,,,,1,,,,,16,100,
-nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,2,,
-os,29,10,6,3,,,26,,,,,,,,,,7,3,,6,
-path,,,18,,,,,,,,,,,,,,,,,18,
-reflect,,,37,,,,,,,,,,,,,,,,,37,
-regexp,10,,20,,,,,3,3,4,,,,,,,,,,20,
-sort,,,1,,,,,,,,,,,,,,,,,1,
-strconv,,,9,,,,,,,,,,,,,,,,,9,
-strings,,,34,,,,,,,,,,,,,,,,,34,
-sync,,,34,,,,,,,,,,,,,,,,,34,
-syscall,5,2,8,5,,,,,,,,,,,,,2,,,8,
-text/scanner,,,3,,,,,,,,,,,,,,,,,3,
-text/tabwriter,,,1,,,,,,,,,,,,,,,,,1,
-text/template,,,6,,,,,,,,,,,,,,,,,6,
+package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:log-injection,sink:nosql-injection,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:sql-injection,sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value
+,,,8,,,,,,,,,,,,,,,,,,,,,3,5
+archive/tar,,,5,,,,,,,,,,,,,,,,,,,,,5,
+archive/zip,,,6,,,,,,,,,,,,,,,,,,,,,6,
+bufio,,,17,,,,,,,,,,,,,,,,,,,,,17,
+bytes,,,43,,,,,,,,,,,,,,,,,,,,,43,
+clevergo.tech/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
+compress/bzip2,,,1,,,,,,,,,,,,,,,,,,,,,1,
+compress/flate,,,4,,,,,,,,,,,,,,,,,,,,,4,
+compress/gzip,,,3,,,,,,,,,,,,,,,,,,,,,3,
+compress/lzw,,,1,,,,,,,,,,,,,,,,,,,,,1,
+compress/zlib,,,4,,,,,,,,,,,,,,,,,,,,,4,
+container/heap,,,5,,,,,,,,,,,,,,,,,,,,,5,
+container/list,,,20,,,,,,,,,,,,,,,,,,,,,20,
+container/ring,,,5,,,,,,,,,,,,,,,,,,,,,5,
+context,,,5,,,,,,,,,,,,,,,,,,,,,5,
+crypto,,,10,,,,,,,,,,,,,,,,,,,,,10,
+database/sql,30,,11,,,,,,,,,,,,30,,,,,,,,,11,
+encoding,,,77,,,,,,,,,,,,,,,,,,,,,77,
+errors,,,3,,,,,,,,,,,,,,,,,,,,,3,
+expvar,,,6,,,,,,,,,,,,,,,,,,,,,6,
+fmt,3,,16,,,,3,,,,,,,,,,,,,,,,,16,
+github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,,,,3,,,,,,
+github.com/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
+github.com/Sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
+github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
+github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
+github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,,,,8,,,,,,
+github.com/antchfx/xpath,4,,,,,,,,,,,,,,,,,,4,,,,,,
+github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/astaxie/beego,71,21,21,,,,34,,5,,,,,,30,2,,,,,,21,,21,
+github.com/beego/beego,142,42,42,,,,68,,10,,,,,,60,4,,,,,,42,,42,
+github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,,,,5,,,,1,1
+github.com/clevergo/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
+github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,,,,
+github.com/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
+github.com/couchbaselabs/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
+github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/davecgh/go-spew/spew,9,,,,,,9,,,,,,,,,,,,,,,,,,
+github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,,,,9,
+github.com/elazarl/goproxy,2,2,2,,,,2,,,,,,,,,,,,,,,2,,2,
+github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,,,,7,,,
+github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,,,,12,
+github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,,,,
+github.com/gin-gonic/gin,3,46,2,,,,,,3,,,,,,,,,,,,,46,,2,
+github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,,,,3,,,
+github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/go-gorm/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
+github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
+github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,,,,6,
+github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+github.com/go-xorm/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
+github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,,,,7,,,,,
+github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,,,,2,,,
+github.com/gofiber/fiber,5,,,,,,,,4,,,,,,,,,1,,,,,,,
+github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/gogf/gf/database/gdb,51,,,,,,,,,,,,,,51,,,,,,,,,,
+github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,,,,11,
+github.com/golang/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
+github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,,,,4,
+github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,,,,1,,,
+github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,,,,3,,,
+github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,,,,1,,,,,
+github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
+github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
+github.com/jinzhu/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
+github.com/jmoiron/sqlx,12,,,,,,,,,,,,,,12,,,,,,,,,,
+github.com/joho/godotenv,,4,,,,,,,,,,,,,,,,,,4,,,,,
+github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,,,,4,
+github.com/kataras/iris/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
+github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
+github.com/kataras/iris/server/web/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
+github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,,,,
+github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,,,,6,,,,,
+github.com/labstack/echo,3,12,2,,,,,,2,,,,,,,1,,,,,,12,,2,
+github.com/lann/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
+github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,,,,
+github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,,,,3,,,,,,
+github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,,,,
+github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
+github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
+github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
+github.com/raindog308/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
+github.com/revel/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
+github.com/robfig/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
+github.com/rqlite/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
+github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,,,,2,,,,,,
+github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,,,,1,
+github.com/sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
+github.com/spf13/afero,34,,,,,,,,34,,,,,,,,,,,,,,,,
+github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
+github.com/uptrace/bun,63,,,,,,,,,,,,,,63,,,,,,,,,,
+github.com/valyala/fasthttp,35,50,5,,,,,,8,,,,17,8,,2,,,,,,50,,5,
+go.mongodb.org/mongo-driver/mongo,14,,,,,,,14,,,,,,,,,,,,,,,,,
+go.uber.org/zap,33,,11,,,,33,,,,,,,,,,,,,,,,,11,
+golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,,,,
+golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,,,,5,
+golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,,,,16,
+golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
+google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,,,,1,
+google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,,,,2,
+google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,,,,8,
+google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,,,,1,
+gopkg.in/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
+gopkg.in/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
+gopkg.in/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
+gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
+gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+gopkg.in/macaron,1,12,1,,,,,,,,,,,,,,,1,,,,12,,1,
+gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
+gopkg.in/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,,,,9,
+gorm.io/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
+html,,,8,,,,,,,,,,,,,,,,,,,,,8,
+io,5,4,34,,,,,,5,,,,,,,,,,,,4,,,34,
+k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,10,
+k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,47,
+k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,,
+launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
+log,20,,3,,,,20,,,,,,,,,,,,,,,,,3,
+math/big,,,1,,,,,,,,,,,,,,,,,,,,,1,
+mime,,,14,,,,,,,,,,,,,,,,,,,,,14,
+net,2,16,100,,,,,,1,,,,,,,,1,,,,,16,,100,
+nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
+os,29,11,6,3,,,,,26,,,,,,,,,,,7,3,,1,6,
+path,,,18,,,,,,,,,,,,,,,,,,,,,18,
+reflect,,,37,,,,,,,,,,,,,,,,,,,,,37,
+regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,20,
+sort,,,1,,,,,,,,,,,,,,,,,,,,,1,
+strconv,,,9,,,,,,,,,,,,,,,,,,,,,9,
+strings,,,34,,,,,,,,,,,,,,,,,,,,,34,
+sync,,,34,,,,,,,,,,,,,,,,,,,,,34,
+syscall,5,2,8,5,,,,,,,,,,,,,,,,2,,,,8,
+text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,3,
+text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,1,
+text/template,,,6,,,,,,,,,,,,,,,,,,,,,6,
+xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
diff --git a/go/documentation/library-coverage/coverage.rst b/go/documentation/library-coverage/coverage.rst
index 848d989d2d5..87ac3e6f1cc 100644
--- a/go/documentation/library-coverage/coverage.rst
+++ b/go/documentation/library-coverage/coverage.rst
@@ -9,27 +9,27 @@ Go framework & library support
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total)
`Afero `_,``github.com/spf13/afero*``,,,34
`CleverGo `_,"``clevergo.tech/clevergo*``, ``github.com/clevergo/clevergo*``",,,2
- `Couchbase official client(gocb) `_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36,
- `Couchbase unofficial client `_,``github.com/couchbaselabs/gocb*``,,18,
+ `Couchbase official client(gocb) `_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36,16
+ `Couchbase unofficial client `_,``github.com/couchbaselabs/gocb*``,,18,8
`Echo `_,``github.com/labstack/echo*``,12,2,3
`Fiber `_,``github.com/gofiber/fiber*``,,,5
`Fosite `_,``github.com/ory/fosite*``,,,2
`Gin `_,``github.com/gin-gonic/gin*``,46,2,3
- `Glog `_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,,
+ `Glog `_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,,270
`Go JOSE `_,"``github.com/go-jose/go-jose*``, ``github.com/square/go-jose*``, ``gopkg.in/square/go-jose*``, ``gopkg.in/go-jose/go-jose*``",,16,12
`Go kit `_,``github.com/go-kit/kit*``,,,1
- `Go-spew `_,``github.com/davecgh/go-spew/spew*``,,,
+ `Go-spew `_,``github.com/davecgh/go-spew/spew*``,,,9
`Gokogiri `_,"``github.com/jbowtie/gokogiri*``, ``github.com/moovweb/gokogiri*``",,,10
`Iris `_,``github.com/kataras/iris*``,,,14
`Kubernetes `_,"``k8s.io/api*``, ``k8s.io/apimachinery*``",,57,
- `Logrus `_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,,
+ `Logrus `_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,,290
`Macaron `_,``gopkg.in/macaron*``,12,1,1
`Revel `_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4
`SendGrid `_,``github.com/sendgrid/sendgrid-go*``,,1,
- `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",32,587,51
+ `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,587,104
`XPath `_,``github.com/antchfx/xpath*``,,,4
`appleboy/gin-jwt `_,``github.com/appleboy/gin-jwt*``,,,1
- `beego `_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,21
+ `beego `_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,213
`chi `_,``github.com/go-chi/chi*``,3,,
`cristalhq/jwt `_,``github.com/cristalhq/jwt*``,,,1
`fasthttp `_,``github.com/valyala/fasthttp*``,50,5,35
@@ -39,7 +39,7 @@ Go framework & library support
`go-sh `_,``github.com/codeskyblue/go-sh*``,,,4
`golang.org/x/crypto/ssh `_,``golang.org/x/crypto/ssh*``,,,4
`golang.org/x/net `_,``golang.org/x/net*``,2,21,
- `goproxy `_,``github.com/elazarl/goproxy*``,2,2,
+ `goproxy `_,``github.com/elazarl/goproxy*``,2,2,2
`gorilla/mux `_,``github.com/gorilla/mux*``,1,,
`gorilla/websocket `_,``github.com/gorilla/websocket*``,3,,
`goxpath `_,``github.com/ChrisTrenkamp/goxpath*``,,,3
@@ -59,7 +59,7 @@ Go framework & library support
`xmlquery `_,``github.com/antchfx/xmlquery*``,,,8
`xpathparser `_,``github.com/santhosh-tekuri/xpathparser*``,,,2
`yaml `_,``gopkg.in/yaml*``,,9,
- `zap `_,``go.uber.org/zap*``,,11,
- Others,"``github.com/caarlos0/env``, ``github.com/gobuffalo/envy``, ``github.com/hashicorp/go-envparse``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``",23,2,
- Totals,,306,911,268
+ `zap `_,``go.uber.org/zap*``,,11,33
+ Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",23,2,391
+ Totals,,307,911,1532
diff --git a/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md b/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md
new file mode 100644
index 00000000000..46f5988b379
--- /dev/null
+++ b/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* A call to a method whose name starts with "Debug", "Error", "Fatal", "Info", "Log", "Output", "Panic", "Print", "Trace", "Warn" or "With" defined on an interface whose name ends in "logger" or "Logger" is now considered a LoggerCall. In particular, it is a sink for `go/clear-text-logging` and `go/log-injection`. This may lead to some more alerts in those queries.
diff --git a/go/ql/lib/ext/database.sql.driver.model.yml b/go/ql/lib/ext/database.sql.driver.model.yml
index c2d780bb7c8..10cfba9388a 100644
--- a/go/ql/lib/ext/database.sql.driver.model.yml
+++ b/go/ql/lib/ext/database.sql.driver.model.yml
@@ -1,4 +1,14 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["database/sql/driver", "Execer", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql/driver", "ExecerContext", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql/driver", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql/driver", "ConnPrepareContext", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql/driver", "Queryer", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql/driver", "QueryerContext", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/database.sql.model.yml b/go/ql/lib/ext/database.sql.model.yml
index e1083f6e49a..5854ced527d 100644
--- a/go/ql/lib/ext/database.sql.model.yml
+++ b/go/ql/lib/ext/database.sql.model.yml
@@ -1,4 +1,32 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["database/sql", "Conn", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Conn", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["database/sql", "Tx", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/fmt.model.yml b/go/ql/lib/ext/fmt.model.yml
index cad64ce0fdf..2baac68da3a 100644
--- a/go/ql/lib/ext/fmt.model.yml
+++ b/go/ql/lib/ext/fmt.model.yml
@@ -1,4 +1,11 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["fmt", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["fmt", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["fmt", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml b/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml
new file mode 100644
index 00000000000..08c0572b894
--- /dev/null
+++ b/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml
@@ -0,0 +1,42 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["beego-orm", "github.com/beego/beego/client/orm"]
+ - ["beego-orm", "github.com/astaxie/beego/orm"]
+ - ["beego-orm", "github.com/beego/beego/orm"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:beego-orm", "Condition", True, "Raw", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "Ormer", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "And", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Delete", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "In", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "InnerJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "InsertInto", "", "", "Argument[0..1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "LeftJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "On", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "RightJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Set", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Subquery", "", "", "Argument[0..1]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Update", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Values", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QueryBuilder", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:beego-orm", "QuerySeter", True, "FilterRaw", "", "", "Argument[1]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml b/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml
new file mode 100644
index 00000000000..b55c3be507d
--- /dev/null
+++ b/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml
@@ -0,0 +1,34 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["beego-logs", "github.com/astaxie/beego/logs"]
+ - ["beego-logs", "github.com/beego/beego/logs"]
+ - ["beego-logs", "github.com/beego/beego/core/logs"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:beego-logs", "", False, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "", False, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego-logs", "BeeLogger", True, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml b/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml
index 4eb0688e37e..63c05b92040 100644
--- a/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml
+++ b/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml
@@ -6,6 +6,11 @@ extensions:
- ["beego-utils", "github.com/astaxie/beego/utils"]
- ["beego-utils", "github.com/beego/beego/utils"]
- ["beego-utils", "github.com/beego/beego/core/utils"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:beego-utils", "", False, "Display", "", "", "Argument[0]", "log-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml b/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml
index 963000fffcc..0c539522c5a 100644
--- a/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml
+++ b/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml
@@ -10,6 +10,18 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
+ # log-injection
+ - ["group:beego", "", False, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:beego", "", False, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"]
# path-injection
- ["group:beego", "", False, "Walk", "", "", "Argument[1]", "path-injection", "manual"]
- ["group:beego", "Controller", True, "SaveToFile", "", "", "Argument[1]", "path-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.couchbase.gocb.model.yml b/go/ql/lib/ext/github.com.couchbase.gocb.model.yml
index ff0a4c22c8d..d17b53dd6da 100644
--- a/go/ql/lib/ext/github.com.couchbase.gocb.model.yml
+++ b/go/ql/lib/ext/github.com.couchbase.gocb.model.yml
@@ -3,28 +3,43 @@ extensions:
pack: codeql/go-all
extensible: packageGrouping
data:
- - ["gocb", "github.com/couchbase/gocb"]
- - ["gocb", "gopkg.in/couchbase/gocb"]
- - ["gocb", "github.com/couchbaselabs/gocb"]
+ - ["gocb1", "fixed-version:github.com/couchbase/gocb"]
+ - ["gocb1", "fixed-version:gopkg.in/couchbase/gocb.v1"]
+ - ["gocb1", "fixed-version:github.com/couchbaselabs/gocb"]
+ - ["gocb2", "github.com/couchbase/gocb/v2"]
+ - ["gocb2", "gopkg.in/couchbase/gocb.v2"]
+ - ["gocb2", "github.com/couchbaselabs/gocb/v2"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:gocb1", "Bucket", True, "ExecuteN1qlQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb1", "Bucket", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb1", "Cluster", True, "ExecuteN1qlQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb1", "Cluster", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb2", "Cluster", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb2", "Cluster", True, "Query", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb2", "Scope", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"]
+ - ["group:gocb2", "Scope", True, "Query", "", "", "Argument[0]", "nosql-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
data:
- - ["group:gocb", "", False, "NewAnalyticsQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "", False, "NewN1qlQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "ContextId", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "Deferred", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "Pretty", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "Priority", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "RawParam", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "AnalyticsQuery", True, "ServerSideTimeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "AdHoc", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "Consistency", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "ConsistentWith", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "Custom", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "PipelineBatch", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "PipelineCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "Profile", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "ReadOnly", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "ScanCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- - ["group:gocb", "N1qlQuery", True, "Timeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "", False, "NewAnalyticsQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "", False, "NewN1qlQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "ContextId", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "Deferred", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "Pretty", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "Priority", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "RawParam", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "AnalyticsQuery", True, "ServerSideTimeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "AdHoc", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "Consistency", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "ConsistentWith", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "Custom", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "PipelineBatch", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "PipelineCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "Profile", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "ReadOnly", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "ScanCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
+ - ["group:gocb1", "N1qlQuery", True, "Timeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
diff --git a/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml b/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml
new file mode 100644
index 00000000000..4b4996926e3
--- /dev/null
+++ b/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml
@@ -0,0 +1,14 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/davecgh/go-spew/spew", "", False, "Dump", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Fdump", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Fprint", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Fprintf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Fprintln", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["github.com/davecgh/go-spew/spew", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml b/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml
index 20e4a26f1cd..9dc8284ea58 100644
--- a/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml
+++ b/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml
@@ -1,4 +1,10 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/elazarl/goproxy", "ProxyCtx", True, "Logf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["github.com/elazarl/goproxy", "ProxyCtx", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml b/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml
new file mode 100644
index 00000000000..030656c6eb8
--- /dev/null
+++ b/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml
@@ -0,0 +1,57 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ # These models are for v1. Some of them hold for v2, but we should model v2 properly.
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Core", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/gogf/gf/database/gdb", "Tx", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.golang.glog.model.yml b/go/ql/lib/ext/github.com.golang.glog.model.yml
new file mode 100644
index 00000000000..275450f2c44
--- /dev/null
+++ b/go/ql/lib/ext/github.com.golang.glog.model.yml
@@ -0,0 +1,102 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["glog", "github.com/golang/glog"]
+ - ["glog", "gopkg.in/glog"]
+ - ["glog", "k8s.io/klog"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:glog", "", False, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ErrorDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Exit", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "ExitDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Exitf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Exitln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "FatalDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "InfoDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "WarningDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "", False, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ErrorDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Exit", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "ExitDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Exitf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Exitln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "FatalDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "InfoDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningContext", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningContextDepth", "", "", "Argument[2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningContextf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningDepth", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "WarningDepthf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:glog", "Verbose", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml b/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml
new file mode 100644
index 00000000000..8c9d19b4b85
--- /dev/null
+++ b/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml
@@ -0,0 +1,17 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/jmoiron/sqlx", "DB", True, "Get", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "DB", True, "MustExec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "DB", True, "NamedExec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "DB", True, "NamedQuery", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "DB", True, "Queryx", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "DB", True, "Select", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "Get", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "MustExec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "NamedExec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "NamedQuery", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "Queryx", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/jmoiron/sqlx", "Tx", True, "Select", "", "", "Argument[1]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml b/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml
new file mode 100644
index 00000000000..6f3c5830e45
--- /dev/null
+++ b/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml
@@ -0,0 +1,51 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["squirrel", "github.com/Masterminds/squirrel"]
+ - ["squirrel", "gopkg.in/Masterminds/squirrel"]
+ - ["squirrel", "github.com/lann/squirrel"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:squirrel", "", False, "Delete", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "", False, "Expr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "", False, "Insert", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "", False, "Select", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "", False, "Update", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+
+ - ["group:squirrel", "DeleteBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "DeleteBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "DeleteBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "DeleteBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"]
+ # DeleteBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used
+
+ - ["group:squirrel", "InsertBuilder", True, "Columns", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "InsertBuilder", True, "Into", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "InsertBuilder", True, "Options", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "InsertBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "InsertBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"]
+
+ - ["group:squirrel", "SelectBuilder", True, "CrossJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "Column", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "Columns", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "SelectBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "InnerJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "LeftJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "Options", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "SelectBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "SelectBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "RightJoin", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "SelectBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"]
+ # SelectBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used
+
+ - ["group:squirrel", "UpdateBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "UpdateBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement
+ - ["group:squirrel", "UpdateBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "UpdateBuilder", True, "Set", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "UpdateBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:squirrel", "UpdateBuilder", True, "Table", "", "", "Argument[0]", "sql-injection", "manual"]
+ # UpdateBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used
diff --git a/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml b/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml
new file mode 100644
index 00000000000..62e24f2c920
--- /dev/null
+++ b/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml
@@ -0,0 +1,35 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["gorqlite", "github.com/rqlite/gorqlite"]
+ - ["gorqlite", "github.com/raindog308/gorqlite"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:gorqlite", "Connection", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueryParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "Queue", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "QueueParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "Write", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteOne", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteOneContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteParameterized", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorqlite", "Connection", True, "WriteParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml b/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml
new file mode 100644
index 00000000000..06f9a54622b
--- /dev/null
+++ b/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml
@@ -0,0 +1,159 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["logrus", "github.com/sirupsen/logrus"]
+ - ["logrus", "github.com/Sirupsen/logrus"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:logrus", "", False, "Debug", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "DebugFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Debugln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "ErrorFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "FatalFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "InfoFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "PanicFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "PrintFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Trace", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "TraceFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Traceln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WarnFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warnln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WarningFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WithError", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WithFields", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "", False, "WithTime", "", "", "Argument[0]", "log-injection", "manual"]
+
+ - ["group:logrus", "Entry", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Log", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Logf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Logln", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Println", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Trace", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Traceln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Entry", True, "WithTime", "", "", "Argument[0]", "log-injection", "manual"]
+
+ - ["group:logrus", "FieldLogger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "FieldLogger", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"]
+
+ - ["group:logrus", "Logger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "DebugFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "ErrorFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "FatalFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "InfoFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Log", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "LogFn", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Logf", "", "", "Argument[1..2]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Logln", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "PanicFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "PrintFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Trace", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "TraceFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Traceln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WarnFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WarningFn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["group:logrus", "Logger", True, "WithTime", "", "", "Argument[0]", "log-injection", "manual"]
diff --git a/go/ql/lib/ext/github.com.uptrace.bun.model.yml b/go/ql/lib/ext/github.com.uptrace.bun.model.yml
new file mode 100644
index 00000000000..a08adb07973
--- /dev/null
+++ b/go/ql/lib/ext/github.com.uptrace.bun.model.yml
@@ -0,0 +1,68 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/uptrace/bun", "", False, "NewRawQuery", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "AddColumnQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "AddColumnQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "AddColumnQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "Conn", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateIndexQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateIndexQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateIndexQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateIndexQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateIndexQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateTableQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateTableQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "CreateTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DeleteQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DeleteQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DeleteQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DropColumnQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DropColumnQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DropColumnQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DropTableQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "DropTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "InsertQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "InsertQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "InsertQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "InsertQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "InsertQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "MergeQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "MergeQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "RawQuery", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "DistinctOn", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "For", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "GroupExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "OrderExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "SelectQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "TruncateTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "UpdateQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "UpdateQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "UpdateQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["github.com/uptrace/bun", "UpdateQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml b/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml
new file mode 100644
index 00000000000..6c2d4afdeae
--- /dev/null
+++ b/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml
@@ -0,0 +1,19 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Aggregate", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "CountDocuments", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "DeleteMany", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "DeleteOne", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Distinct", "", "", "Argument[2]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Find", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOne", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndDelete", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndReplace", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndUpdate", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "ReplaceOne", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "UpdateMany", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "UpdateOne", "", "", "Argument[1]", "nosql-injection", "manual"]
+ - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Watch", "", "", "Argument[1]", "nosql-injection", "manual"]
diff --git a/go/ql/lib/ext/go.uber.org.zap.model.yml b/go/ql/lib/ext/go.uber.org.zap.model.yml
index 2ca7f7e8a80..e9fc971e5fa 100644
--- a/go/ql/lib/ext/go.uber.org.zap.model.yml
+++ b/go/ql/lib/ext/go.uber.org.zap.model.yml
@@ -1,4 +1,41 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["go.uber.org/zap", "Logger", True, "DPanic", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Fatal", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Named", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Panic", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "With", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "Logger", True, "WithOptions", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "DPanic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "DPanicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "DPanicw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Debugw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Errorw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Fatalw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Infow", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Named", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Panicw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "Warnw", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["go.uber.org/zap", "SugaredLogger", True, "With", "", "", "Argument[0]", "log-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/gorm.io.gorm.model.yml b/go/ql/lib/ext/gorm.io.gorm.model.yml
new file mode 100644
index 00000000000..bfcf1fa66a7
--- /dev/null
+++ b/go/ql/lib/ext/gorm.io.gorm.model.yml
@@ -0,0 +1,25 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["gorm", "gorm.io/gorm"]
+ - ["gorm", "github.com/jinzhu/gorm"]
+ - ["gorm", "github.com/go-gorm/gorm"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:gorm", "DB", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Order", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Not", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Table", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Group", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Joins", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Distinct", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:gorm", "DB", True, "Pluck", "", "", "Argument[0]", "sql-injection", "manual"]
diff --git a/go/ql/lib/ext/log.model.yml b/go/ql/lib/ext/log.model.yml
index 7f52a173307..4d1df7cf082 100644
--- a/go/ql/lib/ext/log.model.yml
+++ b/go/ql/lib/ext/log.model.yml
@@ -1,4 +1,28 @@
extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["log", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "", False, "Output", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["log", "", False, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "", False, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "", False, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Output", "", "", "Argument[1]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"]
+ - ["log", "Logger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"]
- addsTo:
pack: codeql/go-all
extensible: summaryModel
diff --git a/go/ql/lib/ext/os.model.yml b/go/ql/lib/ext/os.model.yml
index 3d87eefe43f..2c1c64db93a 100644
--- a/go/ql/lib/ext/os.model.yml
+++ b/go/ql/lib/ext/os.model.yml
@@ -53,6 +53,7 @@ extensions:
- ["os", "", False, "Open", "", "", "ReturnValue[0]", "file", "manual"]
- ["os", "", False, "OpenFile", "", "", "ReturnValue[0]", "file", "manual"]
- ["os", "", False, "ReadFile", "", "", "ReturnValue[0]", "file", "manual"]
+ - ["os", "", False, "Stdin", "", "", "", "stdin", "manual"]
- ["os", "", False, "UserCacheDir", "", "", "ReturnValue[0]", "environment", "manual"]
- ["os", "", False, "UserConfigDir", "", "", "ReturnValue[0]", "environment", "manual"]
- ["os", "", False, "UserHomeDir", "", "", "ReturnValue[0]", "environment", "manual"]
diff --git a/go/ql/lib/ext/xorm.io.xorm.model.yml b/go/ql/lib/ext/xorm.io.xorm.model.yml
new file mode 100644
index 00000000000..5cf1ac4f5d7
--- /dev/null
+++ b/go/ql/lib/ext/xorm.io.xorm.model.yml
@@ -0,0 +1,49 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: packageGrouping
+ data:
+ - ["xorm", "xorm.io/xorm"]
+ - ["xorm", "github.com/go-xorm/xorm"]
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["group:xorm", "Engine", True, "Alias", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "And", "", "", "Argument[0]", "sql-injection", "manual"]
+ # Engine.Exec has to be modeled in QL to select only the first syntactic argument
+ - ["group:xorm", "Engine", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "In", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Join", "", "", "Argument[0..2]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "NotIn", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ # Engine.Query, Engine.QueryInterface and Engine.QueryString have to be modeled in QL to select only the first syntactic argument
+ - ["group:xorm", "Engine", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "SetExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "SQL", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Sum", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Sums", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "SumInt", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "SumsInt", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Engine", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Alias", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "And", "", "", "Argument[0]", "sql-injection", "manual"]
+ # Session.Exec has to be modeled in QL to select only the first syntactic argument
+ - ["group:xorm", "Session", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "In", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Join", "", "", "Argument[0..2]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "NotIn", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"]
+ # Session.Query, Session.QueryInterface and Session.QueryString have to be modeled in QL to select only the first syntactic argument
+ - ["group:xorm", "Session", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "SetExpr", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "SQL", "", "", "Argument[0]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Sum", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Sums", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "SumInt", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "SumsInt", "", "", "Argument[1]", "sql-injection", "manual"]
+ - ["group:xorm", "Session", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"]
diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll
index c15d3683b40..3f0cd0f8885 100644
--- a/go/ql/lib/semmle/go/Concepts.qll
+++ b/go/ql/lib/semmle/go/Concepts.qll
@@ -373,6 +373,48 @@ module LoggerCall {
}
}
+private class DefaultLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
+ DataFlow::ArgumentNode messageComponent;
+
+ DefaultLoggerCall() {
+ sinkNode(messageComponent, "log-injection") and
+ this = messageComponent.getCall()
+ }
+
+ override DataFlow::Node getAMessageComponent() {
+ not messageComponent instanceof DataFlow::ImplicitVarargsSlice and
+ result = messageComponent
+ or
+ messageComponent instanceof DataFlow::ImplicitVarargsSlice and
+ result = this.getAnImplicitVarargsArgument()
+ }
+}
+
+/**
+ * A call to an interface that looks like a logger. It is common to use a
+ * locally-defined interface for logging to make it easy to changing logging
+ * library.
+ */
+private class HeuristicLoggerCall extends LoggerCall::Range, DataFlow::CallNode {
+ HeuristicLoggerCall() {
+ exists(Method m, string tp, string logFunctionPrefix, string name |
+ m = this.getTarget() and
+ m.hasQualifiedName(_, tp, name) and
+ m.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType
+ |
+ tp.regexpMatch(".*[lL]ogger") and
+ logFunctionPrefix =
+ [
+ "Debug", "Error", "Fatal", "Info", "Log", "Output", "Panic", "Print", "Trace", "Warn",
+ "With"
+ ] and
+ name.matches(logFunctionPrefix + "%")
+ )
+ }
+
+ override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
+}
+
/**
* A function that encodes data into a binary or textual format.
*
diff --git a/go/ql/lib/semmle/go/Scopes.qll b/go/ql/lib/semmle/go/Scopes.qll
index f9b9e3a26b9..c3671c74b5c 100644
--- a/go/ql/lib/semmle/go/Scopes.qll
+++ b/go/ql/lib/semmle/go/Scopes.qll
@@ -472,7 +472,7 @@ class Function extends ValueEntity, @functionobject {
/** Gets a parameter of this function. */
Parameter getAParameter() { result = this.getParameter(_) }
- /** Gets the `i`th reslt variable of this function. */
+ /** Gets the `i`th result variable of this function. */
ResultVariable getResult(int i) { result.isResultOf(this.getFuncDecl(), i) }
/** Gets a result variable of this function. */
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index a59c7294e80..5ae7b6a7f0d 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -38,7 +38,8 @@
* first 6 columns, and the `output` column specifies how data leaves the
* element selected by the first 6 columns. An `input` can be either "",
* "Argument[n]", or "Argument[n1..n2]":
- * - "": Selects a write to the selected element in case this is a field.
+ * - "": Selects a write to the selected element in case this is a field or
+ * package-level variable.
* - "Argument[n]": Selects an argument in a call to the selected element.
* The arguments are zero-indexed, and `receiver` specifies the receiver.
* - "Argument[n1..n2]": Similar to "Argument[n]" but selects any argument
@@ -47,7 +48,7 @@
* An `output` can be either "", "Argument[n]", "Argument[n1..n2]", "Parameter",
* "Parameter[n]", "Parameter[n1..n2]", , "ReturnValue", "ReturnValue[n]", or
* "ReturnValue[n1..n2]":
- * - "": Selects a read of a selected field.
+ * - "": Selects a read of a selected field or package-level variable.
* - "Argument[n]": Selects the post-update value of an argument in a call to the
* selected element. That is, the value of the argument after the call returns.
* The arguments are zero-indexed, and `receiver` specifies the receiver.
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
index b82039a32fe..40c68ceb900 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
@@ -399,6 +399,13 @@ module SourceSinkInterpretationInput implements
c = "" and
pragma[only_bind_into](e) = getElementWithQualifier(frn.getField(), frn.getBase())
)
+ or
+ // A package-scope (or universe-scope) variable
+ exists(Variable v | not v instanceof Field |
+ c = "" and
+ n.(DataFlow::ReadNode).reads(v) and
+ pragma[only_bind_into](e).asEntity() = v
+ )
)
}
@@ -420,6 +427,17 @@ module SourceSinkInterpretationInput implements
fw.writesField(base, f, node.asNode()) and
pragma[only_bind_into](e) = getElementWithQualifier(f, base)
)
+ or
+ // A package-scope (or universe-scope) variable
+ exists(Node n, SourceOrSinkElement e, DataFlow::Write w, Variable v |
+ n = node.asNode() and
+ e = mid.asElement() and
+ not v instanceof Field
+ |
+ c = "" and
+ w.writes(v, n) and
+ pragma[only_bind_into](e).asEntity() = v
+ )
}
}
diff --git a/go/ql/lib/semmle/go/frameworks/Beego.qll b/go/ql/lib/semmle/go/frameworks/Beego.qll
index 9f6ee598003..a9e296a1f97 100644
--- a/go/ql/lib/semmle/go/frameworks/Beego.qll
+++ b/go/ql/lib/semmle/go/frameworks/Beego.qll
@@ -33,13 +33,6 @@ module Beego {
result = package(v2modulePath(), "server/web/context")
}
- /** Gets the path for the logs package of beego. */
- string logsPackagePath() {
- result = package(v1modulePath(), "logs")
- or
- result = package(v2modulePath(), "core/logs")
- }
-
/** Gets the path for the utils package of beego. */
string utilsPackagePath() {
result = package(v1modulePath(), "utils")
@@ -172,36 +165,6 @@ module Beego {
override string getAContentType() { none() }
}
- private string getALogFunctionName() {
- result =
- [
- "Alert", "Critical", "Debug", "Emergency", "Error", "Info", "Informational", "Notice",
- "Trace", "Warn", "Warning"
- ]
- }
-
- private class ToplevelBeegoLoggers extends LoggerCall::Range, DataFlow::CallNode {
- ToplevelBeegoLoggers() {
- this.getTarget().hasQualifiedName([packagePath(), logsPackagePath()], getALogFunctionName())
- }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
- private class BeegoLoggerMethods extends LoggerCall::Range, DataFlow::MethodCallNode {
- BeegoLoggerMethods() {
- this.getTarget().hasQualifiedName(logsPackagePath(), "BeeLogger", getALogFunctionName())
- }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
- private class UtilLoggers extends LoggerCall::Range, DataFlow::CallNode {
- UtilLoggers() { this.getTarget().hasQualifiedName(utilsPackagePath(), "Display") }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
private class HtmlQuoteSanitizer extends SharedXss::Sanitizer {
HtmlQuoteSanitizer() {
exists(DataFlow::CallNode c | c.getTarget().hasQualifiedName(packagePath(), "Htmlquote") |
diff --git a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll
index c1de0cf4244..925b0f19fa3 100644
--- a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll
+++ b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll
@@ -14,57 +14,6 @@ module BeegoOrm {
/** Gets the package name `github.com/astaxie/beego/orm`. */
string packagePath() { result = package("github.com/astaxie/beego", "orm") }
- private class DbSink extends SQL::QueryString::Range {
- DbSink() {
- exists(Method m, string methodName, int argNum |
- m.hasQualifiedName(packagePath(), "DB", methodName) and
- (
- methodName = ["Exec", "Prepare", "Query", "QueryRow"] and
- argNum = 0
- or
- methodName = ["ExecContext", "PrepareContext", "QueryContext", "QueryRowContext"] and
- argNum = 1
- )
- |
- this = m.getACall().getArgument(argNum)
- )
- }
- }
-
- private class QueryBuilderSink extends SQL::QueryString::Range {
- // Note this class doesn't do any escaping, unlike the true ORM part of the package
- QueryBuilderSink() {
- exists(Method impl | impl.implements(packagePath(), "QueryBuilder", _) |
- this = impl.getACall().getASyntacticArgument()
- ) and
- this.getType().getUnderlyingType() instanceof StringType
- }
- }
-
- private class OrmerRawSink extends SQL::QueryString::Range {
- OrmerRawSink() {
- exists(Method impl | impl.implements(packagePath(), "Ormer", "Raw") |
- this = impl.getACall().getArgument(0)
- )
- }
- }
-
- private class QuerySeterFilterRawSink extends SQL::QueryString::Range {
- QuerySeterFilterRawSink() {
- exists(Method impl | impl.implements(packagePath(), "QuerySeter", "FilterRaw") |
- this = impl.getACall().getArgument(1)
- )
- }
- }
-
- private class ConditionRawSink extends SQL::QueryString::Range {
- ConditionRawSink() {
- exists(Method impl | impl.implements(packagePath(), "Condition", "Raw") |
- this = impl.getACall().getArgument(1)
- )
- }
- }
-
private class OrmerSource extends StoredXss::Source {
OrmerSource() {
exists(Method impl |
diff --git a/go/ql/lib/semmle/go/frameworks/Couchbase.qll b/go/ql/lib/semmle/go/frameworks/Couchbase.qll
index 5eaa4d20c3a..b5bfbcb22a2 100644
--- a/go/ql/lib/semmle/go/frameworks/Couchbase.qll
+++ b/go/ql/lib/semmle/go/frameworks/Couchbase.qll
@@ -5,57 +5,23 @@
import go
/**
+ * DEPRECATED
+ *
* Provides models of commonly used functions in the official Couchbase Go SDK library.
*/
-module Couchbase {
+deprecated module Couchbase {
/**
+ * DEPRECATED
+ *
* Gets a package path for the official Couchbase Go SDK library.
*
* Note that v1 and v2 have different APIs, but the names are disjoint so there is no need to
* distinguish between them.
*/
- string packagePath() {
+ deprecated string packagePath() {
result =
package([
"gopkg.in/couchbase/gocb", "github.com/couchbase/gocb", "github.com/couchbaselabs/gocb"
], "")
}
-
- /**
- * A query used in an API function acting on a `Bucket` or `Cluster` struct of v1 of
- * the official Couchbase Go library, gocb.
- */
- private class CouchbaseV1Query extends NoSql::Query::Range {
- CouchbaseV1Query() {
- // func (b *Bucket) ExecuteAnalyticsQuery(q *AnalyticsQuery, params interface{}) (AnalyticsResults, error)
- // func (b *Bucket) ExecuteN1qlQuery(q *N1qlQuery, params interface{}) (QueryResults, error)
- // func (c *Cluster) ExecuteAnalyticsQuery(q *AnalyticsQuery, params interface{}) (AnalyticsResults, error)
- // func (c *Cluster) ExecuteN1qlQuery(q *N1qlQuery, params interface{}) (QueryResults, error)
- exists(Method meth, string structName, string methodName |
- structName in ["Bucket", "Cluster"] and
- methodName in ["ExecuteN1qlQuery", "ExecuteAnalyticsQuery"] and
- meth.hasQualifiedName(packagePath(), structName, methodName) and
- this = meth.getACall().getArgument(0)
- )
- }
- }
-
- /**
- * A query used in an API function acting on a `Bucket` or `Cluster` struct of v1 of
- * the official Couchbase Go library, gocb.
- */
- private class CouchbaseV2Query extends NoSql::Query::Range {
- CouchbaseV2Query() {
- // func (c *Cluster) AnalyticsQuery(statement string, opts *AnalyticsOptions) (*AnalyticsResult, error)
- // func (c *Cluster) Query(statement string, opts *QueryOptions) (*QueryResult, error)
- // func (s *Scope) AnalyticsQuery(statement string, opts *AnalyticsOptions) (*AnalyticsResult, error)
- // func (s *Scope) Query(statement string, opts *QueryOptions) (*QueryResult, error)
- exists(Method meth, string structName, string methodName |
- structName in ["Cluster", "Scope"] and
- methodName in ["AnalyticsQuery", "Query"] and
- meth.hasQualifiedName(packagePath(), structName, methodName) and
- this = meth.getACall().getArgument(0)
- )
- }
- }
}
diff --git a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll
index 4d10c8af312..b1bf4571216 100644
--- a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll
+++ b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll
@@ -100,10 +100,4 @@ module ElazarlGoproxy {
override int getFormatStringIndex() { result = 0 }
}
-
- private class ProxyLog extends LoggerCall::Range, DataFlow::MethodCallNode {
- ProxyLog() { this.getTarget() instanceof ProxyLogFunction }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
}
diff --git a/go/ql/lib/semmle/go/frameworks/Glog.qll b/go/ql/lib/semmle/go/frameworks/Glog.qll
index f9f5c9e3f11..146b8a4f814 100644
--- a/go/ql/lib/semmle/go/frameworks/Glog.qll
+++ b/go/ql/lib/semmle/go/frameworks/Glog.qll
@@ -40,14 +40,4 @@ module Glog {
override int getFormatStringIndex() { result = super.getFirstPrintedArg() }
}
-
- private class GlogCall extends LoggerCall::Range, DataFlow::CallNode {
- GlogFunction callee;
-
- GlogCall() { this = callee.getACall() }
-
- override DataFlow::Node getAMessageComponent() {
- result = this.getSyntacticArgument(any(int i | i >= callee.getFirstPrintedArg()))
- }
- }
}
diff --git a/go/ql/lib/semmle/go/frameworks/Logrus.qll b/go/ql/lib/semmle/go/frameworks/Logrus.qll
index f7de9a75dae..83278a4cd9e 100644
--- a/go/ql/lib/semmle/go/frameworks/Logrus.qll
+++ b/go/ql/lib/semmle/go/frameworks/Logrus.qll
@@ -28,12 +28,6 @@ module Logrus {
}
}
- private class LogCall extends LoggerCall::Range, DataFlow::CallNode {
- LogCall() { this = any(LogFunction f).getACall() }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
private class StringFormatters extends StringOps::Formatting::Range instanceof LogFunction {
int argOffset;
diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll
index c2469fc02ac..36932149628 100644
--- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll
+++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll
@@ -31,84 +31,6 @@ module NoSql {
)
}
}
-
- /**
- * Holds if method `name` of struct `Collection` from package
- * [go.mongodb.org/mongo-driver/mongo](https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo)
- * interprets parameter `n` as a query.
- */
- private predicate mongoDbCollectionMethod(string name, int n) {
- // func (coll *Collection) CountDocuments(ctx context.Context, filter interface{},
- // opts ...*options.CountOptions) (int64, error)
- name = "CountDocuments" and n = 1
- or
- // func (coll *Collection) DeleteMany(ctx context.Context, filter interface{},
- // opts ...*options.DeleteOptions) (*DeleteResult, error)
- name = "DeleteMany" and n = 1
- or
- // func (coll *Collection) DeleteOne(ctx context.Context, filter interface{},
- // opts ...*options.DeleteOptions) (*DeleteResult, error)
- name = "DeleteOne" and n = 1
- or
- // func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter interface{},
- // ...) ([]interface{}, error)
- name = "Distinct" and n = 2
- or
- // func (coll *Collection) Find(ctx context.Context, filter interface{},
- // opts ...*options.FindOptions) (*Cursor, error)
- name = "Find" and n = 1
- or
- // func (coll *Collection) FindOne(ctx context.Context, filter interface{},
- // opts ...*options.FindOneOptions) *SingleResult
- name = "FindOne" and n = 1
- or
- // func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{}, ...)
- // *SingleResult
- name = "FindOneAndDelete" and n = 1
- or
- // func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{},
- // replacement interface{}, ...) *SingleResult
- name = "FindOneAndReplace" and n = 1
- or
- // func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{},
- // update interface{}, ...) *SingleResult
- name = "FindOneAndUpdate" and n = 1
- or
- // func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{},
- // replacement interface{}, ...) (*UpdateResult, error)
- name = "ReplaceOne" and n = 1
- or
- // func (coll *Collection) UpdateMany(ctx context.Context, filter interface{},
- // update interface{}, ...) (*UpdateResult, error)
- name = "UpdateMany" and n = 1
- or
- // func (coll *Collection) UpdateOne(ctx context.Context, filter interface{},
- // update interface{}, ...) (*UpdateResult, error)
- name = "UpdateOne" and n = 1
- or
- // func (coll *Collection) Watch(ctx context.Context, pipeline interface{}, ...)
- // (*ChangeStream, error)
- name = "Watch" and n = 1
- or
- // func (coll *Collection) Aggregate(ctx context.Context, pipeline interface{},
- // opts ...*options.AggregateOptions) (*Cursor, error)
- name = "Aggregate" and n = 1
- }
-
- /**
- * A query used in an API function acting on a `Collection` struct of package
- * [go.mongodb.org/mongo-driver/mongo](https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo).
- */
- private class MongoDbCollectionQuery extends Range {
- MongoDbCollectionQuery() {
- exists(Method meth, string methodName, int n |
- mongoDbCollectionMethod(methodName, n) and
- meth.hasQualifiedName(package("go.mongodb.org/mongo-driver", "mongo"), "Collection",
- methodName) and
- this = meth.getACall().getArgument(n)
- )
- }
- }
}
/**
diff --git a/go/ql/lib/semmle/go/frameworks/SQL.qll b/go/ql/lib/semmle/go/frameworks/SQL.qll
index 1a6e2280781..a0e80fde1c9 100644
--- a/go/ql/lib/semmle/go/frameworks/SQL.qll
+++ b/go/ql/lib/semmle/go/frameworks/SQL.qll
@@ -67,41 +67,34 @@ module SQL {
*/
abstract class Range extends DataFlow::Node { }
+ private class DefaultQueryString extends Range {
+ DefaultQueryString() {
+ exists(DataFlow::ArgumentNode arg | sinkNode(arg, "sql-injection") |
+ not arg instanceof DataFlow::ImplicitVarargsSlice and
+ this = arg
+ or
+ arg instanceof DataFlow::ImplicitVarargsSlice and
+ this = arg.getCall().getAnImplicitVarargsArgument()
+ )
+ }
+ }
+
/**
* An argument to an API of the squirrel library that is directly interpreted as SQL without
* taking syntactic structure into account.
*/
private class SquirrelQueryString extends Range {
SquirrelQueryString() {
- exists(Function fn |
- exists(string sq |
- sq =
- package([
- "github.com/Masterminds/squirrel", "gopkg.in/Masterminds/squirrel",
- "github.com/lann/squirrel"
- ], "")
- |
- fn.hasQualifiedName(sq, ["Delete", "Expr", "Insert", "Select", "Update"])
- or
- exists(Method m, string builder | m = fn |
- builder = ["DeleteBuilder", "InsertBuilder", "SelectBuilder", "UpdateBuilder"] and
- m.hasQualifiedName(sq, builder,
- ["Columns", "From", "Options", "OrderBy", "Prefix", "Suffix", "Where"])
- or
- builder = "InsertBuilder" and
- m.hasQualifiedName(sq, builder, ["Replace", "Into"])
- or
- builder = "SelectBuilder" and
- m.hasQualifiedName(sq, builder,
- ["CrossJoin", "GroupBy", "InnerJoin", "LeftJoin", "RightJoin"])
- or
- builder = "UpdateBuilder" and
- m.hasQualifiedName(sq, builder, ["Set", "Table"])
- )
- ) and
- this = fn.getACall().getArgument(0)
+ exists(string sq, Method m, string builder |
+ FlowExtensions::packageGrouping("squirrel", sq) and
+ builder = ["DeleteBuilder", "SelectBuilder", "UpdateBuilder"]
|
- this.getType().getUnderlyingType() instanceof StringType or
+ m.hasQualifiedName(sq, builder, "Where") and
+ this = m.getACall().getArgument(0)
+ ) and
+ (
+ this.getType().getUnderlyingType() instanceof StringType
+ or
this.getType().getUnderlyingType().(SliceType).getElementType() instanceof StringType
)
}
@@ -113,14 +106,6 @@ module SQL {
/** A string that might identify package `go-pg/pg/orm` or a specific version of it. */
private string gopgorm() { result = package("github.com/go-pg/pg", "orm") }
- /** A string that might identify package `github.com/rqlite/gorqlite` or `github.com/raindog308/gorqlite` or a specific version of it. */
- private string gorqlite() {
- result = package(["github.com/rqlite/gorqlite", "github.com/raindog308/gorqlite"], "")
- }
-
- /** A string that might identify package `github.com/gogf/gf/database/gdb` or a specific version of it. */
- private string gogf() { result = package("github.com/gogf/gf", "database/gdb") }
-
/**
* A string argument to an API of `go-pg/pg` that is directly interpreted as SQL without
* taking syntactic structure into account.
@@ -185,94 +170,6 @@ module SQL {
)
}
}
-
- /**
- * A string argument to an API of `github.com/rqlite/gorqlite`, or a specific version of it, that is directly interpreted as SQL without
- * taking syntactic structure into account.
- */
- private class GorqliteQueryString extends Range {
- GorqliteQueryString() {
- // func (conn *Connection) Query(sqlStatements []string) (results []QueryResult, err error)
- // func (conn *Connection) QueryOne(sqlStatement string) (qr QueryResult, err error)
- // func (conn *Connection) Queue(sqlStatements []string) (seq int64, err error)
- // func (conn *Connection) QueueOne(sqlStatement string) (seq int64, err error)
- // func (conn *Connection) Write(sqlStatements []string) (results []WriteResult, err error)
- // func (conn *Connection) WriteOne(sqlStatement string) (wr WriteResult, err error)
- exists(Method m, string name | m.hasQualifiedName(gorqlite(), "Connection", name) |
- name = ["Query", "QueryOne", "Queue", "QueueOne", "Write", "WriteOne"] and
- this = m.getACall().getArgument(0)
- )
- }
- }
-
- /**
- * A string argument to an API of `github.com/gogf/gf/database/gdb`, or a specific version of it, that is directly interpreted as SQL without
- * taking syntactic structure into account.
- */
- private class GogfQueryString extends Range {
- GogfQueryString() {
- exists(Method m, string name | m.implements(gogf(), ["DB", "Core", "TX"], name) |
- // func (c *Core) Exec(sql string, args ...interface{}) (result sql.Result, err error)
- // func (c *Core) GetAll(sql string, args ...interface{}) (Result, error)
- // func (c *Core) GetArray(sql string, args ...interface{}) ([]Value, error)
- // func (c *Core) GetCount(sql string, args ...interface{}) (int, error)
- // func (c *Core) GetOne(sql string, args ...interface{}) (Record, error)
- // func (c *Core) GetValue(sql string, args ...interface{}) (Value, error)
- // func (c *Core) Prepare(sql string, execOnMaster ...bool) (*Stmt, error)
- // func (c *Core) Query(sql string, args ...interface{}) (rows *sql.Rows, err error)
- // func (c *Core) Raw(rawSql string, args ...interface{}) *Model
- name =
- [
- "Query", "Exec", "Prepare", "GetAll", "GetOne", "GetValue", "GetArray", "GetCount",
- "Raw"
- ] and
- this = m.getACall().getArgument(0)
- or
- // func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) error
- // func (c *Core) GetStruct(pointer interface{}, sql string, args ...interface{}) error
- // func (c *Core) GetStructs(pointer interface{}, sql string, args ...interface{}) error
- name = ["GetScan", "GetStruct", "GetStructs"] and
- this = m.getACall().getArgument(1)
- or
- // func (c *Core) DoCommit(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error)
- // func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error)
- // func (c *Core) DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error)
- // func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error)
- // func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (rows *sql.Rows, err error)
- name = ["DoGetAll", "DoQuery", "DoExec", "DoCommit", "DoPrepare"] and
- this = m.getACall().getArgument(2)
- )
- }
- }
- }
-
- /** A model for sinks of GORM. */
- private class GormSink extends SQL::QueryString::Range {
- GormSink() {
- exists(Method meth, string package, string name |
- meth.hasQualifiedName(package, "DB", name) and
- this = meth.getACall().getSyntacticArgument(0) and
- package = Gorm::packagePath() and
- name in [
- "Where", "Raw", "Order", "Not", "Or", "Select", "Table", "Group", "Having", "Joins",
- "Exec", "Distinct", "Pluck"
- ]
- )
- }
- }
-
- /** A model for sinks of github.com/jmoiron/sqlx. */
- private class SqlxSink extends SQL::QueryString::Range {
- SqlxSink() {
- exists(Method meth, string name, int n |
- meth.hasQualifiedName(package("github.com/jmoiron/sqlx", ""), ["DB", "Tx"], name) and
- this = meth.getACall().getArgument(n)
- |
- name = ["Select", "Get"] and n = 1
- or
- name = ["MustExec", "Queryx", "NamedExec", "NamedQuery"] and n = 0
- )
- }
}
}
@@ -291,71 +188,25 @@ module Gorm {
*/
module Xorm {
/** Gets the package name for Xorm. */
- string packagePath() { result = package(["xorm.io/xorm", "github.com/go-xorm/xorm"], "") }
+ string packagePath() { FlowExtensions::packageGrouping("xorm", result) }
/** A model for sinks of XORM. */
private class XormSink extends SQL::QueryString::Range {
XormSink() {
- exists(Method meth, string type, string name, int n |
+ exists(Method meth, string type, string name |
meth.hasQualifiedName(Xorm::packagePath(), type, name) and
- this = meth.getACall().getSyntacticArgument(n) and
- type = ["Engine", "Session"]
+ type = ["Engine", "Session"] and
+ name = ["Exec", "Query", "QueryInterface", "QueryString"]
|
- name =
- [
- "Query", "Exec", "QueryString", "QueryInterface", "SQL", "Where", "And", "Or", "Alias",
- "NotIn", "In", "Select", "SetExpr", "OrderBy", "Having", "GroupBy"
- ] and
- n = 0
- or
- name = ["SumInt", "Sum", "Sums", "SumsInt"] and n = 1
- or
- name = "Join" and n = [0, 1, 2]
+ this = meth.getACall().getSyntacticArgument(0)
)
}
}
}
/**
+ * DEPRECATED
+ *
* Provides classes for working with the [Bun](https://bun.uptrace.dev/) package.
*/
-module Bun {
- /** Gets the package name for Bun package. */
- private string packagePath() { result = package("github.com/uptrace/bun", "") }
-
- /** A model for sinks of Bun. */
- private class BunSink extends SQL::QueryString::Range {
- BunSink() {
- exists(Function f, string m, int arg | this = f.getACall().getArgument(arg) |
- f.hasQualifiedName(packagePath(), m) and
- m = "NewRawQuery" and
- arg = 1
- )
- or
- exists(Method f, string tp, string m, int arg | this = f.getACall().getArgument(arg) |
- f.hasQualifiedName(packagePath(), tp, m) and
- (
- tp = ["DB", "Conn"] and
- m = ["ExecContext", "PrepareContext", "QueryContext", "QueryRowContext"] and
- arg = 1
- or
- tp = ["DB", "Conn"] and
- m = ["Exec", "NewRaw", "Prepare", "Query", "QueryRow", "Raw"] and
- arg = 0
- or
- tp.matches("%Query") and
- m =
- [
- "ColumnExpr", "DistinctOn", "For", "GroupExpr", "Having", "ModelTableExpr",
- "OrderExpr", "TableExpr", "Where", "WhereOr"
- ] and
- arg = 0
- or
- tp = "RawQuery" and
- m = "NewRaw" and
- arg = 0
- )
- )
- }
- }
-}
+deprecated module Bun { }
diff --git a/go/ql/lib/semmle/go/frameworks/Spew.qll b/go/ql/lib/semmle/go/frameworks/Spew.qll
index b12bd0fed81..f49a4aa4d89 100644
--- a/go/ql/lib/semmle/go/frameworks/Spew.qll
+++ b/go/ql/lib/semmle/go/frameworks/Spew.qll
@@ -33,16 +33,6 @@ module Spew {
override int getFormatStringIndex() { result = super.getFirstPrintedArg() }
}
- private class SpewCall extends LoggerCall::Range, DataFlow::CallNode {
- SpewFunction target;
-
- SpewCall() { this = target.getACall() }
-
- override DataFlow::Node getAMessageComponent() {
- result = this.getSyntacticArgument(any(int i | i >= target.getFirstPrintedArg()))
- }
- }
-
// These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet.
/** The `Sprint` function or one of its variants. */
class Sprinter extends TaintTracking::FunctionModel {
diff --git a/go/ql/lib/semmle/go/frameworks/Zap.qll b/go/ql/lib/semmle/go/frameworks/Zap.qll
index 359f9aba410..0928d2b0595 100644
--- a/go/ql/lib/semmle/go/frameworks/Zap.qll
+++ b/go/ql/lib/semmle/go/frameworks/Zap.qll
@@ -34,18 +34,6 @@ module Zap {
override int getFormatStringIndex() { result = 0 }
}
- /**
- * A call to a logger function in Zap.
- *
- * Functions which add data to be included the next time a direct logging
- * function is called are included.
- */
- private class ZapCall extends LoggerCall::Range, DataFlow::MethodCallNode {
- ZapCall() { this = any(ZapFunction f).getACall() }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
// These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet.
/** The function `Fields` that creates an `Option` that can be added to the logger out of `Field`s. */
class FieldsFunction extends TaintTracking::FunctionModel {
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll
index 845225af5bd..f4132688796 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll
@@ -26,7 +26,7 @@ module DatabaseSql {
override DataFlow::Node getAResult() { result = this.getResult(0) }
override SQL::QueryString getAQueryString() {
- result = this.getAnArgument()
+ result = this.getASyntacticArgument()
or
// attempt to resolve a `QueryString` for `Stmt`s using local data flow.
t = "Stmt" and
@@ -34,24 +34,6 @@ module DatabaseSql {
}
}
- /** A query string used in an API function of the `database/sql` package. */
- private class QueryString extends SQL::QueryString::Range {
- QueryString() {
- exists(Method meth, string base, string t, string m, int n |
- t = ["DB", "Tx", "Conn"] and
- meth.hasQualifiedName("database/sql", t, m) and
- this = meth.getACall().getArgument(n)
- |
- base = ["Exec", "Prepare", "Query", "QueryRow"] and
- (
- m = base and n = 0
- or
- m = base + "Context" and n = 1
- )
- )
- }
- }
-
/** A query in the standard `database/sql/driver` package. */
private class DriverQuery extends SQL::Query::Range, DataFlow::MethodCallNode {
DriverQuery() {
@@ -78,36 +60,13 @@ module DatabaseSql {
override DataFlow::Node getAResult() { result = this.getResult(0) }
override SQL::QueryString getAQueryString() {
- result = this.getAnArgument()
+ result = this.getASyntacticArgument()
or
this.getTarget().hasQualifiedName("database/sql/driver", "Stmt") and
result = this.getReceiver().getAPredecessor*().(DataFlow::MethodCallNode).getAnArgument()
}
}
- /** A query string used in an API function of the standard `database/sql/driver` package. */
- private class DriverQueryString extends SQL::QueryString::Range {
- DriverQueryString() {
- exists(Method meth, int n |
- (
- meth.hasQualifiedName("database/sql/driver", "Execer", "Exec") and n = 0
- or
- meth.hasQualifiedName("database/sql/driver", "ExecerContext", "ExecContext") and n = 1
- or
- meth.hasQualifiedName("database/sql/driver", "Conn", "Prepare") and n = 0
- or
- meth.hasQualifiedName("database/sql/driver", "ConnPrepareContext", "PrepareContext") and
- n = 1
- or
- meth.hasQualifiedName("database/sql/driver", "Queryer", "Query") and n = 0
- or
- meth.hasQualifiedName("database/sql/driver", "QueryerContext", "QueryContext") and n = 1
- ) and
- this = meth.getACall().getArgument(n)
- )
- }
- }
-
// These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet.
private class SqlMethodModels extends TaintTracking::FunctionModel, Method {
FunctionInput inp;
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll
index 54794ea21c9..6adbd542e9b 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll
@@ -41,13 +41,6 @@ module Fmt {
Printer() { this.hasQualifiedName("fmt", ["Print", "Printf", "Println"]) }
}
- /** A call to `Print` or similar. */
- private class PrintCall extends LoggerCall::Range, DataFlow::CallNode {
- PrintCall() { this.getTarget() instanceof Printer }
-
- override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() }
- }
-
/** The `Fprint` function or one of its variants. */
private class Fprinter extends TaintTracking::FunctionModel {
Fprinter() {
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll
index 5b402fca1b7..ca74160bf0d 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll
@@ -32,16 +32,6 @@ module Log {
override int getFormatStringIndex() { result = 0 }
}
- private class LogCall extends LoggerCall::Range, DataFlow::CallNode {
- LogFunction target;
-
- LogCall() { this = target.getACall() }
-
- override DataFlow::Node getAMessageComponent() {
- result = this.getSyntacticArgument(any(int i | i >= target.getFirstPrintedArg()))
- }
- }
-
/** A fatal log function, which calls `os.Exit`. */
private class FatalLogFunction extends Function {
FatalLogFunction() { this.hasQualifiedName("log", ["Fatal", "Fatalf", "Fatalln"]) }
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll
index fb153451c59..72ea4cc6c57 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll
@@ -43,12 +43,4 @@ module Os {
input = inp and output = outp
}
}
-
- private class Stdin extends SourceNode {
- Stdin() {
- exists(Variable osStdin | osStdin.hasQualifiedName("os", "Stdin") | this = osStdin.getARead())
- }
-
- override string getThreatModel() { result = "stdin" }
- }
}
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml
index 79bf9128ef5..d89a9e04e16 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml
@@ -35,10 +35,12 @@ extensions:
pack: codeql/go-all
extensible: sourceModel
data:
+ - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
- addsTo:
pack: codeql/go-all
extensible: sinkModel
data:
+ - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected
index fc9adff8942..755c3f82279 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected
@@ -43,3 +43,4 @@ invalidModelRow
| test.go:199:17:199:20 | arg1 | qltest |
| test.go:199:23:199:26 | arg2 | qltest |
| test.go:199:29:199:32 | arg3 | qltest |
+| test.go:202:22:202:25 | temp | qltest |
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml
index 426e094c00c..ec19b822a8c 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml
@@ -3,6 +3,7 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
+ - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkMethod", "", "", "Argument[receiver]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected
index d63fedba3fd..bd1525a984b 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected
@@ -21,3 +21,4 @@ invalidModelRow
| test.go:183:17:183:24 | call to Src1 | qltest |
| test.go:187:24:187:31 | call to Src1 | qltest |
| test.go:191:24:191:31 | call to Src1 | qltest |
+| test.go:201:10:201:28 | selection of SourceVariable | qltest |
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml
index 5493650132c..cda2183894c 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml
@@ -3,9 +3,10 @@ extensions:
pack: codeql/go-all
extensible: sourceModel
data:
+ - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src2", "", "", "ReturnValue", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", True, "Src2", "", "", "ReturnValue", "qltest-w-subtypes", "manual"]
- ["github.com/nonexistent/test", "A", False, "SrcArg", "", "", "Argument[0]", "qltest-arg", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src3", "", "", "ReturnValue[0]", "qltest", "manual"]
- - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"]
\ No newline at end of file
+ - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go
index 33e980dac99..29ed066cd50 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go
@@ -197,6 +197,9 @@ func simpleflow() {
arg3 := src
arg4 := src
b.SinkManyArgs(arg1, arg2, arg3, arg4) // $ hasTaintFlow="arg1" hasTaintFlow="arg2" hasTaintFlow="arg3"
+
+ temp := test.SourceVariable
+ test.SinkVariable = temp // $ hasTaintFlow="temp"
}
type mapstringstringtype map[string]string
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go
index 05a5f741d76..72681cf7238 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go
@@ -72,3 +72,6 @@ func (c C) Get() string { return "" }
func (c *C) SetThroughPointer(f string) {}
func (c *C) GetThroughPointer() string { return "" }
+
+var SourceVariable string
+var SinkVariable string
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml
index 8fbc26ff6cd..924e19a8a73 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml
@@ -35,10 +35,12 @@ extensions:
pack: codeql/go-all
extensible: sourceModel
data:
+ - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
- addsTo:
pack: codeql/go-all
extensible: sinkModel
data:
+ - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected
index 0fe3a614e11..c9940e181c8 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected
@@ -49,3 +49,4 @@ invalidModelRow
| test.go:205:10:205:26 | call to min | qltest |
| test.go:206:10:206:26 | call to min | qltest |
| test.go:207:10:207:26 | call to min | qltest |
+| test.go:210:22:210:25 | temp | qltest |
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml
index 426e094c00c..ec19b822a8c 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml
@@ -3,6 +3,7 @@ extensions:
pack: codeql/go-all
extensible: sinkModel
data:
+ - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkMethod", "", "", "Argument[receiver]", "qltest", "manual"]
- ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected
index d63fedba3fd..6fcfcc2a3bc 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected
@@ -21,3 +21,4 @@ invalidModelRow
| test.go:183:17:183:24 | call to Src1 | qltest |
| test.go:187:24:187:31 | call to Src1 | qltest |
| test.go:191:24:191:31 | call to Src1 | qltest |
+| test.go:209:10:209:28 | selection of SourceVariable | qltest |
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml
index 5493650132c..cda2183894c 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml
@@ -3,9 +3,10 @@ extensions:
pack: codeql/go-all
extensible: sourceModel
data:
+ - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src2", "", "", "ReturnValue", "qltest", "manual"]
- ["github.com/nonexistent/test", "A", True, "Src2", "", "", "ReturnValue", "qltest-w-subtypes", "manual"]
- ["github.com/nonexistent/test", "A", False, "SrcArg", "", "", "Argument[0]", "qltest-arg", "manual"]
- ["github.com/nonexistent/test", "A", False, "Src3", "", "", "ReturnValue[0]", "qltest", "manual"]
- - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"]
\ No newline at end of file
+ - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go
index 82419ae7d59..72c4db35248 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go
@@ -205,6 +205,9 @@ func simpleflow() {
b.Sink1(min(srcInt, 0, 1)) // $ hasValueFlow="call to min"
b.Sink1(min(0, srcInt, 1)) // $ hasValueFlow="call to min"
b.Sink1(min(0, 1, srcInt)) // $ hasValueFlow="call to min"
+
+ temp := test.SourceVariable
+ test.SinkVariable = temp // $ hasValueFlow="temp"
}
type mapstringstringtype map[string]string
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go
index 05a5f741d76..72681cf7238 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go
@@ -72,3 +72,6 @@ func (c C) Get() string { return "" }
func (c *C) SetThroughPointer(f string) {}
func (c *C) GetThroughPointer() string { return "" }
+
+var SourceVariable string
+var SinkVariable string
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected
index 6cc1e09486b..1198f8d41a9 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected
+++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected
@@ -32,40 +32,61 @@
| test.go:59:31:59:39 | untrusted | test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | This query depends on a $@. | test.go:57:15:57:41 | call to UserAgent | user-provided value |
| test.go:65:19:65:27 | untrusted | test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | This query depends on a $@. | test.go:63:15:63:41 | call to UserAgent | user-provided value |
edges
-| test.go:11:15:11:41 | call to UserAgent | test.go:13:11:13:19 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:14:23:14:31 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:15:14:15:22 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:16:26:16:34 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:17:12:17:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:18:24:18:32 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:19:15:19:23 | untrusted | provenance | Src:MaD:1 |
-| test.go:11:15:11:41 | call to UserAgent | test.go:20:27:20:35 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:28:12:28:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:29:10:29:18 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:30:15:30:23 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:31:14:31:22 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:32:15:32:23 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:33:8:33:16 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:34:11:34:19 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:35:9:35:17 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:36:8:36:16 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:37:8:37:16 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:38:13:38:21 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:39:13:39:21 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:40:12:40:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:41:12:41:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:42:9:42:17 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:43:12:43:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:44:16:44:24 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:45:12:45:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:25:15:25:41 | call to UserAgent | test.go:46:14:46:22 | untrusted | provenance | Src:MaD:1 |
-| test.go:26:16:26:42 | call to UserAgent | test.go:44:27:44:36 | untrusted2 | provenance | Src:MaD:1 |
-| test.go:26:16:26:42 | call to UserAgent | test.go:46:25:46:34 | untrusted2 | provenance | Src:MaD:1 |
-| test.go:50:15:50:41 | call to UserAgent | test.go:52:12:52:20 | untrusted | provenance | Src:MaD:1 |
-| test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | provenance | Src:MaD:1 |
-| test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | provenance | Src:MaD:1 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:13:11:13:19 | untrusted | provenance | Src:MaD:22 Sink:MaD:2 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:14:23:14:31 | untrusted | provenance | Src:MaD:22 Sink:MaD:3 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:15:14:15:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:4 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:16:26:16:34 | untrusted | provenance | Src:MaD:22 Sink:MaD:5 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:17:12:17:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:6 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:18:24:18:32 | untrusted | provenance | Src:MaD:22 Sink:MaD:7 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:19:15:19:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:8 |
+| test.go:11:15:11:41 | call to UserAgent | test.go:20:27:20:35 | untrusted | provenance | Src:MaD:22 Sink:MaD:9 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:28:12:28:20 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:29:10:29:18 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:30:15:30:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:13 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:31:14:31:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:15 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:32:15:32:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:18 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:33:8:33:16 | untrusted | provenance | Src:MaD:22 Sink:MaD:16 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:34:11:34:19 | untrusted | provenance | Src:MaD:22 Sink:MaD:20 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:35:9:35:17 | untrusted | provenance | Src:MaD:22 Sink:MaD:11 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:36:8:36:16 | untrusted | provenance | Src:MaD:22 Sink:MaD:17 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:37:8:37:16 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:38:13:38:21 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:39:13:39:21 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:40:12:40:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:12 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:41:12:41:20 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:42:9:42:17 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:43:12:43:20 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:44:16:44:24 | untrusted | provenance | Src:MaD:22 Sink:MaD:14 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:45:12:45:20 | untrusted | provenance | Src:MaD:22 |
+| test.go:25:15:25:41 | call to UserAgent | test.go:46:14:46:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:19 |
+| test.go:26:16:26:42 | call to UserAgent | test.go:44:27:44:36 | untrusted2 | provenance | Src:MaD:22 |
+| test.go:26:16:26:42 | call to UserAgent | test.go:46:25:46:34 | untrusted2 | provenance | Src:MaD:22 Sink:MaD:19 |
+| test.go:50:15:50:41 | call to UserAgent | test.go:52:12:52:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:10 |
+| test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | provenance | Src:MaD:22 Sink:MaD:21 |
+| test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | provenance | Src:MaD:22 Sink:MaD:1 |
models
-| 1 | Source: net/http; Request; true; UserAgent; ; ; ReturnValue; remote; manual |
+| 1 | Sink: group:beego-orm; Condition; true; Raw; ; ; Argument[1]; sql-injection; manual |
+| 2 | Sink: group:beego-orm; DB; true; Exec; ; ; Argument[0]; sql-injection; manual |
+| 3 | Sink: group:beego-orm; DB; true; ExecContext; ; ; Argument[1]; sql-injection; manual |
+| 4 | Sink: group:beego-orm; DB; true; Prepare; ; ; Argument[0]; sql-injection; manual |
+| 5 | Sink: group:beego-orm; DB; true; PrepareContext; ; ; Argument[1]; sql-injection; manual |
+| 6 | Sink: group:beego-orm; DB; true; Query; ; ; Argument[0]; sql-injection; manual |
+| 7 | Sink: group:beego-orm; DB; true; QueryContext; ; ; Argument[1]; sql-injection; manual |
+| 8 | Sink: group:beego-orm; DB; true; QueryRow; ; ; Argument[0]; sql-injection; manual |
+| 9 | Sink: group:beego-orm; DB; true; QueryRowContext; ; ; Argument[1]; sql-injection; manual |
+| 10 | Sink: group:beego-orm; Ormer; true; Raw; ; ; Argument[0]; sql-injection; manual |
+| 11 | Sink: group:beego-orm; QueryBuilder; true; And; ; ; Argument[0]; sql-injection; manual |
+| 12 | Sink: group:beego-orm; QueryBuilder; true; Having; ; ; Argument[0]; sql-injection; manual |
+| 13 | Sink: group:beego-orm; QueryBuilder; true; InnerJoin; ; ; Argument[0]; sql-injection; manual |
+| 14 | Sink: group:beego-orm; QueryBuilder; true; InsertInto; ; ; Argument[0..1]; sql-injection; manual |
+| 15 | Sink: group:beego-orm; QueryBuilder; true; LeftJoin; ; ; Argument[0]; sql-injection; manual |
+| 16 | Sink: group:beego-orm; QueryBuilder; true; On; ; ; Argument[0]; sql-injection; manual |
+| 17 | Sink: group:beego-orm; QueryBuilder; true; Or; ; ; Argument[0]; sql-injection; manual |
+| 18 | Sink: group:beego-orm; QueryBuilder; true; RightJoin; ; ; Argument[0]; sql-injection; manual |
+| 19 | Sink: group:beego-orm; QueryBuilder; true; Subquery; ; ; Argument[0..1]; sql-injection; manual |
+| 20 | Sink: group:beego-orm; QueryBuilder; true; Where; ; ; Argument[0]; sql-injection; manual |
+| 21 | Sink: group:beego-orm; QuerySeter; true; FilterRaw; ; ; Argument[1]; sql-injection; manual |
+| 22 | Source: net/http; Request; true; UserAgent; ; ; ReturnValue; remote; manual |
nodes
| test.go:11:15:11:41 | call to UserAgent | semmle.label | call to UserAgent |
| test.go:13:11:13:19 | untrusted | semmle.label | untrusted |
diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected
similarity index 57%
rename from java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected
rename to go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected
index 8ec8033d086..db33d6d2504 100644
--- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected
@@ -1,2 +1,3 @@
testFailures
+invalidModelRow
failures
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql
new file mode 100644
index 00000000000..eeb43a82fad
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql
@@ -0,0 +1,60 @@
+import go
+import semmle.go.dataflow.ExternalFlow
+import ModelValidation
+import TestUtilities.InlineExpectationsTest
+
+module SqlTest implements TestSig {
+ string getARelevantTag() { result = "query" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "query" and
+ exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
+ q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ element = q.toString() and
+ value = qs.toString()
+ )
+ }
+}
+
+module QueryString implements TestSig {
+ string getARelevantTag() { result = "querystring" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "querystring" and
+ element = "" and
+ exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
+ qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ value = qs.toString()
+ )
+ }
+}
+
+module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
+
+ predicate isSink(DataFlow::Node n) {
+ n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
+ }
+}
+
+module Flow = TaintTracking::Global;
+
+module TaintFlow implements TestSig {
+ string getARelevantTag() { result = "flowfrom" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "flowfrom" and
+ element = "" and
+ exists(DataFlow::Node fromNode, DataFlow::Node toNode |
+ toNode
+ .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ Flow::flow(fromNode, toNode) and
+ value = fromNode.asExpr().(StringLit).getValue()
+ )
+ }
+}
+
+import MakeTest>
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected
deleted file mode 100644
index ca70ed07c33..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected
+++ /dev/null
@@ -1,25 +0,0 @@
-| gorm.go:20:12:20:20 | untrusted | github.com/jinzhu/gorm | DB | Where |
-| gorm.go:21:10:21:18 | untrusted | github.com/jinzhu/gorm | DB | Raw |
-| gorm.go:22:10:22:18 | untrusted | github.com/jinzhu/gorm | DB | Not |
-| gorm.go:23:12:23:20 | untrusted | github.com/jinzhu/gorm | DB | Order |
-| gorm.go:24:9:24:17 | untrusted | github.com/jinzhu/gorm | DB | Or |
-| gorm.go:25:13:25:21 | untrusted | github.com/jinzhu/gorm | DB | Select |
-| gorm.go:26:12:26:20 | untrusted | github.com/jinzhu/gorm | DB | Table |
-| gorm.go:27:12:27:20 | untrusted | github.com/jinzhu/gorm | DB | Group |
-| gorm.go:28:13:28:21 | untrusted | github.com/jinzhu/gorm | DB | Having |
-| gorm.go:29:12:29:20 | untrusted | github.com/jinzhu/gorm | DB | Joins |
-| gorm.go:30:11:30:19 | untrusted | github.com/jinzhu/gorm | DB | Exec |
-| gorm.go:31:12:31:20 | untrusted | github.com/jinzhu/gorm | DB | Pluck |
-| gorm.go:34:12:34:20 | untrusted | gorm.io/gorm | DB | Where |
-| gorm.go:35:10:35:18 | untrusted | gorm.io/gorm | DB | Raw |
-| gorm.go:36:10:36:18 | untrusted | gorm.io/gorm | DB | Not |
-| gorm.go:37:12:37:20 | untrusted | gorm.io/gorm | DB | Order |
-| gorm.go:38:9:38:17 | untrusted | gorm.io/gorm | DB | Or |
-| gorm.go:39:13:39:21 | untrusted | gorm.io/gorm | DB | Select |
-| gorm.go:40:12:40:20 | untrusted | gorm.io/gorm | DB | Table |
-| gorm.go:41:12:41:20 | untrusted | gorm.io/gorm | DB | Group |
-| gorm.go:42:13:42:21 | untrusted | gorm.io/gorm | DB | Having |
-| gorm.go:43:12:43:20 | untrusted | gorm.io/gorm | DB | Joins |
-| gorm.go:44:11:44:19 | untrusted | gorm.io/gorm | DB | Exec |
-| gorm.go:45:15:45:23 | untrusted | gorm.io/gorm | DB | Distinct |
-| gorm.go:46:12:46:20 | untrusted | gorm.io/gorm | DB | Pluck |
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go
index bee8edbf7af..2d736e2407c 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go
@@ -13,36 +13,35 @@ func getUntrustedString() string {
}
func main() {
-
untrusted := getUntrustedString()
db1 := gorm1.DB{}
- db1.Where(untrusted)
- db1.Raw(untrusted)
- db1.Not(untrusted)
- db1.Order(untrusted)
- db1.Or(untrusted)
- db1.Select(untrusted)
- db1.Table(untrusted)
- db1.Group(untrusted)
- db1.Having(untrusted)
- db1.Joins(untrusted)
- db1.Exec(untrusted)
- db1.Pluck(untrusted, nil)
+ db1.Where(untrusted) // $ querystring=untrusted
+ db1.Raw(untrusted) // $ querystring=untrusted
+ db1.Not(untrusted) // $ querystring=untrusted
+ db1.Order(untrusted) // $ querystring=untrusted
+ db1.Or(untrusted) // $ querystring=untrusted
+ db1.Select(untrusted) // $ querystring=untrusted
+ db1.Table(untrusted) // $ querystring=untrusted
+ db1.Group(untrusted) // $ querystring=untrusted
+ db1.Having(untrusted) // $ querystring=untrusted
+ db1.Joins(untrusted) // $ querystring=untrusted
+ db1.Exec(untrusted) // $ querystring=untrusted
+ db1.Pluck(untrusted, nil) // $ querystring=untrusted
db2 := gorm2.DB{}
- db2.Where(untrusted)
- db2.Raw(untrusted)
- db2.Not(untrusted)
- db2.Order(untrusted)
- db2.Or(untrusted)
- db2.Select(untrusted)
- db2.Table(untrusted)
- db2.Group(untrusted)
- db2.Having(untrusted)
- db2.Joins(untrusted)
- db2.Exec(untrusted)
- db2.Distinct(untrusted)
- db2.Pluck(untrusted, nil)
+ db2.Where(untrusted) // $ querystring=untrusted
+ db2.Raw(untrusted) // $ querystring=untrusted
+ db2.Not(untrusted) // $ querystring=untrusted
+ db2.Order(untrusted) // $ querystring=untrusted
+ db2.Or(untrusted) // $ querystring=untrusted
+ db2.Select(untrusted) // $ querystring=untrusted
+ db2.Table(untrusted) // $ querystring=untrusted
+ db2.Group(untrusted) // $ querystring=untrusted
+ db2.Having(untrusted) // $ querystring=untrusted
+ db2.Joins(untrusted) // $ querystring=untrusted
+ db2.Exec(untrusted) // $ querystring=untrusted
+ db2.Distinct(untrusted) // $ querystring=untrusted
+ db2.Pluck(untrusted, nil) // $ querystring=untrusted
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql
deleted file mode 100644
index e08b506deaf..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql
+++ /dev/null
@@ -1,5 +0,0 @@
-import go
-
-from SQL::QueryString qs, Method meth, string a, string b, string c
-where meth.hasQualifiedName(a, b, c) and qs = meth.getACall().getSyntacticArgument(0)
-select qs, a, b, c
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected
similarity index 57%
rename from java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected
rename to go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected
index 8ec8033d086..db33d6d2504 100644
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected
@@ -1,2 +1,3 @@
testFailures
+invalidModelRow
failures
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql
new file mode 100644
index 00000000000..eeb43a82fad
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql
@@ -0,0 +1,60 @@
+import go
+import semmle.go.dataflow.ExternalFlow
+import ModelValidation
+import TestUtilities.InlineExpectationsTest
+
+module SqlTest implements TestSig {
+ string getARelevantTag() { result = "query" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "query" and
+ exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
+ q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ element = q.toString() and
+ value = qs.toString()
+ )
+ }
+}
+
+module QueryString implements TestSig {
+ string getARelevantTag() { result = "querystring" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "querystring" and
+ element = "" and
+ exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
+ qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ value = qs.toString()
+ )
+ }
+}
+
+module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
+
+ predicate isSink(DataFlow::Node n) {
+ n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
+ }
+}
+
+module Flow = TaintTracking::Global;
+
+module TaintFlow implements TestSig {
+ string getARelevantTag() { result = "flowfrom" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "flowfrom" and
+ element = "" and
+ exists(DataFlow::Node fromNode, DataFlow::Node toNode |
+ toNode
+ .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ Flow::flow(fromNode, toNode) and
+ value = fromNode.asExpr().(StringLit).getValue()
+ )
+ }
+}
+
+import MakeTest>
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected
deleted file mode 100644
index 0540a78fb34..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected
+++ /dev/null
@@ -1,12 +0,0 @@
-| sqlx.go:15:17:15:25 | untrusted |
-| sqlx.go:16:14:16:22 | untrusted |
-| sqlx.go:17:14:17:22 | untrusted |
-| sqlx.go:18:12:18:20 | untrusted |
-| sqlx.go:19:15:19:23 | untrusted |
-| sqlx.go:20:16:20:24 | untrusted |
-| sqlx.go:23:17:23:25 | untrusted |
-| sqlx.go:24:14:24:22 | untrusted |
-| sqlx.go:25:14:25:22 | untrusted |
-| sqlx.go:26:12:26:20 | untrusted |
-| sqlx.go:27:15:27:23 | untrusted |
-| sqlx.go:28:16:28:24 | untrusted |
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go
index edc29c4d4ee..e4e8d43395b 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go
@@ -12,19 +12,19 @@ func main() {
db := sqlx.DB{}
untrusted := getUntrustedString()
- db.Select(nil, untrusted)
- db.Get(nil, untrusted)
- db.MustExec(untrusted)
- db.Queryx(untrusted)
- db.NamedExec(untrusted, nil)
- db.NamedQuery(untrusted, nil)
+ db.Select(nil, untrusted) // $ querystring=untrusted
+ db.Get(nil, untrusted) // $ querystring=untrusted
+ db.MustExec(untrusted) // $ querystring=untrusted
+ db.Queryx(untrusted) // $ querystring=untrusted
+ db.NamedExec(untrusted, nil) // $ querystring=untrusted
+ db.NamedQuery(untrusted, nil) // $ querystring=untrusted
tx := sqlx.Tx{}
- tx.Select(nil, untrusted)
- tx.Get(nil, untrusted)
- tx.MustExec(untrusted)
- tx.Queryx(untrusted)
- tx.NamedExec(untrusted, nil)
- tx.NamedQuery(untrusted, nil)
+ tx.Select(nil, untrusted) // $ querystring=untrusted
+ tx.Get(nil, untrusted) // $ querystring=untrusted
+ tx.MustExec(untrusted) // $ querystring=untrusted
+ tx.Queryx(untrusted) // $ querystring=untrusted
+ tx.NamedExec(untrusted, nil) // $ querystring=untrusted
+ tx.NamedQuery(untrusted, nil) // $ querystring=untrusted
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql
deleted file mode 100644
index 7b56fd97441..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql
+++ /dev/null
@@ -1,4 +0,0 @@
-import go
-
-from SQL::QueryString qs
-select qs
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected
new file mode 100644
index 00000000000..105b7026d0c
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected
@@ -0,0 +1,3 @@
+failures
+invalidModelRow
+testFailures
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql
new file mode 100644
index 00000000000..eeb43a82fad
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql
@@ -0,0 +1,60 @@
+import go
+import semmle.go.dataflow.ExternalFlow
+import ModelValidation
+import TestUtilities.InlineExpectationsTest
+
+module SqlTest implements TestSig {
+ string getARelevantTag() { result = "query" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "query" and
+ exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
+ q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ element = q.toString() and
+ value = qs.toString()
+ )
+ }
+}
+
+module QueryString implements TestSig {
+ string getARelevantTag() { result = "querystring" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "querystring" and
+ element = "" and
+ exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
+ qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ value = qs.toString()
+ )
+ }
+}
+
+module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
+
+ predicate isSink(DataFlow::Node n) {
+ n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
+ }
+}
+
+module Flow = TaintTracking::Global;
+
+module TaintFlow implements TestSig {
+ string getARelevantTag() { result = "flowfrom" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "flowfrom" and
+ element = "" and
+ exists(DataFlow::Node fromNode, DataFlow::Node toNode |
+ toNode
+ .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ Flow::flow(fromNode, toNode) and
+ value = fromNode.asExpr().(StringLit).getValue()
+ )
+ }
+}
+
+import MakeTest>
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go
index 8ce4e5b0826..44a2e2c2fce 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go
@@ -22,28 +22,28 @@ func main() {
panic(err)
}
db := bun.NewDB(sqlite, sqlitedialect.New())
- bun.NewRawQuery(db, untrusted)
+ bun.NewRawQuery(db, untrusted) // $ querystring=untrusted
- db.ExecContext(ctx, untrusted)
- db.PrepareContext(ctx, untrusted)
- db.QueryContext(ctx, untrusted)
- db.QueryRowContext(ctx, untrusted)
+ db.ExecContext(ctx, untrusted) // $ querystring=untrusted
+ db.PrepareContext(ctx, untrusted) // $ querystring=untrusted
+ db.QueryContext(ctx, untrusted) // $ querystring=untrusted
+ db.QueryRowContext(ctx, untrusted) // $ querystring=untrusted
- db.Exec(untrusted)
- db.NewRaw(untrusted)
- db.Prepare(untrusted)
- db.Query(untrusted)
- db.QueryRow(untrusted)
- db.Raw(untrusted)
+ db.Exec(untrusted) // $ querystring=untrusted
+ db.NewRaw(untrusted) // $ querystring=untrusted
+ db.Prepare(untrusted) // $ querystring=untrusted
+ db.Query(untrusted) // $ querystring=untrusted
+ db.QueryRow(untrusted) // $ querystring=untrusted
+ db.Raw(untrusted) // $ querystring=untrusted
- db.NewSelect().ColumnExpr(untrusted)
- db.NewSelect().DistinctOn(untrusted)
- db.NewSelect().For(untrusted)
- db.NewSelect().GroupExpr(untrusted)
- db.NewSelect().Having(untrusted)
- db.NewSelect().ModelTableExpr(untrusted)
- db.NewSelect().OrderExpr(untrusted)
- db.NewSelect().TableExpr(untrusted)
- db.NewSelect().Where(untrusted)
- db.NewSelect().WhereOr(untrusted)
+ db.NewSelect().ColumnExpr(untrusted) // $ querystring=untrusted
+ db.NewSelect().DistinctOn(untrusted) // $ querystring=untrusted
+ db.NewSelect().For(untrusted) // $ querystring=untrusted
+ db.NewSelect().GroupExpr(untrusted) // $ querystring=untrusted
+ db.NewSelect().Having(untrusted) // $ querystring=untrusted
+ db.NewSelect().ModelTableExpr(untrusted) // $ querystring=untrusted
+ db.NewSelect().OrderExpr(untrusted) // $ querystring=untrusted
+ db.NewSelect().TableExpr(untrusted) // $ querystring=untrusted
+ db.NewSelect().Where(untrusted) // $ querystring=untrusted
+ db.NewSelect().WhereOr(untrusted) // $ querystring=untrusted
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected
new file mode 100644
index 00000000000..db33d6d2504
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected
@@ -0,0 +1,3 @@
+testFailures
+invalidModelRow
+failures
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql
new file mode 100644
index 00000000000..eeb43a82fad
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql
@@ -0,0 +1,60 @@
+import go
+import semmle.go.dataflow.ExternalFlow
+import ModelValidation
+import TestUtilities.InlineExpectationsTest
+
+module SqlTest implements TestSig {
+ string getARelevantTag() { result = "query" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "query" and
+ exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
+ q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ element = q.toString() and
+ value = qs.toString()
+ )
+ }
+}
+
+module QueryString implements TestSig {
+ string getARelevantTag() { result = "querystring" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "querystring" and
+ element = "" and
+ exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
+ qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ value = qs.toString()
+ )
+ }
+}
+
+module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
+
+ predicate isSink(DataFlow::Node n) {
+ n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
+ }
+}
+
+module Flow = TaintTracking::Global;
+
+module TaintFlow implements TestSig {
+ string getARelevantTag() { result = "flowfrom" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "flowfrom" and
+ element = "" and
+ exists(DataFlow::Node fromNode, DataFlow::Node toNode |
+ toNode
+ .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ Flow::flow(fromNode, toNode) and
+ value = fromNode.asExpr().(StringLit).getValue()
+ )
+ }
+}
+
+import MakeTest>
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected
deleted file mode 100644
index f4e3e4f15b0..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected
+++ /dev/null
@@ -1,47 +0,0 @@
-| gogf.go:12:9:12:11 | sql |
-| gogf.go:13:11:13:13 | sql |
-| gogf.go:14:13:14:15 | sql |
-| gogf.go:15:13:15:15 | sql |
-| gogf.go:16:11:16:13 | sql |
-| gogf.go:17:13:17:15 | sql |
-| gogf.go:18:12:18:14 | sql |
-| gogf.go:19:10:19:12 | sql |
-| gogf.go:20:8:20:10 | sql |
-| gogf.go:21:17:21:19 | sql |
-| gogf.go:22:19:22:21 | sql |
-| gogf.go:23:20:23:22 | sql |
-| gogf.go:24:23:24:25 | sql |
-| gogf.go:25:21:25:23 | sql |
-| gogf.go:26:23:26:25 | sql |
-| gogf.go:27:22:27:24 | sql |
-| gogf.go:28:24:28:26 | sql |
-| gogf.go:32:9:32:11 | sql |
-| gogf.go:33:11:33:13 | sql |
-| gogf.go:34:13:34:15 | sql |
-| gogf.go:35:13:35:15 | sql |
-| gogf.go:36:11:36:13 | sql |
-| gogf.go:37:13:37:15 | sql |
-| gogf.go:38:12:38:14 | sql |
-| gogf.go:39:10:39:12 | sql |
-| gogf.go:40:8:40:10 | sql |
-| gogf.go:41:17:41:19 | sql |
-| gogf.go:42:23:42:25 | sql |
-| gogf.go:43:21:43:23 | sql |
-| gogf.go:44:23:44:25 | sql |
-| gogf.go:45:22:45:24 | sql |
-| gogf.go:46:24:46:26 | sql |
-| gogf.go:51:9:51:11 | sql |
-| gogf.go:52:11:52:13 | sql |
-| gogf.go:53:13:53:15 | sql |
-| gogf.go:54:13:54:15 | sql |
-| gogf.go:55:11:55:13 | sql |
-| gogf.go:56:13:56:15 | sql |
-| gogf.go:57:12:57:14 | sql |
-| gogf.go:58:10:58:12 | sql |
-| gogf.go:59:8:59:10 | sql |
-| gogf.go:60:17:60:19 | sql |
-| gogf.go:61:23:61:25 | sql |
-| gogf.go:62:21:62:23 | sql |
-| gogf.go:63:23:63:25 | sql |
-| gogf.go:64:22:64:24 | sql |
-| gogf.go:65:24:65:26 | sql |
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go
index d0eceaf862c..e2db8016cf0 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go
@@ -4,11 +4,13 @@ package main
//go:generate depstubber -vendor github.com/gogf/gf/database/gdb DB,Core,TX ""
import (
+ "context"
+
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/frame/g"
)
-func gogfCoreTest(sql string, c *gdb.Core) {
+func gogfCoreTest(sql string, c *gdb.Core, ctx context.Context) {
c.Exec(sql, nil) // $ querystring=sql
c.GetAll(sql, nil) // $ querystring=sql
c.GetArray(sql, nil) // $ querystring=sql
@@ -21,14 +23,14 @@ func gogfCoreTest(sql string, c *gdb.Core) {
c.GetScan(nil, sql, nil) // $ querystring=sql
c.GetStruct(nil, sql, nil) // $ querystring=sql
c.GetStructs(nil, sql, nil) // $ querystring=sql
- c.DoCommit(nil, nil, sql, nil) // $ querystring=sql
- c.DoExec(nil, nil, sql, nil) // $ querystring=sql
- c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql
- c.DoQuery(nil, nil, sql, nil) // $ querystring=sql
- c.DoPrepare(nil, nil, sql) // $ querystring=sql
+ c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoExec(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoPrepare(ctx, nil, sql) // $ querystring=sql
}
-func gogfDbtest(sql string, c gdb.DB) {
+func gogfDbtest(sql string, c gdb.DB, ctx context.Context) {
c.Exec(sql, nil) // $ querystring=sql
c.GetAll(sql, nil) // $ querystring=sql
c.GetArray(sql, nil) // $ querystring=sql
@@ -39,14 +41,14 @@ func gogfDbtest(sql string, c gdb.DB) {
c.Query(sql, nil) // $ querystring=sql
c.Raw(sql, nil) // $ querystring=sql
c.GetScan(nil, sql, nil) // $ querystring=sql
- c.DoCommit(nil, nil, sql, nil) // $ querystring=sql
- c.DoExec(nil, nil, sql, nil) // $ querystring=sql
- c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql
- c.DoQuery(nil, nil, sql, nil) // $ querystring=sql
- c.DoPrepare(nil, nil, sql) // $ querystring=sql
+ c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoExec(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoPrepare(ctx, nil, sql) // $ querystring=sql
}
-func gogfGTest(sql string) {
+func gogfGTest(sql string, ctx context.Context) {
c := g.DB("ad")
c.Exec(sql, nil) // $ querystring=sql
c.GetAll(sql, nil) // $ querystring=sql
@@ -58,11 +60,11 @@ func gogfGTest(sql string) {
c.Query(sql, nil) // $ querystring=sql
c.Raw(sql, nil) // $ querystring=sql
c.GetScan(nil, sql, nil) // $ querystring=sql
- c.DoCommit(nil, nil, sql, nil) // $ querystring=sql
- c.DoExec(nil, nil, sql, nil) // $ querystring=sql
- c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql
- c.DoQuery(nil, nil, sql, nil) // $ querystring=sql
- c.DoPrepare(nil, nil, sql) // $ querystring=sql
+ c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoExec(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql
+ c.DoPrepare(ctx, nil, sql) // $ querystring=sql
}
func main() {
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql
deleted file mode 100644
index 7b56fd97441..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql
+++ /dev/null
@@ -1,4 +0,0 @@
-import go
-
-from SQL::QueryString qs
-select qs
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected
new file mode 100644
index 00000000000..db33d6d2504
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected
@@ -0,0 +1,3 @@
+testFailures
+invalidModelRow
+failures
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql
new file mode 100644
index 00000000000..eeb43a82fad
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql
@@ -0,0 +1,60 @@
+import go
+import semmle.go.dataflow.ExternalFlow
+import ModelValidation
+import TestUtilities.InlineExpectationsTest
+
+module SqlTest implements TestSig {
+ string getARelevantTag() { result = "query" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "query" and
+ exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
+ q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ element = q.toString() and
+ value = qs.toString()
+ )
+ }
+}
+
+module QueryString implements TestSig {
+ string getARelevantTag() { result = "querystring" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "querystring" and
+ element = "" and
+ exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
+ qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ value = qs.toString()
+ )
+ }
+}
+
+module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
+
+ predicate isSink(DataFlow::Node n) {
+ n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
+ }
+}
+
+module Flow = TaintTracking::Global;
+
+module TaintFlow implements TestSig {
+ string getARelevantTag() { result = "flowfrom" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "flowfrom" and
+ element = "" and
+ exists(DataFlow::Node fromNode, DataFlow::Node toNode |
+ toNode
+ .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
+ location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
+ Flow::flow(fromNode, toNode) and
+ value = fromNode.asExpr().(StringLit).getValue()
+ )
+ }
+}
+
+import MakeTest>
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod
index 1f243775658..826ed0eb1c0 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod
@@ -2,4 +2,4 @@ module main
go 1.18
-require github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6
+require github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected
deleted file mode 100644
index cbd8166ea5e..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected
+++ /dev/null
@@ -1,6 +0,0 @@
-| gorqlite.go:11:13:11:16 | sqls |
-| gorqlite.go:12:13:12:16 | sqls |
-| gorqlite.go:13:13:13:16 | sqls |
-| gorqlite.go:14:16:14:18 | sql |
-| gorqlite.go:15:16:15:18 | sql |
-| gorqlite.go:16:16:16:18 | sql |
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go
index 9b60c6684e6..ebd6e5fd9f3 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go
@@ -1,20 +1,49 @@
package main
-//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection Open
+//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection,ParameterizedStatement Open
import (
+ "context"
+
"github.com/rqlite/gorqlite"
)
-func gorqlitetest(sql string, sqls []string) {
+func gorqlitetest(sql string, sqls []string, param_sql gorqlite.ParameterizedStatement, param_sqls []gorqlite.ParameterizedStatement, ctx context.Context) {
conn, _ := gorqlite.Open("dbUrl")
- conn.Query(sqls) // $ querystring=sqls
- conn.Queue(sqls) // $ querystring=sqls
- conn.Write(sqls) // $ querystring=sqls
+
+ conn.Query(sqls) // $ querystring=sqls
+ conn.Queue(sqls) // $ querystring=sqls
+ conn.Write(sqls) // $ querystring=sqls
+
conn.QueryOne(sql) // $ querystring=sql
conn.QueueOne(sql) // $ querystring=sql
conn.WriteOne(sql) // $ querystring=sql
+
+ conn.QueryParameterized(param_sqls) // $ querystring=param_sqls
+ conn.QueueParameterized(param_sqls) // $ querystring=param_sqls
+ conn.WriteParameterized(param_sqls) // $ querystring=param_sqls
+
+ conn.QueryOneParameterized(param_sql) // $ querystring=param_sql
+ conn.QueueOneParameterized(param_sql) // $ querystring=param_sql
+ conn.WriteOneParameterized(param_sql) // $ querystring=param_sql
+
+ conn.QueryContext(ctx, sqls) // $ querystring=sqls
+ conn.QueueContext(ctx, sqls) // $ querystring=sqls
+ conn.WriteContext(ctx, sqls) // $ querystring=sqls
+
+ conn.QueryOneContext(ctx, sql) // $ querystring=sql
+ conn.QueueOneContext(ctx, sql) // $ querystring=sql
+ conn.WriteOneContext(ctx, sql) // $ querystring=sql
+
+ conn.QueryParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
+ conn.QueueParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
+ conn.WriteParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls
+
+ conn.QueryOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
+ conn.QueueOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
+ conn.WriteOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql
}
+
func main() {
return
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql
deleted file mode 100644
index 7b56fd97441..00000000000
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql
+++ /dev/null
@@ -1,4 +0,0 @@
-import go
-
-from SQL::QueryString qs
-select qs
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go
index f6f4ca18ec1..0572097582e 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go
@@ -2,11 +2,15 @@
// This is a simple stub for github.com/rqlite/gorqlite, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/rqlite/gorqlite (exports: Connection; functions: Open)
+// Source: github.com/rqlite/gorqlite (exports: Connection,ParameterizedStatement; functions: Open)
// Package gorqlite is a stub of github.com/rqlite/gorqlite, generated by depstubber.
package gorqlite
+import (
+ context "context"
+)
+
type Connection struct {
ID string
}
@@ -29,19 +33,83 @@ func (_ *Connection) Query(_ []string) ([]QueryResult, error) {
return nil, nil
}
+func (_ *Connection) QueryContext(_ context.Context, _ []string) ([]QueryResult, error) {
+ return nil, nil
+}
+
func (_ *Connection) QueryOne(_ string) (QueryResult, error) {
return QueryResult{}, nil
}
+func (_ *Connection) QueryOneContext(_ context.Context, _ string) (QueryResult, error) {
+ return QueryResult{}, nil
+}
+
+func (_ *Connection) QueryOneParameterized(_ ParameterizedStatement) (QueryResult, error) {
+ return QueryResult{}, nil
+}
+
+func (_ *Connection) QueryOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (QueryResult, error) {
+ return QueryResult{}, nil
+}
+
+func (_ *Connection) QueryParameterized(_ []ParameterizedStatement) ([]QueryResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) QueryParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]QueryResult, error) {
+ return nil, nil
+}
+
func (_ *Connection) Queue(_ []string) (int64, error) {
return 0, nil
}
+func (_ *Connection) QueueContext(_ context.Context, _ []string) (int64, error) {
+ return 0, nil
+}
+
func (_ *Connection) QueueOne(_ string) (int64, error) {
return 0, nil
}
-func (_ *Connection) SetConsistencyLevel(_ string) error {
+func (_ *Connection) QueueOneContext(_ context.Context, _ string) (int64, error) {
+ return 0, nil
+}
+
+func (_ *Connection) QueueOneParameterized(_ ParameterizedStatement) (int64, error) {
+ return 0, nil
+}
+
+func (_ *Connection) QueueOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (int64, error) {
+ return 0, nil
+}
+
+func (_ *Connection) QueueParameterized(_ []ParameterizedStatement) (int64, error) {
+ return 0, nil
+}
+
+func (_ *Connection) QueueParameterizedContext(_ context.Context, _ []ParameterizedStatement) (int64, error) {
+ return 0, nil
+}
+
+func (_ *Connection) Request(_ []string) ([]RequestResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) RequestContext(_ context.Context, _ []string) ([]RequestResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) RequestParameterized(_ []ParameterizedStatement) ([]RequestResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) RequestParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]RequestResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) SetConsistencyLevel(_ interface{}) error {
return nil
}
@@ -53,12 +121,41 @@ func (_ *Connection) Write(_ []string) ([]WriteResult, error) {
return nil, nil
}
+func (_ *Connection) WriteContext(_ context.Context, _ []string) ([]WriteResult, error) {
+ return nil, nil
+}
+
func (_ *Connection) WriteOne(_ string) (WriteResult, error) {
return WriteResult{}, nil
}
-func Open(_ string) (Connection, error) {
- return Connection{}, nil
+func (_ *Connection) WriteOneContext(_ context.Context, _ string) (WriteResult, error) {
+ return WriteResult{}, nil
+}
+
+func (_ *Connection) WriteOneParameterized(_ ParameterizedStatement) (WriteResult, error) {
+ return WriteResult{}, nil
+}
+
+func (_ *Connection) WriteOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (WriteResult, error) {
+ return WriteResult{}, nil
+}
+
+func (_ *Connection) WriteParameterized(_ []ParameterizedStatement) ([]WriteResult, error) {
+ return nil, nil
+}
+
+func (_ *Connection) WriteParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]WriteResult, error) {
+ return nil, nil
+}
+
+func Open(_ string) (*Connection, error) {
+ return nil, nil
+}
+
+type ParameterizedStatement struct {
+ Query string
+ Arguments []interface{}
}
type QueryResult struct {
@@ -90,10 +187,20 @@ func (_ *QueryResult) Scan(_ ...interface{}) error {
return nil
}
+func (_ *QueryResult) Slice() ([]interface{}, error) {
+ return nil, nil
+}
+
func (_ *QueryResult) Types() []string {
return nil
}
+type RequestResult struct {
+ Err error
+ Query *QueryResult
+ Write *WriteResult
+}
+
type WriteResult struct {
Err error
Timing float64
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt
index f5e5b9989ed..dafb7c6d1a9 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt
@@ -1,3 +1,3 @@
-# github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6
+# github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19
## explicit
github.com/rqlite/gorqlite
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go
index 15b687c7ad1..d0350643bb0 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go
@@ -1,6 +1,6 @@
package main
-//go:generate depstubber -vendor github.com/Masterminds/squirrel DeleteBuilder,InsertBuilder,SelectBuilder,UpdateBuilder Delete,Expr,Insert,Select,Update
+//go:generate depstubber -vendor github.com/Masterminds/squirrel DeleteBuilder,Eq,InsertBuilder,SelectBuilder,UpdateBuilder Delete,Expr,Insert,Select,Update
import (
"github.com/Masterminds/squirrel"
@@ -10,38 +10,44 @@ func squirrelTest(querypart string) {
squirrel.Expr(querypart) // $ querystring=querypart
deleteBuilder := squirrel.Delete(querypart) // $ querystring=querypart
deleteBuilder.From(querypart) // $ querystring=querypart
- deleteBuilder.OrderBy(querypart) // $ querystring=[]type{args}
+ deleteBuilder.OrderBy(querypart) // $ querystring=querypart
deleteBuilder.Prefix(querypart) // $ querystring=querypart
deleteBuilder.Suffix(querypart) // $ querystring=querypart
deleteBuilder.Where(querypart) // $ querystring=querypart
insertBuilder := squirrel.Insert(querypart) // $ querystring=querypart
- insertBuilder.Columns(querypart) // $ querystring=[]type{args}
- insertBuilder.Options(querypart) // $ querystring=[]type{args}
+ insertBuilder.Columns(querypart) // $ querystring=querypart
+ insertBuilder.Options(querypart) // $ querystring=querypart
insertBuilder.Prefix(querypart) // $ querystring=querypart
insertBuilder.Suffix(querypart) // $ querystring=querypart
insertBuilder.Into(querypart) // $ querystring=querypart
- selectBuilder := squirrel.Select(querypart) // $ querystring=[]type{args}
- selectBuilder.Columns(querypart) // $ querystring=[]type{args}
+ selectBuilder := squirrel.Select(querypart) // $ querystring=querypart
+ selectBuilder.Columns(querypart) // $ querystring=querypart
selectBuilder.From(querypart) // $ querystring=querypart
- selectBuilder.Options(querypart) // $ querystring=[]type{args}
- selectBuilder.OrderBy(querypart) // $ querystring=[]type{args}
+ selectBuilder.Options(querypart) // $ querystring=querypart
+ selectBuilder.OrderBy(querypart) // $ querystring=querypart
selectBuilder.Prefix(querypart) // $ querystring=querypart
selectBuilder.Suffix(querypart) // $ querystring=querypart
selectBuilder.Where(querypart) // $ querystring=querypart
selectBuilder.CrossJoin(querypart) // $ querystring=querypart
- selectBuilder.GroupBy(querypart) // $ querystring=[]type{args}
+ selectBuilder.GroupBy(querypart) // $ querystring=querypart
selectBuilder.InnerJoin(querypart) // $ querystring=querypart
selectBuilder.LeftJoin(querypart) // $ querystring=querypart
selectBuilder.RightJoin(querypart) // $ querystring=querypart
updateBuilder := squirrel.Update(querypart) // $ querystring=querypart
updateBuilder.From(querypart) // $ querystring=querypart
- updateBuilder.OrderBy(querypart) // $ querystring=[]type{args}
+ updateBuilder.OrderBy(querypart) // $ querystring=querypart
updateBuilder.Prefix(querypart) // $ querystring=querypart
updateBuilder.Suffix(querypart) // $ querystring=querypart
updateBuilder.Where(querypart) // $ querystring=querypart
updateBuilder.Set(querypart, "") // $ querystring=querypart
updateBuilder.Table(querypart) // $ querystring=querypart
+
+ // safe
+ wrapped := squirrel.Eq{"id": querypart}
+ deleteBuilder.Where(wrapped)
+ selectBuilder.Where(wrapped)
+ updateBuilder.Where(wrapped)
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go
index 96a30e49d4e..1a9e5ca0e9b 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go
@@ -2,7 +2,7 @@
// This is a simple stub for github.com/Masterminds/squirrel, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/Masterminds/squirrel (exports: DeleteBuilder,InsertBuilder,SelectBuilder,UpdateBuilder; functions: Delete,Expr,Insert,Select,Update)
+// Source: github.com/Masterminds/squirrel (exports: DeleteBuilder,Eq,InsertBuilder,SelectBuilder,UpdateBuilder; functions: Delete,Expr,Insert,Select,Update)
// Package squirrel is a stub of github.com/Masterminds/squirrel, generated by depstubber.
package squirrel
@@ -99,6 +99,12 @@ func (_ DeleteBuilder) Where(_ interface{}, _ ...interface{}) DeleteBuilder {
return DeleteBuilder{}
}
+type Eq map[string]interface{}
+
+func (_ Eq) ToSql() (string, []interface{}, error) {
+ return "", nil, nil
+}
+
func Expr(_ string, _ ...interface{}) Sqlizer {
return nil
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go
index 6b4dbb116ee..f63b33a0e09 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go
+++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go
@@ -10,68 +10,73 @@ import (
func xormtest() {
query := "UntrustedString"
+ arg := "arg"
engine1 := xorm1.Engine{}
- engine1.Query(query) // $ querystring=query
- engine1.QueryString(query) // $ querystring=query
- engine1.QueryInterface(query) // $ querystring=query
- engine1.SQL(query) // $ querystring=query
- engine1.Where(query) // $ querystring=query
- engine1.Alias(query) // $ querystring=query
- engine1.NotIn(query) // $ querystring=query
- engine1.In(query) // $ querystring=query
- engine1.Select(query) // $ querystring=query
- engine1.SetExpr(query, nil) // $ querystring=query
- engine1.OrderBy(query) // $ querystring=query
- engine1.Having(query) // $ querystring=query
- engine1.GroupBy(query) // $ querystring=query
+ engine1.Query(query, arg) // $ querystring=query
+ engine1.Exec(query, arg) // $ querystring=query
+ engine1.QueryString(query, arg) // $ querystring=query
+ engine1.QueryInterface(query, arg) // $ querystring=query
+ engine1.SQL(query) // $ querystring=query
+ engine1.Where(query) // $ querystring=query
+ engine1.Alias(query) // $ querystring=query
+ engine1.NotIn(query) // $ querystring=query
+ engine1.In(query) // $ querystring=query
+ engine1.Select(query) // $ querystring=query
+ engine1.SetExpr(query, nil) // $ querystring=query
+ engine1.OrderBy(query) // $ querystring=query
+ engine1.Having(query) // $ querystring=query
+ engine1.GroupBy(query) // $ querystring=query
engine2 := xorm2.Engine{}
- engine2.Query(query) // $ querystring=query
- engine2.QueryString(query) // $ querystring=query
- engine2.QueryInterface(query) // $ querystring=query
- engine2.SQL(query) // $ querystring=query
- engine2.Where(query) // $ querystring=query
- engine2.Alias(query) // $ querystring=query
- engine2.NotIn(query) // $ querystring=query
- engine2.In(query) // $ querystring=query
- engine2.Select(query) // $ querystring=query
- engine2.SetExpr(query, nil) // $ querystring=query
- engine2.OrderBy(query) // $ querystring=query
- engine2.Having(query) // $ querystring=query
- engine2.GroupBy(query) // $ querystring=query
+ engine2.Query(query, arg) // $ querystring=query
+ engine2.Exec(query, arg) // $ querystring=query
+ engine2.QueryString(query, arg) // $ querystring=query
+ engine2.QueryInterface(query, arg) // $ querystring=query
+ engine2.SQL(query) // $ querystring=query
+ engine2.Where(query) // $ querystring=query
+ engine2.Alias(query) // $ querystring=query
+ engine2.NotIn(query) // $ querystring=query
+ engine2.In(query) // $ querystring=query
+ engine2.Select(query) // $ querystring=query
+ engine2.SetExpr(query, nil) // $ querystring=query
+ engine2.OrderBy(query) // $ querystring=query
+ engine2.Having(query) // $ querystring=query
+ engine2.GroupBy(query) // $ querystring=query
session1 := xorm1.Session{}
- session1.Query(query) // $ querystring=query
- session1.QueryString(query) // $ querystring=query
- session1.QueryInterface(query) // $ querystring=query
- session1.SQL(query) // $ querystring=query
- session1.Where(query) // $ querystring=query
- session1.Alias(query) // $ querystring=query
- session1.NotIn(query) // $ querystring=query
- session1.In(query) // $ querystring=query
- session1.Select(query) // $ querystring=query
- session1.SetExpr(query, nil) // $ querystring=query
- session1.OrderBy(query) // $ querystring=query
- session1.Having(query) // $ querystring=query
- session1.GroupBy(query) // $ querystring=query
- session1.And(query) // $ querystring=query
- session1.Or(query) // $ querystring=query
+ session1.Query(query, arg) // $ querystring=query
+ session1.Exec(query, arg) // $ querystring=query
+ session1.QueryString(query, arg) // $ querystring=query
+ session1.QueryInterface(query, arg) // $ querystring=query
+ session1.SQL(query) // $ querystring=query
+ session1.Where(query) // $ querystring=query
+ session1.Alias(query) // $ querystring=query
+ session1.NotIn(query) // $ querystring=query
+ session1.In(query) // $ querystring=query
+ session1.Select(query) // $ querystring=query
+ session1.SetExpr(query, nil) // $ querystring=query
+ session1.OrderBy(query) // $ querystring=query
+ session1.Having(query) // $ querystring=query
+ session1.GroupBy(query) // $ querystring=query
+ session1.And(query) // $ querystring=query
+ session1.Or(query) // $ querystring=query
session2 := xorm2.Session{}
- session2.Query(query) // $ querystring=query
- session2.QueryString(query) // $ querystring=query
- session2.QueryInterface(query) // $ querystring=query
- session2.SQL(query) // $ querystring=query
- session2.Where(query) // $ querystring=query
- session2.Alias(query) // $ querystring=query
- session2.NotIn(query) // $ querystring=query
- session2.In(query) // $ querystring=query
- session2.Select(query) // $ querystring=query
- session2.SetExpr(query, nil) // $ querystring=query
- session2.OrderBy(query) // $ querystring=query
- session2.Having(query) // $ querystring=query
- session2.GroupBy(query) // $ querystring=query
- session2.And(query) // $ querystring=query
- session2.Or(query) // $ querystring=query
+ session2.Query(query, arg) // $ querystring=query
+ session2.Exec(query, arg) // $ querystring=query
+ session2.QueryString(query, arg) // $ querystring=query
+ session2.QueryInterface(query, arg) // $ querystring=query
+ session2.SQL(query) // $ querystring=query
+ session2.Where(query) // $ querystring=query
+ session2.Alias(query) // $ querystring=query
+ session2.NotIn(query) // $ querystring=query
+ session2.In(query) // $ querystring=query
+ session2.Select(query) // $ querystring=query
+ session2.SetExpr(query, nil) // $ querystring=query
+ session2.OrderBy(query) // $ querystring=query
+ session2.Having(query) // $ querystring=query
+ session2.GroupBy(query) // $ querystring=query
+ session2.And(query) // $ querystring=query
+ session2.Or(query) // $ querystring=query
}
diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected
index c28b1058e7c..8b2f05c297f 100644
--- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected
+++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected
@@ -1,11 +1,12 @@
#select
| test.go:57:11:57:41 | call to EscapeString | test.go:56:2:56:42 | ... := ...[0] | test.go:57:11:57:41 | call to EscapeString | This query depends on a $@. | test.go:56:2:56:42 | ... := ...[0] | user-provided value |
edges
-| test.go:56:2:56:42 | ... := ...[0] | test.go:57:29:57:40 | selection of Value | provenance | Src:MaD:1 |
-| test.go:57:29:57:40 | selection of Value | test.go:57:11:57:41 | call to EscapeString | provenance | MaD:2 |
+| test.go:56:2:56:42 | ... := ...[0] | test.go:57:29:57:40 | selection of Value | provenance | Src:MaD:2 |
+| test.go:57:29:57:40 | selection of Value | test.go:57:11:57:41 | call to EscapeString | provenance | MaD:3 Sink:MaD:1 |
models
-| 1 | Source: net/http; Request; true; Cookie; ; ; ReturnValue[0]; remote; manual |
-| 2 | Summary: golang.org/x/net/html; ; false; EscapeString; ; ; Argument[0]; ReturnValue; taint; manual |
+| 1 | Sink: database/sql; DB; true; Query; ; ; Argument[0]; sql-injection; manual |
+| 2 | Source: net/http; Request; true; Cookie; ; ; ReturnValue[0]; remote; manual |
+| 3 | Summary: golang.org/x/net/html; ; false; EscapeString; ; ; Argument[0]; ReturnValue; taint; manual |
nodes
| test.go:56:2:56:42 | ... := ...[0] | semmle.label | ... := ...[0] |
| test.go:57:11:57:41 | call to EscapeString | semmle.label | call to EscapeString |
diff --git a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
index 79d8809e19f..1ce8c3d1dcf 100644
--- a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
+++ b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
@@ -25,53 +25,53 @@
| mongoDB.go:80:22:80:27 | filter | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:80:22:80:27 | filter | This query depends on a $@. | mongoDB.go:40:20:40:30 | call to Referer | user-provided value |
| mongoDB.go:81:18:81:25 | pipeline | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:81:18:81:25 | pipeline | This query depends on a $@. | mongoDB.go:40:20:40:30 | call to Referer | user-provided value |
edges
-| SqlInjection.go:10:7:11:30 | []type{args} [array] | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | MaD:7 |
-| SqlInjection.go:10:7:11:30 | call to Sprintf | SqlInjection.go:12:11:12:11 | q | provenance | |
-| SqlInjection.go:11:3:11:9 | selection of URL | SqlInjection.go:11:3:11:17 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| SqlInjection.go:10:7:11:30 | []type{args} [array] | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | MaD:23 |
+| SqlInjection.go:10:7:11:30 | call to Sprintf | SqlInjection.go:12:11:12:11 | q | provenance | Sink:MaD:1 |
+| SqlInjection.go:11:3:11:9 | selection of URL | SqlInjection.go:11:3:11:17 | call to Query | provenance | Src:MaD:21 MaD:26 |
| SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:11:3:11:29 | index expression | provenance | |
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | []type{args} [array] | provenance | |
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | FunctionModel |
| issue48.go:17:2:17:33 | ... := ...[0] | issue48.go:18:17:18:17 | b | provenance | |
-| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | provenance | Src:MaD:1 MaD:8 |
-| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... | provenance | MaD:6 |
+| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 |
+| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... | provenance | MaD:22 |
| issue48.go:18:20:18:39 | &... | issue48.go:21:3:21:33 | index expression | provenance | |
-| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:7 |
-| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | |
+| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:23 |
+| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | Sink:MaD:1 |
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | []type{args} [array] | provenance | |
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | call to Sprintf | provenance | FunctionModel |
| issue48.go:27:2:27:34 | ... := ...[0] | issue48.go:28:17:28:18 | b2 | provenance | |
-| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | provenance | Src:MaD:1 MaD:8 |
-| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... | provenance | MaD:6 |
+| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 |
+| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... | provenance | MaD:22 |
| issue48.go:28:21:28:41 | &... | issue48.go:31:3:31:31 | selection of Category | provenance | |
-| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:7 |
-| issue48.go:30:8:31:32 | call to Sprintf | issue48.go:32:11:32:12 | q4 | provenance | |
+| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:23 |
+| issue48.go:30:8:31:32 | call to Sprintf | issue48.go:32:11:32:12 | q4 | provenance | Sink:MaD:1 |
| issue48.go:31:3:31:31 | selection of Category | issue48.go:30:8:31:32 | []type{args} [array] | provenance | |
| issue48.go:31:3:31:31 | selection of Category | issue48.go:30:8:31:32 | call to Sprintf | provenance | FunctionModel |
-| issue48.go:37:17:37:50 | type conversion | issue48.go:37:53:37:73 | &... | provenance | MaD:6 |
-| issue48.go:37:24:37:30 | selection of URL | issue48.go:37:24:37:38 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| issue48.go:37:17:37:50 | type conversion | issue48.go:37:53:37:73 | &... | provenance | MaD:22 |
+| issue48.go:37:24:37:30 | selection of URL | issue48.go:37:24:37:38 | call to Query | provenance | Src:MaD:21 MaD:26 |
| issue48.go:37:24:37:38 | call to Query | issue48.go:37:17:37:50 | type conversion | provenance | |
| issue48.go:37:53:37:73 | &... | issue48.go:40:3:40:31 | selection of Category | provenance | |
-| issue48.go:39:8:40:32 | []type{args} [array] | issue48.go:39:8:40:32 | call to Sprintf | provenance | MaD:7 |
-| issue48.go:39:8:40:32 | call to Sprintf | issue48.go:41:11:41:12 | q5 | provenance | |
+| issue48.go:39:8:40:32 | []type{args} [array] | issue48.go:39:8:40:32 | call to Sprintf | provenance | MaD:23 |
+| issue48.go:39:8:40:32 | call to Sprintf | issue48.go:41:11:41:12 | q5 | provenance | Sink:MaD:1 |
| issue48.go:40:3:40:31 | selection of Category | issue48.go:39:8:40:32 | []type{args} [array] | provenance | |
| issue48.go:40:3:40:31 | selection of Category | issue48.go:39:8:40:32 | call to Sprintf | provenance | FunctionModel |
-| main.go:11:11:11:16 | selection of Form | main.go:11:11:11:28 | index expression | provenance | Src:MaD:2 |
-| main.go:15:11:15:84 | []type{args} [array] | main.go:15:11:15:84 | call to Sprintf | provenance | MaD:7 |
-| main.go:15:63:15:67 | selection of URL | main.go:15:63:15:75 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| main.go:11:11:11:16 | selection of Form | main.go:11:11:11:28 | index expression | provenance | Src:MaD:18 Sink:MaD:1 |
+| main.go:15:11:15:84 | []type{args} [array] | main.go:15:11:15:84 | call to Sprintf | provenance | MaD:23 Sink:MaD:2 |
+| main.go:15:63:15:67 | selection of URL | main.go:15:63:15:75 | call to Query | provenance | Src:MaD:21 MaD:26 |
| main.go:15:63:15:75 | call to Query | main.go:15:63:15:83 | index expression | provenance | |
| main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | []type{args} [array] | provenance | |
-| main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | call to Sprintf | provenance | FunctionModel |
-| main.go:16:11:16:85 | []type{args} [array] | main.go:16:11:16:85 | call to Sprintf | provenance | MaD:7 |
-| main.go:16:63:16:70 | selection of Header | main.go:16:63:16:84 | call to Get | provenance | Src:MaD:3 MaD:9 |
+| main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | call to Sprintf | provenance | FunctionModel Sink:MaD:2 |
+| main.go:16:11:16:85 | []type{args} [array] | main.go:16:11:16:85 | call to Sprintf | provenance | MaD:23 Sink:MaD:2 |
+| main.go:16:63:16:70 | selection of Header | main.go:16:63:16:84 | call to Get | provenance | Src:MaD:19 MaD:25 |
| main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | []type{args} [array] | provenance | |
-| main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | call to Sprintf | provenance | FunctionModel |
+| main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | call to Sprintf | provenance | FunctionModel Sink:MaD:2 |
| main.go:28:17:31:2 | &... [pointer, Category] | main.go:34:3:34:13 | RequestData [pointer, Category] | provenance | |
| main.go:28:18:31:2 | struct literal [Category] | main.go:28:17:31:2 | &... [pointer, Category] | provenance | |
-| main.go:30:13:30:19 | selection of URL | main.go:30:13:30:27 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| main.go:30:13:30:19 | selection of URL | main.go:30:13:30:27 | call to Query | provenance | Src:MaD:21 MaD:26 |
| main.go:30:13:30:27 | call to Query | main.go:30:13:30:39 | index expression | provenance | |
| main.go:30:13:30:39 | index expression | main.go:28:18:31:2 | struct literal [Category] | provenance | |
-| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:7 |
-| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | |
+| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:23 |
+| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | Sink:MaD:1 |
| main.go:34:3:34:13 | RequestData [pointer, Category] | main.go:34:3:34:13 | implicit dereference [Category] | provenance | |
| main.go:34:3:34:13 | implicit dereference [Category] | main.go:34:3:34:22 | selection of Category | provenance | |
| main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | []type{args} [array] | provenance | |
@@ -80,11 +80,11 @@ edges
| main.go:39:2:39:12 | definition of RequestData [pointer, Category] | main.go:43:3:43:13 | RequestData [pointer, Category] | provenance | |
| main.go:40:2:40:12 | RequestData [pointer, Category] | main.go:40:2:40:12 | implicit dereference [Category] | provenance | |
| main.go:40:2:40:12 | implicit dereference [Category] | main.go:39:2:39:12 | definition of RequestData [pointer, Category] | provenance | |
-| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:21 MaD:26 |
| main.go:40:25:40:39 | call to Query | main.go:40:25:40:51 | index expression | provenance | |
| main.go:40:25:40:51 | index expression | main.go:40:2:40:12 | implicit dereference [Category] | provenance | |
-| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:7 |
-| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | |
+| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:23 |
+| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | Sink:MaD:1 |
| main.go:43:3:43:13 | RequestData [pointer, Category] | main.go:43:3:43:13 | implicit dereference [Category] | provenance | |
| main.go:43:3:43:13 | implicit dereference [Category] | main.go:43:3:43:22 | selection of Category | provenance | |
| main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | []type{args} [array] | provenance | |
@@ -93,11 +93,11 @@ edges
| main.go:48:2:48:12 | definition of RequestData [pointer, Category] | main.go:52:3:52:13 | RequestData [pointer, Category] | provenance | |
| main.go:49:3:49:14 | star expression [Category] | main.go:48:2:48:12 | definition of RequestData [pointer, Category] | provenance | |
| main.go:49:4:49:14 | RequestData [pointer, Category] | main.go:49:3:49:14 | star expression [Category] | provenance | |
-| main.go:49:28:49:34 | selection of URL | main.go:49:28:49:42 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| main.go:49:28:49:34 | selection of URL | main.go:49:28:49:42 | call to Query | provenance | Src:MaD:21 MaD:26 |
| main.go:49:28:49:42 | call to Query | main.go:49:28:49:54 | index expression | provenance | |
| main.go:49:28:49:54 | index expression | main.go:49:3:49:14 | star expression [Category] | provenance | |
-| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:7 |
-| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | |
+| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:23 |
+| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | Sink:MaD:1 |
| main.go:52:3:52:13 | RequestData [pointer, Category] | main.go:52:3:52:13 | implicit dereference [Category] | provenance | |
| main.go:52:3:52:13 | implicit dereference [Category] | main.go:52:3:52:22 | selection of Category | provenance | |
| main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | []type{args} [array] | provenance | |
@@ -106,44 +106,60 @@ edges
| main.go:57:2:57:12 | definition of RequestData [pointer, Category] | main.go:61:5:61:15 | RequestData [pointer, Category] | provenance | |
| main.go:58:3:58:14 | star expression [Category] | main.go:57:2:57:12 | definition of RequestData [pointer, Category] | provenance | |
| main.go:58:4:58:14 | RequestData [pointer, Category] | main.go:58:3:58:14 | star expression [Category] | provenance | |
-| main.go:58:28:58:34 | selection of URL | main.go:58:28:58:42 | call to Query | provenance | Src:MaD:5 MaD:10 |
+| main.go:58:28:58:34 | selection of URL | main.go:58:28:58:42 | call to Query | provenance | Src:MaD:21 MaD:26 |
| main.go:58:28:58:42 | call to Query | main.go:58:28:58:54 | index expression | provenance | |
| main.go:58:28:58:54 | index expression | main.go:58:3:58:14 | star expression [Category] | provenance | |
-| main.go:60:7:61:26 | []type{args} [array] | main.go:60:7:61:26 | call to Sprintf | provenance | MaD:7 |
-| main.go:60:7:61:26 | call to Sprintf | main.go:62:11:62:11 | q | provenance | |
+| main.go:60:7:61:26 | []type{args} [array] | main.go:60:7:61:26 | call to Sprintf | provenance | MaD:23 |
+| main.go:60:7:61:26 | call to Sprintf | main.go:62:11:62:11 | q | provenance | Sink:MaD:1 |
| main.go:61:3:61:25 | selection of Category | main.go:60:7:61:26 | []type{args} [array] | provenance | |
| main.go:61:3:61:25 | selection of Category | main.go:60:7:61:26 | call to Sprintf | provenance | FunctionModel |
| main.go:61:4:61:15 | star expression [Category] | main.go:61:3:61:25 | selection of Category | provenance | |
| main.go:61:5:61:15 | RequestData [pointer, Category] | main.go:61:4:61:15 | star expression [Category] | provenance | |
-| mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:42:28:42:41 | untrustedInput | provenance | Src:MaD:4 |
+| mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:42:28:42:41 | untrustedInput | provenance | Src:MaD:20 |
| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:50:34:50:39 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:61:27:61:32 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:63:23:63:28 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:64:22:64:27 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:66:32:66:37 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:69:17:69:22 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:70:20:70:25 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:71:29:71:34 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:72:30:72:35 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:73:29:73:34 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:78:23:78:28 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:79:23:79:28 | filter | provenance | |
-| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:80:22:80:27 | filter | provenance | |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:61:27:61:32 | filter | provenance | Sink:MaD:4 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:63:23:63:28 | filter | provenance | Sink:MaD:5 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:64:22:64:27 | filter | provenance | Sink:MaD:6 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:66:32:66:37 | filter | provenance | Sink:MaD:7 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:69:17:69:22 | filter | provenance | Sink:MaD:8 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:70:20:70:25 | filter | provenance | Sink:MaD:9 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:71:29:71:34 | filter | provenance | Sink:MaD:10 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:72:30:72:35 | filter | provenance | Sink:MaD:11 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:73:29:73:34 | filter | provenance | Sink:MaD:12 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:78:23:78:28 | filter | provenance | Sink:MaD:13 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:79:23:79:28 | filter | provenance | Sink:MaD:14 |
+| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:80:22:80:27 | filter | provenance | Sink:MaD:15 |
| mongoDB.go:42:28:42:41 | untrustedInput | mongoDB.go:42:19:42:42 | struct literal | provenance | Config |
-| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:57:22:57:29 | pipeline | provenance | |
-| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:81:18:81:25 | pipeline | provenance | |
+| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:57:22:57:29 | pipeline | provenance | Sink:MaD:3 |
+| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:81:18:81:25 | pipeline | provenance | Sink:MaD:16 |
| mongoDB.go:50:34:50:39 | filter | mongoDB.go:50:23:50:40 | struct literal | provenance | Config |
models
-| 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual |
-| 2 | Source: net/http; Request; true; Form; ; ; ; remote; manual |
-| 3 | Source: net/http; Request; true; Header; ; ; ; remote; manual |
-| 4 | Source: net/http; Request; true; Referer; ; ; ReturnValue; remote; manual |
-| 5 | Source: net/http; Request; true; URL; ; ; ; remote; manual |
-| 6 | Summary: encoding/json; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual |
-| 7 | Summary: fmt; ; false; Sprintf; ; ; Argument[1].ArrayElement; ReturnValue; taint; manual |
-| 8 | Summary: io/ioutil; ; false; ReadAll; ; ; Argument[0]; ReturnValue[0]; taint; manual |
-| 9 | Summary: net/http; Header; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual |
-| 10 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual |
+| 1 | Sink: database/sql; DB; true; Query; ; ; Argument[0]; sql-injection; manual |
+| 2 | Sink: database/sql; Tx; true; Query; ; ; Argument[0]; sql-injection; manual |
+| 3 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Aggregate; ; ; Argument[1]; nosql-injection; manual |
+| 4 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; CountDocuments; ; ; Argument[1]; nosql-injection; manual |
+| 5 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; DeleteMany; ; ; Argument[1]; nosql-injection; manual |
+| 6 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; DeleteOne; ; ; Argument[1]; nosql-injection; manual |
+| 7 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Distinct; ; ; Argument[2]; nosql-injection; manual |
+| 8 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Find; ; ; Argument[1]; nosql-injection; manual |
+| 9 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOne; ; ; Argument[1]; nosql-injection; manual |
+| 10 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndDelete; ; ; Argument[1]; nosql-injection; manual |
+| 11 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndReplace; ; ; Argument[1]; nosql-injection; manual |
+| 12 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndUpdate; ; ; Argument[1]; nosql-injection; manual |
+| 13 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; ReplaceOne; ; ; Argument[1]; nosql-injection; manual |
+| 14 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; UpdateMany; ; ; Argument[1]; nosql-injection; manual |
+| 15 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; UpdateOne; ; ; Argument[1]; nosql-injection; manual |
+| 16 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Watch; ; ; Argument[1]; nosql-injection; manual |
+| 17 | Source: net/http; Request; true; Body; ; ; ; remote; manual |
+| 18 | Source: net/http; Request; true; Form; ; ; ; remote; manual |
+| 19 | Source: net/http; Request; true; Header; ; ; ; remote; manual |
+| 20 | Source: net/http; Request; true; Referer; ; ; ReturnValue; remote; manual |
+| 21 | Source: net/http; Request; true; URL; ; ; ; remote; manual |
+| 22 | Summary: encoding/json; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual |
+| 23 | Summary: fmt; ; false; Sprintf; ; ; Argument[1].ArrayElement; ReturnValue; taint; manual |
+| 24 | Summary: io/ioutil; ; false; ReadAll; ; ; Argument[0]; ReturnValue[0]; taint; manual |
+| 25 | Summary: net/http; Header; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual |
+| 26 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual |
nodes
| SqlInjection.go:10:7:11:30 | []type{args} [array] | semmle.label | []type{args} [array] |
| SqlInjection.go:10:7:11:30 | call to Sprintf | semmle.label | call to Sprintf |
diff --git a/go/ql/test/query-tests/Security/CWE-117/LogInjection.go b/go/ql/test/query-tests/Security/CWE-117/LogInjection.go
index 4f02cc9aef8..6fb628c4cc3 100644
--- a/go/ql/test/query-tests/Security/CWE-117/LogInjection.go
+++ b/go/ql/test/query-tests/Security/CWE-117/LogInjection.go
@@ -7,7 +7,7 @@ package main
//go:generate depstubber -vendor github.com/davecgh/go-spew/spew "" Dump,Errorf,Print,Printf,Println,Fdump,Fprint,Fprintf,Fprintln
//go:generate depstubber -vendor github.com/elazarl/goproxy ProxyCtx ""
//go:generate depstubber -vendor github.com/golang/glog Level,Verbose Info,InfoDepth,Infof,Infoln,Error,ErrorDepth,Errorf,Errorln,Fatal,FatalDepth,Fatalf,Fatalln,Exit,ExitDepth,Exitf,Exitln,V
-//go:generate depstubber -vendor github.com/sirupsen/logrus Fields,Entry,Logger,Level Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithFields,WithField
+//go:generate depstubber -vendor github.com/sirupsen/logrus FieldLogger,Fields,Entry,Logger,Level Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,New,NewEntry,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithError,WithFields,WithField
//go:generate depstubber -vendor go.uber.org/zap Logger,SugaredLogger NewProduction
import (
@@ -30,6 +30,7 @@ import (
func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
username := req.URL.Query()["username"][0]
+ slice := []any{"username", username}
testFlag := req.URL.Query()["testFlag"][0]
{
@@ -170,129 +171,180 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
}
// sirupsen/logrus
{
- logrus.Debug(username) // $ hasTaintFlow="username"
- logrus.Debugf(username, "") // $ hasTaintFlow="username"
- logrus.Debugf("", username) // $ hasTaintFlow="username"
- logrus.Debugln(username) // $ hasTaintFlow="username"
- logrus.Error(username) // $ hasTaintFlow="username"
- logrus.Errorf(username, "") // $ hasTaintFlow="username"
- logrus.Errorf("", username) // $ hasTaintFlow="username"
- logrus.Errorln(username) // $ hasTaintFlow="username"
- logrus.Fatal(username) // $ hasTaintFlow="username"
- logrus.Fatalf(username, "") // $ hasTaintFlow="username"
- logrus.Fatalf("", username) // $ hasTaintFlow="username"
- logrus.Fatalln(username) // $ hasTaintFlow="username"
- logrus.Info(username) // $ hasTaintFlow="username"
- logrus.Infof(username, "") // $ hasTaintFlow="username"
- logrus.Infof("", username) // $ hasTaintFlow="username"
- logrus.Infoln(username) // $ hasTaintFlow="username"
- logrus.Panic(username) // $ hasTaintFlow="username"
- logrus.Panicf(username, "") // $ hasTaintFlow="username"
- logrus.Panicf("", username) // $ hasTaintFlow="username"
- logrus.Panicln(username) // $ hasTaintFlow="username"
- logrus.Print(username) // $ hasTaintFlow="username"
- logrus.Printf(username, "") // $ hasTaintFlow="username"
- logrus.Printf("", username) // $ hasTaintFlow="username"
- logrus.Println(username) // $ hasTaintFlow="username"
- logrus.Trace(username) // $ hasTaintFlow="username"
- logrus.Tracef(username, "") // $ hasTaintFlow="username"
- logrus.Tracef("", username) // $ hasTaintFlow="username"
- logrus.Traceln(username) // $ hasTaintFlow="username"
- logrus.Warn(username) // $ hasTaintFlow="username"
- logrus.Warnf(username, "") // $ hasTaintFlow="username"
- logrus.Warnf("", username) // $ hasTaintFlow="username"
- logrus.Warnln(username) // $ hasTaintFlow="username"
- logrus.Warning(username) // $ hasTaintFlow="username"
- logrus.Warningf(username, "") // $ hasTaintFlow="username"
- logrus.Warningf("", username) // $ hasTaintFlow="username"
- logrus.Warningln(username) // $ hasTaintFlow="username"
-
+ err := fmt.Errorf("error: %s", username)
fields := make(logrus.Fields)
fields["username"] = username
- entry := logrus.WithFields(fields) // $ hasTaintFlow="fields"
- entry = logrus.WithField("username", username) // $ hasTaintFlow="username"
- entry.Debug(username) // $ hasTaintFlow="username"
- entry.Debugf(username, "") // $ hasTaintFlow="username"
- entry.Debugf("", username) // $ hasTaintFlow="username"
- entry.Debugln(username) // $ hasTaintFlow="username"
- entry.Error(username) // $ hasTaintFlow="username"
- entry.Errorf(username, "") // $ hasTaintFlow="username"
- entry.Errorf("", username) // $ hasTaintFlow="username"
- entry.Errorln(username) // $ hasTaintFlow="username"
- entry.Fatal(username) // $ hasTaintFlow="username"
- entry.Fatalf(username, "") // $ hasTaintFlow="username"
- entry.Fatalf("", username) // $ hasTaintFlow="username"
- entry.Fatalln(username) // $ hasTaintFlow="username"
- entry.Info(username) // $ hasTaintFlow="username"
- entry.Infof(username, "") // $ hasTaintFlow="username"
- entry.Infof("", username) // $ hasTaintFlow="username"
- entry.Infoln(username) // $ hasTaintFlow="username"
- entry.Log(0, username) // $ hasTaintFlow="username"
- entry.Logf(0, username, "") // $ hasTaintFlow="username"
- entry.Logf(0, "", username) // $ hasTaintFlow="username"
- entry.Logln(0, username) // $ hasTaintFlow="username"
- entry.Panic(username) // $ hasTaintFlow="username"
- entry.Panicf(username, "") // $ hasTaintFlow="username"
- entry.Panicf("", username) // $ hasTaintFlow="username"
- entry.Panicln(username) // $ hasTaintFlow="username"
- entry.Print(username) // $ hasTaintFlow="username"
- entry.Printf(username, "") // $ hasTaintFlow="username"
- entry.Printf("", username) // $ hasTaintFlow="username"
- entry.Println(username) // $ hasTaintFlow="username"
- entry.Trace(username) // $ hasTaintFlow="username"
- entry.Tracef(username, "") // $ hasTaintFlow="username"
- entry.Tracef("", username) // $ hasTaintFlow="username"
- entry.Traceln(username) // $ hasTaintFlow="username"
- entry.Warn(username) // $ hasTaintFlow="username"
- entry.Warnf(username, "") // $ hasTaintFlow="username"
- entry.Warnf("", username) // $ hasTaintFlow="username"
- entry.Warnln(username) // $ hasTaintFlow="username"
- entry.Warning(username) // $ hasTaintFlow="username"
- entry.Warningf(username, "") // $ hasTaintFlow="username"
- entry.Warningf("", username) // $ hasTaintFlow="username"
- entry.Warningln(username) // $ hasTaintFlow="username"
+ logger := logrus.New()
+ entry := logrus.NewEntry(logger)
- logger := entry.Logger
- logger.Debug(username) // $ hasTaintFlow="username"
- logger.Debugf(username, "") // $ hasTaintFlow="username"
- logger.Debugf("", username) // $ hasTaintFlow="username"
- logger.Debugln(username) // $ hasTaintFlow="username"
- logger.Error(username) // $ hasTaintFlow="username"
- logger.Errorf(username, "") // $ hasTaintFlow="username"
- logger.Errorf("", username) // $ hasTaintFlow="username"
- logger.Errorln(username) // $ hasTaintFlow="username"
- logger.Fatal(username) // $ hasTaintFlow="username"
- logger.Fatalf(username, "") // $ hasTaintFlow="username"
- logger.Fatalf("", username) // $ hasTaintFlow="username"
- logger.Fatalln(username) // $ hasTaintFlow="username"
- logger.Info(username) // $ hasTaintFlow="username"
- logger.Infof(username, "") // $ hasTaintFlow="username"
- logger.Infof("", username) // $ hasTaintFlow="username"
- logger.Infoln(username) // $ hasTaintFlow="username"
- logger.Log(0, username) // $ hasTaintFlow="username"
- logger.Logf(0, username, "") // $ hasTaintFlow="username"
- logger.Logf(0, "", username) // $ hasTaintFlow="username"
- logger.Logln(0, username) // $ hasTaintFlow="username"
- logger.Panic(username) // $ hasTaintFlow="username"
- logger.Panicf(username, "") // $ hasTaintFlow="username"
- logger.Panicf("", username) // $ hasTaintFlow="username"
- logger.Panicln(username) // $ hasTaintFlow="username"
- logger.Print(username) // $ hasTaintFlow="username"
- logger.Printf(username, "") // $ hasTaintFlow="username"
- logger.Printf("", username) // $ hasTaintFlow="username"
- logger.Println(username) // $ hasTaintFlow="username"
- logger.Trace(username) // $ hasTaintFlow="username"
- logger.Tracef(username, "") // $ hasTaintFlow="username"
- logger.Tracef("", username) // $ hasTaintFlow="username"
- logger.Traceln(username) // $ hasTaintFlow="username"
- logger.Warn(username) // $ hasTaintFlow="username"
- logger.Warnf(username, "") // $ hasTaintFlow="username"
- logger.Warnf("", username) // $ hasTaintFlow="username"
- logger.Warnln(username) // $ hasTaintFlow="username"
- logger.Warning(username) // $ hasTaintFlow="username"
- logger.Warningf(username, "") // $ hasTaintFlow="username"
- logger.Warningf("", username) // $ hasTaintFlow="username"
- logger.Warningln(username) // $ hasTaintFlow="username"
+ logrus.Debug(username) // $ hasTaintFlow="username"
+ logrus.Debugf(username, "") // $ hasTaintFlow="username"
+ logrus.Debugf("", username) // $ hasTaintFlow="username"
+ logrus.Debugln(username) // $ hasTaintFlow="username"
+ logrus.Error(username) // $ hasTaintFlow="username"
+ logrus.Errorf(username, "") // $ hasTaintFlow="username"
+ logrus.Errorf("", username) // $ hasTaintFlow="username"
+ logrus.Errorln(username) // $ hasTaintFlow="username"
+ logrus.Fatal(username) // $ hasTaintFlow="username"
+ logrus.Fatalf(username, "") // $ hasTaintFlow="username"
+ logrus.Fatalf("", username) // $ hasTaintFlow="username"
+ logrus.Fatalln(username) // $ hasTaintFlow="username"
+ logrus.Info(username) // $ hasTaintFlow="username"
+ logrus.Infof(username, "") // $ hasTaintFlow="username"
+ logrus.Infof("", username) // $ hasTaintFlow="username"
+ logrus.Infoln(username) // $ hasTaintFlow="username"
+ logrus.Panic(username) // $ hasTaintFlow="username"
+ logrus.Panicf(username, "") // $ hasTaintFlow="username"
+ logrus.Panicf("", username) // $ hasTaintFlow="username"
+ logrus.Panicln(username) // $ hasTaintFlow="username"
+ logrus.Print(username) // $ hasTaintFlow="username"
+ logrus.Printf(username, "") // $ hasTaintFlow="username"
+ logrus.Printf("", username) // $ hasTaintFlow="username"
+ logrus.Println(username) // $ hasTaintFlow="username"
+ logrus.Trace(username) // $ hasTaintFlow="username"
+ logrus.Tracef(username, "") // $ hasTaintFlow="username"
+ logrus.Tracef("", username) // $ hasTaintFlow="username"
+ logrus.Traceln(username) // $ hasTaintFlow="username"
+ logrus.Warn(username) // $ hasTaintFlow="username"
+ logrus.Warnf(username, "") // $ hasTaintFlow="username"
+ logrus.Warnf("", username) // $ hasTaintFlow="username"
+ logrus.Warnln(username) // $ hasTaintFlow="username"
+ logrus.Warning(username) // $ hasTaintFlow="username"
+ logrus.Warningf(username, "") // $ hasTaintFlow="username"
+ logrus.Warningf("", username) // $ hasTaintFlow="username"
+ logrus.Warningln(username) // $ hasTaintFlow="username"
+ logrus.WithError(err) // $ hasTaintFlow="err"
+ logrus.WithField(username, "") // $ hasTaintFlow="username"
+ logrus.WithField("", username) // $ hasTaintFlow="username"
+ logrus.WithFields(fields) // $ hasTaintFlow="fields"
+
+ entry.Debug(username) // $ hasTaintFlow="username"
+ entry.Debugf(username, "") // $ hasTaintFlow="username"
+ entry.Debugf("", username) // $ hasTaintFlow="username"
+ entry.Debugln(username) // $ hasTaintFlow="username"
+ entry.Error(username) // $ hasTaintFlow="username"
+ entry.Errorf(username, "") // $ hasTaintFlow="username"
+ entry.Errorf("", username) // $ hasTaintFlow="username"
+ entry.Errorln(username) // $ hasTaintFlow="username"
+ entry.Fatal(username) // $ hasTaintFlow="username"
+ entry.Fatalf(username, "") // $ hasTaintFlow="username"
+ entry.Fatalf("", username) // $ hasTaintFlow="username"
+ entry.Fatalln(username) // $ hasTaintFlow="username"
+ entry.Info(username) // $ hasTaintFlow="username"
+ entry.Infof(username, "") // $ hasTaintFlow="username"
+ entry.Infof("", username) // $ hasTaintFlow="username"
+ entry.Infoln(username) // $ hasTaintFlow="username"
+ entry.Log(0, username) // $ hasTaintFlow="username"
+ entry.Logf(0, username, "") // $ hasTaintFlow="username"
+ entry.Logf(0, "", username) // $ hasTaintFlow="username"
+ entry.Logln(0, username) // $ hasTaintFlow="username"
+ entry.Panic(username) // $ hasTaintFlow="username"
+ entry.Panicf(username, "") // $ hasTaintFlow="username"
+ entry.Panicf("", username) // $ hasTaintFlow="username"
+ entry.Panicln(username) // $ hasTaintFlow="username"
+ entry.Print(username) // $ hasTaintFlow="username"
+ entry.Printf(username, "") // $ hasTaintFlow="username"
+ entry.Printf("", username) // $ hasTaintFlow="username"
+ entry.Println(username) // $ hasTaintFlow="username"
+ entry.Trace(username) // $ hasTaintFlow="username"
+ entry.Tracef(username, "") // $ hasTaintFlow="username"
+ entry.Tracef("", username) // $ hasTaintFlow="username"
+ entry.Traceln(username) // $ hasTaintFlow="username"
+ entry.Warn(username) // $ hasTaintFlow="username"
+ entry.Warnf(username, "") // $ hasTaintFlow="username"
+ entry.Warnf("", username) // $ hasTaintFlow="username"
+ entry.Warnln(username) // $ hasTaintFlow="username"
+ entry.Warning(username) // $ hasTaintFlow="username"
+ entry.Warningf(username, "") // $ hasTaintFlow="username"
+ entry.Warningf("", username) // $ hasTaintFlow="username"
+ entry.Warningln(username) // $ hasTaintFlow="username"
+ entry.WithError(err) // $ hasTaintFlow="err"
+ entry.WithField(username, "") // $ hasTaintFlow="username"
+ entry.WithField("", username) // $ hasTaintFlow="username"
+ entry.WithFields(fields) // $ hasTaintFlow="fields"
+
+ logger.Debug(username) // $ hasTaintFlow="username"
+ logger.Debugf(username, "") // $ hasTaintFlow="username"
+ logger.Debugf("", username) // $ hasTaintFlow="username"
+ logger.Debugln(username) // $ hasTaintFlow="username"
+ logger.Error(username) // $ hasTaintFlow="username"
+ logger.Errorf(username, "") // $ hasTaintFlow="username"
+ logger.Errorf("", username) // $ hasTaintFlow="username"
+ logger.Errorln(username) // $ hasTaintFlow="username"
+ logger.Fatal(username) // $ hasTaintFlow="username"
+ logger.Fatalf(username, "") // $ hasTaintFlow="username"
+ logger.Fatalf("", username) // $ hasTaintFlow="username"
+ logger.Fatalln(username) // $ hasTaintFlow="username"
+ logger.Info(username) // $ hasTaintFlow="username"
+ logger.Infof(username, "") // $ hasTaintFlow="username"
+ logger.Infof("", username) // $ hasTaintFlow="username"
+ logger.Infoln(username) // $ hasTaintFlow="username"
+ logger.Log(0, username) // $ hasTaintFlow="username"
+ logger.Logf(0, username, "") // $ hasTaintFlow="username"
+ logger.Logf(0, "", username) // $ hasTaintFlow="username"
+ logger.Logln(0, username) // $ hasTaintFlow="username"
+ logger.Panic(username) // $ hasTaintFlow="username"
+ logger.Panicf(username, "") // $ hasTaintFlow="username"
+ logger.Panicf("", username) // $ hasTaintFlow="username"
+ logger.Panicln(username) // $ hasTaintFlow="username"
+ logger.Print(username) // $ hasTaintFlow="username"
+ logger.Printf(username, "") // $ hasTaintFlow="username"
+ logger.Printf("", username) // $ hasTaintFlow="username"
+ logger.Println(username) // $ hasTaintFlow="username"
+ logger.Trace(username) // $ hasTaintFlow="username"
+ logger.Tracef(username, "") // $ hasTaintFlow="username"
+ logger.Tracef("", username) // $ hasTaintFlow="username"
+ logger.Traceln(username) // $ hasTaintFlow="username"
+ logger.Warn(username) // $ hasTaintFlow="username"
+ logger.Warnf(username, "") // $ hasTaintFlow="username"
+ logger.Warnf("", username) // $ hasTaintFlow="username"
+ logger.Warnln(username) // $ hasTaintFlow="username"
+ logger.Warning(username) // $ hasTaintFlow="username"
+ logger.Warningf(username, "") // $ hasTaintFlow="username"
+ logger.Warningf("", username) // $ hasTaintFlow="username"
+ logger.Warningln(username) // $ hasTaintFlow="username"
+ logger.WithError(err) // $ hasTaintFlow="err"
+ logger.WithField(username, "") // $ hasTaintFlow="username"
+ logger.WithField("", username) // $ hasTaintFlow="username"
+ logger.WithFields(fields) // $ hasTaintFlow="fields"
+
+ var fieldlogger logrus.FieldLogger = entry
+ fieldlogger.Debug(username) // $ hasTaintFlow="username"
+ fieldlogger.Debugf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Debugf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Debugln(username) // $ hasTaintFlow="username"
+ fieldlogger.Error(username) // $ hasTaintFlow="username"
+ fieldlogger.Errorf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Errorf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Errorln(username) // $ hasTaintFlow="username"
+ fieldlogger.Fatal(username) // $ hasTaintFlow="username"
+ fieldlogger.Fatalf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Fatalf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Fatalln(username) // $ hasTaintFlow="username"
+ fieldlogger.Info(username) // $ hasTaintFlow="username"
+ fieldlogger.Infof(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Infof("", username) // $ hasTaintFlow="username"
+ fieldlogger.Infoln(username) // $ hasTaintFlow="username"
+ fieldlogger.Panic(username) // $ hasTaintFlow="username"
+ fieldlogger.Panicf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Panicf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Panicln(username) // $ hasTaintFlow="username"
+ fieldlogger.Print(username) // $ hasTaintFlow="username"
+ fieldlogger.Printf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Printf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Println(username) // $ hasTaintFlow="username"
+ fieldlogger.Warn(username) // $ hasTaintFlow="username"
+ fieldlogger.Warnf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Warnf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Warnln(username) // $ hasTaintFlow="username"
+ fieldlogger.Warning(username) // $ hasTaintFlow="username"
+ fieldlogger.Warningf(username, "") // $ hasTaintFlow="username"
+ fieldlogger.Warningf("", username) // $ hasTaintFlow="username"
+ fieldlogger.Warningln(username) // $ hasTaintFlow="username"
+ fieldlogger.WithError(err) // $ hasTaintFlow="err"
+ fieldlogger.WithField(username, "") // $ hasTaintFlow="username"
+ fieldlogger.WithField("", username) // $ hasTaintFlow="username"
+ fieldlogger.WithFields(fields) // $ hasTaintFlow="fields"
}
// davecgh/go-spew/spew
{
@@ -361,8 +413,34 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
sLogger.Named(username) // $ hasTaintFlow="username"
sLogger.With(username) // $ hasTaintFlow="username"
}
+ // heuristic logger interface
+ {
+ logger.Printf(username) // $ hasTaintFlow="username"
+ logger.Printf("%s", username) // $ hasTaintFlow="username"
+ simpleLogger.Tracew(username) // $ hasTaintFlow="username"
+ simpleLogger.Tracew("%s", username) // $ hasTaintFlow="username"
+ simpleLogger.Debugw("%s %s", slice...) // $ hasTaintFlow="slice"
+ }
+
}
+type Logger interface {
+ Printf(string, ...interface{})
+}
+
+type SimpleLogger interface {
+ Debugw(msg string, keysAndValues ...any)
+ Infow(msg string, keysAndValues ...any)
+ Warnw(msg string, keysAndValues ...any)
+ Errorw(msg string, keysAndValues ...any)
+ Tracew(msg string, keysAndValues ...any)
+}
+
+var (
+ logger Logger
+ simpleLogger SimpleLogger
+)
+
// GOOD: The user-provided value is escaped before being written to the log.
func handlerGood(req *http.Request) {
username := req.URL.Query()["username"][0]
@@ -598,5 +676,4 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
}
sLogger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
-
}
diff --git a/go/ql/test/query-tests/Security/CWE-117/go.mod b/go/ql/test/query-tests/Security/CWE-117/go.mod
index 57b2077a4ed..906d90f31b6 100644
--- a/go/ql/test/query-tests/Security/CWE-117/go.mod
+++ b/go/ql/test/query-tests/Security/CWE-117/go.mod
@@ -1,14 +1,33 @@
module main
-go 1.14
+go 1.23
require (
github.com/astaxie/beego v1.12.3
+ github.com/davecgh/go-spew v1.1.1
github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
- github.com/kr/text v0.2.0 // indirect
github.com/sirupsen/logrus v1.8.1
- github.com/stretchr/testify v1.6.0 // indirect
- golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
+ go.uber.org/zap v1.27.0
k8s.io/klog v1.0.0
)
+
+require (
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/cespare/xxhash/v2 v2.1.1 // indirect
+ github.com/golang/protobuf v1.4.2 // indirect
+ github.com/hashicorp/golang-lru v0.5.4 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/prometheus/client_golang v1.7.0 // indirect
+ github.com/prometheus/client_model v0.2.0 // indirect
+ github.com/prometheus/common v0.10.0 // indirect
+ github.com/prometheus/procfs v0.1.3 // indirect
+ github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
+ go.uber.org/multierr v1.10.0 // indirect
+ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
+ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
+ golang.org/x/text v0.3.0 // indirect
+ google.golang.org/protobuf v1.23.0 // indirect
+ gopkg.in/yaml.v2 v2.2.8 // indirect
+)
diff --git a/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go b/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go
index e8f7bccc446..497d85559bb 100644
--- a/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go
+++ b/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go
@@ -2,7 +2,7 @@
// This is a simple stub for github.com/sirupsen/logrus, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/sirupsen/logrus (exports: Fields,Entry,Logger,Level; functions: Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithFields,WithField)
+// Source: github.com/sirupsen/logrus (exports: FieldLogger,Fields,Entry,Logger,Level; functions: Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,New,NewEntry,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithError,WithFields,WithField)
// Package logrus is a stub of github.com/sirupsen/logrus, generated by depstubber.
package logrus
@@ -148,6 +148,36 @@ func Fatalf(_ string, _ ...interface{}) {}
func Fatalln(_ ...interface{}) {}
+type FieldLogger interface {
+ Debug(_ ...interface{})
+ Debugf(_ string, _ ...interface{})
+ Debugln(_ ...interface{})
+ Error(_ ...interface{})
+ Errorf(_ string, _ ...interface{})
+ Errorln(_ ...interface{})
+ Fatal(_ ...interface{})
+ Fatalf(_ string, _ ...interface{})
+ Fatalln(_ ...interface{})
+ Info(_ ...interface{})
+ Infof(_ string, _ ...interface{})
+ Infoln(_ ...interface{})
+ Panic(_ ...interface{})
+ Panicf(_ string, _ ...interface{})
+ Panicln(_ ...interface{})
+ Print(_ ...interface{})
+ Printf(_ string, _ ...interface{})
+ Println(_ ...interface{})
+ Warn(_ ...interface{})
+ Warnf(_ string, _ ...interface{})
+ Warning(_ ...interface{})
+ Warningf(_ string, _ ...interface{})
+ Warningln(_ ...interface{})
+ Warnln(_ ...interface{})
+ WithError(_ error) *Entry
+ WithField(_ string, _ interface{}) *Entry
+ WithFields(_ Fields) *Entry
+}
+
type Fields map[string]interface{}
type Formatter interface {
@@ -332,6 +362,14 @@ func (_ *Logger) WriterLevel(_ Level) *io.PipeWriter {
return nil
}
+func New() *Logger {
+ return nil
+}
+
+func NewEntry(_ *Logger) *Entry {
+ return nil
+}
+
func Panic(_ ...interface{}) {}
func Panicf(_ string, _ ...interface{}) {}
@@ -362,6 +400,10 @@ func Warningln(_ ...interface{}) {}
func Warnln(_ ...interface{}) {}
+func WithError(_ error) *Entry {
+ return nil
+}
+
func WithField(_ string, _ interface{}) *Entry {
return nil
}
diff --git a/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt b/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt
index a6227c09a93..fa7cb0a9a82 100644
--- a/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt
+++ b/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt
@@ -1,24 +1,134 @@
# github.com/astaxie/beego v1.12.3
-## explicit
+## explicit; go 1.13
github.com/astaxie/beego
+github.com/astaxie/beego/config
+github.com/astaxie/beego/context
+github.com/astaxie/beego/context/param
+github.com/astaxie/beego/grace
+github.com/astaxie/beego/logs
+github.com/astaxie/beego/session
+github.com/astaxie/beego/toolbox
+github.com/astaxie/beego/utils
+# github.com/beorn7/perks v1.0.1
+## explicit; go 1.11
+github.com/beorn7/perks/quantile
+# github.com/cespare/xxhash/v2 v2.1.1
+## explicit; go 1.11
+github.com/cespare/xxhash/v2
+# github.com/davecgh/go-spew v1.1.1
+## explicit
+github.com/davecgh/go-spew/spew
# github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b
## explicit
github.com/elazarl/goproxy
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
## explicit
github.com/golang/glog
-# github.com/kr/text v0.2.0
+# github.com/golang/protobuf v1.4.2
+## explicit; go 1.9
+github.com/golang/protobuf/proto
+github.com/golang/protobuf/ptypes
+github.com/golang/protobuf/ptypes/any
+github.com/golang/protobuf/ptypes/duration
+github.com/golang/protobuf/ptypes/timestamp
+# github.com/hashicorp/golang-lru v0.5.4
+## explicit; go 1.12
+github.com/hashicorp/golang-lru
+github.com/hashicorp/golang-lru/simplelru
+# github.com/matttproud/golang_protobuf_extensions v1.0.1
## explicit
-github.com/kr/text
+github.com/matttproud/golang_protobuf_extensions/pbutil
+# github.com/prometheus/client_golang v1.7.0
+## explicit; go 1.11
+github.com/prometheus/client_golang/prometheus
+github.com/prometheus/client_golang/prometheus/internal
+github.com/prometheus/client_golang/prometheus/promhttp
+# github.com/prometheus/client_model v0.2.0
+## explicit; go 1.9
+github.com/prometheus/client_model/go
+# github.com/prometheus/common v0.10.0
+## explicit; go 1.11
+github.com/prometheus/common/expfmt
+github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
+github.com/prometheus/common/model
+# github.com/prometheus/procfs v0.1.3
+## explicit; go 1.12
+github.com/prometheus/procfs
+github.com/prometheus/procfs/internal/fs
+github.com/prometheus/procfs/internal/util
+# github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644
+## explicit
+github.com/shiena/ansicolor
# github.com/sirupsen/logrus v1.8.1
-## explicit
+## explicit; go 1.13
github.com/sirupsen/logrus
-# github.com/stretchr/testify v1.6.0
+# go.uber.org/multierr v1.10.0
+## explicit; go 1.19
+go.uber.org/multierr
+# go.uber.org/zap v1.27.0
+## explicit; go 1.19
+go.uber.org/zap
+go.uber.org/zap/buffer
+go.uber.org/zap/internal
+go.uber.org/zap/internal/bufferpool
+go.uber.org/zap/internal/color
+go.uber.org/zap/internal/exit
+go.uber.org/zap/internal/pool
+go.uber.org/zap/internal/stacktrace
+go.uber.org/zap/zapcore
+# golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
## explicit
-github.com/stretchr/testify
+golang.org/x/crypto/acme
+golang.org/x/crypto/acme/autocert
+# golang.org/x/net v0.0.0-20190620200207-3b0461eec859
+## explicit; go 1.11
+golang.org/x/net/idna
# golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f
+## explicit; go 1.12
+golang.org/x/sys/internal/unsafeheader
+golang.org/x/sys/unix
+golang.org/x/sys/windows
+# golang.org/x/text v0.3.0
## explicit
-golang.org/x/sys
+golang.org/x/text/secure/bidirule
+golang.org/x/text/transform
+golang.org/x/text/unicode/bidi
+golang.org/x/text/unicode/norm
+# google.golang.org/protobuf v1.23.0
+## explicit; go 1.9
+google.golang.org/protobuf/encoding/prototext
+google.golang.org/protobuf/encoding/protowire
+google.golang.org/protobuf/internal/descfmt
+google.golang.org/protobuf/internal/descopts
+google.golang.org/protobuf/internal/detrand
+google.golang.org/protobuf/internal/encoding/defval
+google.golang.org/protobuf/internal/encoding/messageset
+google.golang.org/protobuf/internal/encoding/tag
+google.golang.org/protobuf/internal/encoding/text
+google.golang.org/protobuf/internal/errors
+google.golang.org/protobuf/internal/fieldnum
+google.golang.org/protobuf/internal/fieldsort
+google.golang.org/protobuf/internal/filedesc
+google.golang.org/protobuf/internal/filetype
+google.golang.org/protobuf/internal/flags
+google.golang.org/protobuf/internal/genname
+google.golang.org/protobuf/internal/impl
+google.golang.org/protobuf/internal/mapsort
+google.golang.org/protobuf/internal/pragma
+google.golang.org/protobuf/internal/set
+google.golang.org/protobuf/internal/strs
+google.golang.org/protobuf/internal/version
+google.golang.org/protobuf/proto
+google.golang.org/protobuf/reflect/protoreflect
+google.golang.org/protobuf/reflect/protoregistry
+google.golang.org/protobuf/runtime/protoiface
+google.golang.org/protobuf/runtime/protoimpl
+google.golang.org/protobuf/types/known/anypb
+google.golang.org/protobuf/types/known/durationpb
+google.golang.org/protobuf/types/known/timestamppb
+# gopkg.in/yaml.v2 v2.2.8
+## explicit
+gopkg.in/yaml.v2
# k8s.io/klog v1.0.0
-## explicit
+## explicit; go 1.12
k8s.io/klog
diff --git a/java/ql/automodel/publish.sh b/java/ql/automodel/publish.sh
deleted file mode 100755
index 7304f0da180..00000000000
--- a/java/ql/automodel/publish.sh
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/bin/bash
-set -e
-
-help="Usage: ./publish [--override-release] [--dry-run]
-Publish the automodel query pack.
-
-If no arguments are provided, publish the version of the codeql repo specified by the latest official release of the codeml-automodel repo.
-If the --override-release argument is provided, your current local HEAD is used (for unofficial releases or patching).
-If the --dry-run argument is provided, the release is not published (for testing purposes)."
-
-# Echo the help message
-if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
- echo "$help"
- exit 0
-fi
-
-# Check the number of arguments are valid
-if [ $# -gt 2 ]; then
- echo "Error: Invalid arguments provided"
- echo "$help"
- exit 1
-fi
-
-OVERRIDE_RELEASE=0
-DRY_RUN=0
-for arg in "$@"
-do
- case $arg in
- --override-release)
- OVERRIDE_RELEASE=1
- shift # Remove --override-release from processing
- ;;
- --dry-run)
- DRY_RUN=1
- shift # Remove --dry-run from processing
- ;;
- *)
- echo "Error: Invalid argument provided: $arg"
- echo "$help"
- exit 1
- ;;
- esac
-done
-
-# Describe what we're about to do based on the command-line arguments
-if [ $OVERRIDE_RELEASE = 1 ]; then
- echo "Publishing the current HEAD of the automodel repo"
-else
- echo "Publishing the version of the automodel repo specified by the latest official release of the codeml-automodel repo"
-fi
-if [ $DRY_RUN = 1 ]; then
- echo "Dry run: we will step through the process but we won't publish the query pack"
-else
- echo "Not a dry run! Publishing the query pack"
-fi
-
-# If we're publishing the codeml-automodel release then we will checkout the sha specified in the release.
-# So we need to check that there are no uncommitted changes in the local branch.
-# And, if we're publishing the current HEAD, it's cleaner to ensure that there are no uncommitted changes.
-if ! git diff --quiet; then
- echo "Error: Uncommitted changes exist. Please commit or stash your changes before publishing."
- exit 1
-fi
-
-# Check the above environment variables are set
-if [ -z "${GITHUB_TOKEN}" ]; then
- echo "Error: GITHUB_TOKEN environment variable not set. Please set this to a token with package:write permissions to codeql."
- exit 1
-fi
-if [ -z "${GH_TOKEN}" ]; then
- echo "Error: GH_TOKEN environment variable not set. Please set this to a token with repo permissions to github/codeml-automodel."
- exit 1
-fi
-
-# Get the sha of the previous release, i.e. the last commit to the main branch that updated the query pack version
-PREVIOUS_RELEASE_SHA=$(git rev-list -n 1 main -- ./src/qlpack.yml)
-if [ -z "$PREVIOUS_RELEASE_SHA" ]; then
- echo "Error: Could not get the sha of the previous release of codeml-automodel query pack"
- exit 1
-else
- echo "Previous query-pack release sha: $PREVIOUS_RELEASE_SHA"
-fi
-
-CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
-CURRENT_SHA=$(git rev-parse HEAD)
-
-if [ $OVERRIDE_RELEASE = 1 ]; then
- # Check that the current HEAD is downstream from PREVIOUS_RELEASE_SHA
- if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$CURRENT_SHA"; then
- echo "Error: The current HEAD is not downstream from the previous release"
- exit 1
- fi
-else
- # Get the latest release of codeml-automodel
- TAG_NAME=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/github/codeml-automodel/releases/latest | jq -r .tag_name)
- # Check TAG_NAME is not empty
- if [ -z "$TAG_NAME" ]; then
- echo "Error: Could not get latest release of codeml-automodel"
- exit 1
- fi
- echo "Updating to latest automodel release: $TAG_NAME"
- # Before downloading, delete any existing release.zip, and ignore failure if not present
- rm release.zip || true
- gh release download $TAG_NAME -A zip -O release.zip --repo 'https://github.com/github/codeml-automodel'
- # Before unzipping, delete any existing release directory, and ignore failure if not present
- rm -rf release || true
- unzip -o release.zip -d release
- REVISION=$(jq -r '.["codeql-sha"]' release/codeml-automodel*/codeml-automodel-release.json)
- echo "The latest codeml-automodel release specifies the codeql sha $REVISION"
- # Check that REVISION is downstream from PREVIOUS_RELEASE_SHA
- if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$REVISION"; then
- echo "Error: The codeql version $REVISION is not downstream of the query-pack version $PREVIOUS_RELEASE_SHA"
- exit 1
- fi
- # Get the version of the codeql code specified by the codeml-automodel release
- git checkout "$REVISION"
-fi
-
-# Get the absolute path of the automodel repo
-AUTOMODEL_ROOT="$(readlink -f "$(dirname $0)")"
-# Get the absolute path of the workspace root
-WORKSPACE_ROOT="$AUTOMODEL_ROOT/../../.."
-# Specify the groups of queries to test and publish
-GRPS="automodel,-test"
-
-# Install the codeql gh extension
-gh extensions install github/gh-codeql
-
-pushd "$AUTOMODEL_ROOT"
-echo Testing automodel queries
-gh codeql test run test
-popd
-
-pushd "$WORKSPACE_ROOT"
-echo "Preparing the release"
-gh codeql pack release --groups $GRPS -v
-
-if [ $DRY_RUN = 1 ]; then
- echo "Dry run: not publishing the query pack"
- gh codeql pack publish --groups $GRPS --dry-run -v
-else
- echo "Not a dry run! Publishing the query pack"
- gh codeql pack publish --groups $GRPS -v
-fi
-
-echo "Bumping versions"
-gh codeql pack post-release --groups $GRPS -v
-popd
-
-# The above commands update
-# ./src/CHANGELOG.md
-# ./src/codeql-pack.release.yml
-# ./src/qlpack.yml
-# and add a new file
-# ./src/change-notes/released/.md
-
-# Get the filename of the most recently created file in ./src/change-notes/released/*.md
-# This will be the file for the new release
-NEW_CHANGE_NOTES_FILE=$(ls -t ./src/change-notes/released/*.md | head -n 1)
-
-# Make a copy of the modified files
-mv ./src/CHANGELOG.md ./src/CHANGELOG.md.dry-run
-mv ./src/codeql-pack.release.yml ./src/codeql-pack.release.yml.dry-run
-mv ./src/qlpack.yml ./src/qlpack.yml.dry-run
-mv "$NEW_CHANGE_NOTES_FILE" ./src/change-notes/released.md.dry-run
-
-if [ $OVERRIDE_RELEASE = 1 ]; then
- # Restore the original files
- git checkout ./src/CHANGELOG.md
- git checkout ./src/codeql-pack.release.yml
- git checkout ./src/qlpack.yml
-else
- # Restore the original files
- git checkout "$CURRENT_BRANCH" --force
-fi
-
-if [ $DRY_RUN = 1 ]; then
- echo "Inspect the updated dry-run version files:"
- ls -l ./src/*.dry-run
- ls -l ./src/change-notes/*.dry-run
-else
- # Add the updated files to the current branch
- echo "Adding the version changes"
- mv -f ./src/CHANGELOG.md.dry-run ./src/CHANGELOG.md
- mv -f ./src/codeql-pack.release.yml.dry-run ./src/codeql-pack.release.yml
- mv -f ./src/qlpack.yml.dry-run ./src/qlpack.yml
- mv -f ./src/change-notes/released.md.dry-run "$NEW_CHANGE_NOTES_FILE"
- git add ./src/CHANGELOG.md
- git add ./src/codeql-pack.release.yml
- git add ./src/qlpack.yml
- git add "$NEW_CHANGE_NOTES_FILE"
- echo "Added the following updated version files to the current branch:"
- git status -s
- echo "To complete the release, please commit these files and merge to the main branch"
-fi
-
-echo "Done"
\ No newline at end of file
diff --git a/java/ql/automodel/src/AutomodelAlertSinkUtil.qll b/java/ql/automodel/src/AutomodelAlertSinkUtil.qll
deleted file mode 100644
index f20c8e57b6c..00000000000
--- a/java/ql/automodel/src/AutomodelAlertSinkUtil.qll
+++ /dev/null
@@ -1,183 +0,0 @@
-private import java
-private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
-private import semmle.code.java.dataflow.TaintTracking
-private import semmle.code.java.security.RequestForgeryConfig
-private import semmle.code.java.security.CommandLineQuery
-private import semmle.code.java.security.SqlConcatenatedQuery
-private import semmle.code.java.security.SqlInjectionQuery
-private import semmle.code.java.security.UrlRedirectQuery
-private import semmle.code.java.security.TaintedPathQuery
-private import semmle.code.java.security.SqlInjectionQuery
-private import AutomodelJavaUtil
-
-private newtype TSinkModel =
- MkSinkModel(
- string package, string type, boolean subtypes, string name, string signature, string ext,
- string input, string kind, string provenance
- ) {
- ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance,
- _)
- }
-
-class SinkModel extends TSinkModel {
- string package;
- string type;
- boolean subtypes;
- string name;
- string signature;
- string ext;
- string input;
- string kind;
- string provenance;
-
- SinkModel() {
- this = MkSinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
- }
-
- /** Gets the package for this sink model. */
- string getPackage() { result = package }
-
- /** Gets the type for this sink model. */
- string getType() { result = type }
-
- /** Gets whether this sink model considers subtypes. */
- boolean getSubtypes() { result = subtypes }
-
- /** Gets the name for this sink model. */
- string getName() { result = name }
-
- /** Gets the signature for this sink model. */
- string getSignature() { result = signature }
-
- /** Gets the input for this sink model. */
- string getInput() { result = input }
-
- /** Gets the extension for this sink model. */
- string getExt() { result = ext }
-
- /** Gets the kind for this sink model. */
- string getKind() { result = kind }
-
- /** Gets the provenance for this sink model. */
- string getProvenance() { result = provenance }
-
- /** Gets the number of instances of this sink model. */
- int getInstanceCount() { result = count(PotentialSinkModelExpr p | p.getSinkModel() = this) }
-
- /** Gets a string representation of this sink model. */
- string toString() {
- result =
- "SinkModel(" + package + ", " + type + ", " + subtypes + ", " + name + ", " + signature + ", "
- + ext + ", " + input + ", " + kind + ", " + provenance + ")"
- }
-
- /** Gets a string representation of this sink model as it would appear in a Models-as-Data file. */
- string getRepr() {
- result =
- "\"" + package + "\", \"" + type + "\", " + pyBool(subtypes) + ", \"" + name + "\", \"" +
- signature + "\", \"" + ext + "\", \"" + input + "\", \"" + kind + "\", \"" + provenance +
- "\""
- }
-}
-
-/** An expression that may correspond to a sink model. */
-class PotentialSinkModelExpr extends Expr {
- /**
- * Holds if this expression has the given signature. The signature should contain enough
- * information to determine a corresponding sink model, if one exists.
- */
- pragma[nomagic]
- predicate hasSignature(
- string package, string type, boolean subtypes, string name, string signature, string input
- ) {
- exists(Call call, Callable callable, int argIdx |
- call.getCallee().getSourceDeclaration() = callable and
- (
- this = call.getArgument(argIdx)
- or
- this = call.getQualifier() and argIdx = -1
- ) and
- (if argIdx = -1 then input = "Argument[this]" else input = "Argument[" + argIdx + "]") and
- package = callable.getDeclaringType().getPackage().getName() and
- type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
- subtypes = considerSubtypes(callable) and
- name = callable.getName() and
- signature = ExternalFlow::paramsString(callable)
- )
- }
-
- /** Gets a sink model that corresponds to this expression. */
- SinkModel getSinkModel() {
- this.hasSignature(result.getPackage(), result.getType(), result.getSubtypes(), result.getName(),
- result.getSignature(), result.getInput())
- }
-}
-
-private string pyBool(boolean b) {
- b = true and result = "True"
- or
- b = false and result = "False"
-}
-
-/**
- * Gets a string representation of the existing sink model at the expression `e`, in the format in
- * which it would appear in a Models-as-Data file. Also restricts the provenance of the sink model
- * to be `ai-generated`.
- */
-string getSinkModelRepr(PotentialSinkModelExpr e) {
- result = e.getSinkModel().getRepr() and
- e.getSinkModel().getProvenance() = "ai-generated"
-}
-
-/**
- * Gets the string representation of a sink model in a format suitable for appending to an alert
- * message.
- */
-string getSinkModelQueryRepr(PotentialSinkModelExpr e) {
- result = "\nsinkModel: " + getSinkModelRepr(e)
-}
-
-/**
- * A parameterised module that takes a dataflow config, and exposes a predicate for counting the
- * number of AI-generated sink models that appear in alerts for that query.
- */
-private module SinkTallier {
- module ConfigFlow = TaintTracking::Global;
-
- predicate getSinkModelCount(int c, SinkModel s) {
- s = any(ConfigFlow::PathNode sink).getNode().asExpr().(PotentialSinkModelExpr).getSinkModel() and
- c =
- strictcount(ConfigFlow::PathNode sink |
- ConfigFlow::flowPath(_, sink) and
- s = sink.getNode().asExpr().(PotentialSinkModelExpr).getSinkModel()
- )
- }
-}
-
-predicate sinkModelTallyPerQuery(string queryName, int alertCount, SinkModel sinkModel) {
- queryName = "java/request-forgery" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/command-line-injection" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/concatenated-sql-query" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/ssrf" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/path-injection" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/unvalidated-url-redirection" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
- or
- queryName = "java/sql-injection" and
- SinkTallier::getSinkModelCount(alertCount, sinkModel)
-}
-
-predicate sinkModelTally(int alertCount, SinkModel sinkModel) {
- sinkModelTallyPerQuery(_, _, sinkModel) and
- alertCount = sum(int c | sinkModelTallyPerQuery(_, c, sinkModel))
-}
diff --git a/java/ql/automodel/src/AutomodelAlertSinks.ql b/java/ql/automodel/src/AutomodelAlertSinks.ql
deleted file mode 100644
index e9af51b4d63..00000000000
--- a/java/ql/automodel/src/AutomodelAlertSinks.ql
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * @name Number of alerts per sink model
- * @description Counts the number of alerts using `ai-generated` sink models.
- * @kind table
- * @id java/ml/metrics-count-alerts-per-sink-model
- * @tags internal automodel metrics
- */
-
-private import java
-private import AutomodelAlertSinkUtil
-
-from int alertCount, SinkModel s
-where sinkModelTally(alertCount, s) and s.getProvenance() = "ai-generated"
-select alertCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes,
- s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext,
- s.getKind() as kind, s.getProvenance() as provenance order by alertCount desc
diff --git a/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql b/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql
deleted file mode 100644
index 64a5038d116..00000000000
--- a/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @name Number of alerts per sink model and query
- * @description Counts the number of alerts per query using `ai-generated` sink models.
- * @kind table
- * @id java/ml/metrics-count-alerts-per-sink-model-and-query
- * @tags internal automodel metrics
- */
-
-private import java
-private import AutomodelAlertSinkUtil
-
-from string queryId, int alertCount, SinkModel s
-where
- sinkModelTallyPerQuery(queryId, alertCount, s) and
- s.getProvenance() = "ai-generated"
-select queryId, alertCount, s.getPackage() as package, s.getType() as type,
- s.getSubtypes() as subtypes, s.getName() as name, s.getSignature() as signature,
- s.getInput() as input, s.getExt() as ext, s.getKind() as kind, s.getProvenance() as provenance
- order by queryId, alertCount desc
diff --git a/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll b/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll
deleted file mode 100644
index 750d776891f..00000000000
--- a/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll
+++ /dev/null
@@ -1,677 +0,0 @@
-/**
- * For internal use only.
- */
-
-private import java
-private import semmle.code.Location as Location
-private import semmle.code.java.dataflow.DataFlow
-private import semmle.code.java.dataflow.TaintTracking
-private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
-private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
-private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
-private import semmle.code.java.Expr as Expr
-private import semmle.code.java.security.QueryInjection
-private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
-private import AutomodelJavaUtil as AutomodelJavaUtil
-private import semmle.code.java.security.PathSanitizer as PathSanitizer
-import AutomodelSharedCharacteristics as SharedCharacteristics
-import AutomodelEndpointTypes as AutomodelEndpointTypes
-
-newtype JavaRelatedLocationType =
- CallContext() or
- MethodDoc() or
- ClassDoc()
-
-newtype TApplicationModeEndpoint =
- TExplicitArgument(Call call, DataFlow::Node arg) {
- AutomodelJavaUtil::isFromSource(call) and
- exists(Argument argExpr |
- arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg()
- ) and
- not AutomodelJavaUtil::isUnexploitableType(arg.getType())
- } or
- TInstanceArgument(Call call, DataFlow::Node arg) {
- AutomodelJavaUtil::isFromSource(call) and
- arg = DataFlow::getInstanceArgument(call) and
- not call instanceof ConstructorCall and
- not AutomodelJavaUtil::isUnexploitableType(arg.getType())
- } or
- TImplicitVarargsArray(Call call, DataFlow::ImplicitVarargsArray arg, int idx) {
- AutomodelJavaUtil::isFromSource(call) and
- call = arg.getCall() and
- idx = call.getCallee().getVaragsParameterIndex() and
- not AutomodelJavaUtil::isUnexploitableType(arg.getType())
- } or
- TMethodReturnValue(MethodCall call) {
- AutomodelJavaUtil::isFromSource(call) and
- not AutomodelJavaUtil::isUnexploitableType(call.getType())
- } or
- TOverriddenParameter(Parameter p, Method overriddenMethod) {
- AutomodelJavaUtil::isFromSource(p) and
- p.getCallable().(Method).overrides(overriddenMethod)
- }
-
-/**
- * An endpoint is a node that is a candidate for modeling.
- */
-abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint {
- /**
- * Gets the callable to be modeled that this endpoint represents.
- */
- abstract Callable getCallable();
-
- /**
- * Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
- *
- * For endpoints that are source candidates, this will be `none()`.
- */
- abstract string getMaDInput();
-
- /**
- * Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
- *
- * For endpoints that are sink candidates, this will be `none()`.
- */
- abstract string getMaDOutput();
-
- abstract Top asTop();
-
- /**
- * Converts the endpoint to a node that can be used in a data flow graph.
- */
- abstract DataFlow::Node asNode();
-
- string getExtensibleType() {
- if not exists(this.getMaDInput()) and exists(this.getMaDOutput())
- then result = "sourceModel"
- else
- if exists(this.getMaDInput()) and not exists(this.getMaDOutput())
- then result = "sinkModel"
- else none() // if both exist, it would be a summaryModel (not yet supported)
- }
-
- abstract string toString();
-}
-
-class TCallArgument = TExplicitArgument or TInstanceArgument or TImplicitVarargsArray;
-
-/**
- * An endpoint that represents an "argument" to a call in a broad sense, including
- * both explicit arguments and the instance argument.
- */
-abstract class CallArgument extends ApplicationModeEndpoint, TCallArgument {
- Call call;
- DataFlow::Node arg;
-
- override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
-
- override string getMaDOutput() { none() }
-
- override DataFlow::Node asNode() { result = arg }
-
- Call getCall() { result = call }
-
- override string toString() { result = arg.toString() }
-}
-
-/**
- * An endpoint that represents an explicit argument to a call.
- */
-class ExplicitArgument extends CallArgument, TExplicitArgument {
- ExplicitArgument() { this = TExplicitArgument(call, arg) }
-
- private int getArgIndex() { this.asTop() = call.getArgument(result) }
-
- override string getMaDInput() { result = "Argument[" + this.getArgIndex() + "]" }
-
- override Top asTop() { result = arg.asExpr() }
-}
-
-/**
- * An endpoint that represents the instance argument to a call.
- */
-class InstanceArgument extends CallArgument, TInstanceArgument {
- InstanceArgument() { this = TInstanceArgument(call, arg) }
-
- override string getMaDInput() { result = "Argument[this]" }
-
- override Top asTop() { if exists(arg.asExpr()) then result = arg.asExpr() else result = call }
-
- override string toString() { result = arg.toString() }
-}
-
-/**
- * An endpoint that represents an implicit varargs array.
- * We choose to represent the varargs array as a single endpoint, rather than as multiple endpoints.
- *
- * This avoids the problem of having to deal with redundant endpoints downstream.
- *
- * In order to be able to distinguish between varargs endpoints and regular endpoints, we export the `isVarargsArray`
- * meta data field in the extraction queries.
- */
-class ImplicitVarargsArray extends CallArgument, TImplicitVarargsArray {
- int idx;
-
- ImplicitVarargsArray() { this = TImplicitVarargsArray(call, arg, idx) }
-
- override string getMaDInput() { result = "Argument[" + idx + "]" }
-
- override Top asTop() { result = call }
-}
-
-/**
- * An endpoint that represents a method call. The `ReturnValue` of a method call
- * may be a source.
- */
-class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue {
- MethodCall call;
-
- MethodReturnValue() { this = TMethodReturnValue(call) }
-
- override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
-
- override string getMaDInput() { none() }
-
- override string getMaDOutput() { result = "ReturnValue" }
-
- override Top asTop() { result = call }
-
- override DataFlow::Node asNode() { result.asExpr() = call }
-
- override string toString() { result = call.toString() }
-}
-
-/**
- * An endpoint that represents a parameter of an overridden method that may be
- * a source.
- */
-class OverriddenParameter extends ApplicationModeEndpoint, TOverriddenParameter {
- Parameter p;
- Method overriddenMethod;
-
- OverriddenParameter() { this = TOverriddenParameter(p, overriddenMethod) }
-
- override Callable getCallable() {
- // NB: we're returning the overridden callable here. This means that the
- // candidate model will be about the overridden method, not the overriding
- // method. This is a more general model, that also applies to other
- // subclasses of the overridden class.
- result = overriddenMethod.getSourceDeclaration()
- }
-
- private int getArgIndex() { p.getCallable().getParameter(result) = p }
-
- override string getMaDInput() { none() }
-
- override string getMaDOutput() { result = "Parameter[" + this.getArgIndex() + "]" }
-
- override Top asTop() { result = p }
-
- override DataFlow::Node asNode() { result.(DataFlow::ParameterNode).asParameter() = p }
-
- override string toString() { result = p.toString() }
-}
-
-/**
- * A candidates implementation.
- *
- * Some important notes:
- * - This mode is using arguments as endpoints.
- * - We use the `CallContext` (the surrounding call expression) as related location.
- */
-module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig {
- // for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
- class Endpoint = ApplicationModeEndpoint;
-
- class EndpointType = AutomodelEndpointTypes::EndpointType;
-
- class SinkType = AutomodelEndpointTypes::SinkType;
-
- class SourceType = AutomodelEndpointTypes::SourceType;
-
- class RelatedLocation = Location::Top;
-
- class RelatedLocationType = JavaRelatedLocationType;
-
- // Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
- predicate isSanitizer(Endpoint e, EndpointType t) {
- exists(t) and
- AutomodelJavaUtil::isUnexploitableType([
- // for most endpoints, we can get the type from the node
- e.asNode().getType(),
- // but not for calls to void methods, where we need to go via the AST
- e.asTop().(Expr).getType()
- ])
- or
- t instanceof AutomodelEndpointTypes::PathInjectionSinkType and
- e.asNode() instanceof PathSanitizer::PathInjectionSanitizer
- }
-
- RelatedLocation asLocation(Endpoint e) { result = e.asTop() }
-
- predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
-
- predicate isSink(Endpoint e, string kind, string provenance) {
- exists(
- string package, string type, boolean subtypes, string name, string signature, string ext,
- string input
- |
- sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
- ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
- provenance, _)
- )
- or
- isCustomSink(e, kind) and provenance = "custom-sink"
- }
-
- predicate isSource(Endpoint e, string kind, string provenance) {
- exists(
- string package, string type, boolean subtypes, string name, string signature, string ext,
- string output
- |
- sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
- ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
- provenance, _)
- )
- }
-
- predicate isNeutral(Endpoint e) {
- exists(string package, string type, string name, string signature, string endpointType |
- sinkSpec(e, package, type, _, name, signature, _, _) and
- endpointType = "sink"
- or
- sourceSpec(e, package, type, _, name, signature, _, _) and
- endpointType = "source"
- |
- ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _)
- )
- }
-
- /**
- * Holds if the endpoint concerns a callable with the given package, type, name and signature.
- *
- * If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and
- * all its overrides are considered.
- */
- additional predicate endpointCallable(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature
- ) {
- exists(Callable c |
- c = e.getCallable() and subtypes in [true, false]
- or
- e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true
- |
- c.hasQualifiedName(package, type, name) and
- signature = ExternalFlow::paramsString(c)
- )
- }
-
- additional predicate sinkSpec(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature,
- string ext, string input
- ) {
- endpointCallable(e, package, type, subtypes, name, signature) and
- ext = "" and
- input = e.getMaDInput()
- }
-
- additional predicate sourceSpec(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature,
- string ext, string output
- ) {
- endpointCallable(e, package, type, subtypes, name, signature) and
- ext = "" and
- output = e.getMaDOutput()
- }
-
- /**
- * Gets the related location for the given endpoint.
- *
- * The only related location we model is the the call expression surrounding to
- * which the endpoint is either argument or qualifier (known as the call context).
- */
- RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
- type = CallContext() and
- result = e.(CallArgument).getCall()
- or
- type = MethodDoc() and
- result = e.getCallable().(Documentable).getJavadoc()
- or
- type = ClassDoc() and
- result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
- }
-}
-
-/**
- * Contains endpoints that are defined in QL code rather than as a MaD model. Ideally this predicate
- * should be empty.
- */
-private predicate isCustomSink(Endpoint e, string kind) {
- e.asNode() instanceof QueryInjectionSink and kind = "sql"
-}
-
-module CharacteristicsImpl =
- SharedCharacteristics::SharedCharacteristics;
-
-class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
-
-class Endpoint = ApplicationCandidatesImpl::Endpoint;
-
-/*
- * Predicates that are used to surface prompt examples and candidates for classification with an ML model.
- */
-
-/**
- * A MetadataExtractor that extracts metadata for application mode.
- */
-class ApplicationModeMetadataExtractor extends string {
- ApplicationModeMetadataExtractor() { this = "ApplicationModeMetadataExtractor" }
-
- predicate hasMetadata(
- Endpoint e, string package, string type, string subtypes, string name, string signature,
- string input, string output, string isVarargsArray, string alreadyAiModeled,
- string extensibleType
- ) {
- exists(Callable callable | e.getCallable() = callable |
- (if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
- (if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
- package = callable.getDeclaringType().getPackage().getName() and
- // we're using the erased types because the MaD convention is to not specify type parameters.
- // Whether something is or isn't a sink doesn't usually depend on the type parameters.
- type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
- subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
- name = callable.getName() and
- signature = ExternalFlow::paramsString(callable) and
- (
- if e instanceof ImplicitVarargsArray
- then isVarargsArray = "true"
- else isVarargsArray = "false"
- ) and
- extensibleType = e.getExtensibleType()
- ) and
- (
- not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
- or
- CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
- )
- }
-}
-
-/**
- * Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isCandidate(
- Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
- string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
-) {
- CharacteristicsImpl::isCandidate(endpoint, _) and
- not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
- u.appliesToEndpoint(endpoint)
- ) and
- any(ApplicationModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargs,
- alreadyAiModeled, extensibleType) and
- // If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a
- // candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's
- // already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We
- // assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink
- // types, and we don't need to reexamine it.
- alreadyAiModeled.matches(["", "%ai-%"]) and
- AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
-}
-
-/**
- * Holds if the given `endpoint` is a negative example for the `extensibleType`
- * because of the `characteristic`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isNegativeExample(
- Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
- string type, string subtypes, string name, string signature, string input, string output,
- string isVarargsArray, string extensibleType
-) {
- characteristic.appliesToEndpoint(endpoint) and
- // the node is known not to be an endpoint of any appropriate type
- forall(AutomodelEndpointTypes::EndpointType tp |
- tp = CharacteristicsImpl::getAPotentialType(endpoint)
- |
- characteristic.hasImplications(tp, false, _)
- ) and
- // the lowest confidence across all endpoint types should be at least highConfidence
- confidence =
- min(float c |
- characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
- ) and
- confidence >= SharedCharacteristics::highConfidence() and
- any(ApplicationModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
- isVarargsArray, _, extensibleType) and
- // It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
- // as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
- not exists(EndpointCharacteristic characteristic2, float confidence2 |
- characteristic2 != characteristic
- |
- characteristic2.appliesToEndpoint(endpoint) and
- confidence2 >= SharedCharacteristics::maximalConfidence() and
- characteristic2
- .hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
- )
-}
-
-/**
- * Holds if the given `endpoint` is a positive example for the `endpointType`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isPositiveExample(
- Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
- string signature, string input, string output, string isVarargsArray, string extensibleType
-) {
- any(ApplicationModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
- isVarargsArray, _, extensibleType) and
- CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) and
- exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
-}
-
-/*
- * EndpointCharacteristic classes that are specific to Automodel for Java.
- */
-
-/**
- * A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks.
- *
- * A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
- * type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
- * the dangerous/interesting thing, so we want the latter to be modeled as the sink.
- *
- * TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
- */
-private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
- UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- e.getCallable().getName().matches("is%") and
- e.getCallable().getReturnType() instanceof BooleanType and
- not ApplicationCandidatesImpl::isSink(e, _, _)
- }
-}
-
-/**
- * A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
- * considered sinks.
- *
- * A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
- * boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
- * dangerous/interesting thing, so we want the latter to be modeled as the sink.
- */
-private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
- UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- exists(Callable callable | callable = e.getCallable() |
- callable.getName().toLowerCase() = ["exists", "notexists"] and
- callable.getReturnType() instanceof BooleanType
- )
- }
-}
-
-/**
- * A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
- * and its return value should not be considered a source.
- */
-private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
-{
- ExceptionCharacteristic() { this = "argument/result of exception-related method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
- (
- e.getExtensibleType() = "sinkModel" and
- not ApplicationCandidatesImpl::isSink(e, _, _)
- or
- e.getExtensibleType() = "sourceModel" and
- not ApplicationCandidatesImpl::isSource(e, _, _) and
- e.getMaDOutput() = "ReturnValue"
- )
- }
-}
-
-/**
- * A negative characteristic that indicates that an endpoint is a MaD taint step. MaD modeled taint steps are global,
- * so they are not sinks for any query. Non-MaD taint steps might be specific to a particular query, so we don't
- * filter those out.
- */
-private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
- IsMaDTaintStepCharacteristic() { this = "taint step" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _)
- or
- FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _)
- or
- FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _)
- or
- FlowSummaryImpl::Private::Steps::summarySetterStep(e.asNode(), _, _, _)
- }
-}
-
-/**
- * A call to a method that's known locally will not be considered as a candidate to model.
- *
- * The reason is that we would expect data/taint flow into the method implementation to uncover
- * any sinks that are present there.
- */
-private class LocalCall extends CharacteristicsImpl::UninterestingToModelCharacteristic {
- LocalCall() { this = "local call" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- e.(CallArgument).getCallable().fromSource()
- or
- e.(MethodReturnValue).getCallable().fromSource()
- }
-}
-
-/**
- * A characteristic that marks endpoints as uninteresting to model, according to the Java ModelExclusions module.
- */
-private class ExcludedFromModeling extends CharacteristicsImpl::UninterestingToModelCharacteristic {
- ExcludedFromModeling() { this = "excluded from modeling" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- ModelExclusions::isUninterestingForModels(e.getCallable())
- }
-}
-
-/**
- * A negative characteristic that filters out non-public methods. Non-public methods are not interesting to include in
- * the standard Java modeling, because they cannot be called from outside the package.
- */
-private class NonPublicMethodCharacteristic extends CharacteristicsImpl::UninterestingToModelCharacteristic
-{
- NonPublicMethodCharacteristic() { this = "non-public method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- exists(Callable c | c = e.getCallable() | not c.isPublic())
- }
-}
-
-/**
- * A negative characteristic that indicates that an endpoint is a non-sink argument to a method whose sinks have already
- * been modeled _manually_. This is restricted to manual sinks only, because only during the manual process do we have
- * the expectation that all sinks present in a method have been considered.
- *
- * WARNING: These endpoints should not be used as negative samples for training, because some sinks may have been missed
- * when the method was modeled. Specifically, as we start using ATM to merge in new declarations, we can be less sure
- * that a method with one argument modeled as a MaD sink has also had its remaining arguments manually reviewed. The
- * ML model might have predicted argument 0 of some method to be a sink but not argument 1, when in fact argument 1 is
- * also a sink.
- */
-private class OtherArgumentToModeledMethodCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic
-{
- OtherArgumentToModeledMethodCharacteristic() {
- this = "other argument to a method that has already been modeled manually"
- }
-
- override predicate appliesToEndpoint(Endpoint e) {
- not ApplicationCandidatesImpl::isSink(e, _, _) and
- exists(CallArgument otherSink |
- ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and
- e.(CallArgument).getCall() = otherSink.getCall() and
- e != otherSink
- )
- }
-}
-
-/**
- * Holds if the type of the given expression is annotated with `@FunctionalInterface`.
- */
-predicate hasFunctionalInterfaceType(Expr e) {
- exists(RefType tp | tp = e.getType().getErasure() |
- tp.getAnAssociatedAnnotation().getType().hasQualifiedName("java.lang", "FunctionalInterface")
- )
-}
-
-/**
- * A characteristic that marks functional expression as likely not sinks.
- *
- * These expressions may well _contain_ sinks, but rarely are sinks themselves.
- */
-private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
- FunctionValueCharacteristic() { this = "function value" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- exists(Expr expr | expr = e.asNode().asExpr() |
- expr instanceof FunctionalExpr or hasFunctionalInterfaceType(expr)
- )
- }
-}
-
-/**
- * A negative characteristic that indicates that an endpoint is not a `to` node for any known taint step. Such a node
- * cannot be tainted, because taint can't flow into it.
- *
- * WARNING: These endpoints should not be used as negative samples for training, because they may include sinks for
- * which our taint tracking modeling is incomplete.
- */
-private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic
-{
- CannotBeTaintedCharacteristic() { this = "cannot be tainted" }
-
- override predicate appliesToEndpoint(Endpoint e) { not this.isKnownOutNodeForStep(e) }
-
- /**
- * Holds if the node `n` is known as the predecessor in a modeled flow step.
- */
- private predicate isKnownOutNodeForStep(Endpoint e) {
- e.asNode().asExpr() instanceof Call or // we just assume flow in that case
- TaintTracking::localTaintStep(_, e.asNode()) or
- FlowSummaryImpl::Private::Steps::summaryThroughStepValue(_, e.asNode(), _) or
- FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(_, e.asNode(), _) or
- FlowSummaryImpl::Private::Steps::summaryGetterStep(_, _, e.asNode(), _) or
- FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e.asNode(), _)
- }
-}
diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql
deleted file mode 100644
index a3fa8b9b46f..00000000000
--- a/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for
- * classification with an ML model.
- *
- * Note: This query does not actually classify the endpoints using the model.
- *
- * @name Automodel candidates (application mode)
- * @description A query to extract automodel candidates in application mode.
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-application-candidates
- * @tags internal extract automodel application-mode candidates
- */
-
-import java
-private import AutomodelApplicationModeCharacteristics
-private import AutomodelJavaUtil
-
-/**
- * Gets a sample of endpoints (of at most `limit` samples) with the given method signature.
- *
- * The main purpose of this helper predicate is to avoid selecting too many candidates, as this may
- * cause the SARIF file to exceed the maximum size limit.
- */
-bindingset[limit]
-private Endpoint getSampleForSignature(
- int limit, string package, string type, string subtypes, string name, string signature,
- string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
-) {
- exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
- num_endpoints =
- count(Endpoint e |
- meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
- alreadyAiModeled, extensibleType)
- )
- |
- result =
- rank[n](Endpoint e, Location loc |
- loc = e.asTop().getLocation() and
- meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
- alreadyAiModeled, extensibleType)
- |
- e
- order by
- loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(),
- loc.getEndLine(), loc.getEndColumn()
- ) and
- // To avoid selecting samples that are too close together (as the ranking above goes by file
- // path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By
- // default this would always include the first sample, so we add a random-chosen prime offset
- // to the first sample index, and reduce modulo the number of endpoints.
- // Finally, we add 1 to the result, as ranking results in a 1-indexed relation.
- n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints)
- )
-}
-
-from
- Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
- DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output,
- DollarAtString isVarargsArray, DollarAtString alreadyAiModeled, DollarAtString extensibleType
-where
- isCandidate(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray,
- extensibleType, alreadyAiModeled) and
- endpoint =
- getSampleForSignature(9, package, type, subtypes, name, signature, input, output,
- isVarargsArray, extensibleType, alreadyAiModeled)
-select endpoint.asNode(),
- "Related locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", // method name
- signature, "signature", //
- input, "input", //
- output, "output", //
- isVarargsArray, "isVarargsArray", //
- alreadyAiModeled, "alreadyAiModeled", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql
deleted file mode 100644
index a399c413fa4..00000000000
--- a/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt.
- *
- * @name Negative examples (application mode)
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-application-negative-examples
- * @tags internal extract automodel application-mode negative examples
- */
-
-private import java
-private import AutomodelApplicationModeCharacteristics
-private import AutomodelEndpointTypes
-private import AutomodelJavaUtil
-
-/**
- * Gets a sample of endpoints (of at most `limit` samples) for which the given characteristic applies.
- *
- * The main purpose of this helper predicate is to avoid selecting too many samples, as this may
- * cause the SARIF file to exceed the maximum size limit.
- */
-bindingset[limit]
-Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) {
- exists(int n, int num_endpoints | num_endpoints = count(Endpoint e | c.appliesToEndpoint(e)) |
- result =
- rank[n](Endpoint e, Location loc |
- loc = e.asTop().getLocation() and c.appliesToEndpoint(e)
- |
- e
- order by
- loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(),
- loc.getEndLine(), loc.getEndColumn()
- ) and
- // To avoid selecting samples that are too close together (as the ranking above goes by file
- // path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By
- // default this would always include the first sample, so we add a random-chosen prime offset
- // to the first sample index, and reduce modulo the number of endpoints.
- // Finally, we add 1 to the result, as ranking results in a 1-indexed relation.
- n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints)
- )
-}
-
-from
- Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
- DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
- DollarAtString signature, DollarAtString input, DollarAtString output,
- DollarAtString isVarargsArray, DollarAtString extensibleType
-where
- endpoint = getSampleForCharacteristic(characteristic, 100) and
- isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
- input, output, isVarargsArray, extensibleType) and
- message = characteristic
-select endpoint.asNode(),
- message + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", //
- signature, "signature", //
- input, "input", //
- output, "output", //
- isVarargsArray, "isVarargsArray", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql
deleted file mode 100644
index faf49b73fc1..00000000000
--- a/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt.
- *
- * @name Positive examples (application mode)
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-application-positive-examples
- * @tags internal extract automodel application-mode positive examples
- */
-
-private import AutomodelApplicationModeCharacteristics
-private import AutomodelEndpointTypes
-private import AutomodelJavaUtil
-
-from
- Endpoint endpoint, EndpointType endpointType, ApplicationModeMetadataExtractor meta,
- DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
- DollarAtString signature, DollarAtString input, DollarAtString output,
- DollarAtString isVarargsArray, DollarAtString extensibleType
-where
- isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
- isVarargsArray, extensibleType)
-select endpoint.asNode(),
- endpointType + "\nrelated locations: $@, $@, $@." +
- "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", //
- signature, "signature", //
- input, "input", //
- output, "output", //
- isVarargsArray, "isVarargsArray", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelCandidateFilter.yml b/java/ql/automodel/src/AutomodelCandidateFilter.yml
deleted file mode 100644
index c945ae3206f..00000000000
--- a/java/ql/automodel/src/AutomodelCandidateFilter.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-automodel-queries
- extensible: automodelCandidateFilter
- data: []
diff --git a/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql b/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql
deleted file mode 100644
index 475e3753810..00000000000
--- a/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @name Number of instances of each sink model
- * @description Counts the number of instances of `ai-generated` sink models.
- * @kind table
- * @id java/ml/metrics-count-instances-per-sink-model
- * @tags internal automodel metrics
- */
-
-private import java
-private import AutomodelAlertSinkUtil
-
-from int instanceCount, SinkModel s
-where
- instanceCount = s.getInstanceCount() and
- instanceCount > 0 and
- s.getProvenance() = "ai-generated"
-select instanceCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes,
- s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext,
- s.getKind() as kind, s.getProvenance() as provenance order by instanceCount desc
diff --git a/java/ql/automodel/src/AutomodelEndpointTypes.qll b/java/ql/automodel/src/AutomodelEndpointTypes.qll
deleted file mode 100644
index f4f7bc8eb7b..00000000000
--- a/java/ql/automodel/src/AutomodelEndpointTypes.qll
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * For internal use only.
- *
- * Defines the set of classes that endpoint scoring models can predict. Endpoint scoring models must
- * only predict classes defined within this file. This file is the source of truth for the integer
- * representation of each of these classes.
- */
-
-/** A class that can be predicted by a classifier. */
-abstract class EndpointType extends string {
- /**
- * Holds when the string matches the name of the sink / source type.
- */
- bindingset[this]
- EndpointType() { any() }
-
- /**
- * Gets the name of the sink/source kind for this endpoint type as used in models-as-data.
- *
- * See https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#LL353C11-L357C31
- * for sink types, and https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#L365
- * for source types.
- */
- final string getKind() { result = this }
-}
-
-/** A class for sink types that can be predicted by a classifier. */
-abstract class SinkType extends EndpointType {
- bindingset[this]
- SinkType() { any() }
-}
-
-/** A sink relevant to the SQL injection query */
-class SqlInjectionSinkType extends SinkType {
- SqlInjectionSinkType() { this = "sql-injection" }
-}
-
-/** A sink relevant to the tainted path injection query. */
-class PathInjectionSinkType extends SinkType {
- PathInjectionSinkType() { this = "path-injection" }
-}
-
-/** A sink relevant to the SSRF query. */
-class RequestForgerySinkType extends SinkType {
- RequestForgerySinkType() { this = "request-forgery" }
-}
-
-/** A sink relevant to the command injection query. */
-class CommandInjectionSinkType extends SinkType {
- CommandInjectionSinkType() { this = "command-injection" }
-}
-
-/** A sink relevant to file storage. */
-class FileContentStoreSinkType extends SinkType {
- FileContentStoreSinkType() { this = "file-content-store" }
-}
-
-/** A sink relevant to HTML injection. */
-class HtmlInjectionSinkType extends SinkType {
- HtmlInjectionSinkType() { this = "html-injection" }
-}
-
-/** A sink relevant to LDAP injection. */
-class LdapInjectionSinkType extends SinkType {
- LdapInjectionSinkType() { this = "ldap-injection" }
-}
-
-/** A sink relevant to URL redirection. */
-class UrlRedirectionSinkType extends SinkType {
- UrlRedirectionSinkType() { this = "url-redirection" }
-}
-
-/** A class for source types that can be predicted by a classifier. */
-abstract class SourceType extends EndpointType {
- bindingset[this]
- SourceType() { any() }
-}
-
-/** A source of remote data. */
-class RemoteSourceType extends SourceType {
- RemoteSourceType() { this = "remote" }
-}
diff --git a/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll b/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll
deleted file mode 100644
index 7f385a41d1e..00000000000
--- a/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll
+++ /dev/null
@@ -1,507 +0,0 @@
-/**
- * For internal use only.
- */
-
-private import java
-private import semmle.code.Location as Location
-private import semmle.code.java.dataflow.DataFlow
-private import semmle.code.java.dataflow.TaintTracking
-private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
-private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
-private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
-private import semmle.code.java.Expr as Expr
-private import semmle.code.java.security.QueryInjection
-private import semmle.code.java.security.RequestForgery
-private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
-private import AutomodelJavaUtil as AutomodelJavaUtil
-import AutomodelSharedCharacteristics as SharedCharacteristics
-import AutomodelEndpointTypes as AutomodelEndpointTypes
-
-newtype JavaRelatedLocationType =
- MethodDoc() or
- ClassDoc()
-
-newtype TFrameworkModeEndpoint =
- TExplicitParameter(Parameter p) {
- AutomodelJavaUtil::isFromSource(p) and
- not AutomodelJavaUtil::isUnexploitableType(p.getType())
- } or
- TQualifier(Callable c) { AutomodelJavaUtil::isFromSource(c) and not c instanceof Constructor } or
- TReturnValue(Callable c) {
- AutomodelJavaUtil::isFromSource(c) and
- c instanceof Constructor
- or
- AutomodelJavaUtil::isFromSource(c) and
- c instanceof Method and
- not AutomodelJavaUtil::isUnexploitableType(c.getReturnType())
- } or
- TOverridableParameter(Method m, Parameter p) {
- AutomodelJavaUtil::isFromSource(p) and
- not AutomodelJavaUtil::isUnexploitableType(p.getType()) and
- p.getCallable() = m and
- m instanceof ModelExclusions::ModelApi and
- AutomodelJavaUtil::isOverridable(m)
- } or
- TOverridableQualifier(Method m) {
- AutomodelJavaUtil::isFromSource(m) and
- m instanceof ModelExclusions::ModelApi and
- AutomodelJavaUtil::isOverridable(m)
- }
-
-/**
- * A framework mode endpoint.
- */
-abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
- /**
- * Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
- *
- * For endpoints that are source candidates, this will be `none()`.
- */
- abstract string getMaDInput();
-
- /**
- * Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
- *
- * For endpoints that are sink candidates, this will be `none()`.
- */
- abstract string getMaDOutput();
-
- /**
- * Returns the name of the parameter of the endpoint.
- */
- abstract string getParamName();
-
- /**
- * Returns the callable that contains the endpoint.
- */
- abstract Callable getCallable();
-
- abstract Top asTop();
-
- abstract string getExtensibleType();
-
- string toString() { result = this.asTop().toString() }
-
- Location getLocation() { result = this.asTop().getLocation() }
-}
-
-class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParameter {
- Parameter param;
-
- ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() }
-
- override string getMaDInput() { result = "Argument[" + param.getPosition() + "]" }
-
- override string getMaDOutput() { none() }
-
- override string getParamName() { result = param.getName() }
-
- override Callable getCallable() { result = param.getCallable() }
-
- override Top asTop() { result = param }
-
- override string getExtensibleType() { result = "sinkModel" }
-}
-
-class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
- Callable callable;
-
- QualifierEndpoint() {
- this = TQualifier(callable) and not callable.isStatic() and callable.fromSource()
- }
-
- override string getMaDInput() { result = "Argument[this]" }
-
- override string getMaDOutput() { none() }
-
- override string getParamName() { result = "this" }
-
- override Callable getCallable() { result = callable }
-
- override Top asTop() { result = callable }
-
- override string getExtensibleType() { result = "sinkModel" }
-}
-
-class ReturnValue extends FrameworkModeEndpoint, TReturnValue {
- Callable callable;
-
- ReturnValue() { this = TReturnValue(callable) and callable.fromSource() }
-
- override string getMaDInput() { none() }
-
- override string getMaDOutput() { result = "ReturnValue" }
-
- override string getParamName() { none() }
-
- override Callable getCallable() { result = callable }
-
- override Top asTop() { result = callable }
-
- override string getExtensibleType() { result = "sourceModel" }
-}
-
-class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter {
- Method method;
- Parameter param;
-
- OverridableParameter() { this = TOverridableParameter(method, param) }
-
- override string getMaDInput() { none() }
-
- override string getMaDOutput() { result = "Parameter[" + param.getPosition() + "]" }
-
- override string getParamName() { result = param.getName() }
-
- override Callable getCallable() { result = method }
-
- override Top asTop() { result = param }
-
- override string getExtensibleType() { result = "sourceModel" }
-}
-
-class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier {
- Method m;
-
- OverridableQualifier() { this = TOverridableQualifier(m) }
-
- override string getMaDInput() { none() }
-
- override string getMaDOutput() { result = "Parameter[this]" }
-
- override string getParamName() { result = "this" }
-
- override Callable getCallable() { result = m }
-
- override Top asTop() { result = m }
-
- override string getExtensibleType() { result = "sourceModel" }
-}
-
-/**
- * A candidates implementation for framework mode.
- *
- * Some important notes:
- * - This mode is using parameters as endpoints.
- * - Sink- and neutral-information is being used from MaD models.
- * - When available, we use method- and class-java-docs as related locations.
- */
-module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
- // for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
- class Endpoint = FrameworkModeEndpoint;
-
- class EndpointType = AutomodelEndpointTypes::EndpointType;
-
- class SinkType = AutomodelEndpointTypes::SinkType;
-
- class SourceType = AutomodelEndpointTypes::SourceType;
-
- class RelatedLocation = Location::Top;
-
- class RelatedLocationType = JavaRelatedLocationType;
-
- // Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
- predicate isSanitizer(Endpoint e, EndpointType t) { none() }
-
- RelatedLocation asLocation(Endpoint e) { result = e.asTop() }
-
- predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
-
- predicate isSink(Endpoint e, string kind, string provenance) {
- exists(
- string package, string type, boolean subtypes, string name, string signature, string ext,
- string input
- |
- sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
- ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
- provenance, _)
- )
- }
-
- predicate isSource(Endpoint e, string kind, string provenance) {
- exists(
- string package, string type, boolean subtypes, string name, string signature, string ext,
- string output
- |
- sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
- ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
- provenance, _)
- )
- }
-
- predicate isNeutral(Endpoint e) {
- exists(string package, string type, string name, string signature, string endpointType |
- sinkSpec(e, package, type, _, name, signature, _, _) and
- endpointType = "sink"
- or
- sourceSpec(e, package, type, _, name, signature, _, _) and
- endpointType = "source"
- |
- ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _)
- )
- }
-
- /**
- * Holds if the endpoint concerns a callable with the given package, type, name and signature.
- *
- * If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and
- * all its overrides are considered.
- */
- additional predicate endpointCallable(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature
- ) {
- exists(Callable c |
- c = e.getCallable() and subtypes in [true, false]
- or
- e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true
- |
- c.hasQualifiedName(package, type, name) and
- signature = ExternalFlow::paramsString(c)
- )
- }
-
- additional predicate sinkSpec(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature,
- string ext, string input
- ) {
- endpointCallable(e, package, type, subtypes, name, signature) and
- ext = "" and
- input = e.getMaDInput()
- }
-
- additional predicate sourceSpec(
- Endpoint e, string package, string type, boolean subtypes, string name, string signature,
- string ext, string output
- ) {
- endpointCallable(e, package, type, subtypes, name, signature) and
- ext = "" and
- output = e.getMaDOutput()
- }
-
- /**
- * Gets the related location for the given endpoint.
- *
- * Related locations can be JavaDoc comments of the class or the method.
- */
- RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
- type = MethodDoc() and
- result = e.getCallable().(Documentable).getJavadoc()
- or
- type = ClassDoc() and
- result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
- }
-}
-
-module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics;
-
-class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
-
-class Endpoint = FrameworkCandidatesImpl::Endpoint;
-
-/*
- * Predicates that are used to surface prompt examples and candidates for classification with an ML model.
- */
-
-/**
- * A MetadataExtractor that extracts metadata for framework mode.
- */
-class FrameworkModeMetadataExtractor extends string {
- FrameworkModeMetadataExtractor() { this = "FrameworkModeMetadataExtractor" }
-
- predicate hasMetadata(
- Endpoint e, string package, string type, string subtypes, string name, string signature,
- string input, string output, string parameterName, string alreadyAiModeled,
- string extensibleType
- ) {
- exists(Callable callable | e.getCallable() = callable |
- (if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
- (if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
- package = callable.getDeclaringType().getPackage().getName() and
- // we're using the erased types because the MaD convention is to not specify type parameters.
- // Whether something is or isn't a sink doesn't usually depend on the type parameters.
- type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
- subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
- name = callable.getName() and
- signature = ExternalFlow::paramsString(callable) and
- (if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and
- e.getExtensibleType() = extensibleType
- ) and
- (
- not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
- or
- CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
- )
- }
-}
-
-/**
- * Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isCandidate(
- Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
- string input, string output, string parameterName, string extensibleType, string alreadyAiModeled
-) {
- CharacteristicsImpl::isCandidate(endpoint, _) and
- not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
- u.appliesToEndpoint(endpoint)
- ) and
- any(FrameworkModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
- alreadyAiModeled, extensibleType) and
- // If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a
- // candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's
- // already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We
- // assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink
- // types, and we don't need to reexamine it.
- alreadyAiModeled.matches(["", "%ai-%"]) and
- AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
-}
-
-/**
- * Holds if the given `endpoint` is a negative example for the `extensibleType`
- * because of the `characteristic`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isNegativeExample(
- Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
- string type, string subtypes, string name, string signature, string input, string output,
- string parameterName, string extensibleType
-) {
- characteristic.appliesToEndpoint(endpoint) and
- // the node is known not to be an endpoint of any appropriate type
- forall(AutomodelEndpointTypes::EndpointType tp |
- tp = CharacteristicsImpl::getAPotentialType(endpoint)
- |
- characteristic.hasImplications(tp, false, _)
- ) and
- // the lowest confidence across all endpoint types should be at least highConfidence
- confidence =
- min(float c |
- characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
- ) and
- confidence >= SharedCharacteristics::highConfidence() and
- any(FrameworkModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
- _, extensibleType) and
- // It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
- // as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
- not exists(EndpointCharacteristic characteristic2, float confidence2 |
- characteristic2 != characteristic
- |
- characteristic2.appliesToEndpoint(endpoint) and
- confidence2 >= SharedCharacteristics::maximalConfidence() and
- characteristic2
- .hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
- )
-}
-
-/**
- * Holds if the given `endpoint` is a positive example for the `endpointType`.
- *
- * The other parameters record various other properties of interest.
- */
-predicate isPositiveExample(
- Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
- string signature, string input, string output, string parameterName, string extensibleType
-) {
- any(FrameworkModeMetadataExtractor meta)
- .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
- _, extensibleType) and
- CharacteristicsImpl::isKnownAs(endpoint, endpointType, _)
-}
-
-/*
- * EndpointCharacteristic classes that are specific to Automodel for Java.
- */
-
-/**
- * A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks,
- * and its return value should not be considered a source.
- *
- * A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
- * type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
- * the dangerous/interesting thing, so we want the latter to be modeled as the sink.
- *
- * TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
- */
-private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
-{
- UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- e.getCallable().getName().matches("is%") and
- e.getCallable().getReturnType() instanceof BooleanType and
- (
- e.getExtensibleType() = "sinkModel" and
- not FrameworkCandidatesImpl::isSink(e, _, _)
- or
- e.getExtensibleType() = "sourceModel" and
- not FrameworkCandidatesImpl::isSource(e, _, _) and
- e.getMaDOutput() = "ReturnValue"
- )
- }
-}
-
-/**
- * A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
- * considered sinks, and its return value should not be considered a source.
- *
- * A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
- * boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
- * dangerous/interesting thing, so we want the latter to be modeled as the sink.
- */
-private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
-{
- UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- exists(Callable callable |
- callable = e.getCallable() and
- callable.getName().toLowerCase() = ["exists", "notexists"] and
- callable.getReturnType() instanceof BooleanType
- |
- e.getExtensibleType() = "sinkModel" and
- not FrameworkCandidatesImpl::isSink(e, _, _)
- or
- e.getExtensibleType() = "sourceModel" and
- not FrameworkCandidatesImpl::isSource(e, _, _) and
- e.getMaDOutput() = "ReturnValue"
- )
- }
-}
-
-/**
- * A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
- * and its return value should not be considered a source.
- */
-private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
-{
- ExceptionCharacteristic() { this = "argument/result of exception-related method" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
- (
- e.getExtensibleType() = "sinkModel" and
- not FrameworkCandidatesImpl::isSink(e, _, _)
- or
- e.getExtensibleType() = "sourceModel" and
- not FrameworkCandidatesImpl::isSource(e, _, _) and
- e.getMaDOutput() = "ReturnValue"
- )
- }
-}
-
-/**
- * A characteristic that limits candidates to parameters of methods that are recognized as `ModelApi`, iow., APIs that
- * are considered worth modeling.
- */
-private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelCharacteristic {
- NotAModelApi() { this = "not a model API" }
-
- override predicate appliesToEndpoint(Endpoint e) {
- not e.getCallable() instanceof ModelExclusions::ModelApi
- }
-}
diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql
deleted file mode 100644
index 83683b4e78f..00000000000
--- a/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for
- * classification with an ML model.
- *
- * Note: This query does not actually classify the endpoints using the model.
- *
- * @name Automodel candidates (framework mode)
- * @description A query to extract automodel candidates in framework mode.
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-framework-candidates
- * @tags internal extract automodel framework-mode candidates
- */
-
-private import AutomodelFrameworkModeCharacteristics
-private import AutomodelJavaUtil
-
-from
- Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
- DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output,
- DollarAtString parameterName, DollarAtString alreadyAiModeled, DollarAtString extensibleType
-where
- isCandidate(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
- extensibleType, alreadyAiModeled)
-select endpoint,
- "Related locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", //
- signature, "signature", //
- input, "input", //
- output, "output", //
- parameterName, "parameterName", //
- alreadyAiModeled, "alreadyAiModeled", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql
deleted file mode 100644
index 05e5951b061..00000000000
--- a/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt.
- *
- * @name Negative examples (framework mode)
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-framework-negative-examples
- * @tags internal extract automodel framework-mode negative examples
- */
-
-private import AutomodelFrameworkModeCharacteristics
-private import AutomodelEndpointTypes
-private import AutomodelJavaUtil
-
-from
- Endpoint endpoint, EndpointCharacteristic characteristic, float confidence,
- DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
- DollarAtString signature, DollarAtString input, DollarAtString output,
- DollarAtString parameterName, DollarAtString extensibleType
-where
- isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
- input, output, parameterName, extensibleType)
-select endpoint,
- characteristic + "\nrelated locations: $@, $@." +
- "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", //
- signature, "signature", //
- input, "input", //
- output, "output", //
- parameterName, "parameterName", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql
deleted file mode 100644
index 7cb023949ed..00000000000
--- a/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt.
- *
- * @name Positive examples (framework mode)
- * @kind problem
- * @problem.severity recommendation
- * @id java/ml/extract-automodel-framework-positive-examples
- * @tags internal extract automodel framework-mode positive examples
- */
-
-private import AutomodelFrameworkModeCharacteristics
-private import AutomodelEndpointTypes
-private import AutomodelJavaUtil
-
-from
- Endpoint endpoint, EndpointType endpointType, DollarAtString package, DollarAtString type,
- DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
- DollarAtString output, DollarAtString parameterName, DollarAtString extensibleType
-where
- isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
- parameterName, extensibleType)
-select endpoint,
- endpointType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
- CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
- package, "package", //
- type, "type", //
- subtypes, "subtypes", //
- name, "name", //
- signature, "signature", //
- input, "input", //
- output, "output", //
- parameterName, "parameterName", //
- extensibleType, "extensibleType"
diff --git a/java/ql/automodel/src/AutomodelJavaUtil.qll b/java/ql/automodel/src/AutomodelJavaUtil.qll
deleted file mode 100644
index 368fb172483..00000000000
--- a/java/ql/automodel/src/AutomodelJavaUtil.qll
+++ /dev/null
@@ -1,111 +0,0 @@
-private import java
-private import AutomodelEndpointTypes as AutomodelEndpointTypes
-
-/**
- * A helper class to represent a string value that can be returned by a query using $@ notation.
- *
- * It extends `string`, but adds a mock `hasLocationInfo` method that returns the string itself as the file name.
- *
- * Use this, when you want to return a string value from a query using $@ notation - the string value
- * will be included in the sarif file.
- *
- *
- * Background information on `hasLocationInfo`:
- * https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-location-information
- */
-class DollarAtString extends string {
- bindingset[this]
- DollarAtString() { any() }
-
- bindingset[this]
- predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
- path = this and sl = 1 and sc = 1 and el = 1 and ec = 1
- }
-}
-
-/**
- * Holds for all combinations of MaD kinds (`kind`) and their human readable
- * descriptions.
- */
-predicate isKnownKind(string kind, AutomodelEndpointTypes::EndpointType type) {
- kind = type.getKind()
-}
-
-/**
- * By convention, the subtypes property of the MaD declaration should only be
- * true when there _can_ exist any subtypes with a different implementation.
- *
- * It would technically be ok to always use the value 'true', but this would
- * break convention.
- */
-pragma[nomagic]
-boolean considerSubtypes(Callable callable) {
- if
- callable.isStatic() or
- callable.getDeclaringType().isStatic() or
- callable.isFinal() or
- callable.getDeclaringType().isFinal()
- then result = false
- else result = true
-}
-
-/**
- * Holds if the given package, type, name and signature is a candidate for automodeling.
- *
- * This predicate is extensible, so that different endpoints can be selected at runtime.
- */
-extensible predicate automodelCandidateFilter(
- string package, string type, string name, string signature
-);
-
-/**
- * Holds if the given package, type, name and signature is a candidate for automodeling.
- *
- * This relies on an extensible predicate, and if that is not supplied then
- * all endpoints are considered candidates.
- */
-bindingset[package, type, name, signature]
-predicate includeAutomodelCandidate(string package, string type, string name, string signature) {
- not automodelCandidateFilter(_, _, _, _) or
- automodelCandidateFilter(package, type, name, signature)
-}
-
-/**
- * Holds if the given program element corresponds to a piece of source code,
- * that is, it is not compiler-generated.
- *
- * Note: This is a stricter check than `Element::fromSource`, which simply
- * checks whether the element is in a source file as opposed to a JAR file.
- * There can be compiler-generated elements in source files (especially for
- * Kotlin), which we also want to exclude.
- */
-predicate isFromSource(Element e) {
- // from a source file (not a JAR)
- e.fromSource() and
- // not explicitly marked as compiler-generated
- not e.isCompilerGenerated() and
- // does not have a dummy location
- not e.hasLocationInfo(_, 0, 0, 0, 0)
-}
-
-/**
- * Holds if taint cannot flow through the given type (because it is a numeric
- * type or some other type with a fixed set of values).
- */
-predicate isUnexploitableType(Type tp) {
- tp instanceof PrimitiveType or
- tp instanceof BoxedType or
- tp instanceof NumberType or
- tp instanceof VoidType
-}
-
-/**
- * Holds if the given method can be overridden, that is, it is not final,
- * static, or private.
- */
-predicate isOverridable(Method m) {
- not m.getDeclaringType().isFinal() and
- not m.isFinal() and
- not m.isStatic() and
- not m.isPrivate()
-}
diff --git a/java/ql/automodel/src/AutomodelSharedCharacteristics.qll b/java/ql/automodel/src/AutomodelSharedCharacteristics.qll
deleted file mode 100644
index 273c5d30dec..00000000000
--- a/java/ql/automodel/src/AutomodelSharedCharacteristics.qll
+++ /dev/null
@@ -1,412 +0,0 @@
-float maximalConfidence() { result = 1.0 }
-
-float highConfidence() { result = 0.9 }
-
-float mediumConfidence() { result = 0.6 }
-
-/**
- * A specification of how to instantiate the shared characteristics for a given candidate class.
- *
- * The `CandidateSig` implementation specifies a type to use for Endpoints (eg., `ParameterNode`), as well as a type
- * to label endpoint classes (the `EndpointType`). One of the endpoint classes needs to be a 'negative' class, meaning
- * "not any of the other known endpoint types".
- */
-signature module CandidateSig {
- /**
- * An endpoint is a potential candidate for modeling. This will typically be bound to the language's
- * DataFlow node class, or a subtype thereof.
- */
- class Endpoint {
- /**
- * Gets the kind of this endpoint, either "sourceModel" or "sinkModel".
- */
- string getExtensibleType();
-
- /**
- * Gets a string representation of this endpoint.
- */
- string toString();
- }
-
- /**
- * A related location for an endpoint. This will typically be bound to the supertype of all AST nodes (eg., `Top`).
- */
- class RelatedLocation;
-
- /**
- * A label for a related location.
- *
- * Eg., method-doc, class-doc, etc.
- */
- class RelatedLocationType;
-
- /**
- * An endpoint type considered by this specification.
- */
- class EndpointType extends string;
-
- /**
- * A sink endpoint type considered by this specification.
- */
- class SinkType extends EndpointType;
-
- /**
- * A source endpoint type considered by this specification.
- */
- class SourceType extends EndpointType;
-
- /**
- * Gets the endpoint as a location.
- *
- * This is a utility function to convert an endpoint to its corresponding location.
- */
- RelatedLocation asLocation(Endpoint e);
-
- /**
- * Defines what MaD kinds are known, and what endpoint type they correspond to.
- */
- predicate isKnownKind(string kind, EndpointType type);
-
- /**
- * Holds if `e` is a flow sanitizer, and has type `t`.
- */
- predicate isSanitizer(Endpoint e, EndpointType t);
-
- /**
- * Holds if `e` is a sink with the label `kind`, and provenance `provenance`.
- */
- predicate isSink(Endpoint e, string kind, string provenance);
-
- /**
- * Holds if `e` is a source with the label `kind`, and provenance `provenance`.
- */
- predicate isSource(Endpoint e, string kind, string provenance);
-
- /**
- * Holds if `e` is not a source or sink of any kind.
- */
- predicate isNeutral(Endpoint e);
-
- /**
- * Gets a related location.
- *
- * A related location is a source code location that may hold extra information about an endpoint that can be useful
- * to the machine learning model.
- *
- * For example, a related location for a method call may be the documentation comment of a method.
- */
- RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType name);
-}
-
-/**
- * A set of shared characteristics for a given candidate class.
- *
- * This module is language-agnostic, although the `CandidateSig` module will be language-specific.
- *
- * The language specific implementation can also further extend the behavior of this module by adding additional
- * implementations of endpoint characteristics exported by this module.
- */
-module SharedCharacteristics {
- predicate isSink = Candidate::isSink/3;
-
- predicate isNeutral = Candidate::isNeutral/1;
-
- predicate isModeled(Candidate::Endpoint e, string kind, string extensibleKind, string provenance) {
- Candidate::isSink(e, kind, provenance) and extensibleKind = "sinkModel"
- or
- Candidate::isSource(e, kind, provenance) and extensibleKind = "sourceModel"
- }
-
- /**
- * Holds if `endpoint` is modeled as `endpointType`.
- */
- predicate isKnownAs(
- Candidate::Endpoint endpoint, Candidate::EndpointType endpointType,
- EndpointCharacteristic characteristic
- ) {
- // If the list of characteristics includes positive indicators with maximal confidence for this class, then it's a
- // known sink for the class.
- characteristic.appliesToEndpoint(endpoint) and
- characteristic.hasImplications(endpointType, true, maximalConfidence())
- }
-
- /**
- * Gets a potential type of this endpoint to make sure that sources are
- * associated with source types and sinks with sink types.
- */
- Candidate::EndpointType getAPotentialType(Candidate::Endpoint endpoint) {
- endpoint.getExtensibleType() = "sourceModel" and
- result instanceof Candidate::SourceType
- or
- endpoint.getExtensibleType() = "sinkModel" and
- result instanceof Candidate::SinkType
- }
-
- /**
- * Holds if the given `endpoint` should be considered as a candidate for type `endpointType`,
- * and classified by the ML model.
- *
- * A candidate is an endpoint that cannot be excluded from `endpointType` based on its characteristics.
- */
- predicate isCandidate(Candidate::Endpoint endpoint, Candidate::EndpointType endpointType) {
- endpointType = getAPotentialType(endpoint) and
- not exists(getAnExcludingCharacteristic(endpoint, endpointType))
- }
-
- /**
- * Gets the related location of `e` with name `name`, if it exists.
- * Otherwise, gets the candidate itself.
- */
- Candidate::RelatedLocation getRelatedLocationOrCandidate(
- Candidate::Endpoint e, Candidate::RelatedLocationType type
- ) {
- if exists(Candidate::getRelatedLocation(e, type))
- then result = Candidate::getRelatedLocation(e, type)
- else result = Candidate::asLocation(e)
- }
-
- /**
- * Gets a characteristics that disbar `endpoint` from being a candidate for `endpointType`
- * with at least medium confidence.
- */
- EndpointCharacteristic getAnExcludingCharacteristic(
- Candidate::Endpoint endpoint, Candidate::EndpointType endpointType
- ) {
- result.appliesToEndpoint(endpoint) and
- exists(float confidence |
- confidence >= mediumConfidence() and
- result.hasImplications(endpointType, false, confidence)
- )
- }
-
- /**
- * A set of characteristics that a particular endpoint might have. This set of characteristics is used to make decisions
- * about whether to include the endpoint in the training set and with what kind, as well as whether to score the
- * endpoint at inference time.
- */
- abstract class EndpointCharacteristic extends string {
- /**
- * Holds for the string that is the name of the characteristic. This should describe some property of an endpoint
- * that is meaningful for determining whether it's a sink, and if so, of which sink type.
- */
- bindingset[this]
- EndpointCharacteristic() { any() }
-
- /**
- * Holds for endpoints that have this characteristic.
- */
- abstract predicate appliesToEndpoint(Candidate::Endpoint n);
-
- /**
- * This predicate describes what the characteristic tells us about an endpoint.
- *
- * Params:
- * endpointType: The sink/source type.
- * isPositiveIndicator: If true, this characteristic indicates that this endpoint _is_ a member of the class; if
- * false, it indicates that it _isn't_ a member of the class.
- * confidence: A float in [0, 1], which tells us how strong an indicator this characteristic is for the endpoint
- * belonging / not belonging to the given class. A confidence near zero means this characteristic is a very weak
- * indicator of whether or not the endpoint belongs to the class. A confidence of 1 means that all endpoints with
- * this characteristic definitively do/don't belong to the class.
- */
- abstract predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- );
-
- /** Indicators with confidence at or above this threshold are considered to be high-confidence indicators. */
- final float getHighConfidenceThreshold() { result = 0.8 }
- }
-
- /**
- * A high-confidence characteristic that indicates that an endpoint is a sink of a specified type. These endpoints can
- * be used as positive samples for training or for a few-shot prompt.
- */
- abstract class SinkCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- SinkCharacteristic() { any() }
-
- abstract Candidate::EndpointType getSinkType();
-
- final override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType = this.getSinkType() and
- isPositiveIndicator = true and
- confidence = maximalConfidence()
- }
- }
-
- /**
- * A high-confidence characteristic that indicates that an endpoint is a source of a specified type. These endpoints can
- * be used as positive samples for training or for a few-shot prompt.
- */
- abstract class SourceCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- SourceCharacteristic() { any() }
-
- abstract Candidate::EndpointType getSourceType();
-
- final override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType = this.getSourceType() and
- isPositiveIndicator = true and
- confidence = maximalConfidence()
- }
- }
-
- /**
- * A high-confidence characteristic that indicates that an endpoint is not a sink of any type. These endpoints can be
- * used as negative samples for training or for a few-shot prompt.
- */
- abstract class NotASinkCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- NotASinkCharacteristic() { any() }
-
- override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType instanceof Candidate::SinkType and
- isPositiveIndicator = false and
- confidence = highConfidence()
- }
- }
-
- /**
- * A high-confidence characteristic that indicates that an endpoint is not a source of any type. These endpoints can be
- * used as negative samples for training or for a few-shot prompt.
- */
- abstract class NotASourceCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- NotASourceCharacteristic() { any() }
-
- override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType instanceof Candidate::SourceType and
- isPositiveIndicator = false and
- confidence = highConfidence()
- }
- }
-
- /**
- * A high-confidence characteristic that indicates that an endpoint is neither a source nor a sink of any type.
- */
- abstract class NeitherSourceNorSinkCharacteristic extends NotASinkCharacteristic,
- NotASourceCharacteristic
- {
- bindingset[this]
- NeitherSourceNorSinkCharacteristic() { any() }
-
- final override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- NotASinkCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence) or
- NotASourceCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence)
- }
- }
-
- /**
- * A medium-confidence characteristic that indicates that an endpoint is unlikely to be a sink of any type. These
- * endpoints can be excluded from scoring at inference time, both to save time and to avoid false positives. They should
- * not, however, be used as negative samples for training or for a few-shot prompt, because they may include a small
- * number of sinks.
- */
- abstract class LikelyNotASinkCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- LikelyNotASinkCharacteristic() { any() }
-
- override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType instanceof Candidate::SinkType and
- isPositiveIndicator = false and
- confidence = mediumConfidence()
- }
- }
-
- /**
- * A characteristic that indicates not necessarily that an endpoint is not a sink, but rather that it is not a sink
- * that's interesting to model in the standard Java libraries. These filters should be removed when extracting sink
- * candidates within a user's codebase for customized modeling.
- *
- * These endpoints should not be used as negative samples for training or for a few-shot prompt, because they are not
- * necessarily non-sinks.
- */
- abstract class UninterestingToModelCharacteristic extends EndpointCharacteristic {
- bindingset[this]
- UninterestingToModelCharacteristic() { any() }
-
- override predicate hasImplications(
- Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
- ) {
- endpointType instanceof Candidate::SinkType and
- isPositiveIndicator = false and
- confidence = mediumConfidence()
- }
- }
-
- /**
- * Contains default implementations that are derived solely from the `CandidateSig` implementation.
- */
- private module DefaultCharacteristicImplementations {
- /**
- * Endpoints identified as sinks by the `CandidateSig` implementation are sinks with maximal confidence.
- */
- private class KnownSinkCharacteristic extends SinkCharacteristic {
- string madKind;
- Candidate::EndpointType endpointType;
- string provenance;
-
- KnownSinkCharacteristic() {
- Candidate::isKnownKind(madKind, endpointType) and
- // bind "this" to a unique string differing from that of the SinkType classes
- this = madKind + "_" + provenance + "_characteristic" and
- Candidate::isSink(_, madKind, provenance)
- }
-
- override predicate appliesToEndpoint(Candidate::Endpoint e) {
- Candidate::isSink(e, madKind, provenance)
- }
-
- override Candidate::EndpointType getSinkType() { result = endpointType }
- }
-
- private class KnownSourceCharacteristic extends SourceCharacteristic {
- string madKind;
- Candidate::EndpointType endpointType;
- string provenance;
-
- KnownSourceCharacteristic() {
- Candidate::isKnownKind(madKind, endpointType) and
- // bind "this" to a unique string differing from that of the SinkType classes
- this = madKind + "_" + provenance + "_characteristic" and
- Candidate::isSource(_, madKind, provenance)
- }
-
- override predicate appliesToEndpoint(Candidate::Endpoint e) {
- Candidate::isSource(e, madKind, provenance)
- }
-
- override Candidate::EndpointType getSourceType() { result = endpointType }
- }
-
- /**
- * A negative characteristic that indicates that an endpoint was manually modeled as a neutral model.
- */
- private class NeutralModelCharacteristic extends NeitherSourceNorSinkCharacteristic {
- NeutralModelCharacteristic() { this = "known non-sink" }
-
- override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isNeutral(e) }
- }
-
- /**
- * A negative characteristic that indicates that an endpoint is a sanitizer, and thus not a source.
- */
- private class IsSanitizerCharacteristic extends NotASourceCharacteristic {
- IsSanitizerCharacteristic() { this = "known sanitizer" }
-
- override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) }
- }
- }
-}
diff --git a/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql b/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql
deleted file mode 100644
index ed61ccfbbfd..00000000000
--- a/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * This file contains query predicates for use when gathering metrics at scale using Multi Repo
- * Variant Analysis.
- */
-
-private import java
-private import AutomodelAlertSinkUtil
-
-/**
- * Holds if `alertCount` is the number of alerts for the query with ID `queryId` for which the
- * sinks correspond to the given `ai-generated` sink model.
- */
-query predicate sinkModelCountPerQuery(
- string queryId, int alertCount, string package, string type, boolean subtypes, string name,
- string signature, string input, string ext, string kind, string provenance
-) {
- exists(SinkModel s |
- sinkModelTallyPerQuery(queryId, alertCount, s) and
- s.getProvenance() = "ai-generated" and
- s.getPackage() = package and
- s.getType() = type and
- s.getSubtypes() = subtypes and
- s.getName() = name and
- s.getSignature() = signature and
- s.getInput() = input and
- s.getExt() = ext and
- s.getKind() = kind and
- s.getProvenance() = provenance
- )
-}
-
-/**
- * Holds if `instanceCount` is the number of instances corresponding to the given `ai-generated`
- * sink model (as identified by the `package`, `name`, `input`, etc.).
- */
-query predicate instanceCount(
- int instanceCount, string package, string type, boolean subtypes, string name, string signature,
- string input, string ext, string kind, string provenance
-) {
- exists(SinkModel s |
- instanceCount = s.getInstanceCount() and
- instanceCount > 0 and
- s.getProvenance() = "ai-generated" and
- s.getPackage() = package and
- s.getType() = type and
- s.getSubtypes() = subtypes and
- s.getName() = name and
- s.getSignature() = signature and
- s.getInput() = input and
- s.getExt() = ext and
- s.getKind() = kind and
- s.getProvenance() = provenance
- )
-}
-
-// MRVA requires a select clause, so we repurpose it to tell us which query predicates had results.
-from string hadResults
-where
- sinkModelCountPerQuery(_, _, _, _, _, _, _, _, _, _, _) and hadResults = "sinkModelCountPerQuery"
- or
- instanceCount(_, _, _, _, _, _, _, _, _, _) and hadResults = "instanceCount"
-select hadResults
diff --git a/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md b/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md
new file mode 100644
index 00000000000..2b554d6de20
--- /dev/null
+++ b/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md
@@ -0,0 +1,4 @@
+---
+category: breaking
+---
+* Dropped the Java Automodel queries.
diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql b/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql
deleted file mode 100644
index b7e1efc4532..00000000000
--- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql
+++ /dev/null
@@ -1,35 +0,0 @@
-import java
-import AutomodelApplicationModeCharacteristics as Characteristics
-import AutomodelExtractionTests
-
-module TestHelper implements TestHelperSig {
- Location getEndpointLocation(Characteristics::Endpoint endpoint) {
- result = endpoint.asTop().getLocation()
- }
-
- predicate isCandidate(
- Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType
- ) {
- Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
- extensibleType, _)
- }
-
- predicate isPositiveExample(
- Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
- string input, string output, string extensibleType
- ) {
- Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
- output, _, extensibleType)
- }
-
- predicate isNegativeExample(
- Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType
- ) {
- Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
- extensibleType)
- }
-}
-
-import MakeTest>
diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java
deleted file mode 100644
index b0f3482a732..00000000000
--- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java
+++ /dev/null
@@ -1,8 +0,0 @@
-import hudson.Plugin;
-
-public class PluginImpl extends Plugin {
- @Override
- public void configure(String name, String value) { // $ sourceModelCandidate=configure(String,String):Parameter[0] sourceModelCandidate=configure(String,String):Parameter[1]
- // ...
- }
-}
diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java
deleted file mode 100644
index 9691cf86c15..00000000000
--- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.github.codeql.test;
-
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.nio.file.CopyOption;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Supplier;
-import java.io.File;
-import java.io.FileFilter;
-import java.nio.file.FileVisitOption;
-import java.net.URLConnection;
-import java.util.concurrent.FutureTask;
-
-class Test {
- public static void main(String[] args) throws Exception {
- AtomicReference reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
- reference.set( // $ sinkModelCandidate=set(Object):Argument[this]
- args[0] // $ negativeSinkExample=set(Object):Argument[0] // modeled as a flow step
- ); // not a source candidate (return type is void)
- }
-
- public static void callSupplier(Supplier supplier) {
- supplier.get(); // not a source candidate (lambda flow)
- }
-
- public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
- Files.copy(
- source, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[0](path-injection)
- target, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[1](path-injection)
- option // no candidate (not modeled, but source and target are modeled)
- ); // $ sourceModelCandidate=copy(Path,Path,CopyOption[]):ReturnValue
- }
-
- public static InputStream getInputStream(Path openPath) throws Exception {
- return Files.newInputStream(
- openPath // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) // sink candidate because "only" ai-modeled, and useful as a candidate in regression testing
- ); // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
- }
-
- public static InputStream getInputStream(String openPath, String otherPath) throws Exception {
- return Test.getInputStream( // the call is not a source candidate (argument to local call)
- Paths.get(
- openPath, // $ negativeSinkExample=get(String,String[]):Argument[0] // modeled as a flow step
- otherPath
- ) // $ sourceModelCandidate=get(String,String[]):ReturnValue negativeSinkExample=get(String,String[]):Argument[1]
- );
- }
-
- public static int compareFiles(File f1, File f2) {
- return f1.compareTo( // $ negativeSinkExample=compareTo(File):Argument[this]
- f2 // $ negativeSinkExample=compareTo(File):Argument[0] // modeled as not a sink
- ); // not a source candidate (return type is int)
- }
-
- public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
- Files.walk(
- p, // $ negativeSinkExample=walk(Path,FileVisitOption[]):Argument[0] // modeled as a flow step
- o, // the implicit varargs array is a candidate, annotated on the last line of the call
- o // not a candidate (only the first arg corresponding to a varargs array
- // is extracted)
- ); // $ sourceModelCandidate=walk(Path,FileVisitOption[]):ReturnValue sinkModelCandidate=walk(Path,FileVisitOption[]):Argument[1]
- }
-
- public static void WebSocketExample(URLConnection c) throws Exception {
- c.getInputStream(); // $ sinkModelCandidate=getInputStream():Argument[this] positiveSourceExample=getInputStream():ReturnValue(remote) // not a source candidate (manual modeling)
- c.connect(); // $ sinkModelCandidate=connect():Argument[this] // not a source candidate (return type is void)
- }
-
- public static void fileFilterExample(File f, FileFilter ff) {
- f.listFiles( // $ sinkModelCandidate=listFiles(FileFilter):Argument[this]
- ff
- ); // $ sourceModelCandidate=listFiles(FileFilter):ReturnValue
- }
-}
-
-class OverrideTest extends Exception {
- public void printStackTrace(PrintWriter writer) { // $ sourceModelCandidate=printStackTrace(PrintWriter):Parameter[0]
- return;
- }
-
-}
-
-class TaskUtils {
- public FutureTask getTask() {
- FutureTask ft = new FutureTask(() -> {
- // ^-- no sink candidate for the `this` qualifier of a constructor
- return 42;
- });
- return ft;
- }
-}
-
-class MoreTests {
- public static void FilesListExample(Path p) throws Exception {
- Files.list(
- Files.createDirectories(
- p // $ positiveSinkExample=createDirectories(Path,FileAttribute[]):Argument[0](path-injection)
- ) // $ sourceModelCandidate=createDirectories(Path,FileAttribute[]):ReturnValue negativeSinkExample=list(Path):Argument[0] // modeled as a flow step
- ); // $ sourceModelCandidate=list(Path):ReturnValue
-
- Files.delete(
- p // $ sinkModelCandidate=delete(Path):Argument[0] positiveSinkExample=delete(Path):Argument[0](path-injection)
- ); // not a source candidate (return type is void)
-
- Files.deleteIfExists(
- p // $ sinkModelCandidate=deleteIfExists(Path):Argument[0] positiveSinkExample=deleteIfExists(Path):Argument[0](path-injection)
- ); // not a source candidate (return type is boolean)
- }
-}
\ No newline at end of file
diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java
deleted file mode 100644
index 3ad79abb8df..00000000000
--- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package hudson;
-
-/** Plugin doc */
-public class Plugin {
- /** Configure method doc */
- public void configure(String name, String value) {}
-}
diff --git a/java/ql/automodel/test/AutomodelExtractionTests.qll b/java/ql/automodel/test/AutomodelExtractionTests.qll
deleted file mode 100644
index fbc407c67f0..00000000000
--- a/java/ql/automodel/test/AutomodelExtractionTests.qll
+++ /dev/null
@@ -1,77 +0,0 @@
-import java
-import TestUtilities.InlineExpectationsTest
-import AutomodelSharedCharacteristics
-
-signature module TestHelperSig {
- Location getEndpointLocation(Candidate::Endpoint e);
-
- predicate isCandidate(
- Candidate::Endpoint e, string name, string signature, string input, string output,
- string extensibleType
- );
-
- predicate isPositiveExample(
- Candidate::Endpoint e, string endpointType, string name, string signature, string input,
- string output, string extensibleType
- );
-
- predicate isNegativeExample(
- Candidate::Endpoint e, string name, string signature, string input, string output,
- string extensibleType
- );
-}
-
-module Extraction TestHelper> implements TestSig {
- string getARelevantTag() {
- result in [
- "sourceModelCandidate", "sinkModelCandidate", // a candidate source/sink
- "positiveSourceExample", "positiveSinkExample", // a known source/sink
- "negativeSourceExample", "negativeSinkExample" // a known non-source/non-sink
- ]
- }
-
- /**
- * If `extensibleType` is `sourceModel` then the result is `ifSource`, if it
- * is `sinkModel` then the result is `ifSink`.
- */
- bindingset[extensibleType, ifSource, ifSink]
- private string ifSource(string extensibleType, string ifSource, string ifSink) {
- extensibleType = "sourceModel" and result = ifSource
- or
- extensibleType = "sinkModel" and result = ifSink
- }
-
- additional predicate selectEndpoint(
- Candidate::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType, string tag, string suffix
- ) {
- TestHelper::isCandidate(endpoint, name, signature, input, output, extensibleType) and
- tag = ifSource(extensibleType, "sourceModelCandidate", "sinkModelCandidate") and
- suffix = ""
- or
- TestHelper::isNegativeExample(endpoint, name, signature, input, output, extensibleType) and
- tag = "negative" + ifSource(extensibleType, "Source", "Sink") + "Example" and
- suffix = ""
- or
- exists(string endpointType |
- TestHelper::isPositiveExample(endpoint, endpointType, name, signature, input, output,
- extensibleType) and
- tag = "positive" + ifSource(extensibleType, "Source", "Sink") + "Example" and
- suffix = "(" + endpointType + ")"
- )
- }
-
- predicate hasActualResult(Location location, string element, string tag, string value) {
- exists(
- Candidate::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType, string suffix
- |
- selectEndpoint(endpoint, name, signature, input, output, extensibleType, tag, suffix)
- |
- TestHelper::getEndpointLocation(endpoint) = location and
- endpoint.toString() = element and
- // for source models only the output is relevant, and vice versa for sink models
- value = name + signature + ":" + ifSource(extensibleType, output, input) + suffix
- )
- }
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql
deleted file mode 100644
index 0d5e8611870..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql
+++ /dev/null
@@ -1,35 +0,0 @@
-import java
-import AutomodelFrameworkModeCharacteristics as Characteristics
-import AutomodelExtractionTests
-
-module TestHelper implements TestHelperSig {
- Location getEndpointLocation(Characteristics::Endpoint endpoint) {
- result = endpoint.asTop().getLocation()
- }
-
- predicate isCandidate(
- Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType
- ) {
- Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
- extensibleType, _)
- }
-
- predicate isPositiveExample(
- Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
- string input, string output, string extensibleType
- ) {
- Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
- output, _, extensibleType)
- }
-
- predicate isNegativeExample(
- Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
- string extensibleType
- ) {
- Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
- extensibleType)
- }
-}
-
-import MakeTest>
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java
deleted file mode 100644
index 62bd773cc2e..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.github.codeql.test;
-
-public class MyWriter extends java.io.Writer {
- @Override
- public void write(char[] cbuf, int off, int len) { // $ sinkModelCandidate=write(char[],int,int):Argument[this] positiveSinkExample=write(char[],int,int):Argument[0](file-content-store) sourceModelCandidate=write(char[],int,int):Parameter[this] sourceModelCandidate=write(char[],int,int):Parameter[0]
- }
-
- @Override
- public void close() { // $ sinkModelCandidate=close():Argument[this] sourceModelCandidate=close():Parameter[this]
- }
-
- @Override
- public void flush() { // $ sinkModelCandidate=flush():Argument[this] sourceModelCandidate=flush():Parameter[this]
- }
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java
deleted file mode 100644
index b106d3da594..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.github.codeql.test;
-
-/**
- * No candidates in this class, as it's not public!
- */
-class NonPublicClass {
- public void noCandidates(String here) {
- System.out.println(here);
- }
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java
deleted file mode 100644
index 79fabff0664..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.github.codeql.test;
-
-public class PublicClass {
- public void stuff(String arg) { // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // source candidates because it is an overrideable method
- System.out.println(arg);
- }
-
- public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // `arg` is not a source candidate (not overrideabe); `this` is not a candidate (static method)
- System.out.println(arg);
- }
-
- protected void nonPublicStuff(String arg) { // $ sinkModelCandidate=nonPublicStuff(String):Argument[this] sourceModelCandidate=nonPublicStuff(String):Parameter[this] sinkModelCandidate=nonPublicStuff(String):Argument[0] sourceModelCandidate=nonPublicStuff(String):Parameter[0]
- System.out.println(arg);
- }
-
- void packagePrivateStuff(String arg) { // no candidates because the method is not public
- System.out.println(arg);
- }
-
- public PublicClass(Object input) { // $ sourceModelCandidate=PublicClass(Object):ReturnValue sinkModelCandidate=PublicClass(Object):Argument[0] // `this` is not a candidate because it is a constructor
- }
-
- // `input` and `input` are source candidates, but not sink candidates (is-style method)
- public Boolean isIgnored(Object input) { // $ negativeSinkExample=isIgnored(Object):Argument[this] sourceModelCandidate=isIgnored(Object):Parameter[this] negativeSinkExample=isIgnored(Object):Argument[0] sourceModelCandidate=isIgnored(Object):Parameter[0]
- return false;
- }
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java
deleted file mode 100644
index d4f80b3c698..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.github.codeql.test;
-
-public interface PublicInterface {
- public int stuff(String arg); // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // result is _not_ a source candidate source (primitive return type)
-
- public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // not a source candidate (static method)
- System.out.println(arg);
- }
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java
deleted file mode 100644
index 8bfe83e2339..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package java.io;
-
-public class File {
- public int compareTo( // $ negativeSinkExample=compareTo(File):Argument[this] sourceModelCandidate=compareTo(File):Parameter[this] // modeled as neutral for sinks
- File pathname // $ negativeSinkExample=compareTo(File):Argument[0] sourceModelCandidate=compareTo(File):Parameter[0] // modeled as neutral for sinks
- ) {
- return 0;
- }
-
- public boolean setLastModified(long time) { // $ sinkModelCandidate=setLastModified(long):Argument[this] sourceModelCandidate=setLastModified(long):Parameter[this] // time is not a candidate (primitive type)
- return false;
- } // return value is not a source candidate because it's a primitive
-}
diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java
deleted file mode 100644
index a833ba5f6e2..00000000000
--- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package java.nio.file;
-
-import java.io.InputStream;
-import java.io.FileInputStream;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.OpenOption;
-
-public class Files {
- public static void copy( // method result is not a candidate source (void)
- Path source, // $ positiveSinkExample=copy(Path,OutputStream):Argument[0](path-injection) // manual model exists
- OutputStream out // $ sinkModelCandidate=copy(Path,OutputStream):Argument[1]
- /* NB: may be worthwhile to implement the
- same behavior as in application mode where out would not be a
- candidate because there already is a model for another parameter of
- the same method and we assume that methods are always modeled
- completely.
- */
- ) throws IOException {
- // ...
- }
-
- public static InputStream newInputStream( // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
- Path openPath, // $ positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] // known sink, but still a candidate (ai-modeled, and useful as a candidate in regression testing)
- OpenOption... options // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[1]
- ) throws IOException {
- return new FileInputStream(openPath.toFile());
- }
-}
diff --git a/java/ql/automodel/test/change-notes/2024-05-23-Version1.md b/java/ql/automodel/test/change-notes/2024-05-23-Version1.md
deleted file mode 100644
index 5840e51017b..00000000000
--- a/java/ql/automodel/test/change-notes/2024-05-23-Version1.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: breaking
----
-* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
diff --git a/java/ql/automodel/test/qlpack.yml b/java/ql/automodel/test/qlpack.yml
deleted file mode 100644
index 46138d9435c..00000000000
--- a/java/ql/automodel/test/qlpack.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-name: codeql/java-automodel-tests
-version: 1.0.0-dev
-groups:
- - java
- - automodel
- - test
-dependencies:
- codeql/java-all: ${workspace}
- codeql/java-automodel-queries: ${workspace}
- codeql/java-tests: ${workspace}
-extractor: java
-tests: .
-warnOnImplicitThis: true
\ No newline at end of file
diff --git a/java/ql/lib/semmle/code/java/security/Encryption.qll b/java/ql/lib/semmle/code/java/security/Encryption.qll
index 6fc7f6b7d16..dae80b19be1 100644
--- a/java/ql/lib/semmle/code/java/security/Encryption.qll
+++ b/java/ql/lib/semmle/code/java/security/Encryption.qll
@@ -223,10 +223,7 @@ string getAnInsecureHashAlgorithmName() {
}
private string rankedInsecureAlgorithm(int i) {
- // In this case we know these are being used for encryption, so we want to match
- // weak hash algorithms too.
- result =
- rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName())
+ result = rank[i](string s | s = getAnInsecureAlgorithmName())
}
private string insecureAlgorithmString(int i) {
@@ -250,7 +247,7 @@ string getASecureAlgorithmName() {
result =
[
"RSA", "SHA-?256", "SHA-?512", "CCM", "GCM", "AES(?)",
- "Blowfish", "ECIES"
+ "Blowfish", "ECIES", "SHA3-(256|384|512)"
]
}
diff --git a/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll b/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll
index 1533b61dd5e..060a30f87e6 100644
--- a/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll
@@ -30,7 +30,11 @@ class InsecureAlgoLiteral extends InsecureAlgorithm, ShortStringLiteral {
s.length() > 1 and
not s.regexpMatch(getSecureAlgorithmRegex()) and
// Exclude results covered by another query.
- not s.regexpMatch(getInsecureAlgorithmRegex())
+ not s.regexpMatch(getInsecureAlgorithmRegex()) and
+ // Exclude results covered by `InsecureAlgoProperty`.
+ // This removes duplicates when a string literal is a default value for the property,
+ // such as "MD5" in the following: `props.getProperty("hashAlg2", "MD5")`.
+ not exists(InsecureAlgoProperty insecAlgoProp | this = insecAlgoProp.getAnArgument())
)
}
diff --git a/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md b/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md
new file mode 100644
index 00000000000..b4ac88bcdc6
--- /dev/null
+++ b/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* The `java/weak-cryptographic-algorithm` query has been updated to no longer report uses of hash functions such as `MD5` and `SHA1` even if they are known to be weak. These hash algorithms are used very often in non-sensitive contexts, making the query too imprecise in practice. The `java/potentially-weak-cryptographic-algorithm` query has been updated to report these uses instead.
diff --git a/java/ql/src/change-notes/2024-11-22-sha3.md b/java/ql/src/change-notes/2024-11-22-sha3.md
new file mode 100644
index 00000000000..61dbc35162e
--- /dev/null
+++ b/java/ql/src/change-notes/2024-11-22-sha3.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added SHA3 to the list of secure hashing algorithms. As a result the `java/potentially-weak-cryptographic-algorithm` query should no longer flag up uses of SHA3.
diff --git a/java/ql/test/library-tests/dataflow/getter/getter.expected b/java/ql/test/library-tests/dataflow/getter/getter.expected
index b5af3f91a59..9a36107f198 100644
--- a/java/ql/test/library-tests/dataflow/getter/getter.expected
+++ b/java/ql/test/library-tests/dataflow/getter/getter.expected
@@ -1,6 +1,5 @@
| A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo |
| A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo |
| A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo |
-| A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo |
| A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
| A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected
index 612e1c73054..94719b47739 100644
--- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected
+++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected
@@ -1,14 +1,8 @@
#select
| Test.java:19:20:19:50 | getInstance(...) | Test.java:19:45:19:49 | "DES" | Test.java:19:45:19:49 | "DES" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | DES |
| Test.java:42:14:42:38 | getInstance(...) | Test.java:42:33:42:37 | "RC2" | Test.java:42:33:42:37 | "RC2" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | RC2 |
-| WeakHashing.java:21:30:21:92 | getInstance(...) | WeakHashing.java:21:86:21:90 | "MD5" : String | WeakHashing.java:21:56:21:91 | getProperty(...) | Cryptographic algorithm $@ is weak and should not be used. | WeakHashing.java:21:86:21:90 | "MD5" | MD5 |
edges
-| WeakHashing.java:21:86:21:90 | "MD5" : String | WeakHashing.java:21:56:21:91 | getProperty(...) | provenance | MaD:1 |
-models
-| 1 | Summary: java.util; Properties; true; getProperty; (String,String); ; Argument[1]; ReturnValue; value; manual |
nodes
| Test.java:19:45:19:49 | "DES" | semmle.label | "DES" |
| Test.java:42:33:42:37 | "RC2" | semmle.label | "RC2" |
-| WeakHashing.java:21:56:21:91 | getProperty(...) | semmle.label | getProperty(...) |
-| WeakHashing.java:21:86:21:90 | "MD5" : String | semmle.label | "MD5" : String |
subpaths
diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java
index 6a3565fc141..8858576cb90 100644
--- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java
+++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java
@@ -25,5 +25,8 @@ public class WeakHashing {
// OK: Property does not exist and default is secure
MessageDigest ok2 = MessageDigest.getInstance(props.getProperty("hashAlg3", "SHA-256"));
+
+ // GOOD: Using a strong hashing algorithm
+ MessageDigest ok3 = MessageDigest.getInstance("SHA3-512");
}
-}
\ No newline at end of file
+}
diff --git a/javascript/extractor/lib/typescript/package-lock.json b/javascript/extractor/lib/typescript/package-lock.json
index 50a9e0a66ca..1978e396324 100644
--- a/javascript/extractor/lib/typescript/package-lock.json
+++ b/javascript/extractor/lib/typescript/package-lock.json
@@ -6,7 +6,7 @@
"": {
"name": "typescript-parser-wrapper",
"dependencies": {
- "typescript": "^5.6.2"
+ "typescript": "^5.7.2"
},
"devDependencies": {
"@types/node": "18.15.3"
@@ -20,9 +20,9 @@
"license": "MIT"
},
"node_modules/typescript": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
- "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
+ "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json
index bf650ec457a..9d77f4ab740 100644
--- a/javascript/extractor/lib/typescript/package.json
+++ b/javascript/extractor/lib/typescript/package.json
@@ -2,7 +2,7 @@
"name": "typescript-parser-wrapper",
"private": true,
"dependencies": {
- "typescript": "5.6.2"
+ "typescript": "^5.7.2"
},
"scripts": {
"build": "tsc --project tsconfig.json",
diff --git a/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts b/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts
index 29e78b136e8..f2a1644e18f 100644
--- a/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts
+++ b/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts
@@ -1,17 +1,3022 @@
-type Output = {
- (...args: S): any;
-};
-
-declare function createThing(
- type: K,
- fn: (...args: S) => any
-): Output;
-
-const one = createThing("one", () => ({}));
-
-const two = createThing("two", () => ({}));
-
-const three = createThing("three", (cursor: string) => null);
-const four = createThing("four", (error: number) => null);
-
-type Events = Array;
+console.log(
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1 +
+ 1
+);
diff --git a/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md b/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md
new file mode 100644
index 00000000000..e3fe3b6aef2
--- /dev/null
+++ b/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md
@@ -0,0 +1,5 @@
+---
+category: minorAnalysis
+---
+* Added taint-steps for `Array.prototype.findLast`
+* Added taint-steps for `Array.prototype.findLastIndex`
diff --git a/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md b/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md
new file mode 100644
index 00000000000..dda4d878760
--- /dev/null
+++ b/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added taint-steps for `String.prototype.toWellFormed`.
diff --git a/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md b/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md
new file mode 100644
index 00000000000..8511727f8e7
--- /dev/null
+++ b/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added taint-steps for `Map.groupBy` and `Object.groupBy`.
diff --git a/javascript/ql/lib/semmle/javascript/Arrays.qll b/javascript/ql/lib/semmle/javascript/Arrays.qll
index 7ce37130996..bec711b835a 100644
--- a/javascript/ql/lib/semmle/javascript/Arrays.qll
+++ b/javascript/ql/lib/semmle/javascript/Arrays.qll
@@ -384,10 +384,10 @@ private module ArrayLibraries {
}
/**
- * Gets a call to `Array.prototype.find` or a polyfill implementing the same functionality.
+ * Gets a call to `Array.prototype.find` or `Array.prototype.findLast` or a polyfill implementing the same functionality.
*/
DataFlow::CallNode arrayFindCall(DataFlow::Node array) {
- result.(DataFlow::MethodCallNode).getMethodName() = "find" and
+ result.(DataFlow::MethodCallNode).getMethodName() in ["find", "findLast"] and
array = result.getReceiver()
or
result = DataFlow::moduleImport(["array.prototype.find", "array-find"]).getACall() and
@@ -483,4 +483,31 @@ private module ArrayLibraries {
)
}
}
+
+ /**
+ * Defines a data flow step that tracks the flow of data through callback functions in arrays.
+ */
+ private class ArrayCallBackDataFlowStep extends PreCallGraphStep {
+ override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
+ exists(DataFlow::MethodCallNode call |
+ call.getMethodName() = ["findLast", "find", "findLastIndex"] and
+ prop = arrayLikeElement() and
+ obj = call.getReceiver() and
+ element = call.getCallback(0).getParameter(0)
+ )
+ }
+ }
+
+ /**
+ * This step models the propagation of data from the array to the callback function's parameter.
+ */
+ private class ArrayCallBackDataTaintStep extends TaintTracking::SharedTaintStep {
+ override predicate step(DataFlow::Node obj, DataFlow::Node element) {
+ exists(DataFlow::MethodCallNode call |
+ call.getMethodName() = ["findLast", "find", "findLastIndex"] and
+ obj = call.getReceiver() and
+ element = call.getCallback(0).getParameter(0)
+ )
+ }
+ }
}
diff --git a/javascript/ql/lib/semmle/javascript/Collections.qll b/javascript/ql/lib/semmle/javascript/Collections.qll
index a0e251554ff..028c3abe4b3 100644
--- a/javascript/ql/lib/semmle/javascript/Collections.qll
+++ b/javascript/ql/lib/semmle/javascript/Collections.qll
@@ -151,4 +151,32 @@ private module CollectionDataFlow {
)
}
}
+
+ /**
+ * A step for a call to `groupBy` on an iterable object.
+ */
+ private class GroupByTaintStep extends TaintTracking::SharedTaintStep {
+ override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
+ exists(DataFlow::MethodCallNode call |
+ call = DataFlow::globalVarRef(["Map", "Object"]).getAMemberCall("groupBy") and
+ pred = call.getArgument(0) and
+ (succ = call.getCallback(1).getParameter(0) or succ = call)
+ )
+ }
+ }
+
+ /**
+ * A step for handling data flow and taint tracking for the groupBy method on iterable objects.
+ * Ensures propagation of taint and data flow through the groupBy operation.
+ */
+ private class GroupByDataFlowStep extends PreCallGraphStep {
+ override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
+ exists(DataFlow::MethodCallNode call |
+ call = DataFlow::globalVarRef("Map").getAMemberCall("groupBy") and
+ pred = call.getArgument(0) and
+ succ = call and
+ prop = mapValueUnknownKey()
+ )
+ }
+ }
}
diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll
index a19691e9448..6b6fc9c4b07 100644
--- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll
+++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll
@@ -612,7 +612,7 @@ module TaintTracking {
"italics", "link", "padEnd", "padStart", "repeat", "replace", "replaceAll", "slice",
"small", "split", "strike", "sub", "substr", "substring", "sup",
"toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim",
- "trimLeft", "trimRight"
+ "trimLeft", "trimRight", "toWellFormed"
]
or
// sorted, interesting, properties of Object.prototype
diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql
index ea5f2fb9755..818f0d922d4 100644
--- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql
+++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql
@@ -114,7 +114,7 @@ predicate hasNonVoidCallbackMethod(string name) {
name =
[
"every", "filter", "find", "findIndex", "flatMap", "map", "reduce", "reduceRight", "some",
- "sort"
+ "sort", "findLastIndex", "findLast"
]
}
diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected
index 4332f14c45e..07fabfb7270 100644
--- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected
+++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected
@@ -14,6 +14,7 @@
| arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x |
| arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) |
| arrays.js:2:16:2:23 | "source" | arrays.js:109:8:109:24 | arr8_spread.pop() |
+| arrays.js:2:16:2:23 | "source" | arrays.js:111:8:111:33 | arr.fin ... llback) |
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
@@ -25,3 +26,8 @@
| arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() |
| arrays.js:99:31:99:38 | "source" | arrays.js:100:8:100:17 | arr8.pop() |
| arrays.js:103:55:103:62 | "source" | arrays.js:105:8:105:25 | arr8_variant.pop() |
+| arrays.js:114:19:114:26 | "source" | arrays.js:115:50:115:53 | item |
+| arrays.js:114:19:114:26 | "source" | arrays.js:116:10:116:16 | element |
+| arrays.js:120:19:120:26 | "source" | arrays.js:121:46:121:49 | item |
+| arrays.js:120:19:120:26 | "source" | arrays.js:122:10:122:16 | element |
+| arrays.js:126:19:126:26 | "source" | arrays.js:127:55:127:58 | item |
diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.ql b/javascript/ql/test/library-tests/Arrays/DataFlow.ql
index 80c9f068a10..5c5f4a0d10e 100644
--- a/javascript/ql/test/library-tests/Arrays/DataFlow.ql
+++ b/javascript/ql/test/library-tests/Arrays/DataFlow.ql
@@ -3,7 +3,10 @@ import javascript
class ArrayFlowConfig extends DataFlow::Configuration {
ArrayFlowConfig() { this = "ArrayFlowConfig" }
- override predicate isSource(DataFlow::Node source) { source.asExpr().getStringValue() = "source" }
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr().getStringValue() = "source" or
+ source.(DataFlow::CallNode).getCalleeName() = "source"
+ }
override predicate isSink(DataFlow::Node sink) {
sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument()
diff --git a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected
index a531715bfb6..246a52e803b 100644
--- a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected
+++ b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected
@@ -15,6 +15,7 @@
| arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x |
| arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) |
| arrays.js:2:16:2:23 | "source" | arrays.js:109:8:109:24 | arr8_spread.pop() |
+| arrays.js:2:16:2:23 | "source" | arrays.js:111:8:111:33 | arr.fin ... llback) |
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
@@ -29,3 +30,13 @@
| arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:36 | ["sourc ... => !!x) |
| arrays.js:99:31:99:38 | "source" | arrays.js:100:8:100:17 | arr8.pop() |
| arrays.js:103:55:103:62 | "source" | arrays.js:105:8:105:25 | arr8_variant.pop() |
+| arrays.js:114:19:114:26 | "source" | arrays.js:115:50:115:53 | item |
+| arrays.js:114:19:114:26 | "source" | arrays.js:116:10:116:16 | element |
+| arrays.js:120:19:120:26 | "source" | arrays.js:121:46:121:49 | item |
+| arrays.js:120:19:120:26 | "source" | arrays.js:122:10:122:16 | element |
+| arrays.js:126:19:126:26 | "source" | arrays.js:127:55:127:58 | item |
+| arrays.js:131:17:131:24 | source() | arrays.js:132:46:132:49 | item |
+| arrays.js:131:17:131:24 | source() | arrays.js:133:10:133:17 | element1 |
+| arrays.js:137:17:137:24 | source() | arrays.js:138:50:138:53 | item |
+| arrays.js:137:17:137:24 | source() | arrays.js:139:10:139:17 | element1 |
+| arrays.js:143:17:143:24 | source() | arrays.js:144:55:144:58 | item |
diff --git a/javascript/ql/test/library-tests/Arrays/TaintFlow.ql b/javascript/ql/test/library-tests/Arrays/TaintFlow.ql
index cee2f294a34..d8f18759162 100644
--- a/javascript/ql/test/library-tests/Arrays/TaintFlow.ql
+++ b/javascript/ql/test/library-tests/Arrays/TaintFlow.ql
@@ -3,7 +3,10 @@ import javascript
class ArrayTaintFlowConfig extends TaintTracking::Configuration {
ArrayTaintFlowConfig() { this = "ArrayTaintFlowConfig" }
- override predicate isSource(DataFlow::Node source) { source.asExpr().getStringValue() = "source" }
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr().getStringValue() = "source" or
+ source.(DataFlow::CallNode).getCalleeName() = "source"
+ }
override predicate isSink(DataFlow::Node sink) {
sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument()
diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js
index 579741fa3aa..deedf29f6f6 100644
--- a/javascript/ql/test/library-tests/Arrays/arrays.js
+++ b/javascript/ql/test/library-tests/Arrays/arrays.js
@@ -107,4 +107,41 @@
var arr8_spread = [];
arr8_spread = arr8_spread.toSpliced(0, 0, ...arr);
sink(arr8_spread.pop()); // NOT OK
+
+ sink(arr.findLast(someCallback)); // NOT OK
+
+ { // Test for findLast function
+ const list = ["source"];
+ const element = list.findLast((item) => sink(item)); // NOT OK
+ sink(element); // NOT OK
+ }
+
+ { // Test for find function
+ const list = ["source"];
+ const element = list.find((item) => sink(item)); // NOT OK
+ sink(element); // NOT OK
+ }
+
+ { // Test for findLastIndex function
+ const list = ["source"];
+ const element = list.findLastIndex((item) => sink(item)); // NOT OK
+ sink(element); // OK
+ }
+ {
+ const arr = source();
+ const element1 = arr.find((item) => sink(item)); // NOT OK
+ sink(element1); // NOT OK
+ }
+
+ {
+ const arr = source();
+ const element1 = arr.findLast((item) => sink(item)); // NOT OK
+ sink(element1); // NOT OK
+ }
+
+ {
+ const arr = source();
+ const element1 = arr.findLastIndex((item) => sink(item)); // NOT OK
+ sink(element1); // OK
+ }
});
diff --git a/javascript/ql/test/library-tests/Arrays/printAst.expected b/javascript/ql/test/library-tests/Arrays/printAst.expected
index a7333b29485..a825b12f3fb 100644
--- a/javascript/ql/test/library-tests/Arrays/printAst.expected
+++ b/javascript/ql/test/library-tests/Arrays/printAst.expected
@@ -1,9 +1,9 @@
nodes
-| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.label | [ParExpr] (functi ... T OK }) |
-| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); |
-| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 |
-| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.label | [FunctionExpr] functio ... OT OK } |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.label | [BlockStmt] { let ... OT OK } |
+| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.label | [ParExpr] (functi ... } }) |
+| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | semmle.label | [ExprStmt] (functi ... } }); |
+| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | semmle.order | 1 |
+| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.label | [FunctionExpr] functio ... K } } |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.label | [BlockStmt] { let ... K } } |
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... |
| arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source |
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" |
@@ -487,6 +487,146 @@ nodes
| arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.label | [DotExpr] arr8_spread.pop |
| arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.label | [MethodCallExpr] arr8_spread.pop() |
| arrays.js:109:20:109:22 | [Label] pop | semmle.label | [Label] pop |
+| arrays.js:111:3:111:6 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.label | [CallExpr] sink(ar ... lback)) |
+| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.label | [ExprStmt] sink(ar ... back)); |
+| arrays.js:111:8:111:10 | [VarRef] arr | semmle.label | [VarRef] arr |
+| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.label | [DotExpr] arr.findLast |
+| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.label | [MethodCallExpr] arr.fin ... llback) |
+| arrays.js:111:12:111:19 | [Label] findLast | semmle.label | [Label] findLast |
+| arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.label | [VarRef] someCallback |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } |
+| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... |
+| arrays.js:114:11:114:14 | [VarDecl] list | semmle.label | [VarDecl] list |
+| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] |
+| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] |
+| arrays.js:114:19:114:26 | [Literal] "source" | semmle.label | [Literal] "source" |
+| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... |
+| arrays.js:115:11:115:17 | [VarDecl] element | semmle.label | [VarDecl] element |
+| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:115:21:115:24 | [VarRef] list | semmle.label | [VarRef] list |
+| arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.label | [DotExpr] list.findLast |
+| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) |
+| arrays.js:115:26:115:33 | [Label] findLast | semmle.label | [Label] findLast |
+| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:115:45:115:48 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:115:50:115:53 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:116:5:116:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) |
+| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); |
+| arrays.js:116:10:116:16 | [VarRef] element | semmle.label | [VarRef] element |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } |
+| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... |
+| arrays.js:120:11:120:14 | [VarDecl] list | semmle.label | [VarDecl] list |
+| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] |
+| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] |
+| arrays.js:120:19:120:26 | [Literal] "source" | semmle.label | [Literal] "source" |
+| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... |
+| arrays.js:121:11:121:17 | [VarDecl] element | semmle.label | [VarDecl] element |
+| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:121:21:121:24 | [VarRef] list | semmle.label | [VarRef] list |
+| arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.label | [DotExpr] list.find |
+| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) |
+| arrays.js:121:26:121:29 | [Label] find | semmle.label | [Label] find |
+| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:121:41:121:44 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:121:46:121:49 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:122:5:122:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) |
+| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); |
+| arrays.js:122:10:122:16 | [VarRef] element | semmle.label | [VarRef] element |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } |
+| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... |
+| arrays.js:126:11:126:14 | [VarDecl] list | semmle.label | [VarDecl] list |
+| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] |
+| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] |
+| arrays.js:126:19:126:26 | [Literal] "source" | semmle.label | [Literal] "source" |
+| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... |
+| arrays.js:127:11:127:17 | [VarDecl] element | semmle.label | [VarDecl] element |
+| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:127:21:127:24 | [VarRef] list | semmle.label | [VarRef] list |
+| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.label | [DotExpr] list.findLastIndex |
+| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) |
+| arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.label | [Label] findLastIndex |
+| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:127:50:127:53 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:127:55:127:58 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:128:5:128:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) |
+| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); |
+| arrays.js:128:10:128:16 | [VarRef] element | semmle.label | [VarRef] element |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } |
+| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... |
+| arrays.js:131:11:131:13 | [VarDecl] arr | semmle.label | [VarDecl] arr |
+| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() |
+| arrays.js:131:17:131:22 | [VarRef] source | semmle.label | [VarRef] source |
+| arrays.js:131:17:131:24 | [CallExpr] source() | semmle.label | [CallExpr] source() |
+| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... |
+| arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 |
+| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:132:22:132:24 | [VarRef] arr | semmle.label | [VarRef] arr |
+| arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.label | [DotExpr] arr.find |
+| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) |
+| arrays.js:132:26:132:29 | [Label] find | semmle.label | [Label] find |
+| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:132:41:132:44 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:132:46:132:49 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:133:5:133:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) |
+| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); |
+| arrays.js:133:10:133:17 | [VarRef] element1 | semmle.label | [VarRef] element1 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } |
+| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... |
+| arrays.js:137:11:137:13 | [VarDecl] arr | semmle.label | [VarDecl] arr |
+| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() |
+| arrays.js:137:17:137:22 | [VarRef] source | semmle.label | [VarRef] source |
+| arrays.js:137:17:137:24 | [CallExpr] source() | semmle.label | [CallExpr] source() |
+| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... |
+| arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 |
+| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:138:22:138:24 | [VarRef] arr | semmle.label | [VarRef] arr |
+| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.label | [DotExpr] arr.findLast |
+| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) |
+| arrays.js:138:26:138:33 | [Label] findLast | semmle.label | [Label] findLast |
+| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:138:45:138:48 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:138:50:138:53 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:139:5:139:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) |
+| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); |
+| arrays.js:139:10:139:17 | [VarRef] element1 | semmle.label | [VarRef] element1 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } |
+| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... |
+| arrays.js:143:11:143:13 | [VarDecl] arr | semmle.label | [VarDecl] arr |
+| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() |
+| arrays.js:143:17:143:22 | [VarRef] source | semmle.label | [VarRef] source |
+| arrays.js:143:17:143:24 | [CallExpr] source() | semmle.label | [CallExpr] source() |
+| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... |
+| arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 |
+| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) |
+| arrays.js:144:22:144:24 | [VarRef] arr | semmle.label | [VarRef] arr |
+| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.label | [DotExpr] arr.findLastIndex |
+| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) |
+| arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.label | [Label] findLastIndex |
+| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) |
+| arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.label | [SimpleParameter] item |
+| arrays.js:144:50:144:53 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) |
+| arrays.js:144:55:144:58 | [VarRef] item | semmle.label | [VarRef] item |
+| arrays.js:145:5:145:8 | [VarRef] sink | semmle.label | [VarRef] sink |
+| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) |
+| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); |
+| arrays.js:145:10:145:17 | [VarRef] element1 | semmle.label | [VarRef] element1 |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
@@ -544,6 +684,32 @@ nodes
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
@@ -552,128 +718,142 @@ nodes
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
edges
-| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.label | 1 |
-| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.order | 1 |
-| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.label | 1 |
-| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.order | 1 |
-| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.label | 5 |
-| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.order | 5 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | 47 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.order | 47 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | 48 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.order | 48 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.label | 49 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.order | 49 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.label | 50 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.order | 50 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.label | 51 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.order | 51 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.label | 52 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.order | 52 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.label | 53 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.order | 53 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.label | 54 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.order | 54 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 55 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 55 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.label | 56 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.order | 56 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.label | 57 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.order | 57 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 58 |
-| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 58 |
+| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.label | 1 |
+| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.order | 1 |
+| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.label | 1 |
+| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.order | 1 |
+| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.label | 5 |
+| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.order | 5 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | 47 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.order | 47 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | 48 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.order | 48 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.label | 49 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.order | 49 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.label | 50 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.order | 50 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.label | 51 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.order | 51 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.label | 52 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.order | 52 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.label | 53 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.order | 53 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.label | 54 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.order | 54 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 55 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 55 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.label | 56 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.order | 56 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.label | 57 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.order | 57 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 58 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 58 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.label | 59 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.order | 59 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.label | 60 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.order | 60 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.label | 61 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.order | 61 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.label | 62 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.order | 62 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.label | 63 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.order | 63 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.label | 64 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.order | 64 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.label | 65 |
+| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.order | 65 |
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 |
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 |
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 |
@@ -1490,6 +1670,272 @@ edges
| arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | arrays.js:109:20:109:22 | [Label] pop | semmle.order | 2 |
| arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.label | 0 |
| arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.order | 0 |
+| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | arrays.js:111:3:111:6 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | arrays.js:111:3:111:6 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.label | 1 |
+| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.order | 1 |
+| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:8:111:10 | [VarRef] arr | semmle.label | 1 |
+| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:8:111:10 | [VarRef] arr | semmle.order | 1 |
+| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:12:111:19 | [Label] findLast | semmle.label | 2 |
+| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:12:111:19 | [Label] findLast | semmle.order | 2 |
+| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.label | 0 |
+| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.order | 0 |
+| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.label | 1 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.order | 1 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.label | 2 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.order | 2 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.label | 3 |
+| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.order | 3 |
+| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 |
+| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 |
+| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:11:114:14 | [VarDecl] list | semmle.label | 1 |
+| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:11:114:14 | [VarDecl] list | semmle.order | 1 |
+| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.label | 2 |
+| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.order | 2 |
+| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | arrays.js:114:19:114:26 | [Literal] "source" | semmle.label | 1 |
+| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | arrays.js:114:19:114:26 | [Literal] "source" | semmle.order | 1 |
+| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:11:115:17 | [VarDecl] element | semmle.label | 1 |
+| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:11:115:17 | [VarDecl] element | semmle.order | 1 |
+| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 |
+| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 |
+| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:21:115:24 | [VarRef] list | semmle.label | 1 |
+| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:21:115:24 | [VarRef] list | semmle.order | 1 |
+| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:26:115:33 | [Label] findLast | semmle.label | 2 |
+| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:26:115:33 | [Label] findLast | semmle.order | 2 |
+| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.label | 0 |
+| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.order | 0 |
+| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:115:45:115:54 | [CallExpr] sink(item) | arrays.js:115:45:115:48 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:115:45:115:54 | [CallExpr] sink(item) | arrays.js:115:45:115:48 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:115:45:115:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:115:45:115:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:116:5:116:17 | [CallExpr] sink(element) | arrays.js:116:5:116:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:116:5:116:17 | [CallExpr] sink(element) | arrays.js:116:5:116:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:116:5:116:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:116:5:116:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.label | 1 |
+| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.order | 1 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.label | 1 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.order | 1 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.label | 2 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.order | 2 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.label | 3 |
+| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.order | 3 |
+| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 |
+| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 |
+| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:11:120:14 | [VarDecl] list | semmle.label | 1 |
+| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:11:120:14 | [VarDecl] list | semmle.order | 1 |
+| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.label | 2 |
+| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.order | 2 |
+| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | arrays.js:120:19:120:26 | [Literal] "source" | semmle.label | 1 |
+| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | arrays.js:120:19:120:26 | [Literal] "source" | semmle.order | 1 |
+| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:11:121:17 | [VarDecl] element | semmle.label | 1 |
+| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:11:121:17 | [VarDecl] element | semmle.order | 1 |
+| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 |
+| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 |
+| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:21:121:24 | [VarRef] list | semmle.label | 1 |
+| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:21:121:24 | [VarRef] list | semmle.order | 1 |
+| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:26:121:29 | [Label] find | semmle.label | 2 |
+| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:26:121:29 | [Label] find | semmle.order | 2 |
+| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.label | 0 |
+| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.order | 0 |
+| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:121:41:121:50 | [CallExpr] sink(item) | arrays.js:121:41:121:44 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:121:41:121:50 | [CallExpr] sink(item) | arrays.js:121:41:121:44 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:121:41:121:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:121:41:121:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:122:5:122:17 | [CallExpr] sink(element) | arrays.js:122:5:122:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:122:5:122:17 | [CallExpr] sink(element) | arrays.js:122:5:122:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:122:5:122:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:122:5:122:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.label | 1 |
+| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.order | 1 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.label | 1 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.order | 1 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.label | 2 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.order | 2 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.label | 3 |
+| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.order | 3 |
+| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 |
+| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 |
+| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:11:126:14 | [VarDecl] list | semmle.label | 1 |
+| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:11:126:14 | [VarDecl] list | semmle.order | 1 |
+| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.label | 2 |
+| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.order | 2 |
+| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | arrays.js:126:19:126:26 | [Literal] "source" | semmle.label | 1 |
+| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | arrays.js:126:19:126:26 | [Literal] "source" | semmle.order | 1 |
+| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:11:127:17 | [VarDecl] element | semmle.label | 1 |
+| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:11:127:17 | [VarDecl] element | semmle.order | 1 |
+| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 |
+| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 |
+| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:21:127:24 | [VarRef] list | semmle.label | 1 |
+| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:21:127:24 | [VarRef] list | semmle.order | 1 |
+| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.label | 2 |
+| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.order | 2 |
+| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.label | 0 |
+| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.order | 0 |
+| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:127:50:127:59 | [CallExpr] sink(item) | arrays.js:127:50:127:53 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:127:50:127:59 | [CallExpr] sink(item) | arrays.js:127:50:127:53 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:127:50:127:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:127:50:127:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:128:5:128:17 | [CallExpr] sink(element) | arrays.js:128:5:128:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:128:5:128:17 | [CallExpr] sink(element) | arrays.js:128:5:128:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:128:5:128:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:128:5:128:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.label | 1 |
+| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.order | 1 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.label | 1 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.order | 1 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.label | 2 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.order | 2 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.label | 3 |
+| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.order | 3 |
+| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.label | 1 |
+| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.order | 1 |
+| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:11:131:13 | [VarDecl] arr | semmle.label | 1 |
+| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:11:131:13 | [VarDecl] arr | semmle.order | 1 |
+| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:17:131:24 | [CallExpr] source() | semmle.label | 2 |
+| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:17:131:24 | [CallExpr] source() | semmle.order | 2 |
+| arrays.js:131:17:131:24 | [CallExpr] source() | arrays.js:131:17:131:22 | [VarRef] source | semmle.label | 0 |
+| arrays.js:131:17:131:24 | [CallExpr] source() | arrays.js:131:17:131:22 | [VarRef] source | semmle.order | 0 |
+| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.label | 1 |
+| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.order | 1 |
+| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 |
+| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 |
+| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:22:132:24 | [VarRef] arr | semmle.label | 1 |
+| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:22:132:24 | [VarRef] arr | semmle.order | 1 |
+| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:26:132:29 | [Label] find | semmle.label | 2 |
+| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:26:132:29 | [Label] find | semmle.order | 2 |
+| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.label | 0 |
+| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.order | 0 |
+| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:132:41:132:50 | [CallExpr] sink(item) | arrays.js:132:41:132:44 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:132:41:132:50 | [CallExpr] sink(item) | arrays.js:132:41:132:44 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:132:41:132:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:132:41:132:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | arrays.js:133:5:133:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | arrays.js:133:5:133:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.label | 1 |
+| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.order | 1 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.label | 1 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.order | 1 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.label | 2 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.order | 2 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.label | 3 |
+| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.order | 3 |
+| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.label | 1 |
+| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.order | 1 |
+| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:11:137:13 | [VarDecl] arr | semmle.label | 1 |
+| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:11:137:13 | [VarDecl] arr | semmle.order | 1 |
+| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:17:137:24 | [CallExpr] source() | semmle.label | 2 |
+| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:17:137:24 | [CallExpr] source() | semmle.order | 2 |
+| arrays.js:137:17:137:24 | [CallExpr] source() | arrays.js:137:17:137:22 | [VarRef] source | semmle.label | 0 |
+| arrays.js:137:17:137:24 | [CallExpr] source() | arrays.js:137:17:137:22 | [VarRef] source | semmle.order | 0 |
+| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.label | 1 |
+| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.order | 1 |
+| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 |
+| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 |
+| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:22:138:24 | [VarRef] arr | semmle.label | 1 |
+| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:22:138:24 | [VarRef] arr | semmle.order | 1 |
+| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:26:138:33 | [Label] findLast | semmle.label | 2 |
+| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:26:138:33 | [Label] findLast | semmle.order | 2 |
+| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.label | 0 |
+| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.order | 0 |
+| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:138:45:138:54 | [CallExpr] sink(item) | arrays.js:138:45:138:48 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:138:45:138:54 | [CallExpr] sink(item) | arrays.js:138:45:138:48 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:138:45:138:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:138:45:138:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | arrays.js:139:5:139:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | arrays.js:139:5:139:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.label | 1 |
+| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.order | 1 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.label | 1 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.order | 1 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.label | 2 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.order | 2 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.label | 3 |
+| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.order | 3 |
+| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.label | 1 |
+| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.order | 1 |
+| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:11:143:13 | [VarDecl] arr | semmle.label | 1 |
+| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:11:143:13 | [VarDecl] arr | semmle.order | 1 |
+| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:17:143:24 | [CallExpr] source() | semmle.label | 2 |
+| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:17:143:24 | [CallExpr] source() | semmle.order | 2 |
+| arrays.js:143:17:143:24 | [CallExpr] source() | arrays.js:143:17:143:22 | [VarRef] source | semmle.label | 0 |
+| arrays.js:143:17:143:24 | [CallExpr] source() | arrays.js:143:17:143:22 | [VarRef] source | semmle.order | 0 |
+| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.label | 1 |
+| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.order | 1 |
+| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.label | 1 |
+| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.order | 1 |
+| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 |
+| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 |
+| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:22:144:24 | [VarRef] arr | semmle.label | 1 |
+| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:22:144:24 | [VarRef] arr | semmle.order | 1 |
+| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.label | 2 |
+| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.order | 2 |
+| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.label | 0 |
+| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.order | 0 |
+| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.label | 5 |
+| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.order | 5 |
+| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| arrays.js:144:50:144:59 | [CallExpr] sink(item) | arrays.js:144:50:144:53 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:144:50:144:59 | [CallExpr] sink(item) | arrays.js:144:50:144:53 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:144:50:144:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:144:50:144:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | arrays.js:145:5:145:8 | [VarRef] sink | semmle.label | 0 |
+| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | arrays.js:145:5:145:8 | [VarRef] sink | semmle.order | 0 |
+| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.label | 1 |
+| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.order | 1 |
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 |
| file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 |
@@ -1634,6 +2080,46 @@ edges
| file://:0:0:0:0 | (Arguments) | arrays.js:108:45:108:50 | [SpreadElement] ...arr | semmle.order | 2 |
| file://:0:0:0:0 | (Arguments) | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:115:50:115:53 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:115:50:115:53 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:116:10:116:16 | [VarRef] element | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:116:10:116:16 | [VarRef] element | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:121:46:121:49 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:121:46:121:49 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:122:10:122:16 | [VarRef] element | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:122:10:122:16 | [VarRef] element | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:127:55:127:58 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:127:55:127:58 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:128:10:128:16 | [VarRef] element | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:128:10:128:16 | [VarRef] element | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:132:46:132:49 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:132:46:132:49 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:133:10:133:17 | [VarRef] element1 | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:133:10:133:17 | [VarRef] element1 | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:138:50:138:53 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:138:50:138:53 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:139:10:139:17 | [VarRef] element1 | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:139:10:139:17 | [VarRef] element1 | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:144:55:144:58 | [VarRef] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:144:55:144:58 | [VarRef] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:145:10:145:17 | [VarRef] element1 | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | arrays.js:145:10:145:17 | [VarRef] element1 | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 |
@@ -1652,5 +2138,17 @@ edges
| file://:0:0:0:0 | (Parameters) | arrays.js:95:27:95:27 | [SimpleParameter] x | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.order | 0 |
graphProperties
| semmle.graphKind | tree |
diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected
index f81405a32a2..b6d5ab1e435 100644
--- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected
+++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected
@@ -209,6 +209,10 @@ typeInferenceMismatch
| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:27:14:27:22 | RegExp.$1 |
| static-capture-groups.js:32:17:32:24 | source() | static-capture-groups.js:38:10:38:18 | RegExp.$1 |
| static-capture-groups.js:42:12:42:19 | source() | static-capture-groups.js:43:14:43:22 | RegExp.$1 |
+| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:3:10:3:25 | x.toWellFormed() |
+| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:6:10:6:20 | wellFormedX |
+| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:9:10:9:26 | concatWellFormedX |
+| string-immutable-operations.js:11:10:11:17 | source() | string-immutable-operations.js:11:10:11:32 | source( ... ormed() |
| string-replace.js:3:13:3:20 | source() | string-replace.js:14:10:14:13 | data |
| string-replace.js:3:13:3:20 | source() | string-replace.js:18:10:18:13 | data |
| string-replace.js:3:13:3:20 | source() | string-replace.js:21:6:21:41 | safe(). ... taint) |
@@ -244,8 +248,19 @@ typeInferenceMismatch
| tst.js:2:13:2:20 | source() | tst.js:66:10:66:16 | xSorted |
| tst.js:2:13:2:20 | source() | tst.js:68:10:68:23 | x.toReversed() |
| tst.js:2:13:2:20 | source() | tst.js:70:10:70:18 | xReversed |
-| tst.js:2:13:2:20 | source() | tst.js:72:10:72:17 | x.with() |
-| tst.js:2:13:2:20 | source() | tst.js:74:10:74:14 | xWith |
+| tst.js:2:13:2:20 | source() | tst.js:72:10:72:31 | Map.gro ... z => z) |
+| tst.js:2:13:2:20 | source() | tst.js:74:10:74:34 | Object. ... z => z) |
+| tst.js:2:13:2:20 | source() | tst.js:78:55:78:58 | item |
+| tst.js:2:13:2:20 | source() | tst.js:79:14:79:20 | grouped |
+| tst.js:2:13:2:20 | source() | tst.js:100:10:100:17 | x.with() |
+| tst.js:2:13:2:20 | source() | tst.js:102:10:102:14 | xWith |
+| tst.js:75:22:75:29 | source() | tst.js:75:10:75:52 | Map.gro ... (item)) |
+| tst.js:75:22:75:29 | source() | tst.js:75:47:75:50 | item |
+| tst.js:82:23:82:30 | source() | tst.js:83:58:83:61 | item |
+| tst.js:82:23:82:30 | source() | tst.js:84:14:84:20 | grouped |
+| tst.js:87:22:87:29 | source() | tst.js:90:14:90:25 | taintedValue |
+| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue |
+| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) |
| xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text |
| xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result |
| xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr |
diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected
index 33a27661ecd..3b89229b2d7 100644
--- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected
+++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected
@@ -112,3 +112,5 @@
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
| tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe |
+| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue |
+| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) |
diff --git a/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js b/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js
new file mode 100644
index 00000000000..79e93fab002
--- /dev/null
+++ b/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js
@@ -0,0 +1,12 @@
+function test() {
+ let x = source();
+ sink(x.toWellFormed()); // NOT OK
+
+ const wellFormedX = x.toWellFormed();
+ sink(wellFormedX); // NOT OK
+
+ const concatWellFormedX = "/" + wellFormedX + "!";
+ sink(concatWellFormedX); // NOT OK
+
+ sink(source().toWellFormed()); // NOT OK
+}
diff --git a/javascript/ql/test/library-tests/TaintTracking/tst.js b/javascript/ql/test/library-tests/TaintTracking/tst.js
index 13b4ea48d8d..8fbc5e525bd 100644
--- a/javascript/ql/test/library-tests/TaintTracking/tst.js
+++ b/javascript/ql/test/library-tests/TaintTracking/tst.js
@@ -69,6 +69,34 @@ function test() {
const xReversed = x.toReversed();
sink(xReversed) // NOT OK
+ sink(Map.groupBy(x, z => z)); // NOT OK
+ sink(Custom.groupBy(x, z => z)); // OK
+ sink(Object.groupBy(x, z => z)); // NOT OK
+ sink(Map.groupBy(source(), (item) => sink(item))); // NOT OK
+
+ {
+ const grouped = Map.groupBy(x, (item) => sink(item)); // NOT OK
+ sink(grouped); // NOT OK
+ }
+ {
+ const list = [source()];
+ const grouped = Map.groupBy(list, (item) => sink(item)); // NOT OK
+ sink(grouped); // NOT OK
+ }
+ {
+ const data = source();
+ const result = Object.groupBy(data, item => item);
+ const taintedValue = result[notDefined()];
+ sink(taintedValue); // NOT OK
+ }
+ {
+ const data = source();
+ const map = Map.groupBy(data, item => item);
+ const taintedValue = map.get(true);
+ sink(taintedValue); // NOT OK
+ sink(map.get(true)); // NOT OK
+ }
+
sink(x.with()) // NOT OK
const xWith = x.with();
sink(xWith) // NOT OK
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
index 3061a6ba1f0..df304b899bb 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
+++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
@@ -1877,8 +1877,35 @@ nodes
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | semmle.label | [MethodCallExpr] obj[key ... rCase() |
| tst.ts:508:21:508:23 | [VarRef] key | semmle.label | [VarRef] key |
| tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.label | [Label] toUpperCase |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | semmle.label | [NamespaceDeclaration] namespa ... type. } |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | semmle.order | 92 |
+| tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.label | [VarDecl] TS57 |
+| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.label | [DeclStmt] const a = ... |
+| tst.ts:514:17:514:17 | [VarDecl] a | semmle.label | [VarDecl] a |
+| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.label | [VariableDeclarator] a: symbol |
+| tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol |
+| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.label | [ExportDeclaration] export ... }; } |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.label | [ClassDefinition,TypeDefinition] class A ... }; } |
+| tst.ts:515:16:515:16 | [VarDecl] A | semmle.label | [VarDecl] A |
+| tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
+| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} |
+| tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} |
+| tst.ts:515:18:515:17 | [Label] constructor | semmle.label | [Label] constructor |
+| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.label | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } |
+| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.label | [FunctionExpr] [a]() { return 1 } |
+| tst.ts:516:8:516:8 | [VarRef] a | semmle.label | [VarRef] a |
+| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.label | [BlockStmt] { return 1 } |
+| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.label | [ReturnStmt] return 1 |
+| tst.ts:516:22:516:22 | [Literal] 1 | semmle.label | [Literal] 1 |
+| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.label | [DeclStmt] const e1 = ... |
+| tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.label | [VarDecl] e1 |
+| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.label | [VariableDeclarator] e1: A[typeof a] |
+| tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.label | [LocalTypeAccess] A |
+| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.label | [IndexedAccessTypeExpr] A[typeof a] |
+| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.label | [TypeofTypeExpr] typeof a |
+| tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.label | [LocalVarTypeAccess] a |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } |
-| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 92 |
+| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 93 |
| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } |
| tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | [VarDecl] tstModuleCJS |
| tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' |
@@ -1896,7 +1923,7 @@ nodes
| tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' |
| tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' |
| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } |
-| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 93 |
+| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 94 |
| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } |
| tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.label | [VarDecl] tstModuleES |
| tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' |
@@ -1914,7 +1941,7 @@ nodes
| tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' |
| tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' |
| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
-| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 94 |
+| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 |
| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixA.ts' |
@@ -1922,7 +1949,7 @@ nodes
| tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.label | [ReturnStmt] return ... xA.ts'; |
| tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.label | [Literal] 'tstSuffixA.ts' |
| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
-| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 |
+| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 96 |
| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ios.ts' |
@@ -1930,7 +1957,7 @@ nodes
| tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.label | [ReturnStmt] return ... os.ts'; |
| tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.label | [Literal] 'tstSuffixB.ios.ts' |
| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
-| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 96 |
+| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 97 |
| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ts' |
@@ -1938,16 +1965,16 @@ nodes
| tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.label | [ReturnStmt] return ... xB.ts'; |
| tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.label | [Literal] 'tstSuffixB.ts' |
| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; |
-| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 97 |
+| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 98 |
| type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B |
| type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean |
| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... |
-| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 98 |
+| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 99 |
| type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b |
| type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B |
| type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B |
| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; |
-| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 99 |
+| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 100 |
| type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray |
| type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T |
| type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T |
@@ -1959,14 +1986,14 @@ nodes
| type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray |
| type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... |
-| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 100 |
+| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 101 |
| type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> |
| type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray |
| type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray |
| type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; |
-| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 101 |
+| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 102 |
| type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json |
| type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] |
| type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -1982,12 +2009,12 @@ nodes
| type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... |
-| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 102 |
+| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 103 |
| type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json |
| type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json |
| type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; |
-| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 103 |
+| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 104 |
| type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode |
| type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] |
| type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -2003,7 +2030,7 @@ nodes
| type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
| type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] |
| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... |
-| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 104 |
+| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 105 |
| type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode |
| type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] |
| type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
@@ -2028,12 +2055,12 @@ nodes
| type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" |
| type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" |
| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
-| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 105 |
+| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 106 |
| type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} |
-| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 106 |
+| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 107 |
| type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} |
| type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
@@ -2041,36 +2068,36 @@ nodes
| type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} |
| type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor |
| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... |
-| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 107 |
+| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 108 |
| type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj |
| type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C |
| type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C |
| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} |
-| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 108 |
+| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 109 |
| type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} |
| type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E |
| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... |
-| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 109 |
+| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 110 |
| type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj |
| type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E |
| type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E |
| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} |
-| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 110 |
+| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 111 |
| type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} |
| type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N |
| type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; |
| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... |
-| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 111 |
+| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 112 |
| type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj |
| type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N |
| type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N |
| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
-| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 112 |
+| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 113 |
| type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } |
-| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 113 |
+| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 114 |
| type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I |
| type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S |
| type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S |
@@ -2078,14 +2105,14 @@ nodes
| type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; |
| type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S |
| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... |
-| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 114 |
+| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 115 |
| type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i |
| type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I |
| type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I |
| type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I |
| type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } |
-| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 115 |
+| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 116 |
| type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
| type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} |
@@ -2097,14 +2124,14 @@ nodes
| type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T |
| type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... |
-| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 116 |
+| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 117 |
| type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C |
| type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C |
| type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C |
| type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } |
-| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 117 |
+| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 118 |
| type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color |
| type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red |
| type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red |
@@ -2113,29 +2140,29 @@ nodes
| type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue |
| type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue |
| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... |
-| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 118 |
+| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 119 |
| type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color |
| type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color |
| type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color |
| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } |
-| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 119 |
+| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 120 |
| type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember |
| type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member |
| type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member |
| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... |
-| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 120 |
+| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 121 |
| type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e |
| type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember |
| type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember |
| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; |
-| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 121 |
+| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 122 |
| type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias |
| type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T |
| type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T |
| type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] |
| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... |
-| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 122 |
+| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 123 |
| type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray |
| type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> |
| type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias |
@@ -5534,6 +5561,56 @@ edges
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.order | 2 |
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.label | 0 |
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.order | 0 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.label | 1 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.order | 1 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.label | 2 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.order | 2 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.label | 3 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.order | 3 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.label | 4 |
+| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.order | 4 |
+| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.label | 1 |
+| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.order | 1 |
+| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:17:514:17 | [VarDecl] a | semmle.label | 1 |
+| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:17:514:17 | [VarDecl] a | semmle.order | 1 |
+| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.label | 2 |
+| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.order | 2 |
+| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.label | 1 |
+| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.order | 1 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:16:515:16 | [VarDecl] A | semmle.label | 1 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:16:515:16 | [VarDecl] A | semmle.order | 1 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | 2 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.order | 2 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.label | 3 |
+| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.order | 3 |
+| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.label | 2 |
+| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.order | 2 |
+| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [Label] constructor | semmle.label | 1 |
+| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [Label] constructor | semmle.order | 1 |
+| tst.ts:515:18:515:17 | [FunctionExpr] () {} | tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.label | 5 |
+| tst.ts:515:18:515:17 | [FunctionExpr] () {} | tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.order | 5 |
+| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.label | 1 |
+| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.order | 1 |
+| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:8:516:8 | [VarRef] a | semmle.label | 2 |
+| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:8:516:8 | [VarRef] a | semmle.order | 2 |
+| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.label | 5 |
+| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.order | 5 |
+| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.label | 1 |
+| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.order | 1 |
+| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | tst.ts:516:22:516:22 | [Literal] 1 | semmle.label | 1 |
+| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | tst.ts:516:22:516:22 | [Literal] 1 | semmle.order | 1 |
+| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.label | 1 |
+| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.order | 1 |
+| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.label | 1 |
+| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.order | 1 |
+| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.label | 2 |
+| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.order | 2 |
+| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.label | 1 |
+| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.order | 1 |
+| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.label | 2 |
+| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.order | 2 |
+| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.label | 1 |
+| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.order | 1 |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | 1 |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.order | 1 |
| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | 0 |
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
index b786fae3713..150ce186724 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
+++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected
@@ -728,6 +728,13 @@ getExprType
| tst.ts:508:17:508:38 | obj[key ... rCase() | string |
| tst.ts:508:21:508:23 | key | string |
| tst.ts:508:26:508:36 | toUpperCase | () => string |
+| tst.ts:513:11:513:14 | TS57 | typeof TS57 in tst.ts |
+| tst.ts:514:17:514:17 | a | symbol |
+| tst.ts:515:16:515:16 | A | A |
+| tst.ts:516:7:516:24 | [a]() { return 1 } | () => number |
+| tst.ts:516:8:516:8 | a | symbol |
+| tst.ts:516:22:516:22 | 1 | 1 |
+| tst.ts:519:17:519:18 | e1 | () => number |
| tstModuleCJS.cts:1:17:1:28 | tstModuleCJS | () => "a" \| "b" |
| tstModuleCJS.cts:2:12:2:15 | Math | Math |
| tstModuleCJS.cts:2:12:2:22 | Math.random | () => number |
@@ -843,6 +850,7 @@ getTypeDefinitionType
| tst.ts:447:5:458:5 | class P ... }\\n } | Person |
| tst.ts:473:5:476:5 | class S ... ;\\n } | SomeClass |
| tst.ts:481:5:481:34 | type Pa ... T, T]; | Pair3 |
+| tst.ts:515:10:517:3 | class A ... };\\n } | A |
| type_alias.ts:1:1:1:17 | type B = boolean; | boolean |
| type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray |
| type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json |
@@ -1219,6 +1227,11 @@ getTypeExprType
| tst.ts:506:27:506:32 | string | string |
| tst.ts:506:35:506:41 | unknown | unknown |
| tst.ts:506:50:506:55 | string | string |
+| tst.ts:514:20:514:25 | symbol | symbol |
+| tst.ts:519:21:519:21 | A | A |
+| tst.ts:519:21:519:31 | A[typeof a] | () => number |
+| tst.ts:519:23:519:30 | typeof a | symbol |
+| tst.ts:519:30:519:30 | a | symbol |
| tstModuleCJS.cts:1:33:1:35 | 'a' | "a" |
| tstModuleCJS.cts:1:33:1:41 | 'a' \| 'b' | "a" \| "b" |
| tstModuleCJS.cts:1:39:1:41 | 'b' | "b" |
@@ -1290,6 +1303,7 @@ getTypeExprType
missingToString
referenceDefinition
| A | badTypes.ts:5:1:5:29 | interfa ... is.B {} |
+| A | tst.ts:515:10:517:3 | class A ... };\\n } |
| Action | tst.ts:252:3:254:50 | type Ac ... ring }; |
| Alias | type_definitions.ts:21:1:21:20 | type Alias = T[]; |
| Alias | type_definitions.ts:21:1:21:20 | type Alias = T[]; |
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts
index 4c29465b564..87f876be9d0 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts
+++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts
@@ -508,4 +508,13 @@ module TS55 {
var str = obj[key].toUpperCase(); // Now okay, previously was error
}
}
-}
\ No newline at end of file
+}
+
+namespace TS57{
+ declare const a: symbol;
+ export class A {
+ [a]() { return 1 };
+ }
+
+ declare const e1: A[typeof a]; // Now okay, previously was compilation error TS2538: Type 'symbol' cannot be used as an index type.
+}
diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected
index 1cbbd9faa5a..dec3eea044d 100644
--- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected
+++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected
@@ -7,3 +7,5 @@
| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function onlySideEffects2 |
| tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function |
| tst.js:80:12:80:50 | filter( ... 3) } ) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:80:28:80:48 | x => { ... x, 3) } | callback function |
+| tst.js:114:12:114:56 | [1,2,3] ... 3); }) | the $@ does not return anything, yet the return value from the call to findLastIndex is used. | tst.js:114:34:114:55 | n => { ... , 3); } | callback function |
+| tst.js:117:12:117:51 | [1,2,3] ... 3); }) | the $@ does not return anything, yet the return value from the call to findLast is used. | tst.js:117:29:117:50 | n => { ... , 3); } | callback function |
diff --git a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js
index dbedb3dee3c..7b9968115f5 100644
--- a/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js
+++ b/javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js
@@ -107,3 +107,13 @@ class Bar extends Foo {
console.log(super()); // OK.
}
}
+
+() => {
+ let equals = (x, y) => { return x === y; };
+
+ var foo = [1,2,3].findLastIndex(n => { equals(n, 3); }) // NOT OK
+ console.log(foo);
+
+ var foo = [1,2,3].findLast(n => { equals(n, 3); }) // NOT OK
+ console.log(foo);
+}
diff --git a/misc/codegen/codegen.py b/misc/codegen/codegen.py
index acc8e59bba5..ae3a67d3fba 100755
--- a/misc/codegen/codegen.py
+++ b/misc/codegen/codegen.py
@@ -54,6 +54,8 @@ def _parse_args() -> argparse.Namespace:
"generated qll file importing every class file"),
p.add_argument("--ql-test-output",
help="output directory for QL generated extractor test files"),
+ p.add_argument("--ql-cfg-output",
+ help="output directory for QL CFG layer (optional)."),
p.add_argument("--cpp-output",
help="output directory for generated C++ files, required if trap or cpp is provided to "
"--generate"),
diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py
index c5e7153489b..e42c9d01552 100755
--- a/misc/codegen/generators/qlgen.py
+++ b/misc/codegen/generators/qlgen.py
@@ -118,17 +118,18 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
type_is_hideable="ql_hideable" in lookup[prop.type].pragmas if prop.type in lookup else False,
internal="ql_internal" in prop.pragmas,
)
+ ql_name = prop.pragmas.get("ql_name", prop.name)
if prop.is_single:
args.update(
- singular=inflection.camelize(prop.name),
+ singular=inflection.camelize(ql_name),
tablename=inflection.tableize(cls.name),
tableparams=["this"] + ["result" if p is prop else "_" for p in cls.properties if p.is_single],
doc=_get_doc(cls, prop),
)
elif prop.is_repeated:
args.update(
- singular=inflection.singularize(inflection.camelize(prop.name)),
- plural=inflection.pluralize(inflection.camelize(prop.name)),
+ singular=inflection.singularize(inflection.camelize(ql_name)),
+ plural=inflection.pluralize(inflection.camelize(ql_name)),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "index", "result"] if not prop.is_unordered else ["this", "result"],
doc=_get_doc(cls, prop, plural=False),
@@ -136,14 +137,14 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
)
elif prop.is_optional:
args.update(
- singular=inflection.camelize(prop.name),
+ singular=inflection.camelize(ql_name),
tablename=inflection.tableize(f"{cls.name}_{prop.name}"),
tableparams=["this", "result"],
doc=_get_doc(cls, prop),
)
elif prop.is_predicate:
args.update(
- singular=inflection.camelize(prop.name, uppercase_first_letter=False),
+ singular=inflection.camelize(ql_name, uppercase_first_letter=False),
tablename=inflection.underscore(f"{cls.name}_{prop.name}"),
tableparams=["this"],
doc=_get_doc(cls, prop),
@@ -154,12 +155,16 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic
def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> ql.Class:
+ if "ql_name" in cls.pragmas:
+ raise Error("ql_name is not supported yet for classes, only for properties")
prev_child = ""
properties = []
for p in cls.properties:
prop = get_ql_property(cls, p, lookup, prev_child)
if prop.is_child:
prev_child = prop.singular
+ if prop.type in lookup and lookup[prop.type].cfg:
+ prop.cfg = True
properties.append(prop)
return ql.Class(
name=cls.name,
@@ -171,6 +176,16 @@ def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> q
doc=cls.doc,
hideable="ql_hideable" in cls.pragmas,
internal="ql_internal" in cls.pragmas,
+ cfg=cls.cfg,
+ )
+
+
+def get_ql_cfg_class(cls: schema.Class, lookup: typing.Dict[str, ql.Class]) -> ql.CfgClass:
+ return ql.CfgClass(
+ name=cls.name,
+ bases=[base for base in cls.bases if lookup[base.base].cfg],
+ properties=cls.properties,
+ doc=cls.doc
)
@@ -361,6 +376,7 @@ def generate(opts, renderer):
input = opts.schema
out = opts.ql_output
stub_out = opts.ql_stub_output
+ cfg_out = opts.ql_cfg_output
test_out = opts.ql_test_output
missing_test_source_filename = "MISSING_SOURCE.txt"
include_file = stub_out.with_suffix(".qll")
@@ -385,6 +401,7 @@ def generate(opts, renderer):
imports = {}
imports_impl = {}
classes_used_by = {}
+ cfg_classes = []
generated_import_prefix = get_import(out, opts.root_dir)
registry = opts.generated_registry or pathlib.Path(
os.path.commonpath((out, stub_out, test_out)), ".generated.list")
@@ -402,6 +419,8 @@ def generate(opts, renderer):
imports[c.name] = path
path_impl = get_import(stub_out / c.dir / "internal" / c.name, opts.root_dir)
imports_impl[c.name + "Impl"] = path_impl + "Impl"
+ if c.cfg:
+ cfg_classes.append(get_ql_cfg_class(c, classes))
for c in classes.values():
qll = out / c.path.with_suffix(".qll")
@@ -411,6 +430,14 @@ def generate(opts, renderer):
c.import_prefix = generated_import_prefix
renderer.render(c, qll)
+ if cfg_out:
+ cfg_classes_val = ql.CfgClasses(
+ include_file_import=get_import(include_file, opts.root_dir),
+ classes=cfg_classes
+ )
+ cfg_qll = cfg_out / "CfgNodes.qll"
+ renderer.render(cfg_classes_val, cfg_qll)
+
for c in data.classes.values():
path = _get_path(c)
path_impl = _get_path_impl(c)
diff --git a/misc/codegen/lib/ql.py b/misc/codegen/lib/ql.py
index 1920a813e20..1182c7f5dc1 100644
--- a/misc/codegen/lib/ql.py
+++ b/misc/codegen/lib/ql.py
@@ -45,6 +45,7 @@ class Property:
synth: bool = False
type_is_hideable: bool = False
internal: bool = False
+ cfg: bool = False
def __post_init__(self):
if self.tableparams:
@@ -110,6 +111,7 @@ class Class:
internal: bool = False
doc: List[str] = field(default_factory=list)
hideable: bool = False
+ cfg: bool = False
def __post_init__(self):
def get_bases(bases): return [Base(str(b), str(prev)) for b, prev in zip(bases, itertools.chain([""], bases))]
@@ -333,3 +335,18 @@ class Synth:
cls: "Synth.FinalClass"
import_prefix: str
+
+
+@dataclass
+class CfgClass:
+ name: str
+ bases: List[Base] = field(default_factory=list)
+ properties: List[Property] = field(default_factory=list)
+ doc: List[str] = field(default_factory=list)
+
+
+@dataclass
+class CfgClasses:
+ template: ClassVar = 'ql_cfg_nodes'
+ include_file_import: Optional[str] = None
+ classes: List[CfgClass] = field(default_factory=list)
diff --git a/misc/codegen/lib/schema.py b/misc/codegen/lib/schema.py
index c5c3dc810b6..23f1aea2ba4 100644
--- a/misc/codegen/lib/schema.py
+++ b/misc/codegen/lib/schema.py
@@ -94,6 +94,7 @@ class Class:
properties: List[Property] = field(default_factory=list)
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
doc: List[str] = field(default_factory=list)
+ cfg: bool = False
def __post_init__(self):
if not isinstance(self.pragmas, dict):
diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py
index 997b85b4ca6..8651240c1a3 100644
--- a/misc/codegen/lib/schemadefs.py
+++ b/misc/codegen/lib/schemadefs.py
@@ -72,11 +72,11 @@ def include(source: str):
@_dataclass
class _Namespace:
""" simple namespacing mechanism """
- name: str
+ _name: str
def add(self, pragma: "_PragmaBase", key: str | None = None):
self.__dict__[pragma.pragma] = pragma
- pragma.pragma = key or f"{self.name}_{pragma.pragma}"
+ pragma.pragma = key or f"{self._name}_{pragma.pragma}"
@_dataclass
@@ -87,7 +87,7 @@ class _SynthModifier(_schema.PropertyModifier, _Namespace):
prop.synth = self.synth
def negate(self) -> _schema.PropertyModifier:
- return _SynthModifier(self.name, False)
+ return _SynthModifier(self._name, False)
qltest = _Namespace("qltest")
@@ -239,6 +239,7 @@ qltest.add(_ParametrizedClassPragma("test_with", inherited=True, factory=_schema
ql.add(_ParametrizedClassPragma("default_doc_name", factory=lambda doc: doc))
ql.add(_ClassPragma("hideable", inherited=True))
ql.add(_Pragma("internal"))
+ql.add(_ParametrizedPragma("name", factory=lambda name: name))
cpp.add(_Pragma("skip"))
@@ -256,30 +257,24 @@ synth.add(_ParametrizedClassPragma("on_arguments", factory=lambda **kwargs:
_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth")
+@_dataclass(frozen=True)
class _PropertyModifierList(_schema.PropertyModifier):
- def __init__(self):
- self._mods = []
+ _mods: tuple[_schema.PropertyModifier, ...]
def __or__(self, other: _schema.PropertyModifier):
- self._mods.append(other)
- return self
+ return _PropertyModifierList(self._mods + (other,))
def modify(self, prop: Property):
for m in self._mods:
m.modify(prop)
-class _PropertyAnnotation:
- def __or__(self, other: _schema.PropertyModifier):
- return _PropertyModifierList() | other
-
-
-_ = _PropertyAnnotation()
+_ = _PropertyModifierList(())
drop = object()
-def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, replace_bases: _Dict[type, type] | None = None) -> _Callable[[type], _PropertyAnnotation]:
+def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, replace_bases: _Dict[type, type] | None = None, cfg: bool = False) -> _Callable[[type], _PropertyModifierList]:
"""
Add or modify schema annotations after a class has been defined previously.
@@ -287,7 +282,7 @@ def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, repl
`replace_bases` can be used to replace bases on the annotated class.
"""
- def decorator(cls: type) -> _PropertyAnnotation:
+ def decorator(cls: type) -> _PropertyModifierList:
if cls.__name__ != "_":
raise _schema.Error("Annotation classes must be named _")
if cls.__doc__ is not None:
@@ -298,6 +293,7 @@ def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, repl
annotated_cls.__bases__ = tuple(replace_bases.get(b, b) for b in annotated_cls.__bases__)
if add_bases:
annotated_cls.__bases__ += tuple(add_bases)
+ annotated_cls.__cfg__ = cfg
for a in dir(cls):
if a.startswith(_schema.inheritable_pragma_prefix):
setattr(annotated_cls, a, getattr(cls, a))
@@ -306,7 +302,7 @@ def annotate(annotated_cls: type, add_bases: _Iterable[type] | None = None, repl
del annotated_cls.__annotations__[p]
elif p in annotated_cls.__annotations__:
annotated_cls.__annotations__[p] |= a
- elif isinstance(a, (_PropertyAnnotation, _PropertyModifierList)):
+ elif isinstance(a, (_PropertyModifierList, _PropertyModifierList)):
raise _schema.Error(f"annotated property {p} not present in annotated class "
f"{annotated_cls.__name__}")
else:
diff --git a/misc/codegen/loaders/schemaloader.py b/misc/codegen/loaders/schemaloader.py
index 069e3b65474..dd1edee1de0 100644
--- a/misc/codegen/loaders/schemaloader.py
+++ b/misc/codegen/loaders/schemaloader.py
@@ -53,6 +53,7 @@ def _get_class(cls: type) -> schema.Class:
bases=[b.__name__ for b in cls.__bases__ if b is not object],
derived=derived,
pragmas=pragmas,
+ cfg=cls.__cfg__ if hasattr(cls, "__cfg__") else False,
# in the following we don't use `getattr` to avoid inheriting
properties=[
a | _PropertyNamer(n)
diff --git a/misc/codegen/templates/ql_cfg_nodes.mustache b/misc/codegen/templates/ql_cfg_nodes.mustache
new file mode 100644
index 00000000000..a2edf4410be
--- /dev/null
+++ b/misc/codegen/templates/ql_cfg_nodes.mustache
@@ -0,0 +1,199 @@
+// generated by {{generator}}, do not edit
+/**
+ * This module provides generated wrappers around the `CfgNode` type.
+ *
+ * INTERNAL: Do not import directly.
+ */
+
+private import codeql.util.Location
+private import codeql.util.Unit
+private import {{include_file_import}}
+
+/** Provides the input to `MakeCfgNodes` */
+signature module InputSig {
+ class CfgNode {
+ AstNode getAstNode();
+
+ string toString();
+
+ Loc getLocation();
+ }
+
+ AstNode getDesugared(AstNode n);
+}
+
+/**
+ * Given a `CfgNode` implementation, provides the module `Nodes` that
+ * contains wrappers around `CfgNode` for relevant classes.
+ */
+module MakeCfgNodes Input> {
+ private import Input
+
+ final private class AstNodeFinal = AstNode;
+
+ final private class CfgNodeFinal = CfgNode;
+
+ /**
+ * INTERNAL: Do not expose.
+ */
+ abstract class ParentAstNode extends AstNodeFinal {
+ /**
+ * Holds if `child` is a (possibly nested) child of this AST node
+ * for which we would like to find a matching CFG child.
+ */
+ abstract predicate relevantChild(AstNode child);
+ }
+
+ /**
+ * INTERNAL: Do not expose.
+ */
+ abstract class ChildMapping extends Unit {
+ /**
+ * Holds if `child` is a (possibly nested) child of AST node `parent`
+ * for which we would like to find a matching CFG child.
+ */
+ final predicate relevantChild(AstNode parent, AstNode child) {
+ parent.(ParentAstNode).relevantChild(child)
+ }
+
+ /**
+ * Holds if there is a control flow path from `cfn` to `cfnChild`, where `cfn`
+ * is a control flow node for this AST node, and `cfnChild` is a control flow
+ * node for `child`.
+ *
+ * This predicate should be implemented at the place where `MakeCfgNodes` is
+ * invoked. Ideally, `MakeCfgNodes` should be a higher-order parameterized
+ * module, but since that is currently not supported, we achieve the "callback"
+ * effect using this `abstract` class instead.
+ */
+ cached
+ abstract predicate hasCfgChild(AstNode parent, AstNode child, CfgNode cfn, CfgNode cfnChild);
+ }
+
+ /** Provides sub classes of `CfgNode`. */
+ module Nodes {
+ {{#classes}}
+ private final class Parent{{name}} extends ParentAstNode, {{name}} {
+ override predicate relevantChild(AstNode child) {
+ none()
+ {{#properties}}
+ {{#cfg}}
+ or
+ child = this.{{getter}}({{#is_indexed}}_{{/is_indexed}})
+ {{/cfg}}
+ {{/properties}}
+ }
+ }
+
+ /**
+ {{#doc}}
+ * {{.}}
+ {{/doc}}
+ */
+ final class {{name}}CfgNode extends CfgNodeFinal{{#bases}}, {{.}}CfgNode{{/bases}} {
+ private {{name}} node;
+
+ {{name}}CfgNode() {
+ node = this.getAstNode()
+ }
+
+ /** Gets the underlying `{{name}}`. */
+ {{name}} get{{name}}() { result = node }
+
+ {{#properties}}
+ /**
+ * {{>ql_property_doc}} *
+ {{#description}}
+ * {{.}}
+ {{/description}}
+ {{#internal}}
+ * INTERNAL: Do not use.
+ {{/internal}}
+ */
+ {{type}}{{#cfg}}CfgNode{{/cfg}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) {
+ {{#cfg}}
+ any(ChildMapping mapping).hasCfgChild(node, node.{{getter}}({{#is_indexed}}index{{/is_indexed}}), this, result)
+ {{/cfg}}
+ {{^cfg}}
+ {{^is_predicate}}result = {{/is_predicate}}node.{{getter}}({{#is_indexed}}index{{/is_indexed}})
+ {{/cfg}}
+ }
+
+ {{#is_optional}}
+ /**
+ * Holds if `{{getter}}({{#is_repeated}}index{{/is_repeated}})` exists.
+ {{#internal}}
+ * INTERNAL: Do not use.
+ {{/internal}}
+ */
+ predicate has{{singular}}({{#is_repeated}}int index{{/is_repeated}}) {
+ exists(this.{{getter}}({{#is_repeated}}index{{/is_repeated}}))
+ }
+ {{/is_optional}}
+ {{#is_indexed}}
+
+ /**
+ * Gets any of the {{doc_plural}}.
+ {{#internal}}
+ * INTERNAL: Do not use.
+ {{/internal}}
+ */
+ {{type}}{{#cfg}}CfgNode{{/cfg}} {{indefinite_getter}}() {
+ result = this.{{getter}}(_)
+ }
+ {{^is_optional}}
+
+ /**
+ * Gets the number of {{doc_plural}}.
+ {{#internal}}
+ * INTERNAL: Do not use.
+ {{/internal}}
+ */
+ int getNumberOf{{plural}}() {
+ result = count(int i | exists(this.{{getter}}(i)))
+ }
+ {{/is_optional}}
+ {{/is_indexed}}
+ {{#is_unordered}}
+ /**
+ * Gets the number of {{doc_plural}}.
+ {{#internal}}
+ * INTERNAL: Do not use.
+ {{/internal}}
+ */
+ int getNumberOf{{plural}}() {
+ result = count(this.{{getter}}())
+ }
+ {{/is_unordered}}
+ {{/properties}}
+ }
+ {{/classes}}
+ }
+
+ module Consistency {
+ private predicate hasCfgNode(AstNode astNode) {
+ astNode = any(CfgNode cfgNode).getAstNode()
+ }
+
+ query predicate missingCfgChild(CfgNode parent, string pred, int i, AstNode child) {
+ none()
+ {{#classes}}
+ {{#properties}}
+ {{#cfg}}
+ or
+ pred = "{{getter}}" and
+ parent = any(Nodes::{{name}}CfgNode cfgNode, {{name}} astNode |
+ astNode = cfgNode.get{{name}}() and
+ child = getDesugared(astNode.{{getter}}({{#is_indexed}}i{{/is_indexed}}))
+ {{^is_indexed}}and i = -1{{/is_indexed}} and
+ hasCfgNode(child) and
+ not child = cfgNode.{{getter}}({{#is_indexed}}i{{/is_indexed}}).getAstNode()
+ |
+ cfgNode
+ )
+ {{/cfg}}
+ {{/properties}}
+ {{/classes}}
+ }
+ }
+}
\ No newline at end of file
diff --git a/python/extractor/semmle/python/passes/pruner.py b/python/extractor/semmle/python/passes/pruner.py
index d6363e529f1..fe3b03d453c 100644
--- a/python/extractor/semmle/python/passes/pruner.py
+++ b/python/extractor/semmle/python/passes/pruner.py
@@ -196,6 +196,25 @@ class SkippedVisitor(ASTVisitor):
if isinstance(node.value, ast.Name):
self.nodes.add(node.value)
+class NotBooleanTestVisitor(ASTVisitor):
+ """Visitor that checks if a test is not a boolean test."""
+
+ def __init__(self):
+ self.nodes = set()
+
+ def visit_MatchLiteralPattern(self, node):
+ # MatchLiteralPatterns _look_ like boolean tests, but are not.
+ # Thus, without this check, we would interpret
+ #
+ # match x:
+ # case False:
+ # pass
+ #
+ # (and similarly for True) as if it was a boolean test. This would cause the true edge
+ # (leading to pass) to be pruned later on.
+ if isinstance(node.literal, ast.Name) and node.literal.id in ('True', 'False'):
+ self.nodes.add(node.literal)
+
class NonlocalVisitor(ASTVisitor):
def __init__(self):
self.names = set()
@@ -306,6 +325,8 @@ def effective_constants_definitions(bool_const_defns, graph, branching_edges):
def do_pruning(tree, graph):
v = BoolConstVisitor()
v.visit(tree)
+ not_boolean_test = NotBooleanTestVisitor()
+ not_boolean_test.visit(tree)
nonlocals = NonlocalVisitor()
nonlocals.visit(tree)
global_vars = GlobalVisitor()
@@ -353,6 +374,8 @@ def do_pruning(tree, graph):
b = const_value(pred.node)
if b is None:
continue
+ if pred.node in not_boolean_test.nodes:
+ continue
if b.contradicts(val):
to_be_removed.add((pred, succ))
if not to_be_removed:
diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected
new file mode 100644
index 00000000000..366de37b867
--- /dev/null
+++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected
@@ -0,0 +1,4 @@
+argumentToEnsureNotTaintedNotMarkedAsSpurious
+untaintedArgumentToEnsureTaintedNotMarkedAsMissing
+testFailures
+failures
diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py
new file mode 100644
index 00000000000..7719021890f
--- /dev/null
+++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py
@@ -0,0 +1,118 @@
+import threading
+import time
+
+# Test 1
+# TP - Flow is tracked through a global variable
+foo1 = None
+
+def bar1():
+ time.sleep(1)
+ ensure_tainted(foo1) # $tainted
+
+# The intent of these tests is to test how dataflow is handled through shared state accessed by different threads;
+# but the presense or absense of the actual call to start a thread does not affect the results (there is no special modelling for Thread)
+# threading.Thread(target=bar).start()
+
+foo1 = TAINTED_STRING
+
+# Test 2
+# FN - Flow is *not* tracked through an access path on a global variable
+foo2 = []
+
+def bar2():
+ time.sleep(1)
+ ensure_tainted(foo2[0]) # $MISSING:tainted
+
+threading.Thread(target=bar2).start()
+
+foo2.append(TAINTED_STRING)
+
+# Test 3
+# FN - Flow is not found even when there is a direct call
+foo3 = []
+
+def bar3():
+ time.sleep(1)
+ ensure_tainted(foo2[0]) # $MISSING:tainted
+
+foo3.append(TAINTED_STRING)
+bar3()
+
+# Tast 4
+# TP - Sanity check: Flow is found through a ListElement directly without a call
+foo4 = []
+foo4.append(TAINTED_STRING)
+ensure_tainted(foo4[0]) # $tainted
+
+# Test 5
+# FN - Flow is *not* tracked through a shared captured but non-global variable
+def test5():
+ foo5 = None
+
+ def bar5():
+ time.sleep(1)
+ ensure_tainted(foo5) # $MISSING:tainted
+
+ threading.Thread(target=bar5).start() # Only the presense of this thread call makes this an FN rather than a TN
+
+ foo5 = TAINTED_STRING
+
+ # Test 6
+ # TP - Flow is tracked through a shared captured but non-global variable with a direct call
+def test6():
+ foo6 = []
+
+ def bar6():
+ time.sleep(1)
+ ensure_tainted(foo6[0]) # $tainted
+
+ foo6.append(TAINTED_STRING)
+ bar6()
+
+
+# Test 7
+# FN - Flow is *not* found through an access path on a global variable that's also used as a parameter
+# We'd like to cover this case in order to be able to cover this CVE: https://github.com/github/codeql-python-CVE-coverage/issues/3176
+
+foo7 = []
+
+def bar7():
+ time.sleep(1)
+ ensure_tainted(foo7[0]) # $MISSING: tainted
+
+def baz7(loc_foo):
+ loc_foo.append(TAINTED_STRING)
+
+threading.Thread(target=bar7).start()
+
+baz7(foo7)
+
+# Test 8
+# FN - Flow is also *not* found in the above case through a direct call
+
+foo8 = []
+
+def bar8():
+ time.sleep(1)
+ ensure_tainted(foo8[0]) # $MISSING: tainted
+
+def baz8(loc_foo):
+ loc_foo.append(TAINTED_STRING)
+
+baz8(foo8)
+bar8()
+
+# Test 9
+# TP - Flow is found in the above case when the variable is captured rather than global
+
+def test9():
+ foo9 = []
+ def bar9():
+ time.sleep(1)
+ ensure_tainted(foo9[0]) # $tainted
+
+ def baz9(loc_foo):
+ loc_foo.append(TAINTED_STRING)
+
+ baz9(foo9)
+ bar9()
\ No newline at end of file
diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql
new file mode 100644
index 00000000000..dd01b5d3e34
--- /dev/null
+++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql
@@ -0,0 +1,3 @@
+import python
+import experimental.meta.InlineTaintTest
+import MakeInlineTaintTest
diff --git a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected
index 013d7a0fe68..2417041f472 100644
--- a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected
+++ b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.expected
@@ -4,5 +4,3 @@
| test.py:21:5:21:38 | For | This statement is unreachable. |
| test.py:28:9:28:21 | ExprStmt | This statement is unreachable. |
| test.py:84:5:84:21 | ExceptStmt | This statement is unreachable. |
-| test.py:144:13:144:16 | Pass | This statement is unreachable. |
-| test.py:147:9:148:16 | Case | This statement is unreachable. |
diff --git a/rust/ast-generator/src/main.rs b/rust/ast-generator/src/main.rs
index 665ffbac6c7..41e6caa6de3 100644
--- a/rust/ast-generator/src/main.rs
+++ b/rust/ast-generator/src/main.rs
@@ -14,24 +14,26 @@ fn project_root() -> PathBuf {
PathBuf::from(dir).parent().unwrap().to_owned()
}
-fn class_name(type_name: &String) -> String {
- match type_name.as_str() {
- "BinExpr" => "BinaryExpr".to_owned(),
- "ElseBranch" => "Expr".to_owned(),
- "Fn" => "Function".to_owned(),
- "Literal" => "LiteralExpr".to_owned(),
- "Type" => "TypeRef".to_owned(),
- _ => type_name.to_owned(),
- }
+fn class_name(type_name: &str) -> String {
+ let name = match type_name {
+ "BinExpr" => "BinaryExpr",
+ "ElseBranch" => "Expr",
+ "Fn" => "Function",
+ "Literal" => "LiteralExpr",
+ "Type" => "TypeRef",
+ _ => type_name,
+ };
+ name.to_owned()
}
-fn property_name(type_name: &String, field_name: &String) -> String {
- match (type_name.as_str(), field_name.as_str()) {
- ("Path", "segment") => "part".to_owned(),
- (_, "then_branch") => "then".to_owned(),
- (_, "else_branch") => "else_".to_owned(),
- _ => field_name.to_owned(),
- }
+fn property_name(type_name: &str, field_name: &str) -> String {
+ let name = match (type_name, field_name) {
+ ("Path", "segment") => "part",
+ (_, "then_branch") => "then",
+ (_, "else_branch") => "else_",
+ _ => field_name,
+ };
+ name.to_owned()
}
fn to_lower_snake_case(s: &str) -> String {
@@ -61,7 +63,7 @@ fn write_schema(
for node in &grammar.enums {
let super_classses = if let Some(cls) = super_types.get(&node.name) {
- let super_classes: Vec = cls.iter().map(class_name).collect();
+ let super_classes: Vec = cls.iter().map(|s| class_name(s)).collect();
super_classes.join(",")
} else {
"AstNode".to_owned()
@@ -76,7 +78,7 @@ fn write_schema(
}
for node in &grammar.nodes {
let super_classses = if let Some(cls) = super_types.get(&node.name) {
- let super_classes: Vec = cls.iter().map(class_name).collect();
+ let super_classes: Vec = cls.iter().map(|s| class_name(s)).collect();
super_classes.join(",")
} else {
"AstNode".to_owned()
diff --git a/rust/codegen.conf b/rust/codegen.conf
index 29b6edc8985..d40fada446b 100644
--- a/rust/codegen.conf
+++ b/rust/codegen.conf
@@ -4,6 +4,7 @@
--dbscheme=ql/lib/rust.dbscheme
--ql-output=ql/lib/codeql/rust/elements/internal/generated
--ql-stub-output=ql/lib/codeql/rust/elements
+--ql-cfg-output=ql/lib/codeql/rust/controlflow/internal/generated
--ql-test-output=ql/test/extractor-tests/generated
--rust-output=extractor/src/generated
--script-name=codegen
diff --git a/rust/extractor/src/generated/.generated.list b/rust/extractor/src/generated/.generated.list
index 7335c95f7b8..3ff79b9b041 100644
--- a/rust/extractor/src/generated/.generated.list
+++ b/rust/extractor/src/generated/.generated.list
@@ -1,2 +1,2 @@
mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7
-top.rs cdfb9890318d847e6db320abd8b9e9939524ecc47bcdc8491b9c8253bd3178c2 cdfb9890318d847e6db320abd8b9e9939524ecc47bcdc8491b9c8253bd3178c2
+top.rs 4504ceb7e13020d5b19a4b938395fa2d5d804a962743985efe8563903448ae0c 4504ceb7e13020d5b19a4b938395fa2d5d804a962743985efe8563903448ae0c
diff --git a/rust/extractor/src/generated/top.rs b/rust/extractor/src/generated/top.rs
index 13a0adecbca..a3e1d7aac80 100644
--- a/rust/extractor/src/generated/top.rs
+++ b/rust/extractor/src/generated/top.rs
@@ -1501,57 +1501,35 @@ impl From> for trap::Label {
}
#[derive(Debug)]
-pub struct Param {
- pub id: trap::TrapId,
- pub attrs: Vec>,
- pub pat: Option>,
- pub ty: Option>,
+pub struct ParamBase {
+ _unused: ()
}
-impl trap::TrapEntry for Param {
- fn extract_id(&mut self) -> trap::TrapId {
- std::mem::replace(&mut self.id, trap::TrapId::Star)
- }
-
- fn emit(self, id: trap::Label, out: &mut trap::Writer) {
- out.add_tuple("params", vec![id.into()]);
- for (i, v) in self.attrs.into_iter().enumerate() {
- out.add_tuple("param_attrs", vec![id.into(), i.into(), v.into()]);
- }
- if let Some(v) = self.pat {
- out.add_tuple("param_pats", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.ty {
- out.add_tuple("param_ties", vec![id.into(), v.into()]);
- }
- }
+impl trap::TrapClass for ParamBase {
+ fn class_name() -> &'static str { "ParamBase" }
}
-impl trap::TrapClass for Param {
- fn class_name() -> &'static str { "Param" }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme Param is a subclass of AstNode
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme ParamBase is a subclass of AstNode
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme Param is a subclass of Element
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme ParamBase is a subclass of Element
unsafe {
Self::from_untyped(value.as_untyped())
}
}
}
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme Param is a subclass of Locatable
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme ParamBase is a subclass of Locatable
unsafe {
Self::from_untyped(value.as_untyped())
}
@@ -2203,72 +2181,6 @@ impl From> for trap::Label {
}
}
-#[derive(Debug)]
-pub struct SelfParam {
- pub id: trap::TrapId,
- pub attrs: Vec>,
- pub is_mut: bool,
- pub lifetime: Option>,
- pub name: Option>,
- pub ty: Option>,
-}
-
-impl trap::TrapEntry for SelfParam {
- fn extract_id(&mut self) -> trap::TrapId {
- std::mem::replace(&mut self.id, trap::TrapId::Star)
- }
-
- fn emit(self, id: trap::Label, out: &mut trap::Writer) {
- out.add_tuple("self_params", vec![id.into()]);
- for (i, v) in self.attrs.into_iter().enumerate() {
- out.add_tuple("self_param_attrs", vec![id.into(), i.into(), v.into()]);
- }
- if self.is_mut {
- out.add_tuple("self_param_is_mut", vec![id.into()]);
- }
- if let Some(v) = self.lifetime {
- out.add_tuple("self_param_lifetimes", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.name {
- out.add_tuple("self_param_names", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.ty {
- out.add_tuple("self_param_ties", vec![id.into(), v.into()]);
- }
- }
-}
-
-impl trap::TrapClass for SelfParam {
- fn class_name() -> &'static str { "SelfParam" }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme SelfParam is a subclass of AstNode
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme SelfParam is a subclass of Element
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme SelfParam is a subclass of Locatable
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
#[derive(Debug)]
pub struct SourceFile {
pub id: trap::TrapId,
@@ -3568,97 +3480,6 @@ impl From> for trap::Label {
}
}
-#[derive(Debug)]
-pub struct BlockExpr {
- pub id: trap::TrapId,
- pub attrs: Vec>,
- pub is_async: bool,
- pub is_const: bool,
- pub is_gen: bool,
- pub is_move: bool,
- pub is_try: bool,
- pub is_unsafe: bool,
- pub label: Option>,
- pub stmt_list: Option>,
-}
-
-impl trap::TrapEntry for BlockExpr {
- fn extract_id(&mut self) -> trap::TrapId {
- std::mem::replace(&mut self.id, trap::TrapId::Star)
- }
-
- fn emit(self, id: trap::Label, out: &mut trap::Writer) {
- out.add_tuple("block_exprs", vec![id.into()]);
- for (i, v) in self.attrs.into_iter().enumerate() {
- out.add_tuple("block_expr_attrs", vec![id.into(), i.into(), v.into()]);
- }
- if self.is_async {
- out.add_tuple("block_expr_is_async", vec![id.into()]);
- }
- if self.is_const {
- out.add_tuple("block_expr_is_const", vec![id.into()]);
- }
- if self.is_gen {
- out.add_tuple("block_expr_is_gen", vec![id.into()]);
- }
- if self.is_move {
- out.add_tuple("block_expr_is_move", vec![id.into()]);
- }
- if self.is_try {
- out.add_tuple("block_expr_is_try", vec![id.into()]);
- }
- if self.is_unsafe {
- out.add_tuple("block_expr_is_unsafe", vec![id.into()]);
- }
- if let Some(v) = self.label {
- out.add_tuple("block_expr_labels", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.stmt_list {
- out.add_tuple("block_expr_stmt_lists", vec![id.into(), v.into()]);
- }
- }
-}
-
-impl trap::TrapClass for BlockExpr {
- fn class_name() -> &'static str { "BlockExpr" }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme BlockExpr is a subclass of AstNode
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme BlockExpr is a subclass of Element
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme BlockExpr is a subclass of Expr
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme BlockExpr is a subclass of Locatable
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
#[derive(Debug)]
pub struct BoxPat {
pub id: trap::TrapId,
@@ -4582,81 +4403,6 @@ impl From> for trap::Label {
}
}
-#[derive(Debug)]
-pub struct ForExpr {
- pub id: trap::TrapId,
- pub attrs: Vec>,
- pub iterable: Option>,
- pub label: Option>,
- pub loop_body: Option>,
- pub pat: Option>,
-}
-
-impl trap::TrapEntry for ForExpr {
- fn extract_id(&mut self) -> trap::TrapId {
- std::mem::replace(&mut self.id, trap::TrapId::Star)
- }
-
- fn emit(self, id: trap::Label, out: &mut trap::Writer) {
- out.add_tuple("for_exprs", vec![id.into()]);
- for (i, v) in self.attrs.into_iter().enumerate() {
- out.add_tuple("for_expr_attrs", vec![id.into(), i.into(), v.into()]);
- }
- if let Some(v) = self.iterable {
- out.add_tuple("for_expr_iterables", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.label {
- out.add_tuple("for_expr_labels", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.loop_body {
- out.add_tuple("for_expr_loop_bodies", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.pat {
- out.add_tuple("for_expr_pats", vec![id.into(), v.into()]);
- }
- }
-}
-
-impl trap::TrapClass for ForExpr {
- fn class_name() -> &'static str { "ForExpr" }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme ForExpr is a subclass of AstNode
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme ForExpr is a subclass of Element
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme ForExpr is a subclass of Expr
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme ForExpr is a subclass of Locatable
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
#[derive(Debug)]
pub struct ForType {
pub id: trap::TrapId,
@@ -5168,6 +4914,51 @@ impl From> for trap::Label {
}
}
+#[derive(Debug)]
+pub struct LabelableExpr {
+ _unused: ()
+}
+
+impl trap::TrapClass for LabelableExpr {
+ fn class_name() -> &'static str { "LabelableExpr" }
+}
+
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme LabelableExpr is a subclass of AstNode
+ unsafe {
+ Self::from_untyped(value.as_untyped())
+ }
+ }
+}
+
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme LabelableExpr is a subclass of Element
+ unsafe {
+ Self::from_untyped(value.as_untyped())
+ }
+ }
+}
+
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme LabelableExpr is a subclass of Expr
+ unsafe {
+ Self::from_untyped(value.as_untyped())
+ }
+ }
+}
+
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme LabelableExpr is a subclass of Locatable
+ unsafe {
+ Self::from_untyped(value.as_untyped())
+ }
+ }
+}
+
#[derive(Debug)]
pub struct LetExpr {
pub id: trap::TrapId,
@@ -5558,73 +5349,6 @@ impl From> for trap::Label {
}
}
-#[derive(Debug)]
-pub struct LoopExpr {
- pub id: trap::TrapId,
- pub attrs: Vec>,
- pub label: Option>,
- pub loop_body: Option>,
-}
-
-impl trap::TrapEntry for LoopExpr {
- fn extract_id(&mut self) -> trap::TrapId {
- std::mem::replace(&mut self.id, trap::TrapId::Star)
- }
-
- fn emit(self, id: trap::Label, out: &mut trap::Writer) {
- out.add_tuple("loop_exprs", vec![id.into()]);
- for (i, v) in self.attrs.into_iter().enumerate() {
- out.add_tuple("loop_expr_attrs", vec![id.into(), i.into(), v.into()]);
- }
- if let Some(v) = self.label {
- out.add_tuple("loop_expr_labels", vec![id.into(), v.into()]);
- }
- if let Some(v) = self.loop_body {
- out.add_tuple("loop_expr_loop_bodies", vec![id.into(), v.into()]);
- }
- }
-}
-
-impl trap::TrapClass for LoopExpr {
- fn class_name() -> &'static str { "LoopExpr" }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme LoopExpr is a subclass of AstNode
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme LoopExpr is a subclass of Element
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme LoopExpr is a subclass of Expr
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
-impl From> for trap::Label {
- fn from(value: trap::Label) -> Self {
- // SAFETY: this is safe because in the dbscheme LoopExpr is a subclass of Locatable
- unsafe {
- Self::from_untyped(value.as_untyped())
- }
- }
-}
-
#[derive(Debug)]
pub struct MacroExpr {
pub id: trap::TrapId,
@@ -6050,6 +5774,73 @@ impl From> for trap::Label {
}
}
+#[derive(Debug)]
+pub struct Param {
+ pub id: trap::TrapId,
+ pub attrs: Vec>,
+ pub ty: Option>,
+ pub pat: Option>,
+}
+
+impl trap::TrapEntry for Param {
+ fn extract_id(&mut self) -> trap::TrapId {
+ std::mem::replace(&mut self.id, trap::TrapId::Star)
+ }
+
+ fn emit(self, id: trap::Label, out: &mut trap::Writer) {
+ out.add_tuple("params", vec![id.into()]);
+ for (i, v) in self.attrs.into_iter().enumerate() {
+ out.add_tuple("param_base_attrs", vec![id.into(), i.into(), v.into()]);
+ }
+ if let Some(v) = self.ty {
+ out.add_tuple("param_base_ties", vec![id.into(), v.into()]);
+ }
+ if let Some(v) = self.pat {
+ out.add_tuple("param_pats", vec![id.into(), v.into()]);
+ }
+ }
+}
+
+impl trap::TrapClass for Param {
+ fn class_name() -> &'static str { "Param" }
+}
+
+impl From> for trap::Label {
+ fn from(value: trap::Label) -> Self {
+ // SAFETY: this is safe because in the dbscheme Param is a subclass of AstNode
+ unsafe {
+ Self::from_untyped(value.as_untyped())
+ }
+ }
+}
+
+impl From> for trap::Label