mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge remote-tracking branch 'origin/main' into nickrolfe/active_support_flow_summaries
This commit is contained in:
36
.github/workflows/compile-queries.yml
vendored
36
.github/workflows/compile-queries.yml
vendored
@@ -2,11 +2,11 @@ name: "Compile all queries using the latest stable CodeQL CLI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main] # makes sure the cache gets populated
|
||||
pull_request:
|
||||
branches:
|
||||
branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
|
||||
- main
|
||||
- "rc/*"
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
compile-queries:
|
||||
@@ -14,31 +14,33 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# calculate the merge-base with main, in a way that works both on PRs and pushes to main.
|
||||
- name: Calculate merge-base
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
env:
|
||||
BASE_BRANCH: ${{ github.base_ref }}
|
||||
run: |
|
||||
MERGE_BASE=$(git merge-base --fork-point origin/$BASE_BRANCH)
|
||||
MERGE_BASE=$(git cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ")
|
||||
echo "merge-base=$MERGE_BASE" >> $GITHUB_ENV
|
||||
- name: Calculate merge-base - branch
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
# using github.sha instead, since we're directly on a branch, and not in a PR
|
||||
run: |
|
||||
MERGE_BASE=${{ github.sha }}
|
||||
echo "merge-base=$MERGE_BASE" >> $GITHUB_ENV
|
||||
- name: Cache CodeQL query compilation
|
||||
- name: Read CodeQL query compilation - PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '*/ql/src/.cache'
|
||||
# current GH HEAD first, merge-base second, generic third
|
||||
key: codeql-stable-compile-${{ github.sha }}
|
||||
key: codeql-compile-pr-${{ github.sha }} # deliberately not using the `compile-compile-main` keys here.
|
||||
restore-keys: |
|
||||
codeql-stable-compile-${{ env.merge-base }}
|
||||
codeql-stable-compile-
|
||||
codeql-compile-${{ github.base_ref }}-${{ env.merge-base }}
|
||||
codeql-compile-${{ github.base_ref }}-
|
||||
codeql-compile-main-
|
||||
- name: Fill CodeQL query compilation cache - main
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '*/ql/src/.cache'
|
||||
key: codeql-compile-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
||||
restore-keys: | # restore from another random commit, to speed up compilation.
|
||||
codeql-compile-${{ github.ref_name }}-
|
||||
codeql-compile-main-
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
|
||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -51,12 +51,14 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/create-extractor-pack
|
||||
- uses: ./swift/actions/run-quick-tests
|
||||
- uses: ./swift/actions/print-unextracted
|
||||
build-and-test-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/create-extractor-pack
|
||||
- uses: ./swift/actions/run-quick-tests
|
||||
- uses: ./swift/actions/print-unextracted
|
||||
qltests-linux:
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -50,19 +50,18 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
|
||||
input.isParameter(2) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
|
||||
input.isParameter(3) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(0) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
(
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
|
||||
input.isParameter(2)
|
||||
or
|
||||
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
|
||||
input.isParameter(3)
|
||||
or
|
||||
input.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
(output.isParameterDeref(0) or output.isReturnValueDeref())
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int param) {
|
||||
|
||||
@@ -13,11 +13,18 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
|
||||
where
|
||||
ffc = fl.getUse() and
|
||||
expected = fl.getNumArgNeeded() and
|
||||
given = ffc.getNumFormatArgument() and
|
||||
expected < given and
|
||||
fl.specsAreKnown()
|
||||
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()
|
||||
fl.specsAreKnown() and
|
||||
(
|
||||
if ffc.isInMacroExpansion()
|
||||
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
|
||||
else ffcName = ffc.getTarget().getName()
|
||||
)
|
||||
select ffc,
|
||||
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
|
||||
given.toString()
|
||||
|
||||
@@ -16,11 +16,18 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
|
||||
where
|
||||
ffc = fl.getUse() and
|
||||
expected = fl.getNumArgNeeded() and
|
||||
given = ffc.getNumFormatArgument() and
|
||||
expected > given and
|
||||
fl.specsAreKnown()
|
||||
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()
|
||||
fl.specsAreKnown() and
|
||||
(
|
||||
if ffc.isInMacroExpansion()
|
||||
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
|
||||
else ffcName = ffc.getTarget().getName()
|
||||
)
|
||||
select ffc,
|
||||
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
|
||||
given.toString()
|
||||
|
||||
@@ -87,4 +87,7 @@ postWithInFlow
|
||||
| test.cpp:465:3:465:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:465:4:465:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:470:22:470:22 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:35:505:35 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
|
||||
@@ -582,6 +582,13 @@ postWithInFlow
|
||||
| test.cpp:489:7:489:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:491:5:491:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:494:5:494:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:504:7:504:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:35:505:35 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:9:7:9:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:10:12:10:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:10:27:10:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
||||
@@ -494,3 +494,14 @@ void regression_with_phi_flow(int clean1) {
|
||||
x = source();
|
||||
}
|
||||
}
|
||||
|
||||
int intOutparamSourceMissingReturn(int *p) {
|
||||
*p = source();
|
||||
// return deliberately omitted to test IR dataflow behavior
|
||||
}
|
||||
|
||||
void viaOutparamMissingReturn() {
|
||||
int x = 0;
|
||||
intOutparamSourceMissingReturn(&x);
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
@@ -5964,6 +5964,7 @@
|
||||
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:3:172:8 | call to strcat | |
|
||||
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
|
||||
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
|
||||
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:3:172:8 | call to strcat | TAINT |
|
||||
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
|
||||
| taint.cpp:180:19:180:19 | p | taint.cpp:180:19:180:19 | p | |
|
||||
| taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | |
|
||||
@@ -6373,12 +6374,14 @@
|
||||
| taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
|
||||
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:562:7:562:11 | dest1 | |
|
||||
| taint.cpp:561:16:561:21 | source | taint.cpp:561:2:561:7 | call to strcat | TAINT |
|
||||
| taint.cpp:561:16:561:21 | source | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:562:7:562:11 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
|
||||
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:2:564:7 | call to strcat | |
|
||||
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
|
||||
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
|
||||
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:565:7:565:11 | dest2 | |
|
||||
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:2:564:7 | call to strcat | TAINT |
|
||||
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
|
||||
| taint.cpp:565:7:565:11 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
|
||||
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
@@ -6405,9 +6408,12 @@
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:575:7:575:11 | dest1 | |
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
|
||||
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:574:48:574:48 | n | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:48:574:48 | n | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:574:51:574:56 | ref arg source | taint.cpp:573:49:573:54 | source | |
|
||||
| taint.cpp:574:51:574:56 | source | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:51:574:56 | source | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
|
||||
@@ -6421,8 +6427,11 @@
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:581:7:581:11 | dest3 | |
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | |
|
||||
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:48:580:48 | n | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:48:580:48 | n | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:51:580:55 | ref arg clean | taint.cpp:573:32:573:36 | clean | |
|
||||
| taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
|
||||
|
||||
@@ -574,8 +574,8 @@ void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned ch
|
||||
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
|
||||
sink(dest1); // $ SPURIOUS: ast,ir
|
||||
sink(*dest1); // $ ast,ir
|
||||
sink(dest2); // $ SPURIOUS: ir
|
||||
sink(*dest2); // $ ir
|
||||
sink(dest2); // $ SPURIOUS: ast,ir
|
||||
sink(*dest2); // $ ast,ir
|
||||
|
||||
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
|
||||
sink(dest3);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
|
||||
| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
|
||||
| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
|
||||
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 |
|
||||
| macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| test.c:7:2:7:7 | call to printf | Format expects 0 arguments but given 1 |
|
||||
| test.c:21:2:21:7 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| test.c:27:3:27:8 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| test.c:31:3:31:8 | call to printf | Format expects 1 arguments but given 3 |
|
||||
| test.c:32:3:32:8 | call to printf | Format expects 1 arguments but given 2 |
|
||||
| test.c:39:3:39:8 | call to printf | Format expects 2 arguments but given 5 |
|
||||
| test.c:40:3:40:8 | call to printf | Format expects 2 arguments but given 4 |
|
||||
| test.c:41:3:41:8 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
|
||||
| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
|
||||
| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 2 |
|
||||
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format for myPrintf expects 2 arguments but given 3 |
|
||||
| macros.cpp:12:2:12:31 | call to printf | Format for printf (in a macro expansion) expects 2 arguments but given 3 |
|
||||
| macros.cpp:16:2:16:30 | call to printf | Format for printf (in a macro expansion) expects 2 arguments but given 3 |
|
||||
| test.c:7:2:7:7 | call to printf | Format for printf expects 0 arguments but given 1 |
|
||||
| test.c:21:2:21:7 | call to printf | Format for printf expects 2 arguments but given 3 |
|
||||
| test.c:27:3:27:8 | call to printf | Format for printf expects 2 arguments but given 3 |
|
||||
| test.c:31:3:31:8 | call to printf | Format for printf expects 1 arguments but given 3 |
|
||||
| test.c:32:3:32:8 | call to printf | Format for printf expects 1 arguments but given 2 |
|
||||
| test.c:39:3:39:8 | call to printf | Format for printf expects 2 arguments but given 5 |
|
||||
| test.c:40:3:40:8 | call to printf | Format for printf expects 2 arguments but given 4 |
|
||||
| test.c:41:3:41:8 | call to printf | Format for printf expects 2 arguments but given 3 |
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
|
||||
| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
|
||||
| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
|
||||
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 |
|
||||
| macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 |
|
||||
| macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 |
|
||||
| test.c:9:2:9:7 | call to printf | Format expects 1 arguments but given 0 |
|
||||
| test.c:12:2:12:7 | call to printf | Format expects 2 arguments but given 1 |
|
||||
| test.c:15:2:15:7 | call to printf | Format expects 3 arguments but given 2 |
|
||||
| test.c:19:2:19:7 | call to printf | Format expects 2 arguments but given 1 |
|
||||
| test.c:29:3:29:8 | call to printf | Format expects 2 arguments but given 1 |
|
||||
| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
|
||||
| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
|
||||
| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format for myMultiplyDefinedPrintf expects 1 arguments but given 0 |
|
||||
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format for myPrintf expects 2 arguments but given 1 |
|
||||
| macros.cpp:14:2:14:37 | call to printf | Format for printf (in a macro expansion) expects 4 arguments but given 3 |
|
||||
| macros.cpp:21:2:21:36 | call to printf | Format for printf (in a macro expansion) expects 4 arguments but given 3 |
|
||||
| macros.cpp:32:2:32:25 | call to printf | Format for printf (in a macro expansion) expects 1 arguments but given 0 |
|
||||
| test.c:9:2:9:7 | call to printf | Format for printf expects 1 arguments but given 0 |
|
||||
| test.c:12:2:12:7 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:15:2:15:7 | call to printf | Format for printf expects 3 arguments but given 2 |
|
||||
| test.c:19:2:19:7 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:29:3:29:8 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
|
||||
@@ -13,10 +13,21 @@ void testMacros(int a, int b, int c)
|
||||
GOODPRINTF("%i %i %i\n", a, b, c); // GOOD
|
||||
GOODPRINTF("%i %i %i %i\n", a, b, c); // BAD: too few format arguments
|
||||
|
||||
BADPRINTF("%i %i\n", a, b, 0); // BAD: too many format arguments
|
||||
BADPRINTF("%i %i\n", a, b, 0); // DUBIOUS: too many format arguments
|
||||
// ^ here there are too many format arguments, but the design of the Macro forces the user
|
||||
// to do this, and the extra argument is harmlessly ignored in practice. Reporting these
|
||||
// results can be extremely noisy (e.g. in openldap).
|
||||
BADPRINTF("%i %i %i\n", a, b, c); // GOOD
|
||||
BADPRINTF("%i %i %i %i\n", a, b, c); // BAD: too few format arguments
|
||||
}
|
||||
|
||||
#define DOTHING(x) \
|
||||
printf("doing thing: " #x); x
|
||||
|
||||
void testMacros2()
|
||||
{
|
||||
int x;
|
||||
|
||||
DOTHING(x++); // GOOD
|
||||
DOTHING(printf("%i", x)); // BAD: the printf inside the macro has too few format arguments
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
class Activate extends ActiveConfiguration {
|
||||
override predicate activateToSinkConfig() { any() }
|
||||
}
|
||||
|
||||
from DataFlowTargetApi api, string sink
|
||||
where sink = captureSink(api)
|
||||
select sink order by sink
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
class Activate extends ActiveConfiguration {
|
||||
override predicate activateFromSourceConfig() { any() }
|
||||
}
|
||||
|
||||
from DataFlowTargetApi api, string source
|
||||
where source = captureSource(api)
|
||||
select source order by source
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
|
||||
private import CaptureModelsSpecific
|
||||
|
||||
class ActiveConfiguration extends Unit {
|
||||
predicate activateThroughFlowConfig() { none() }
|
||||
|
||||
predicate activateFromSourceConfig() { none() }
|
||||
|
||||
predicate activateToSinkConfig() { none() }
|
||||
}
|
||||
|
||||
class DataFlowTargetApi extends TargetApiSpecific {
|
||||
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
|
||||
}
|
||||
@@ -140,7 +148,9 @@ private class TaintStore extends DataFlow::FlowState {
|
||||
* This can be used to generate Flow summaries for APIs from parameter to return.
|
||||
*/
|
||||
private class ThroughFlowConfig extends TaintTracking::Configuration {
|
||||
ThroughFlowConfig() { this = "ThroughFlowConfig" }
|
||||
ThroughFlowConfig() {
|
||||
this = "ThroughFlowConfig" and any(ActiveConfiguration ac).activateThroughFlowConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
@@ -210,7 +220,9 @@ string captureThroughFlow(DataFlowTargetApi api) {
|
||||
* via its return (then the API itself becomes a source).
|
||||
*/
|
||||
private class FromSourceConfiguration extends TaintTracking::Configuration {
|
||||
FromSourceConfiguration() { this = "FromSourceConfiguration" }
|
||||
FromSourceConfiguration() {
|
||||
this = "FromSourceConfiguration" and any(ActiveConfiguration ac).activateFromSourceConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) }
|
||||
|
||||
@@ -250,8 +262,13 @@ string captureSource(DataFlowTargetApi api) {
|
||||
* This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field)
|
||||
* into an existing known sink (then the API itself becomes a sink).
|
||||
*/
|
||||
private class PropagateToSinkConfiguration extends PropagateToSinkConfigurationSpecific {
|
||||
PropagateToSinkConfiguration() { this = "parameters or fields flowing into sinks" }
|
||||
private class PropagateToSinkConfiguration extends TaintTracking::Configuration {
|
||||
PropagateToSinkConfiguration() {
|
||||
this = "parameters or fields flowing into sinks" and
|
||||
any(ActiveConfiguration ac).activateToSinkConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { apiSource(source) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { ExternalFlow::sinkNode(sink, _) }
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ module TaintTracking = CS::TaintTracking;
|
||||
|
||||
class Type = CS::Type;
|
||||
|
||||
class Unit = DataFlowPrivate::Unit;
|
||||
|
||||
/**
|
||||
* Holds if any of the parameters of `api` are `System.Func<>`.
|
||||
*/
|
||||
@@ -174,15 +176,11 @@ private predicate isRelevantMemberAccess(DataFlow::Node node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Language specific parts of the `PropagateToSinkConfiguration`.
|
||||
* Holds if `source` is an api entrypoint relevant for creating sink models.
|
||||
*/
|
||||
class PropagateToSinkConfigurationSpecific extends CS::TaintTracking::Configuration {
|
||||
PropagateToSinkConfigurationSpecific() { this = "parameters or fields flowing into sinks" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
(isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode) and
|
||||
isRelevantForModels(source.getEnclosingCallable())
|
||||
}
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
(isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode) and
|
||||
isRelevantForModels(source.getEnclosingCallable())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
private import CaptureModels
|
||||
|
||||
private class Activate extends ActiveConfiguration {
|
||||
override predicate activateThroughFlowConfig() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture fluent APIs that return `this`.
|
||||
* Example of a fluent API:
|
||||
|
||||
@@ -88,6 +88,22 @@ class KeyPairGenerator extends RefType {
|
||||
KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `verify` method of the class `javax.net.ssl.HostnameVerifier`. */
|
||||
class HostnameVerifierVerify extends Method {
|
||||
HostnameVerifierVerify() {
|
||||
@@ -367,8 +383,8 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec {
|
||||
override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) }
|
||||
}
|
||||
|
||||
/** A method call to the Java class `java.security.KeyPairGenerator`. */
|
||||
class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec {
|
||||
/** A call to the `getInstance` method declared in `java.security.KeyPairGenerator`. */
|
||||
class JavaSecurityKeyPairGenerator extends JavaSecurityAlgoSpec {
|
||||
JavaSecurityKeyPairGenerator() {
|
||||
exists(Method m | m.getAReference() = this |
|
||||
m.getDeclaringType() instanceof KeyPairGenerator and
|
||||
@@ -378,3 +394,53 @@ class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec {
|
||||
|
||||
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.AlgorithmParameterGenerator`. */
|
||||
class AlgorithmParameterGenerator extends RefType {
|
||||
AlgorithmParameterGenerator() {
|
||||
this.hasQualifiedName("java.security", "AlgorithmParameterGenerator")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `init` method declared in `java.security.AlgorithmParameterGenerator`. */
|
||||
class AlgoParamGeneratorInitMethod extends Method {
|
||||
AlgoParamGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof AlgorithmParameterGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `getInstance` method declared in `java.security.AlgorithmParameterGenerator`. */
|
||||
class JavaSecurityAlgoParamGenerator extends JavaSecurityAlgoSpec {
|
||||
JavaSecurityAlgoParamGenerator() {
|
||||
exists(Method m | m.getAReference() = this |
|
||||
m.getDeclaringType() instanceof AlgorithmParameterGenerator and
|
||||
m.getName() = "getInstance"
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
|
||||
}
|
||||
|
||||
/** An implementation of the `java.security.spec.AlgorithmParameterSpec` interface. */
|
||||
abstract class AlgorithmParameterSpec extends RefType { }
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
class EcGenParameterSpec extends AlgorithmParameterSpec {
|
||||
EcGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.RSAKeyGenParameterSpec`. */
|
||||
class RsaKeyGenParameterSpec extends AlgorithmParameterSpec {
|
||||
RsaKeyGenParameterSpec() { this.hasQualifiedName("java.security.spec", "RSAKeyGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.DSAGenParameterSpec`. */
|
||||
class DsaGenParameterSpec extends AlgorithmParameterSpec {
|
||||
DsaGenParameterSpec() { this.hasQualifiedName("java.security.spec", "DSAGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `javax.crypto.spec.DHGenParameterSpec`. */
|
||||
class DhGenParameterSpec extends AlgorithmParameterSpec {
|
||||
DhGenParameterSpec() { this.hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec") }
|
||||
}
|
||||
|
||||
193
java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
Normal file
193
java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
Normal file
@@ -0,0 +1,193 @@
|
||||
/** Provides classes and predicates related to insufficient key sizes in Java. */
|
||||
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
/** A source for an insufficient key size. */
|
||||
abstract class InsufficientKeySizeSource extends DataFlow::Node {
|
||||
/** Holds if this source has the specified `state`. */
|
||||
predicate hasState(DataFlow::FlowState state) { state instanceof DataFlow::FlowStateEmpty }
|
||||
}
|
||||
|
||||
/** A sink for an insufficient key size. */
|
||||
abstract class InsufficientKeySizeSink extends DataFlow::Node {
|
||||
/** Holds if this sink has the specified `state`. */
|
||||
predicate hasState(DataFlow::FlowState state) { state instanceof DataFlow::FlowStateEmpty }
|
||||
}
|
||||
|
||||
/** Provides models for asymmetric cryptography. */
|
||||
private module Asymmetric {
|
||||
/** Provides models for non-elliptic-curve asymmetric cryptography. */
|
||||
private module NonEllipticCurve {
|
||||
/** A source for an insufficient key size used in RSA, DSA, and DH algorithms. */
|
||||
private class Source extends InsufficientKeySizeSource {
|
||||
Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() }
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** A sink for an insufficient key size used in RSA, DSA, and DH algorithms. */
|
||||
private class Sink extends InsufficientKeySizeSink {
|
||||
Sink() {
|
||||
exists(KeyPairGenInit kpgInit, KeyPairGen kpg |
|
||||
kpg.getAlgoName().matches(["RSA", "DSA", "DH"]) and
|
||||
DataFlow::localExprFlow(kpg, kpgInit.getQualifier()) and
|
||||
this.asExpr() = kpgInit.getKeySizeArg()
|
||||
)
|
||||
or
|
||||
exists(Spec spec | this.asExpr() = spec.getKeySizeArg())
|
||||
}
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** Returns the minimum recommended key size for RSA, DSA, and DH algorithms. */
|
||||
private int getMinKeySize() { result = 2048 }
|
||||
|
||||
/** An instance of an RSA, DSA, or DH algorithm specification. */
|
||||
private class Spec extends ClassInstanceExpr {
|
||||
Spec() {
|
||||
this.getConstructedType() instanceof RsaKeyGenParameterSpec or
|
||||
this.getConstructedType() instanceof DsaGenParameterSpec or
|
||||
this.getConstructedType() instanceof DhGenParameterSpec
|
||||
}
|
||||
|
||||
/** Gets the `keysize` argument of this instance. */
|
||||
Argument getKeySizeArg() { result = this.getArgument(0) }
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides models for elliptic-curve asymmetric cryptography. */
|
||||
private module EllipticCurve {
|
||||
/** A source for an insufficient key size used in elliptic curve (EC) algorithms. */
|
||||
private class Source extends InsufficientKeySizeSource {
|
||||
Source() {
|
||||
this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize()
|
||||
or
|
||||
// the below is needed for cases when the key size is embedded in the curve name
|
||||
getKeySize(this.asExpr().(StringLiteral).getValue()) < getMinKeySize()
|
||||
}
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** A sink for an insufficient key size used in elliptic curve (EC) algorithms. */
|
||||
private class Sink extends InsufficientKeySizeSink {
|
||||
Sink() {
|
||||
exists(KeyPairGenInit kpgInit, KeyPairGen kpg |
|
||||
kpg.getAlgoName().matches("EC%") and
|
||||
DataFlow::localExprFlow(kpg, kpgInit.getQualifier()) and
|
||||
this.asExpr() = kpgInit.getKeySizeArg()
|
||||
)
|
||||
or
|
||||
exists(Spec s | this.asExpr() = s.getKeySizeArg())
|
||||
}
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** Returns the minimum recommended key size for elliptic curve (EC) algorithms. */
|
||||
private int getMinKeySize() { result = 256 }
|
||||
|
||||
/** Returns the key size from an EC algorithm's curve name string */
|
||||
bindingset[algorithm]
|
||||
private int getKeySize(string algorithm) {
|
||||
algorithm.matches("sec%") and // specification such as "secp256r1"
|
||||
result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
or
|
||||
algorithm.matches("X9.62%") and // specification such as "X9.62 prime192v2"
|
||||
result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
or
|
||||
algorithm.matches(["prime%", "c2tnb%"]) and // specification such as "prime192v2"
|
||||
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
}
|
||||
|
||||
/** An instance of an elliptic curve (EC) algorithm specification. */
|
||||
private class Spec extends ClassInstanceExpr {
|
||||
Spec() { this.getConstructedType() instanceof EcGenParameterSpec }
|
||||
|
||||
/** Gets the `keysize` argument of this instance. */
|
||||
Argument getKeySizeArg() { result = this.getArgument(0) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `initialize` method declared in `java.security.KeyPairGenerator`
|
||||
* or to the `init` method declared in `java.security.AlgorithmParameterGenerator`.
|
||||
*/
|
||||
private class KeyPairGenInit extends MethodAccess {
|
||||
KeyPairGenInit() {
|
||||
this.getMethod() instanceof KeyPairGeneratorInitMethod or
|
||||
this.getMethod() instanceof AlgoParamGeneratorInitMethod
|
||||
}
|
||||
|
||||
/** Gets the `keysize` argument of this call. */
|
||||
Argument getKeySizeArg() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a `java.security.KeyPairGenerator`
|
||||
* or of a `java.security.AlgorithmParameterGenerator`.
|
||||
*/
|
||||
private class KeyPairGen extends GeneratorAlgoSpec {
|
||||
KeyPairGen() {
|
||||
this instanceof JavaSecurityKeyPairGenerator or
|
||||
this instanceof JavaSecurityAlgoParamGenerator
|
||||
}
|
||||
|
||||
override Expr getAlgoSpec() {
|
||||
result =
|
||||
[
|
||||
this.(JavaSecurityKeyPairGenerator).getAlgoSpec(),
|
||||
this.(JavaSecurityAlgoParamGenerator).getAlgoSpec()
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides models for symmetric cryptography. */
|
||||
private module Symmetric {
|
||||
/** A source for an insufficient key size used in AES algorithms. */
|
||||
private class Source extends InsufficientKeySizeSource {
|
||||
Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() }
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** A sink for an insufficient key size used in AES algorithms. */
|
||||
private class Sink extends InsufficientKeySizeSink {
|
||||
Sink() {
|
||||
exists(KeyGenInit kgInit, KeyGen kg |
|
||||
kg.getAlgoName() = "AES" and
|
||||
DataFlow::localExprFlow(kg, kgInit.getQualifier()) and
|
||||
this.asExpr() = kgInit.getKeySizeArg()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() }
|
||||
}
|
||||
|
||||
/** Returns the minimum recommended key size for AES algorithms. */
|
||||
private int getMinKeySize() { result = 128 }
|
||||
|
||||
/** A call to the `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
private class KeyGenInit extends MethodAccess {
|
||||
KeyGenInit() { this.getMethod() instanceof KeyGeneratorInitMethod }
|
||||
|
||||
/** Gets the `keysize` argument of this call. */
|
||||
Argument getKeySizeArg() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/** An instance of a `javax.crypto.KeyGenerator`. */
|
||||
private class KeyGen extends GeneratorAlgoSpec instanceof JavaxCryptoKeyGenerator {
|
||||
override Expr getAlgoSpec() { result = JavaxCryptoKeyGenerator.super.getAlgoSpec() }
|
||||
}
|
||||
}
|
||||
|
||||
/** An instance of a generator that specifies an encryption algorithm. */
|
||||
abstract private class GeneratorAlgoSpec extends CryptoAlgoSpec {
|
||||
/** Returns an uppercase string representing the algorithm name specified by this generator object. */
|
||||
string getAlgoName() {
|
||||
result = this.getAlgoSpec().(CompileTimeConstantExpr).getStringValue().toUpperCase()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/** Provides data flow configurations to be used in queries related to insufficient key sizes. */
|
||||
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.InsufficientKeySize
|
||||
|
||||
/** A data flow configuration for tracking key sizes used in cryptographic algorithms. */
|
||||
class KeySizeConfiguration extends DataFlow::Configuration {
|
||||
KeySizeConfiguration() { this = "KeySizeConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
source.(InsufficientKeySizeSource).hasState(state)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
sink.(InsufficientKeySizeSink).hasState(state)
|
||||
}
|
||||
}
|
||||
55
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelp
Normal file
55
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelp
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Modern encryption relies on the computational infeasibility of breaking a cipher and decoding its
|
||||
message without the key. As computational power increases, the ability to break ciphers grows, and key
|
||||
sizes need to become larger as a result. Cryptographic algorithms that use too small of a key size are
|
||||
vulnerable to brute force attacks, which can reveal sensitive data.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use a key of the recommended size or larger. The key size should be at least 128 bits for AES encryption,
|
||||
256 bits for elliptic-curve cryptography (ECC), and 2048 bits for RSA, DSA, or DH encryption.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following code uses cryptographic algorithms with insufficient key sizes.
|
||||
</p>
|
||||
|
||||
<sample src="InsufficientKeySizeBad.java" />
|
||||
|
||||
<p>
|
||||
To fix the code, change the key sizes to be the recommended size or
|
||||
larger for each algorithm.
|
||||
</p>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Wikipedia:
|
||||
<a href="http://en.wikipedia.org/wiki/Key_size">Key size</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="https://en.wikipedia.org/wiki/Strong_cryptography">Strong cryptography</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#algorithms">
|
||||
Cryptographic Storage Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP: <a href="https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/04-Testing_for_Weak_Encryption">
|
||||
Testing for Weak Encryption</a>.
|
||||
</li>
|
||||
<li>
|
||||
NIST:
|
||||
<a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf">
|
||||
Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
22
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql
Normal file
22
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @name Use of a cryptographic algorithm with insufficient key size
|
||||
* @description Using cryptographic algorithms with too small a key size can
|
||||
* allow an attacker to compromise security.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @id java/insufficient-key-size
|
||||
* @tags security
|
||||
* external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.InsufficientKeySizeQuery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, KeySizeConfiguration cfg
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This $@ is less than the recommended key size of " + source.getState() + " bits.",
|
||||
source.getNode(), "key size"
|
||||
15
java/ql/src/Security/CWE/CWE-326/InsufficientKeySizeBad.java
Normal file
15
java/ql/src/Security/CWE/CWE-326/InsufficientKeySizeBad.java
Normal file
@@ -0,0 +1,15 @@
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen1.initialize(1024); // BAD: Key size is less than 2048
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen2.initialize(1024); // BAD: Key size is less than 2048
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DH");
|
||||
keyPairGen3.initialize(1024); // BAD: Key size is less than 2048
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp112r1"); // BAD: Key size is less than 256
|
||||
keyPairGen4.initialize(ecSpec);
|
||||
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(64); // BAD: Key size is less than 128
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `java/insufficient-key-size` has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @luchua-bc](https://github.com/github/codeql/pull/4926).
|
||||
@@ -1,37 +0,0 @@
|
||||
public class InsufficientKeySize {
|
||||
public void CryptoMethod() {
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
// BAD: Key size is less than 128
|
||||
keyGen1.init(64);
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
// GOOD: Key size is no less than 128
|
||||
keyGen2.init(128);
|
||||
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen1.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen2.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen3.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen4.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1");
|
||||
keyPairGen5.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1");
|
||||
keyPairGen6.initialize(ecSpec2);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>This rule finds uses of encryption algorithms with too small a key size. Encryption algorithms
|
||||
are vulnerable to brute force attack when too small a key size is used.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>The key should be at least 2048 bits long when using RSA and DSA encryption, 256 bits long when using EC encryption, and 128 bits long when using
|
||||
symmetric encryption.</p>
|
||||
</recommendation>
|
||||
|
||||
<references>
|
||||
|
||||
<li>
|
||||
Wikipedia.
|
||||
<a href="http://en.wikipedia.org/wiki/Key_size">Key size</a>
|
||||
</li>
|
||||
<li>
|
||||
SonarSource.
|
||||
<a href="https://rules.sonarsource.com/java/type/Vulnerability/RSPEC-4426">Cryptographic keys should be robust</a>
|
||||
</li>
|
||||
<li>
|
||||
CWE.
|
||||
<a href="https://cwe.mitre.org/data/definitions/326.html">CWE-326: Inadequate Encryption Strength</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,153 +0,0 @@
|
||||
/**
|
||||
* @name Weak encryption: Insufficient key size
|
||||
* @description Finds uses of encryption algorithms with too small a key size
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insufficient-key-size
|
||||
* @tags security
|
||||
* external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
class ECGenParameterSpec extends RefType {
|
||||
ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the key size in the EC algorithm string */
|
||||
bindingset[algorithm]
|
||||
int getECKeySize(string algorithm) {
|
||||
algorithm.matches("sec%") and // specification such as "secp256r1"
|
||||
result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
or
|
||||
algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2"
|
||||
result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
or
|
||||
(algorithm.matches("prime%") or algorithm.matches("c2tnb%")) and //specification such as "prime192v2"
|
||||
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
}
|
||||
|
||||
/** Taint configuration tracking flow from a key generator to a `init` method call. */
|
||||
class KeyGeneratorInitConfiguration extends TaintTracking::Configuration {
|
||||
KeyGeneratorInitConfiguration() { this = "KeyGeneratorInitConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof JavaxCryptoKeyGenerator
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
sink.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint configuration tracking flow from a keypair generator to a `initialize` method call. */
|
||||
class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration {
|
||||
KeyPairGeneratorInitConfiguration() { this = "KeyPairGeneratorInitConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof JavaSecurityKeyPairGenerator
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
sink.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if a symmetric `KeyGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
bindingset[type]
|
||||
predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
exists(
|
||||
JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration cc, DataFlow::PathNode source,
|
||||
DataFlow::PathNode dest
|
||||
|
|
||||
jcg.getAlgoSpec().(StringLiteral).getValue() = type and
|
||||
source.getNode().asExpr() = jcg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
cc.hasFlowPath(source, dest)
|
||||
) and
|
||||
ma.getArgument(0).(IntegerLiteral).getIntValue() < 128 and
|
||||
msg = "Key size should be at least 128 bits for " + type + " encryption."
|
||||
}
|
||||
|
||||
/** Holds if an AES `KeyGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortAESKey(MethodAccess ma, string msg) { hasShortSymmetricKey(ma, msg, "AES") }
|
||||
|
||||
/** Holds if an asymmetric `KeyPairGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
bindingset[type]
|
||||
predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase() = type and
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kc.hasFlowPath(source, dest)
|
||||
) and
|
||||
ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and
|
||||
msg = "Key size should be at least 2048 bits for " + type + " encryption."
|
||||
}
|
||||
|
||||
/** Holds if a DSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortDsaKeyPair(MethodAccess ma, string msg) {
|
||||
hasShortAsymmetricKeyPair(ma, msg, "DSA") or hasShortAsymmetricKeyPair(ma, msg, "DH")
|
||||
}
|
||||
|
||||
/** Holds if a RSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortRsaKeyPair(MethodAccess ma, string msg) {
|
||||
hasShortAsymmetricKeyPair(ma, msg, "RSA")
|
||||
}
|
||||
|
||||
/** Holds if an EC `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortECKeyPair(MethodAccess ma, string msg) {
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest, ClassInstanceExpr cie
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and // ECC variants such as ECDH and ECDSA
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kc.hasFlowPath(source, dest) and
|
||||
DataFlow::localExprFlow(cie, ma.getArgument(0)) and
|
||||
ma.getArgument(0).getType() instanceof ECGenParameterSpec and
|
||||
getECKeySize(cie.getArgument(0).(StringLiteral).getValue()) < 256
|
||||
) and
|
||||
msg = "Key size should be at least 256 bits for EC encryption."
|
||||
}
|
||||
|
||||
from Expr e, string msg
|
||||
where
|
||||
hasShortAESKey(e, msg) or
|
||||
hasShortDsaKeyPair(e, msg) or
|
||||
hasShortRsaKeyPair(e, msg) or
|
||||
hasShortECKeyPair(e, msg)
|
||||
select e, msg
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
class Activate extends ActiveConfiguration {
|
||||
override predicate activateToSinkConfig() { any() }
|
||||
}
|
||||
|
||||
from DataFlowTargetApi api, string sink
|
||||
where sink = captureSink(api)
|
||||
select sink order by sink
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
class Activate extends ActiveConfiguration {
|
||||
override predicate activateFromSourceConfig() { any() }
|
||||
}
|
||||
|
||||
from DataFlowTargetApi api, string source
|
||||
where source = captureSource(api)
|
||||
select source order by source
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
|
||||
private import CaptureModelsSpecific
|
||||
|
||||
class ActiveConfiguration extends Unit {
|
||||
predicate activateThroughFlowConfig() { none() }
|
||||
|
||||
predicate activateFromSourceConfig() { none() }
|
||||
|
||||
predicate activateToSinkConfig() { none() }
|
||||
}
|
||||
|
||||
class DataFlowTargetApi extends TargetApiSpecific {
|
||||
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
|
||||
}
|
||||
@@ -140,7 +148,9 @@ private class TaintStore extends DataFlow::FlowState {
|
||||
* This can be used to generate Flow summaries for APIs from parameter to return.
|
||||
*/
|
||||
private class ThroughFlowConfig extends TaintTracking::Configuration {
|
||||
ThroughFlowConfig() { this = "ThroughFlowConfig" }
|
||||
ThroughFlowConfig() {
|
||||
this = "ThroughFlowConfig" and any(ActiveConfiguration ac).activateThroughFlowConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
@@ -210,7 +220,9 @@ string captureThroughFlow(DataFlowTargetApi api) {
|
||||
* via its return (then the API itself becomes a source).
|
||||
*/
|
||||
private class FromSourceConfiguration extends TaintTracking::Configuration {
|
||||
FromSourceConfiguration() { this = "FromSourceConfiguration" }
|
||||
FromSourceConfiguration() {
|
||||
this = "FromSourceConfiguration" and any(ActiveConfiguration ac).activateFromSourceConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) }
|
||||
|
||||
@@ -250,8 +262,13 @@ string captureSource(DataFlowTargetApi api) {
|
||||
* This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field)
|
||||
* into an existing known sink (then the API itself becomes a sink).
|
||||
*/
|
||||
private class PropagateToSinkConfiguration extends PropagateToSinkConfigurationSpecific {
|
||||
PropagateToSinkConfiguration() { this = "parameters or fields flowing into sinks" }
|
||||
private class PropagateToSinkConfiguration extends TaintTracking::Configuration {
|
||||
PropagateToSinkConfiguration() {
|
||||
this = "parameters or fields flowing into sinks" and
|
||||
any(ActiveConfiguration ac).activateToSinkConfig()
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { apiSource(source) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { ExternalFlow::sinkNode(sink, _) }
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ module TaintTracking = Tt::TaintTracking;
|
||||
|
||||
class Type = J::Type;
|
||||
|
||||
class Unit = J::Unit;
|
||||
|
||||
private J::Method superImpl(J::Method m) {
|
||||
result = m.getAnOverride() and
|
||||
not exists(result.getAnOverride()) and
|
||||
@@ -223,24 +225,21 @@ predicate isOwnInstanceAccessNode(ReturnNode node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Language specific parts of the `PropagateToSinkConfiguration`.
|
||||
* Holds if `source` is an api entrypoint relevant for creating sink models.
|
||||
*/
|
||||
class PropagateToSinkConfigurationSpecific extends TaintTracking::Configuration {
|
||||
PropagateToSinkConfigurationSpecific() { this = "parameters or fields flowing into sinks" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
|
||||
source instanceof DataFlow::ParameterNode
|
||||
) and
|
||||
source.getEnclosingCallable().isPublic() and
|
||||
exists(J::RefType t |
|
||||
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
|
||||
not t instanceof J::TypeObject and
|
||||
t.isPublic()
|
||||
) and
|
||||
isRelevantForModels(source.getEnclosingCallable())
|
||||
}
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
(
|
||||
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
|
||||
source instanceof DataFlow::ParameterNode
|
||||
) and
|
||||
source.getEnclosingCallable().isPublic() and
|
||||
exists(J::RefType t |
|
||||
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
|
||||
not t instanceof J::TypeObject and
|
||||
t.isPublic()
|
||||
) and
|
||||
isRelevantForModels(source.getEnclosingCallable()) and
|
||||
exists(asPartialModel(source.getEnclosingCallable()))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
private import CaptureModels
|
||||
|
||||
private class Activate extends ActiveConfiguration {
|
||||
override predicate activateThroughFlowConfig() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture fluent APIs that return `this`.
|
||||
* Example of a fluent API:
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
| InsufficientKeySize.java:9:9:9:24 | init(...) | Key size should be at least 128 bits for AES encryption. |
|
||||
| InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. |
|
||||
| InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. |
|
||||
| InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:68:9:68:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:78:9:78:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:87:9:87:37 | initialize(...) | Key size should be at least 2048 bits for DH encryption. |
|
||||
@@ -1,93 +0,0 @@
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
public class InsufficientKeySize {
|
||||
public void CryptoMethod() throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
// BAD: Key size is less than 128
|
||||
keyGen1.init(64);
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
// GOOD: Key size is no less than 128
|
||||
keyGen2.init(128);
|
||||
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen1.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen2.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen3.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen4.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1");
|
||||
keyPairGen5.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
keyPairGen6.initialize(new ECGenParameterSpec("secp112r1"));
|
||||
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1");
|
||||
keyPairGen7.initialize(ecSpec2);
|
||||
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2");
|
||||
keyPairGen8.initialize(ecSpec3);
|
||||
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3");
|
||||
keyPairGen9.initialize(ecSpec4);
|
||||
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1");
|
||||
keyPairGen10.initialize(ecSpec5);
|
||||
|
||||
KeyPairGenerator keyPairGen11 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1");
|
||||
keyPairGen11.initialize(ecSpec6);
|
||||
|
||||
KeyPairGenerator keyPairGen12 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec7 = new ECGenParameterSpec("prime192v2");
|
||||
keyPairGen12.initialize(ecSpec7);
|
||||
|
||||
KeyPairGenerator keyPairGen13 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec8 = new ECGenParameterSpec("prime256v1");
|
||||
keyPairGen13.initialize(ecSpec8);
|
||||
|
||||
KeyPairGenerator keyPairGen14 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec9 = new ECGenParameterSpec("c2tnb191v1");
|
||||
keyPairGen14.initialize(ecSpec9);
|
||||
|
||||
KeyPairGenerator keyPairGen15 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec10 = new ECGenParameterSpec("c2tnb431r1");
|
||||
keyPairGen15.initialize(ecSpec10);
|
||||
|
||||
KeyPairGenerator keyPairGen16 = KeyPairGenerator.getInstance("dh");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen16.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen17 = KeyPairGenerator.getInstance("DH");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen17.initialize(2048);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-326/InsufficientKeySize.ql
|
||||
@@ -0,0 +1,256 @@
|
||||
import javax.crypto.KeyGenerator;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.AlgorithmParameterGenerator;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
import java.security.spec.DSAGenParameterSpec;
|
||||
import javax.crypto.spec.DHGenParameterSpec;
|
||||
|
||||
|
||||
public class InsufficientKeySizeTest {
|
||||
public void keySizeTesting() throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
|
||||
/* AES (Symmetric): minimum recommended key size is 128 */
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
keyGen1.init(64); // $ hasInsufficientKeySize
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
keyGen2.init(128); // Safe: Key size is no less than 128
|
||||
|
||||
/* Test with local variable as keysize */
|
||||
final int size1 = 64; // compile-time constant
|
||||
int size2 = 64; // not a compile-time constant
|
||||
|
||||
KeyGenerator keyGen3 = KeyGenerator.getInstance("AES");
|
||||
keyGen3.init(size1); // $ hasInsufficientKeySize
|
||||
|
||||
KeyGenerator keyGen4 = KeyGenerator.getInstance("AES");
|
||||
keyGen4.init(size2); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test variables passed to another method */
|
||||
KeyGenerator keyGen5 = KeyGenerator.getInstance("AES"); // MISSING: test KeyGenerator variable as argument
|
||||
testSymmetricVariable(size2, keyGen5); // test with variable as key size
|
||||
testSymmetricInt(64); // test with int literal as key size
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "AES"; // compile-time constant
|
||||
KeyGenerator keyGen6 = KeyGenerator.getInstance(algoName1);
|
||||
keyGen6.init(64); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "AES"; // not a compile-time constant
|
||||
KeyGenerator keyGen7 = KeyGenerator.getInstance(algoName2);
|
||||
keyGen7.init(64); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// RSA (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("RSA");
|
||||
RSAKeyGenParameterSpec rsaSpec = new RSAKeyGenParameterSpec(1024, null); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(rsaSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen4.initialize(new RSAKeyGenParameterSpec(1024, null)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with local variable as keysize */
|
||||
final int size1 = 1024; // compile-time constant
|
||||
int size2 = 1024; // not a compile-time constant
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen5.initialize(size1); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen6.initialize(size2); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test variables passed to another method */
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("RSA"); // MISSING: test KeyGenerator variable as argument
|
||||
testAsymmetricNonEcVariable(size2, keyPairGen7); // test with variable as key size
|
||||
testAsymmetricNonEcInt(1024); // test with int literal as key size
|
||||
|
||||
/* Test getting key size as return value of another method */
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen8.initialize(getRSAKeySize()); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "RSA"; // compile-time constant
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance(algoName1);
|
||||
keyPairGen9.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "RSA"; // not a compile-time constant
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance(algoName2);
|
||||
keyPairGen10.initialize(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// DSA (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
DSAGenParameterSpec dsaSpec = new DSAGenParameterSpec(1024, 0); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(dsaSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen4.initialize(new DSAGenParameterSpec(1024, 0)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test `AlgorithmParameterGenerator` */
|
||||
AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DSA");
|
||||
paramGen.init(1024); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "DSA"; // compile-time constant
|
||||
AlgorithmParameterGenerator paramGen1 = AlgorithmParameterGenerator.getInstance(algoName1);
|
||||
paramGen1.init(1024); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "DSA"; // not a compile-time constant
|
||||
AlgorithmParameterGenerator paramGen2 = AlgorithmParameterGenerator.getInstance(algoName2);
|
||||
paramGen2.init(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// DH (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("dh");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DH");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DH");
|
||||
DHGenParameterSpec dhSpec = new DHGenParameterSpec(1024, 0); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(dhSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DH");
|
||||
keyPairGen4.initialize(new DHGenParameterSpec(1024, 0)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test `AlgorithmParameterGenerator` */
|
||||
AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH");
|
||||
paramGen.init(1024); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// EC (Asymmetric): minimum recommended key size is 256
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen1.initialize(128); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with keysize as curve name in spec */
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); // $ hasInsufficientKeySize
|
||||
keyPairGen2.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen3.initialize(new ECGenParameterSpec("secp112r1")); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); // Safe: Key size is no less than 256
|
||||
keyPairGen4.initialize(ecSpec2);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2"); // $ hasInsufficientKeySize
|
||||
keyPairGen5.initialize(ecSpec3);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3"); // $ hasInsufficientKeySize
|
||||
keyPairGen6.initialize(ecSpec4);
|
||||
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); // $ hasInsufficientKeySize
|
||||
keyPairGen7.initialize(ecSpec5);
|
||||
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1"); // Safe: Key size is no less than 256
|
||||
keyPairGen8.initialize(ecSpec6);
|
||||
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec7 = new ECGenParameterSpec("prime192v2"); // $ hasInsufficientKeySize
|
||||
keyPairGen9.initialize(ecSpec7);
|
||||
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec8 = new ECGenParameterSpec("prime256v1"); // Safe: Key size is no less than 256
|
||||
keyPairGen10.initialize(ecSpec8);
|
||||
|
||||
KeyPairGenerator keyPairGen14 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec9 = new ECGenParameterSpec("c2tnb191v1"); // $ hasInsufficientKeySize
|
||||
keyPairGen14.initialize(ecSpec9);
|
||||
|
||||
KeyPairGenerator keyPairGen15 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec10 = new ECGenParameterSpec("c2tnb431r1");
|
||||
keyPairGen15.initialize(ecSpec10); // Safe: Key size is no less than 256
|
||||
|
||||
/* Test variables passed to another method */
|
||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp112r1"); // $ hasInsufficientKeySize
|
||||
testAsymmetricEcSpecVariable(ecSpec); // test spec as an argument
|
||||
int size = 128;
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC"); // MISSING: test KeyGenerator variable as argument
|
||||
testAsymmetricEcIntVariable(size, keyPairGen); // test with variable as key size
|
||||
testAsymmetricEcIntLiteral(128); // test with int literal as key size
|
||||
|
||||
/* Test with variable as curve name argument in `ECGenParameterSpec` constructor. */
|
||||
final String curveName1 = "secp112r1"; // compile-time constant
|
||||
KeyPairGenerator keyPairGen16 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec11 = new ECGenParameterSpec(curveName1); // $ hasInsufficientKeySize
|
||||
keyPairGen16.initialize(ecSpec11);
|
||||
|
||||
String curveName2 = "secp112r1"; // not a compile-time constant
|
||||
KeyPairGenerator keyPairGen17 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec12 = new ECGenParameterSpec(curveName2); // $ hasInsufficientKeySize
|
||||
keyPairGen17.initialize(ecSpec12);
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSymmetricVariable(int keySize, KeyGenerator kg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(keySize); // $ hasInsufficientKeySize
|
||||
kg.init(64); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testSymmetricInt(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricNonEcVariable(int keySize, KeyPairGenerator kpg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
kpg.initialize(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricNonEcInt(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcSpecVariable(ECGenParameterSpec spec) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(spec); // sink is above where `spec` variable is initialized
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcIntVariable(int keySize, KeyPairGenerator kpg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
kpg.initialize(128); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcIntLiteral(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public int getRSAKeySize(){ return 1024; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import java
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.java.security.InsufficientKeySizeQuery
|
||||
|
||||
class InsufficientKeySizeTest extends InlineExpectationsTest {
|
||||
InsufficientKeySizeTest() { this = "InsufficientKeySize" }
|
||||
|
||||
override string getARelevantTag() { result = "hasInsufficientKeySize" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasInsufficientKeySize" and
|
||||
exists(DataFlow::PathNode source, DataFlow::PathNode sink |
|
||||
exists(KeySizeConfiguration cfg | cfg.hasFlowPath(source, sink))
|
||||
|
|
||||
sink.getNode().getLocation() = location and
|
||||
element = sink.getNode().toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
31
java/ql/test/query-tests/security/CWE-326/SignatureTest.java
Normal file
31
java/ql/test/query-tests/security/CWE-326/SignatureTest.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Adds tests to check for FPs related to RSA/DSA versus EC */
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.Signature;
|
||||
|
||||
public class SignatureTest
|
||||
{
|
||||
|
||||
public void performTest()
|
||||
throws Exception
|
||||
{
|
||||
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
|
||||
kpGen.initialize(2048); // Safe
|
||||
KeyPair kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("DSA", "BC");
|
||||
kpGen.initialize(2048); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("EC", "BC");
|
||||
kpGen.initialize(256); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("EC", "BC");
|
||||
kpGen.initialize(521); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class Main {
|
||||
* A version identifier that should be updated every time the extractor changes in such a way that
|
||||
* it may produce different tuples for the same file under the same {@link ExtractorConfig}.
|
||||
*/
|
||||
public static final String EXTRACTOR_VERSION = "2022-09-19";
|
||||
public static final String EXTRACTOR_VERSION = "2022-11-08";
|
||||
|
||||
public static final Pattern NEWLINE = Pattern.compile("\n");
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.semmle.js.extractor;
|
||||
import com.semmle.util.data.StringUtil;
|
||||
import com.semmle.util.exception.CatastrophicError;
|
||||
import com.semmle.util.exception.UserError;
|
||||
import com.semmle.util.locations.LineTable;
|
||||
import com.semmle.util.trap.TrapWriter;
|
||||
import com.semmle.util.trap.TrapWriter.Label;
|
||||
import com.semmle.util.trap.TrapWriter.Table;
|
||||
@@ -76,8 +77,10 @@ public class YAMLExtractor implements IExtractor {
|
||||
|
||||
private final boolean tolerateParseErrors;
|
||||
|
||||
private TextualExtractor textualExtractor;
|
||||
private LocationManager locationManager;
|
||||
private TrapWriter trapWriter;
|
||||
private LineTable lineTable;
|
||||
|
||||
/**
|
||||
* The underlying SnakeYAML parser; we use the relatively low-level {@linkplain Parser} instead of
|
||||
@@ -93,8 +96,16 @@ public class YAMLExtractor implements IExtractor {
|
||||
this.tolerateParseErrors = config.isTolerateParseErrors();
|
||||
}
|
||||
|
||||
private LineTable getLineTable() {
|
||||
if (lineTable == null) {
|
||||
lineTable = new LineTable(this.textualExtractor.getSource());
|
||||
}
|
||||
return lineTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoCInfo extract(TextualExtractor textualExtractor) {
|
||||
this.textualExtractor = textualExtractor;
|
||||
locationManager = textualExtractor.getLocationManager();
|
||||
trapWriter = textualExtractor.getTrapwriter();
|
||||
|
||||
@@ -253,6 +264,18 @@ public class YAMLExtractor implements IExtractor {
|
||||
endLine = endMark.getLine() + 1;
|
||||
endColumn = endMark.getColumn();
|
||||
|
||||
// Avoid emitting column zero for non-empty locations
|
||||
if (endColumn == 0 && !(startLine == endLine && startColumn == endColumn)) {
|
||||
String source = textualExtractor.getSource();
|
||||
int offset = getLineTable().getOffsetFromPoint(endMark.getLine(), endMark.getColumn()) - 1;
|
||||
while (offset > 0 && isNewLine((int)source.charAt(offset))) {
|
||||
--offset;
|
||||
}
|
||||
com.semmle.util.locations.Position adjustedEndPos = getLineTable().getEndPositionFromOffset(offset);
|
||||
endLine = adjustedEndPos.getLine();
|
||||
endColumn = adjustedEndPos.getColumn();
|
||||
}
|
||||
|
||||
locationManager.emitSnippetLocation(label, startLine, startColumn, endLine, endColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ yaml(#20006,3,#20003,-1,"","*cyc")
|
||||
locations_default(#20007,#10000,3,15,3,18)
|
||||
yaml_locations(#20006,#20007)
|
||||
yaml(#20003,1,#20000,-1,"tag:yaml.org,2002:map","&cyc")
|
||||
#20008=@"loc,{#10000},2,9,4,0"
|
||||
locations_default(#20008,#10000,2,9,4,0)
|
||||
#20008=@"loc,{#10000},2,9,3,19"
|
||||
locations_default(#20008,#10000,2,9,3,19)
|
||||
yaml_locations(#20003,#20008)
|
||||
yaml(#20000,1,#10000,0,"tag:yaml.org,2002:map","cyclic: &cyc")
|
||||
#20009=@"loc,{#10000},2,1,4,0"
|
||||
locations_default(#20009,#10000,2,1,4,0)
|
||||
#20009=@"loc,{#10000},2,1,3,19"
|
||||
locations_default(#20009,#10000,2,1,3,19)
|
||||
yaml_locations(#20000,#20009)
|
||||
numlines(#10000,3,0,0)
|
||||
filetype(#10000,"yaml")
|
||||
|
||||
@@ -33,8 +33,8 @@ yaml(#20008,0,#20007,0,"tag:yaml.org,2002:str","xx [[ "" ... xxx; xx")
|
||||
locations_default(#20009,#10000,4,5,4,102)
|
||||
yaml_locations(#20008,#20009)
|
||||
yaml(#20007,2,#20000,-2,"tag:yaml.org,2002:seq","- xx [[ ... xxx; xx")
|
||||
#20010=@"loc,{#10000},4,3,6,0"
|
||||
locations_default(#20010,#10000,4,3,6,0)
|
||||
#20010=@"loc,{#10000},4,3,4,103"
|
||||
locations_default(#20010,#10000,4,3,4,103)
|
||||
yaml_locations(#20007,#20010)
|
||||
#20011=*
|
||||
yaml_scalars(#20011,0,"xxxxxx")
|
||||
@@ -88,16 +88,16 @@ yaml(#20028,0,#20017,-3,"tag:yaml.org,2002:str","xxxxxx")
|
||||
locations_default(#20029,#10000,10,13,10,18)
|
||||
yaml_locations(#20028,#20029)
|
||||
yaml(#20017,1,#20016,0,"tag:yaml.org,2002:map","xx: xxxxx")
|
||||
#20030=@"loc,{#10000},8,7,14,0"
|
||||
locations_default(#20030,#10000,8,7,14,0)
|
||||
#20030=@"loc,{#10000},8,7,12,27"
|
||||
locations_default(#20030,#10000,8,7,12,27)
|
||||
yaml_locations(#20017,#20030)
|
||||
yaml(#20016,2,#20013,-1,"tag:yaml.org,2002:seq","- xx: xxxxx")
|
||||
#20031=@"loc,{#10000},8,5,14,0"
|
||||
locations_default(#20031,#10000,8,5,14,0)
|
||||
#20031=@"loc,{#10000},8,5,12,27"
|
||||
locations_default(#20031,#10000,8,5,12,27)
|
||||
yaml_locations(#20016,#20031)
|
||||
yaml(#20013,1,#20000,-3,"tag:yaml.org,2002:map","xxxxxxx:")
|
||||
#20032=@"loc,{#10000},7,3,14,0"
|
||||
locations_default(#20032,#10000,7,3,14,0)
|
||||
#20032=@"loc,{#10000},7,3,12,27"
|
||||
locations_default(#20032,#10000,7,3,12,27)
|
||||
yaml_locations(#20013,#20032)
|
||||
#20033=*
|
||||
yaml_scalars(#20033,0,"xxxxx")
|
||||
@@ -120,12 +120,12 @@ yaml(#20039,0,#20038,0,"tag:yaml.org,2002:str","xxxx_xxxxxxx")
|
||||
locations_default(#20040,#10000,16,7,16,18)
|
||||
yaml_locations(#20039,#20040)
|
||||
yaml(#20038,2,#20035,-1,"tag:yaml.org,2002:seq","- xxxx_xxxxxxx")
|
||||
#20041=@"loc,{#10000},16,5,18,0"
|
||||
locations_default(#20041,#10000,16,5,18,0)
|
||||
#20041=@"loc,{#10000},16,5,16,19"
|
||||
locations_default(#20041,#10000,16,5,16,19)
|
||||
yaml_locations(#20038,#20041)
|
||||
yaml(#20035,1,#20000,-4,"tag:yaml.org,2002:map","xxxxxxxxxxx:")
|
||||
#20042=@"loc,{#10000},15,3,18,0"
|
||||
locations_default(#20042,#10000,15,3,18,0)
|
||||
#20042=@"loc,{#10000},15,3,16,19"
|
||||
locations_default(#20042,#10000,15,3,16,19)
|
||||
yaml_locations(#20035,#20042)
|
||||
#20043=*
|
||||
yaml_scalars(#20043,0,"xxxxxx")
|
||||
@@ -171,8 +171,8 @@ yaml(#20056,0,#20045,-3,"tag:yaml.org,2002:str","xxx xxx xxxx")
|
||||
locations_default(#20057,#10000,21,11,21,22)
|
||||
yaml_locations(#20056,#20057)
|
||||
yaml(#20045,1,#20000,-5,"tag:yaml.org,2002:map","xxxx_xxxxxxx: xxxx")
|
||||
#20058=@"loc,{#10000},19,3,23,0"
|
||||
locations_default(#20058,#10000,19,3,23,0)
|
||||
#20058=@"loc,{#10000},19,3,21,23"
|
||||
locations_default(#20058,#10000,19,3,21,23)
|
||||
yaml_locations(#20045,#20058)
|
||||
#20059=*
|
||||
yaml_scalars(#20059,0,"xxx")
|
||||
@@ -201,16 +201,16 @@ yaml(#20067,0,#20064,-1,"tag:yaml.org,2002:str","xxxxxxx ... xxxxxx=")
|
||||
locations_default(#20068,#10000,26,13,26,696)
|
||||
yaml_locations(#20067,#20068)
|
||||
yaml(#20064,1,#20061,-1,"tag:yaml.org,2002:map","xxxxxx: ... xxxxxx=")
|
||||
#20069=@"loc,{#10000},26,5,27,0"
|
||||
locations_default(#20069,#10000,26,5,27,0)
|
||||
#20069=@"loc,{#10000},26,5,26,697"
|
||||
locations_default(#20069,#10000,26,5,26,697)
|
||||
yaml_locations(#20064,#20069)
|
||||
yaml(#20061,1,#20000,-6,"tag:yaml.org,2002:map","xxxxxx:")
|
||||
#20070=@"loc,{#10000},24,3,27,0"
|
||||
locations_default(#20070,#10000,24,3,27,0)
|
||||
#20070=@"loc,{#10000},24,3,26,697"
|
||||
locations_default(#20070,#10000,24,3,26,697)
|
||||
yaml_locations(#20061,#20070)
|
||||
yaml(#20000,1,#10000,0,"tag:yaml.org,2002:map","xxxxxxxx: xxxx_xx")
|
||||
#20071=@"loc,{#10000},1,1,27,0"
|
||||
locations_default(#20071,#10000,1,1,27,0)
|
||||
#20071=@"loc,{#10000},1,1,26,697"
|
||||
locations_default(#20071,#10000,1,1,26,697)
|
||||
yaml_locations(#20000,#20071)
|
||||
numlines(#10000,26,0,0)
|
||||
filetype(#10000,"yaml")
|
||||
|
||||
@@ -63,8 +63,8 @@ yaml(#20018,0,#20011,-2,"tag:yaml.org,2002:str","Gale")
|
||||
locations_default(#20019,#10000,6,14,6,17)
|
||||
yaml_locations(#20018,#20019)
|
||||
yaml(#20011,1,#20000,-3,"tag:yaml.org,2002:map","given: Dorothy")
|
||||
#20020=@"loc,{#10000},5,5,8,0"
|
||||
locations_default(#20020,#10000,5,5,8,0)
|
||||
#20020=@"loc,{#10000},5,5,6,18"
|
||||
locations_default(#20020,#10000,5,5,6,18)
|
||||
yaml_locations(#20011,#20020)
|
||||
#20021=*
|
||||
yaml_scalars(#20021,0,"items")
|
||||
@@ -188,12 +188,12 @@ yaml(#20061,0,#20042,-5,"tag:yaml.org,2002:int","1")
|
||||
locations_default(#20062,#10000,18,18,18,18)
|
||||
yaml_locations(#20061,#20062)
|
||||
yaml(#20042,1,#20023,1,"tag:yaml.org,2002:map","part_no: E1628")
|
||||
#20063=@"loc,{#10000},14,7,20,0"
|
||||
locations_default(#20063,#10000,14,7,20,0)
|
||||
#20063=@"loc,{#10000},14,7,18,19"
|
||||
locations_default(#20063,#10000,14,7,18,19)
|
||||
yaml_locations(#20042,#20063)
|
||||
yaml(#20023,2,#20000,-4,"tag:yaml.org,2002:seq","- part_no: A4786")
|
||||
#20064=@"loc,{#10000},9,5,20,0"
|
||||
locations_default(#20064,#10000,9,5,20,0)
|
||||
#20064=@"loc,{#10000},9,5,18,19"
|
||||
locations_default(#20064,#10000,9,5,18,19)
|
||||
yaml_locations(#20023,#20064)
|
||||
#20065=*
|
||||
yaml_scalars(#20065,0,"bill-to")
|
||||
@@ -214,8 +214,8 @@ yaml_scalars(#20070,124,"123 Tornado Alley
|
||||
Suite 16
|
||||
")
|
||||
yaml(#20070,0,#20067,-1,"tag:yaml.org,2002:str","|")
|
||||
#20071=@"loc,{#10000},21,13,24,0"
|
||||
locations_default(#20071,#10000,21,13,24,0)
|
||||
#20071=@"loc,{#10000},21,13,23,21"
|
||||
locations_default(#20071,#10000,21,13,23,21)
|
||||
yaml_locations(#20070,#20071)
|
||||
#20072=*
|
||||
yaml_scalars(#20072,0,"city")
|
||||
@@ -242,8 +242,8 @@ yaml(#20078,0,#20067,-3,"tag:yaml.org,2002:str","KS")
|
||||
locations_default(#20079,#10000,25,13,25,14)
|
||||
yaml_locations(#20078,#20079)
|
||||
yaml(#20067,1,#20000,-5,"tag:yaml.org,2002:map","&id001")
|
||||
#20080=@"loc,{#10000},20,11,27,0"
|
||||
locations_default(#20080,#10000,20,11,27,0)
|
||||
#20080=@"loc,{#10000},20,11,25,15"
|
||||
locations_default(#20080,#10000,20,11,25,15)
|
||||
yaml_locations(#20067,#20080)
|
||||
#20081=*
|
||||
yaml_scalars(#20081,0,"ship-to")
|
||||
|
||||
@@ -75,6 +75,16 @@ private DataFlow::Node getAValueExportedByPackage() {
|
||||
result = getAnExportFromModule(mod)
|
||||
)
|
||||
or
|
||||
// re-export of a value from another module
|
||||
// `module.exports.foo = require("./other").bar;`
|
||||
// other.js:
|
||||
// `module.exports.bar = function () { ... };`
|
||||
exists(DataFlow::PropRead read, Import imp |
|
||||
read = getAValueExportedByPackage() and
|
||||
read.getBase().getALocalSource() = imp.getImportedModuleNode() and
|
||||
result = imp.getImportedModule().getAnExportedValue(read.getPropertyName())
|
||||
)
|
||||
or
|
||||
// require("./other-module.js"); inside an AMD module.
|
||||
exists(Module mod, CallExpr call |
|
||||
call = getAValueExportedByPackage().asExpr() and
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an issue with multi-line strings in YAML files being associated with an invalid location,
|
||||
causing alerts related to such strings to appear at the top of the YAML file.
|
||||
@@ -2,10 +2,10 @@
|
||||
| sub/.eslintrc.json:2:14:5:3 | {\\n ... lse\\n } | aNonWritableGlobal | false | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.json:2:14:5:3 | {\\n ... lse\\n } | aWritableGlobal | true | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.json:2:14:5:3 | {\\n ... lse\\n } | aWritableGlobal | true | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:6:0 | aWritab ... l: true | aNonWritableGlobal | false | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:6:0 | aWritab ... l: true | aNonWritableGlobal | false | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:6:0 | aWritab ... l: true | aWritableGlobal | true | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:6:0 | aWritab ... l: true | aWritableGlobal | true | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:4:30 | aWritab ... l: true | aNonWritableGlobal | false | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:4:30 | aWritab ... l: true | aNonWritableGlobal | false | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:4:30 | aWritab ... l: true | aWritableGlobal | true | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/.eslintrc.yml:3:5:4:30 | aWritab ... l: true | aWritableGlobal | true | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/package.json:5:20:8:9 | {\\n ... } | aNonWritableGlobal | false | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/package.json:5:20:8:9 | {\\n ... } | aNonWritableGlobal | false | sub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
| sub/package.json:5:20:8:9 | {\\n ... } | aWritableGlobal | true | sub/subsub/tst.js:1:1:1:15 | aWritableGlobal |
|
||||
|
||||
@@ -30,7 +30,7 @@ nodes
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | semmle.label | [YamlSequence] - "name ... Knopf" |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | semmle.order | 3 |
|
||||
| tst.yml:1:3:1:8 | [YamlScalar] "name" | semmle.label | [YamlScalar] "name" |
|
||||
| tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | semmle.label | [YamlMapping] "name": "Jim Knopf" |
|
||||
| tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | semmle.label | [YamlMapping] "name": "Jim Knopf" |
|
||||
| tst.yml:1:11:1:21 | [YamlScalar] "Jim Knopf" | semmle.label | [YamlScalar] "Jim Knopf" |
|
||||
| tst.yml:2:3:2:9 | [YamlScalar] address | semmle.label | [YamlScalar] address |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | semmle.label | [YamlMapping] { |
|
||||
@@ -41,12 +41,12 @@ nodes
|
||||
| tst.yml:5:5:5:13 | [YamlScalar] "country" | semmle.label | [YamlScalar] "country" |
|
||||
| tst.yml:5:16:5:27 | [YamlScalar] "Lummerland" | semmle.label | [YamlScalar] "Lummerland" |
|
||||
| tst.yml:7:3:7:6 | [YamlScalar] name | semmle.label | [YamlScalar] name |
|
||||
| tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | semmle.label | [YamlMapping] name: Frau Mahlzahn |
|
||||
| tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | semmle.label | [YamlMapping] name: Frau Mahlzahn |
|
||||
| tst.yml:7:9:7:21 | [YamlScalar] Frau Mahlzahn | semmle.label | [YamlScalar] Frau Mahlzahn |
|
||||
| tst.yml:8:3:8:9 | [YamlScalar] address | semmle.label | [YamlScalar] address |
|
||||
| tst.yml:9:5:9:10 | [YamlScalar] street | semmle.label | [YamlScalar] street |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | semmle.label | [YamlMapping] street: \| |
|
||||
| tst.yml:9:13:11:0 | [YamlScalar] \| | semmle.label | [YamlScalar] \| |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | semmle.label | [YamlMapping] street: \| |
|
||||
| tst.yml:9:13:10:21 | [YamlScalar] \| | semmle.label | [YamlScalar] \| |
|
||||
| tst.yml:11:5:11:10 | [YamlScalar] number | semmle.label | [YamlScalar] number |
|
||||
| tst.yml:11:13:11:15 | [YamlScalar] 133 | semmle.label | [YamlScalar] 133 |
|
||||
| tst.yml:12:5:12:11 | [YamlScalar] country | semmle.label | [YamlScalar] country |
|
||||
@@ -67,8 +67,8 @@ edges
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:3:14:3:13 | [YamlScalar] | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:5:9:10 | [YamlScalar] street | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:5:9:10 | [YamlScalar] street | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:13:11:0 | [YamlScalar] \| | semmle.label | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:13:11:0 | [YamlScalar] \| | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:13:10:21 | [YamlScalar] \| | semmle.label | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 0) street: | tst.yml:9:13:10:21 | [YamlScalar] \| | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 0) x: | merge.yaml:1:8:1:8 | [YamlScalar] x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 0) x: | merge.yaml:1:8:1:8 | [YamlScalar] x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 0) x: | merge.yaml:1:11:1:12 | [YamlScalar] 23 | semmle.label | 1 |
|
||||
@@ -87,8 +87,8 @@ edges
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:2:12:6:3 | [YamlMapping] { | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:8:3:8:9 | [YamlScalar] address | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:8:3:8:9 | [YamlScalar] address | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:9:5:14:0 | [YamlMapping] street: \| | semmle.label | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:9:5:14:0 | [YamlMapping] street: \| | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:9:5:13:19 | [YamlMapping] street: \| | semmle.label | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 1) address: | tst.yml:9:5:13:19 | [YamlMapping] street: \| | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Mapping 1) number: | tst.yml:4:5:4:12 | [YamlScalar] "number" | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 1) number: | tst.yml:4:5:4:12 | [YamlScalar] "number" | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Mapping 1) number: | tst.yml:4:15:4:16 | [YamlScalar] -1 | semmle.label | 1 |
|
||||
@@ -121,31 +121,31 @@ edges
|
||||
| merge.yaml:2:3:3:8 | [YamlMapping] x: 56 | file://:0:0:0:0 | (Mapping 0) x: | semmle.order | 0 |
|
||||
| merge.yaml:2:3:3:8 | [YamlMapping] x: 56 | file://:0:0:0:0 | (Mapping 1) <<: | semmle.label | 1 |
|
||||
| merge.yaml:2:3:3:8 | [YamlMapping] x: 56 | file://:0:0:0:0 | (Mapping 1) <<: | semmle.order | 1 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | semmle.label | 0 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | semmle.order | 0 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | semmle.label | 1 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | semmle.order | 1 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | semmle.label | 0 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | semmle.order | 0 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | semmle.label | 1 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | semmle.order | 1 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:14:3:14:23 | [YamlScalar] !includ ... nal.yml | semmle.label | 2 |
|
||||
| tst.yml:1:1:14:23 | [YamlSequence] - "name ... Knopf" | tst.yml:14:3:14:23 | [YamlScalar] !includ ... nal.yml | semmle.order | 2 |
|
||||
| tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 0) name: | semmle.label | 0 |
|
||||
| tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 0) name: | semmle.order | 0 |
|
||||
| tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 1) address: | semmle.label | 1 |
|
||||
| tst.yml:1:3:7:0 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 1) address: | semmle.order | 1 |
|
||||
| tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 0) name: | semmle.label | 0 |
|
||||
| tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 0) name: | semmle.order | 0 |
|
||||
| tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 1) address: | semmle.label | 1 |
|
||||
| tst.yml:1:3:6:4 | [YamlMapping] "name": "Jim Knopf" | file://:0:0:0:0 | (Mapping 1) address: | semmle.order | 1 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 0) street: | semmle.label | 0 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 0) street: | semmle.order | 0 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 1) number: | semmle.label | 1 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 1) number: | semmle.order | 1 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 2) country: | semmle.label | 2 |
|
||||
| tst.yml:2:12:6:3 | [YamlMapping] { | file://:0:0:0:0 | (Mapping 2) country: | semmle.order | 2 |
|
||||
| tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 0) name: | semmle.label | 0 |
|
||||
| tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 0) name: | semmle.order | 0 |
|
||||
| tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 1) address: | semmle.label | 1 |
|
||||
| tst.yml:7:3:14:0 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 1) address: | semmle.order | 1 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 0) street: | semmle.label | 0 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 0) street: | semmle.order | 0 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 1) number: | semmle.label | 1 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 1) number: | semmle.order | 1 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 2) country: | semmle.label | 2 |
|
||||
| tst.yml:9:5:14:0 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 2) country: | semmle.order | 2 |
|
||||
| tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 0) name: | semmle.label | 0 |
|
||||
| tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 0) name: | semmle.order | 0 |
|
||||
| tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 1) address: | semmle.label | 1 |
|
||||
| tst.yml:7:3:13:19 | [YamlMapping] name: Frau Mahlzahn | file://:0:0:0:0 | (Mapping 1) address: | semmle.order | 1 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 0) street: | semmle.label | 0 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 0) street: | semmle.order | 0 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 1) number: | semmle.label | 1 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 1) number: | semmle.order | 1 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 2) country: | semmle.label | 2 |
|
||||
| tst.yml:9:5:13:19 | [YamlMapping] street: \| | file://:0:0:0:0 | (Mapping 2) country: | semmle.order | 2 |
|
||||
graphProperties
|
||||
| semmle.graphKind | tree |
|
||||
|
||||
@@ -12,16 +12,16 @@ yamlMapping_maps
|
||||
| merge.yaml:2:3:3:8 | x: 56 | merge.yaml:1:15:1:15 | y | merge.yaml:1:18:1:19 | 42 |
|
||||
| merge.yaml:2:3:3:8 | x: 56 | merge.yaml:2:3:2:3 | x | merge.yaml:2:6:2:7 | 56 |
|
||||
| merge.yaml:2:3:3:8 | x: 56 | merge.yaml:3:3:3:4 | << | merge.yaml:1:3:1:21 | &A { x: 23, y: 42 } |
|
||||
| tst.yml:1:3:7:0 | "name": "Jim Knopf" | tst.yml:1:3:1:8 | "name" | tst.yml:1:11:1:21 | "Jim Knopf" |
|
||||
| tst.yml:1:3:7:0 | "name": "Jim Knopf" | tst.yml:2:3:2:9 | address | tst.yml:2:12:6:3 | { |
|
||||
| tst.yml:1:3:6:4 | "name": "Jim Knopf" | tst.yml:1:3:1:8 | "name" | tst.yml:1:11:1:21 | "Jim Knopf" |
|
||||
| tst.yml:1:3:6:4 | "name": "Jim Knopf" | tst.yml:2:3:2:9 | address | tst.yml:2:12:6:3 | { |
|
||||
| tst.yml:2:12:6:3 | { | tst.yml:3:5:3:12 | "street" | tst.yml:3:14:3:13 | |
|
||||
| tst.yml:2:12:6:3 | { | tst.yml:4:5:4:12 | "number" | tst.yml:4:15:4:16 | -1 |
|
||||
| tst.yml:2:12:6:3 | { | tst.yml:5:5:5:13 | "country" | tst.yml:5:16:5:27 | "Lummerland" |
|
||||
| tst.yml:7:3:14:0 | name: Frau Mahlzahn | tst.yml:7:3:7:6 | name | tst.yml:7:9:7:21 | Frau Mahlzahn |
|
||||
| tst.yml:7:3:14:0 | name: Frau Mahlzahn | tst.yml:8:3:8:9 | address | tst.yml:9:5:14:0 | street: \| |
|
||||
| tst.yml:9:5:14:0 | street: \| | tst.yml:9:5:9:10 | street | tst.yml:9:13:11:0 | \| |
|
||||
| tst.yml:9:5:14:0 | street: \| | tst.yml:11:5:11:10 | number | tst.yml:11:13:11:15 | 133 |
|
||||
| tst.yml:9:5:14:0 | street: \| | tst.yml:12:5:12:11 | country | tst.yml:12:14:13:18 | < |
|
||||
| tst.yml:7:3:13:19 | name: Frau Mahlzahn | tst.yml:7:3:7:6 | name | tst.yml:7:9:7:21 | Frau Mahlzahn |
|
||||
| tst.yml:7:3:13:19 | name: Frau Mahlzahn | tst.yml:8:3:8:9 | address | tst.yml:9:5:13:19 | street: \| |
|
||||
| tst.yml:9:5:13:19 | street: \| | tst.yml:9:5:9:10 | street | tst.yml:9:13:10:21 | \| |
|
||||
| tst.yml:9:5:13:19 | street: \| | tst.yml:11:5:11:10 | number | tst.yml:11:13:11:15 | 133 |
|
||||
| tst.yml:9:5:13:19 | street: \| | tst.yml:12:5:12:11 | country | tst.yml:12:14:13:18 | < |
|
||||
yamlNode
|
||||
| external.yml:1:1:1:2 | 42 | tag:yaml.org,2002:int |
|
||||
| merge.yaml:1:1:3:8 | - &A { ... y: 42 } | tag:yaml.org,2002:seq |
|
||||
@@ -37,7 +37,7 @@ yamlNode
|
||||
| merge.yaml:3:7:3:8 | *A | |
|
||||
| tst.yml:1:1:14:23 | - "name ... Knopf" | tag:yaml.org,2002:seq |
|
||||
| tst.yml:1:3:1:8 | "name" | tag:yaml.org,2002:str |
|
||||
| tst.yml:1:3:7:0 | "name": "Jim Knopf" | tag:yaml.org,2002:map |
|
||||
| tst.yml:1:3:6:4 | "name": "Jim Knopf" | tag:yaml.org,2002:map |
|
||||
| tst.yml:1:11:1:21 | "Jim Knopf" | tag:yaml.org,2002:str |
|
||||
| tst.yml:2:3:2:9 | address | tag:yaml.org,2002:str |
|
||||
| tst.yml:2:12:6:3 | { | tag:yaml.org,2002:map |
|
||||
@@ -48,12 +48,12 @@ yamlNode
|
||||
| tst.yml:5:5:5:13 | "country" | tag:yaml.org,2002:str |
|
||||
| tst.yml:5:16:5:27 | "Lummerland" | tag:yaml.org,2002:str |
|
||||
| tst.yml:7:3:7:6 | name | tag:yaml.org,2002:str |
|
||||
| tst.yml:7:3:14:0 | name: Frau Mahlzahn | tag:yaml.org,2002:map |
|
||||
| tst.yml:7:3:13:19 | name: Frau Mahlzahn | tag:yaml.org,2002:map |
|
||||
| tst.yml:7:9:7:21 | Frau Mahlzahn | tag:yaml.org,2002:str |
|
||||
| tst.yml:8:3:8:9 | address | tag:yaml.org,2002:str |
|
||||
| tst.yml:9:5:9:10 | street | tag:yaml.org,2002:str |
|
||||
| tst.yml:9:5:14:0 | street: \| | tag:yaml.org,2002:map |
|
||||
| tst.yml:9:13:11:0 | \| | tag:yaml.org,2002:str |
|
||||
| tst.yml:9:5:13:19 | street: \| | tag:yaml.org,2002:map |
|
||||
| tst.yml:9:13:10:21 | \| | tag:yaml.org,2002:str |
|
||||
| tst.yml:11:5:11:10 | number | tag:yaml.org,2002:str |
|
||||
| tst.yml:11:13:11:15 | 133 | tag:yaml.org,2002:int |
|
||||
| tst.yml:12:5:12:11 | country | tag:yaml.org,2002:str |
|
||||
@@ -81,7 +81,7 @@ yamlScalar
|
||||
| tst.yml:7:9:7:21 | Frau Mahlzahn | | Frau Mahlzahn |
|
||||
| tst.yml:8:3:8:9 | address | | address |
|
||||
| tst.yml:9:5:9:10 | street | | street |
|
||||
| tst.yml:9:13:11:0 | \| | \| | Alte Strasse\n |
|
||||
| tst.yml:9:13:10:21 | \| | \| | Alte Strasse\n |
|
||||
| tst.yml:11:5:11:10 | number | | number |
|
||||
| tst.yml:11:13:11:15 | 133 | | 133 |
|
||||
| tst.yml:12:5:12:11 | country | | country |
|
||||
|
||||
@@ -2,6 +2,12 @@ on: issue_comment
|
||||
|
||||
jobs:
|
||||
echo-chamber:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
echo '${{ github.event.comment.body }}'
|
||||
|
||||
echo-chamber2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
on: issue_comment
|
||||
|
||||
# same as comment_issue but this file ends with a line break
|
||||
|
||||
jobs:
|
||||
echo-chamber:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
echo '${{ github.event.comment.body }}'
|
||||
@@ -1 +1,3 @@
|
||||
| .github/workflows/comment_issue.yml:7:12:8:47 | \| | Potential injection from the github.event.comment.body context, which may be controlled by an external user. |
|
||||
| .github/workflows/comment_issue.yml:7:12:8:48 | \| | Potential injection from the github.event.comment.body context, which may be controlled by an external user. |
|
||||
| .github/workflows/comment_issue.yml:13:12:14:47 | \| | Potential injection from the github.event.comment.body context, which may be controlled by an external user. |
|
||||
| .github/workflows/comment_issue_newline.yml:9:14:10:50 | \| | Potential injection from the github.event.comment.body context, which may be controlled by an external user. |
|
||||
|
||||
@@ -117,6 +117,12 @@ nodes
|
||||
| lib.js:128:9:128:20 | obj[path[0]] |
|
||||
| lib.js:128:13:128:16 | path |
|
||||
| lib.js:128:13:128:19 | path[0] |
|
||||
| sublib/other.js:5:28:5:31 | path |
|
||||
| sublib/other.js:5:28:5:31 | path |
|
||||
| sublib/other.js:6:7:6:18 | obj[path[0]] |
|
||||
| sublib/other.js:6:7:6:18 | obj[path[0]] |
|
||||
| sublib/other.js:6:11:6:14 | path |
|
||||
| sublib/other.js:6:11:6:17 | path[0] |
|
||||
| sublib/sub.js:1:37:1:40 | path |
|
||||
| sublib/sub.js:1:37:1:40 | path |
|
||||
| sublib/sub.js:2:3:2:14 | obj[path[0]] |
|
||||
@@ -289,6 +295,11 @@ edges
|
||||
| lib.js:128:13:128:16 | path | lib.js:128:13:128:19 | path[0] |
|
||||
| lib.js:128:13:128:19 | path[0] | lib.js:128:9:128:20 | obj[path[0]] |
|
||||
| lib.js:128:13:128:19 | path[0] | lib.js:128:9:128:20 | obj[path[0]] |
|
||||
| sublib/other.js:5:28:5:31 | path | sublib/other.js:6:11:6:14 | path |
|
||||
| sublib/other.js:5:28:5:31 | path | sublib/other.js:6:11:6:14 | path |
|
||||
| sublib/other.js:6:11:6:14 | path | sublib/other.js:6:11:6:17 | path[0] |
|
||||
| sublib/other.js:6:11:6:17 | path[0] | sublib/other.js:6:7:6:18 | obj[path[0]] |
|
||||
| sublib/other.js:6:11:6:17 | path[0] | sublib/other.js:6:7:6:18 | obj[path[0]] |
|
||||
| sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:7:2:10 | path |
|
||||
| sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:7:2:10 | path |
|
||||
| sublib/sub.js:2:7:2:10 | path | sublib/sub.js:2:7:2:13 | path[0] |
|
||||
@@ -356,6 +367,7 @@ edges
|
||||
| lib.js:108:3:108:10 | obj[one] | lib.js:104:13:104:21 | arguments | lib.js:108:3:108:10 | obj[one] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:104:13:104:21 | arguments | library input |
|
||||
| lib.js:119:13:119:24 | obj[path[0]] | lib.js:118:29:118:32 | path | lib.js:119:13:119:24 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:118:29:118:32 | path | library input |
|
||||
| lib.js:128:9:128:20 | obj[path[0]] | lib.js:127:14:127:17 | path | lib.js:128:9:128:20 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:127:14:127:17 | path | library input |
|
||||
| sublib/other.js:6:7:6:18 | obj[path[0]] | sublib/other.js:5:28:5:31 | path | sublib/other.js:6:7:6:18 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | sublib/other.js:5:28:5:31 | path | library input |
|
||||
| sublib/sub.js:2:3:2:14 | obj[path[0]] | sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:3:2:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | sublib/sub.js:1:37:1:40 | path | library input |
|
||||
| tst.js:8:5:8:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:8:5:8:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input |
|
||||
| tst.js:9:5:9:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:9:5:9:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input |
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
(function () {
|
||||
function Foobar() {}
|
||||
|
||||
Foobar.prototype = {
|
||||
method: function (obj, path, value) {
|
||||
obj[path[0]][path[1]] = value; // NOT OK
|
||||
},
|
||||
};
|
||||
|
||||
module.exports.foobar = Foobar;
|
||||
|
||||
module.other.notExported = function (obj, path, value) {
|
||||
obj[path[0]][path[1]] = value; // OK - not exported
|
||||
}
|
||||
})();
|
||||
@@ -1,3 +1,6 @@
|
||||
module.exports.set = function (obj, path, value) {
|
||||
obj[path[0]][path[1]] = value; // NOT OK
|
||||
}
|
||||
}
|
||||
|
||||
var other = require('./other')
|
||||
exports.foobar = other.foobar;
|
||||
@@ -36,6 +36,13 @@ private module Cached {
|
||||
not s instanceof ModuleBase and
|
||||
result = getEnclosingMethod(s.getOuterScope())
|
||||
}
|
||||
|
||||
cached
|
||||
Toplevel getEnclosingToplevel(Scope s) {
|
||||
result = s
|
||||
or
|
||||
result = getEnclosingToplevel(s.getOuterScope())
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
@@ -66,6 +73,9 @@ class AstNode extends TAstNode {
|
||||
/** Gets the enclosing method, if any. */
|
||||
final MethodBase getEnclosingMethod() { result = getEnclosingMethod(scopeOfInclSynth(this)) }
|
||||
|
||||
/** Gets the enclosing top-level. */
|
||||
final Toplevel getEnclosingToplevel() { result = getEnclosingToplevel(scopeOfInclSynth(this)) }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
cached
|
||||
string toString() { none() }
|
||||
|
||||
@@ -271,10 +271,7 @@ module Http {
|
||||
|
||||
/** Gets the URL pattern for this route, if it can be statically determined. */
|
||||
string getUrlPattern() {
|
||||
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
|
||||
this.getUrlPatternArg().getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
result = strNode.getExpr().getConstantValue().getStringlikeValue()
|
||||
)
|
||||
result = this.getUrlPatternArg().getALocalSource().getConstantValue().getStringlikeValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,10 +535,12 @@ module Http {
|
||||
|
||||
/** Gets the mimetype of this HTTP response, if it can be statically determined. */
|
||||
string getMimetype() {
|
||||
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
|
||||
this.getMimetypeOrContentTypeArg().getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
result = strNode.getExpr().getConstantValue().getStringlikeValue().splitAt(";", 0)
|
||||
)
|
||||
result =
|
||||
this.getMimetypeOrContentTypeArg()
|
||||
.getALocalSource()
|
||||
.getConstantValue()
|
||||
.getStringlikeValue()
|
||||
.splitAt(";", 0)
|
||||
or
|
||||
not exists(this.getMimetypeOrContentTypeArg()) and
|
||||
result = this.getMimetypeDefault()
|
||||
|
||||
@@ -170,6 +170,24 @@ module ConstantValue {
|
||||
|
||||
/** A constant `nil` value. */
|
||||
class ConstantNilValue extends ConstantValue, TNil { }
|
||||
|
||||
/** Gets the integer constant `x`. */
|
||||
ConstantValue fromInt(int x) { result.getInt() = x }
|
||||
|
||||
/** Gets the float constant `x`. */
|
||||
ConstantValue fromFloat(float x) { result.getFloat() = x }
|
||||
|
||||
/** Gets the string constant `x`. */
|
||||
ConstantValue fromString(string x) { result.getString() = x }
|
||||
|
||||
/** Gets the symbol constant `x`. */
|
||||
ConstantValue fromSymbol(string x) { result.getSymbol() = x }
|
||||
|
||||
/** Gets the regexp constant `x`. */
|
||||
ConstantValue fromRegExp(string x) { result.getRegExp() = x }
|
||||
|
||||
/** Gets the string, symbol, or regexp constant `x`. */
|
||||
ConstantValue fromStringlikeValue(string x) { result.getStringlikeValue() = x }
|
||||
}
|
||||
|
||||
/** An access to a constant. */
|
||||
|
||||
@@ -3,6 +3,7 @@ private import codeql.ruby.CFG
|
||||
private import internal.AST
|
||||
private import internal.Module
|
||||
private import internal.TreeSitter
|
||||
private import internal.Scope
|
||||
|
||||
/**
|
||||
* A representation of a run-time `module` or `class` value.
|
||||
@@ -23,6 +24,22 @@ class Module extends TModule {
|
||||
/** Gets an `include`d module. */
|
||||
Module getAnIncludedModule() { result = getAnIncludedModule(this) }
|
||||
|
||||
/** Gets the super class or an included or prepended module. */
|
||||
Module getAnImmediateAncestor() {
|
||||
result = [this.getSuperClass(), this.getAPrependedModule(), this.getAnIncludedModule()]
|
||||
}
|
||||
|
||||
/** Gets a direct subclass or module including or prepending this one. */
|
||||
Module getAnImmediateDescendent() { this = result.getAnImmediateAncestor() }
|
||||
|
||||
/** Gets a module that is transitively subclassed, included, or prepended by this module. */
|
||||
pragma[inline]
|
||||
Module getAnAncestor() { result = this.getAnImmediateAncestor*() }
|
||||
|
||||
/** Gets a module that transitively subclasses, includes, or prepends this module. */
|
||||
pragma[inline]
|
||||
Module getADescendent() { result = this.getAnImmediateDescendent*() }
|
||||
|
||||
/** Holds if this module is a class. */
|
||||
pragma[noinline]
|
||||
predicate isClass() {
|
||||
@@ -63,6 +80,99 @@ class Module extends TModule {
|
||||
loc.getStartColumn()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a constant or `self` access that refers to this module. */
|
||||
private Expr getAnImmediateReferenceBase() {
|
||||
resolveConstantReadAccess(result) = this
|
||||
or
|
||||
result.(SelfVariableAccess).getVariable() = this.getADeclaration().getModuleSelfVariable()
|
||||
}
|
||||
|
||||
/** Gets a singleton class that augments this module object. */
|
||||
SingletonClass getASingletonClass() { result.getValue() = this.getAnImmediateReferenceBase() }
|
||||
|
||||
/**
|
||||
* Gets a singleton method on this module, either declared as a singleton method
|
||||
* or an instance method on a singleton class.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
MethodBase getAnOwnSingletonMethod() {
|
||||
result.(SingletonMethod).getObject() = this.getAnImmediateReferenceBase()
|
||||
or
|
||||
result = this.getASingletonClass().getAMethod().(Method)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance method named `name` declared in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
Method getOwnInstanceMethod(string name) { result = this.getADeclaration().getMethod(name) }
|
||||
|
||||
/**
|
||||
* Gets an instance method declared in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
Method getAnOwnInstanceMethod() { result = this.getADeclaration().getMethod(_) }
|
||||
|
||||
/**
|
||||
* Gets the instance method named `name` available in this module, including methods inherited
|
||||
* from ancestors.
|
||||
*/
|
||||
Method getInstanceMethod(string name) { result = lookupMethod(this, name) }
|
||||
|
||||
/**
|
||||
* Gets an instance method available in this module, including methods inherited
|
||||
* from ancestors.
|
||||
*/
|
||||
Method getAnInstanceMethod() { result = lookupMethod(this, _) }
|
||||
|
||||
/** Gets a constant or `self` access that refers to this module. */
|
||||
Expr getAnImmediateReference() {
|
||||
result = this.getAnImmediateReferenceBase()
|
||||
or
|
||||
result.(SelfVariableAccess).getVariable().getDeclaringScope() = this.getAnOwnSingletonMethod()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string getEnclosingModuleName() {
|
||||
exists(string qname |
|
||||
qname = this.getQualifiedName() and
|
||||
result = qname.regexpReplaceAll("::[^:]*$", "") and
|
||||
qname != result
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string getOwnModuleName() {
|
||||
result = this.getQualifiedName().regexpReplaceAll("^.*::", "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing module, as it appears in the qualified name of this module.
|
||||
*
|
||||
* For example, the parent module of `A::B` is `A`, and `A` itself has no parent module.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Module getParentModule() { result.getQualifiedName() = this.getEnclosingModuleName() }
|
||||
|
||||
/**
|
||||
* Gets a module named `name` declared inside this one (not aliased), provided
|
||||
* that such a module is defined or reopened in the current codebase.
|
||||
*
|
||||
* For example, for `A::B` the nested module named `C` would be `A::B::C`.
|
||||
*
|
||||
* Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
|
||||
* module whose qualified name is not `A::B::C`, then it will not be found by
|
||||
* this predicate.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Module getNestedModule(string name) {
|
||||
result.getParentModule() = this and
|
||||
result.getOwnModuleName() = name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,6 +251,46 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
|
||||
|
||||
/** Gets the representation of the run-time value of this module or class. */
|
||||
Module getModule() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `self` variable in the module-level scope.
|
||||
*
|
||||
* Does not include the `self` variable from any of the methods in the module.
|
||||
*/
|
||||
SelfVariable getModuleSelfVariable() { result.getDeclaringScope() = this }
|
||||
|
||||
/** Gets the nearest enclosing `Namespace` or `Toplevel`, possibly this module itself. */
|
||||
Namespace getNamespaceOrToplevel() {
|
||||
result = this
|
||||
or
|
||||
not this instanceof Namespace and
|
||||
result = this.getEnclosingModule().getNamespaceOrToplevel()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression denoting the super class or an included or prepended module.
|
||||
*
|
||||
* For example, `C` is an ancestor expression of `M` in each of the following examples:
|
||||
* ```rb
|
||||
* class M < C
|
||||
* end
|
||||
*
|
||||
* module M
|
||||
* include C
|
||||
* prepend C
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
Expr getAnAncestorExpr() {
|
||||
exists(MethodCall call |
|
||||
call.getReceiver().(SelfVariableAccess).getVariable() = this.getModuleSelfVariable() and
|
||||
call.getMethodName() = ["include", "prepend"] and
|
||||
result = call.getArgument(0) and
|
||||
scopeOfInclSynth(call) = this // only permit calls directly in the module scope, not in a block
|
||||
)
|
||||
or
|
||||
result = this.(ClassDeclaration).getSuperclassExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -289,7 +289,7 @@ module Ssa {
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = "<captured>" }
|
||||
final override string toString() { result = "<captured> " + this.getSourceVariable() }
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
@@ -119,11 +119,27 @@ module LocalFlow {
|
||||
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
|
||||
*/
|
||||
predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) {
|
||||
nodeTo = getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter())
|
||||
or
|
||||
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom -> nodeTo` is a step from a parameter to a capture entry node for
|
||||
* that parameter.
|
||||
*
|
||||
* This is intended to recover from flow not currently recognised by ordinary capture flow.
|
||||
*/
|
||||
predicate localFlowSsaParamCaptureInput(Node nodeFrom, Node nodeTo) {
|
||||
exists(Ssa::CapturedEntryDefinition def |
|
||||
nodeFrom.asParameter().(NamedParameter).getVariable() = def.getSourceVariable()
|
||||
or
|
||||
nodeFrom.(SelfParameterNode).getSelfVariable() = def.getSourceVariable()
|
||||
|
|
||||
nodeTo.(SsaDefinitionNode).getDefinition() = def
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
|
||||
* involving SSA definition `def`.
|
||||
@@ -309,7 +325,7 @@ private module Cached {
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -338,7 +354,7 @@ private module Cached {
|
||||
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -349,7 +365,12 @@ private module Cached {
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
/** This is the local flow predicate that is used in type tracking. */
|
||||
/**
|
||||
* This is the local flow predicate that is used in type tracking.
|
||||
*
|
||||
* This needs to exclude `localFlowSsaParamInput` due to a performance trick
|
||||
* in type tracking, where such steps are treated as call steps.
|
||||
*/
|
||||
cached
|
||||
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
@@ -396,7 +417,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate isLocalSourceNode(Node n) {
|
||||
n instanceof ParameterNode
|
||||
n instanceof TParameterNode
|
||||
or
|
||||
// Expressions that can't be reached from another entry definition or expression
|
||||
n instanceof ExprNode and
|
||||
@@ -1272,7 +1293,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
|
||||
creation.asExpr() =
|
||||
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
|
||||
c.asCallable() = mc.getBlock().getExpr() and
|
||||
mc.getExpr().getMethodName() = "lambda"
|
||||
mc.getExpr().getMethodName() = ["lambda", "proc"]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,30 @@ class Node extends TNode {
|
||||
* Gets a data flow node to which data may flow from this node in one local step.
|
||||
*/
|
||||
Node getASuccessor() { localFlowStep(this, result) }
|
||||
|
||||
/** Gets the constant value of this expression, if any. */
|
||||
ConstantValue getConstantValue() { result = this.asExpr().getConstantValue() }
|
||||
|
||||
/**
|
||||
* Gets the callable corresponding to this block, lambda expression, or call to `proc` or `lambda`.
|
||||
*
|
||||
* For example, gets the callable in each of the following cases:
|
||||
* ```rb
|
||||
* { |x| x } # block expression
|
||||
* ->(x) { x } # lambda expression
|
||||
* proc { |x| x } # call to 'proc'
|
||||
* lambda { |x| x } # call to 'lambda'
|
||||
* ```
|
||||
*/
|
||||
pragma[noinline]
|
||||
CallableNode asCallable() {
|
||||
result = this
|
||||
or
|
||||
exists(DataFlowCallable c |
|
||||
lambdaCreation(this, _, c) and
|
||||
result.asCallableAstNode() = c.asCallable()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow node corresponding to a call in the control-flow graph. */
|
||||
@@ -124,6 +148,31 @@ class CallNode extends LocalSourceNode, ExprNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a setter method.
|
||||
*
|
||||
* For example,
|
||||
* ```rb
|
||||
* self.foo = 10
|
||||
* a[0] = 10
|
||||
* ```
|
||||
*/
|
||||
class SetterCallNode extends CallNode {
|
||||
SetterCallNode() { this.getExprNode().getExpr() instanceof SetterMethodCall }
|
||||
|
||||
/**
|
||||
* Gets the name of the method being called without the trailing `=`. For example, in the following
|
||||
* two statements the target name is `value`:
|
||||
* ```rb
|
||||
* foo.value=(1)
|
||||
* foo.value = 1
|
||||
* ```
|
||||
*/
|
||||
final string getTargetName() {
|
||||
result = this.getExprNode().getExpr().(SetterMethodCall).getTargetName()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*
|
||||
@@ -144,7 +193,7 @@ class ExprNode extends Node, TExprNode {
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParameterNode extends Node, TParameterNode instanceof ParameterNodeImpl {
|
||||
class ParameterNode extends LocalSourceNode, TParameterNode instanceof ParameterNodeImpl {
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
final Parameter getParameter() { result = super.getParameter() }
|
||||
|
||||
@@ -177,6 +226,80 @@ class LocalSourceNode extends Node {
|
||||
*/
|
||||
pragma[inline]
|
||||
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
|
||||
|
||||
/**
|
||||
* Gets a node to which data may flow from this node in zero or
|
||||
* more local data-flow steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
Node getALocalUse() { hasLocalSource(result, this) }
|
||||
|
||||
/** Gets a method call where this node flows to the receiver. */
|
||||
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
|
||||
|
||||
/** Gets a call to a method named `name`, where this node flows to the receiver. */
|
||||
CallNode getAMethodCall(string name) { Cached::hasMethodCall(this, result, name) }
|
||||
|
||||
/** Gets a call `obj.name` with no arguments, where this node flows to `obj`. */
|
||||
CallNode getAnAttributeRead(string name) {
|
||||
result = this.getAMethodCall(name) and
|
||||
result.getNumberOfArguments() = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value assigned to `name` on this object, such as the `x` in `obj.name = x`.
|
||||
*
|
||||
* Concretely, this gets the argument of any call to `name=` where this node flows to the receiver.
|
||||
*/
|
||||
Node getAnAttributeWriteValue(string name) {
|
||||
result = this.getAMethodCall(name + "=").getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an access to an element on this node, such as `obj[key]`.
|
||||
*
|
||||
* Concretely this gets a call to `[]` with 1 argument, where this node flows to the receiver.
|
||||
*/
|
||||
CallNode getAnElementRead() {
|
||||
result = this.getAMethodCall("[]") and result.getNumberOfArguments() = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an access to the element `key` on this node, such as `obj[:key]`.
|
||||
*
|
||||
* Concretely this gets a call to `[]` where this node flows to the receiver
|
||||
* and the first and only argument has the constant value `key`.
|
||||
*/
|
||||
CallNode getAnElementRead(ConstantValue key) {
|
||||
result = this.getAnElementRead() and
|
||||
key = result.getArgument(0).getConstantValue()
|
||||
}
|
||||
|
||||
private CallNode getAnElementWriteCall() {
|
||||
result = this.getAMethodCall("[]=") and
|
||||
result.getNumberOfArguments() = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value stored as an element on this node, such as the `x` in `obj[key] = x`.
|
||||
*
|
||||
* Concretely, this gets the second argument from any call to `[]=` where this node flows to the receiver.
|
||||
*/
|
||||
Node getAnElementWriteValue() { result = this.getAnElementWriteCall().getArgument(1) }
|
||||
|
||||
/**
|
||||
* Gets the `x` in `obj[key] = x`, where this node flows to `obj`.
|
||||
*
|
||||
* Concretely, this gets the second argument from any call to `[]=` where this node flows to the receiver
|
||||
* and the first argument has constant value `key`.
|
||||
*/
|
||||
Node getAnElementWriteValue(ConstantValue key) {
|
||||
exists(CallNode call |
|
||||
call = this.getAnElementWriteCall() and
|
||||
call.getArgument(0).getConstantValue() = key and
|
||||
result = call.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,18 +319,76 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
|
||||
}
|
||||
|
||||
cached
|
||||
private predicate hasLocalSource(Node sink, Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof LocalSourceNode
|
||||
or
|
||||
exists(Node mid |
|
||||
hasLocalSource(mid, source) and
|
||||
localFlowStepTypeTracker(mid, sink)
|
||||
)
|
||||
private module Cached {
|
||||
cached
|
||||
predicate hasLocalSource(Node sink, Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof LocalSourceNode
|
||||
or
|
||||
exists(Node mid | hasLocalSource(mid, source) |
|
||||
localFlowStepTypeTracker(mid, sink)
|
||||
or
|
||||
// Explicitly include the SSA param input step as type-tracking omits this step.
|
||||
LocalFlow::localFlowSsaParamInput(mid, sink)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamCaptureInput(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
|
||||
source.flowsTo(call.getReceiver()) and
|
||||
call.getMethodName() = name
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasYieldCall(BlockParameterNode block, CallNode yield) {
|
||||
exists(MethodBase method, YieldCall call |
|
||||
block.getMethod() = method and
|
||||
call.getEnclosingMethod() = method and
|
||||
yield.asExpr().getExpr() = call
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A place in which a named constant can be looked up during constant lookup.
|
||||
*/
|
||||
cached
|
||||
newtype TConstLookupScope =
|
||||
/** Look up in a qualified constant name `base::`. */
|
||||
MkQualifiedLookup(ConstantAccess base) or
|
||||
/** Look up in the ancestors of `mod`. */
|
||||
MkAncestorLookup(Module mod) or
|
||||
/** Look up in a module syntactically nested in a declaration of `mod`. */
|
||||
MkNestedLookup(Module mod) or
|
||||
/** Pseudo-scope for accesses that are known to resolve to `mod`. */
|
||||
MkExactLookup(Module mod)
|
||||
|
||||
/**
|
||||
* Gets a `LocalSourceNode` to represent the constant read or written by `access`.
|
||||
*/
|
||||
cached
|
||||
LocalSourceNode getConstantAccessNode(ConstantAccess access) {
|
||||
// Namespaces don't evaluate to the constant being accessed, they return the value of their last statement.
|
||||
// Use the definition of 'self' in the namespace as the representative in this case.
|
||||
result.(SsaDefinitionNode).getDefinition().(Ssa::SelfDefinition).getSourceVariable() =
|
||||
access.(Namespace).getModuleSelfVariable()
|
||||
or
|
||||
not access instanceof Namespace and
|
||||
result.asExpr().getExpr() = access
|
||||
}
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
predicate forceCachingBackref() { exists(any(ConstRef const).getConstant(_)) }
|
||||
}
|
||||
|
||||
private import Cached
|
||||
|
||||
/** Gets a node corresponding to expression `e`. */
|
||||
ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e }
|
||||
|
||||
@@ -562,3 +743,591 @@ abstract deprecated class BarrierGuard extends CfgNodes::ExprCfgNode {
|
||||
result.asExpr() = this.getAMaybeGuardedCapturedDef().getARead()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of a run-time module or class.
|
||||
*
|
||||
* This is equivalent to the type `Ast::Module` but provides data-flow specific methods.
|
||||
*/
|
||||
class ModuleNode instanceof Module {
|
||||
/** Gets a declaration of this module, if any. */
|
||||
final ModuleBase getADeclaration() { result = super.getADeclaration() }
|
||||
|
||||
/** Gets the super class of this module, if any. */
|
||||
final ModuleNode getSuperClass() { result = super.getSuperClass() }
|
||||
|
||||
/** Gets an immediate sub class of this module, if any. */
|
||||
final ModuleNode getASubClass() { result = super.getASubClass() }
|
||||
|
||||
/** Gets a `prepend`ed module. */
|
||||
final ModuleNode getAPrependedModule() { result = super.getAPrependedModule() }
|
||||
|
||||
/** Gets an `include`d module. */
|
||||
final ModuleNode getAnIncludedModule() { result = super.getAnIncludedModule() }
|
||||
|
||||
/** Gets the super class or an included or prepended module. */
|
||||
final ModuleNode getAnImmediateAncestor() { result = super.getAnImmediateAncestor() }
|
||||
|
||||
/** Gets a direct subclass or module including or prepending this one. */
|
||||
final ModuleNode getAnImmediateDescendent() { result = super.getAnImmediateDescendent() }
|
||||
|
||||
/** Gets a module that is transitively subclassed, included, or prepended by this module. */
|
||||
pragma[inline]
|
||||
final ModuleNode getAnAncestor() { result = super.getAnAncestor() }
|
||||
|
||||
/** Gets a module that transitively subclasses, includes, or prepends this module. */
|
||||
pragma[inline]
|
||||
final ModuleNode getADescendent() { result = super.getADescendent() }
|
||||
|
||||
/**
|
||||
* Gets the expression node denoting the super class or an included or prepended module.
|
||||
*
|
||||
* For example, `C` is an ancestor expression of `M` in each of the following examples:
|
||||
* ```rb
|
||||
* class M < C
|
||||
* end
|
||||
*
|
||||
* module M
|
||||
* include C
|
||||
* prepend C
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final ExprNode getAnAncestorExpr() {
|
||||
result.asExpr().getExpr() = super.getADeclaration().getAnAncestorExpr()
|
||||
}
|
||||
|
||||
/** Holds if this module is a class. */
|
||||
predicate isClass() { super.isClass() }
|
||||
|
||||
/** Gets a textual representation of this module. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets the qualified name of this module, if any.
|
||||
*
|
||||
* Only modules that can be resolved will have a qualified name.
|
||||
*/
|
||||
final string getQualifiedName() { result = super.getQualifiedName() }
|
||||
|
||||
/** Gets the location of this module. */
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
|
||||
/**
|
||||
* Gets `self` in a declaration of this module.
|
||||
*
|
||||
* This only gets `self` at the module level, not inside any (singleton) method.
|
||||
*/
|
||||
LocalSourceNode getModuleLevelSelf() {
|
||||
result.(SsaDefinitionNode).getVariable() = super.getADeclaration().getModuleSelfVariable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets `self` in the module declaration or in one of its singleton methods.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
LocalSourceNode getAnOwnModuleSelf() {
|
||||
result = this.getModuleLevelSelf()
|
||||
or
|
||||
result = this.getAnOwnSingletonMethod().getSelfParameter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a call to method `name` on `self` in the module-level scope of this module.
|
||||
*
|
||||
* For example,
|
||||
* ```rb
|
||||
* module M
|
||||
* include A # getAModuleLevelCall("include")
|
||||
* foo :bar # getAModuleLevelCall("foo")
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
CallNode getAModuleLevelCall(string name) {
|
||||
result = this.getModuleLevelSelf().getAMethodCall(name)
|
||||
}
|
||||
|
||||
/** Gets a constant or `self` variable that refers to this module. */
|
||||
LocalSourceNode getAnImmediateReference() {
|
||||
result.asExpr().getExpr() = super.getAnImmediateReference()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a singleton method declared in this module (or in a singleton class
|
||||
* augmenting this module).
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
MethodNode getAnOwnSingletonMethod() {
|
||||
result.asCallableAstNode() = super.getAnOwnSingletonMethod()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton method named `name` declared in this module (or in a singleton class
|
||||
* augmenting this module).
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
MethodNode getOwnSingletonMethod(string name) {
|
||||
result = this.getAnOwnSingletonMethod() and
|
||||
result.getMethodName() = name
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance method declared in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
MethodNode getAnOwnInstanceMethod() {
|
||||
result.asCallableAstNode() = this.getADeclaration().getAMethod().(Method)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance method named `name` declared in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
MethodNode getOwnInstanceMethod(string name) {
|
||||
result = this.getAnOwnInstanceMethod() and
|
||||
result.getMethodName() = name
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `self` parameter of an instance method declared in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
ParameterNode getAnOwnInstanceSelf() {
|
||||
result = TSelfParameterNode(this.getAnOwnInstanceMethod().asCallableAstNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `self` parameter of an instance method available in this module,
|
||||
* including those inherited from ancestors.
|
||||
*/
|
||||
ParameterNode getAnInstanceSelf() {
|
||||
// Make sure to include the 'self' in overridden instance methods
|
||||
result = this.getAnAncestor().getAnOwnInstanceSelf()
|
||||
}
|
||||
|
||||
private InstanceVariableAccess getAnOwnInstanceVariableAccess(string name) {
|
||||
exists(InstanceVariable v |
|
||||
v.getDeclaringScope() = this.getADeclaration() and
|
||||
v.getName() = name and
|
||||
result.getVariable() = v
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an access to the instance variable `name` in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
LocalSourceNode getAnOwnInstanceVariableRead(string name) {
|
||||
result.asExpr().getExpr() =
|
||||
this.getAnOwnInstanceVariableAccess(name).(InstanceVariableReadAccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the right-hand side of an assignment to the instance variable `name` in this module.
|
||||
*
|
||||
* Does not take inheritance into account.
|
||||
*/
|
||||
Node getAnOwnInstanceVariableWriteValue(string name) {
|
||||
exists(AssignExpr assignment |
|
||||
assignment.getLeftOperand() = this.getAnOwnInstanceVariableAccess(name) and
|
||||
result.asExpr().getExpr() = assignment.getRightOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance method named `name` available in this module, including methods inherited
|
||||
* from ancestors.
|
||||
*
|
||||
* Overridden methods are not included.
|
||||
*/
|
||||
MethodNode getInstanceMethod(string name) {
|
||||
result.asCallableAstNode() = super.getInstanceMethod(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance method available in this module, including methods inherited
|
||||
* from ancestors.
|
||||
*
|
||||
* Overridden methods are not included.
|
||||
*/
|
||||
MethodNode getAnInstanceMethod() { result = this.getInstanceMethod(_) }
|
||||
|
||||
/**
|
||||
* Gets the enclosing module, as it appears in the qualified name of this module.
|
||||
*
|
||||
* For example, the parent module of `A::B` is `A`, and `A` itself has no parent module.
|
||||
*/
|
||||
ModuleNode getParentModule() { result = super.getParentModule() }
|
||||
|
||||
/**
|
||||
* Gets a module named `name` declared inside this one (not aliased), provided
|
||||
* that such a module is defined or reopened in the current codebase.
|
||||
*
|
||||
* For example, for `A::B` the nested module named `C` would be `A::B::C`.
|
||||
*
|
||||
* Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
|
||||
* module whose qualified name is not `A::B::C`, then it will not be found by
|
||||
* this predicate.
|
||||
*/
|
||||
ModuleNode getNestedModule(string name) { result = super.getNestedModule(name) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of a run-time class.
|
||||
*/
|
||||
class ClassNode extends ModuleNode {
|
||||
ClassNode() { this.isClass() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node corresponding to a method, block, or lambda expression.
|
||||
*/
|
||||
class CallableNode extends ExprNode {
|
||||
private Callable callable;
|
||||
|
||||
CallableNode() { this.asExpr().getExpr() = callable }
|
||||
|
||||
/** Gets the underlying AST node as a `Callable`. */
|
||||
Callable asCallableAstNode() { result = callable }
|
||||
|
||||
private ParameterPosition getParameterPosition(ParameterNodeImpl node) {
|
||||
node.isSourceParameterOf(callable, result)
|
||||
}
|
||||
|
||||
/** Gets the `n`th positional parameter. */
|
||||
ParameterNode getParameter(int n) { this.getParameterPosition(result).isPositional(n) }
|
||||
|
||||
/** Gets the keyword parameter of the given name. */
|
||||
ParameterNode getKeywordParameter(string name) {
|
||||
this.getParameterPosition(result).isKeyword(name)
|
||||
}
|
||||
|
||||
/** Gets the `self` parameter of this callable, if any. */
|
||||
ParameterNode getSelfParameter() { this.getParameterPosition(result).isSelf() }
|
||||
|
||||
/**
|
||||
* Gets the `hash-splat` parameter. This is a synthetic parameter holding
|
||||
* a hash object with entries for each keyword argument passed to the function.
|
||||
*/
|
||||
ParameterNode getHashSplatParameter() { this.getParameterPosition(result).isHashSplat() }
|
||||
|
||||
/**
|
||||
* Gets the block parameter of this method, if any.
|
||||
*/
|
||||
ParameterNode getBlockParameter() { this.getParameterPosition(result).isBlock() }
|
||||
|
||||
/**
|
||||
* Gets a `yield` in this method or `.call` on the block parameter.
|
||||
*/
|
||||
CallNode getABlockCall() {
|
||||
hasYieldCall(this.getBlockParameter(), result)
|
||||
or
|
||||
result = this.getBlockParameter().getAMethodCall("call")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the canonical return node from this callable.
|
||||
*
|
||||
* Each callable has exactly one such node, and its location may not correspond
|
||||
* to any particular return site - consider using `getAReturningNode` to get nodes
|
||||
* whose locations correspond to return sites.
|
||||
*/
|
||||
Node getReturn() { result.(SynthReturnNode).getCfgScope() = callable }
|
||||
|
||||
/**
|
||||
* Gets a data flow node whose value is about to be returned by this callable.
|
||||
*/
|
||||
Node getAReturningNode() { result = this.getReturn().(SynthReturnNode).getAnInput() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node corresponding to a method (possibly a singleton method).
|
||||
*/
|
||||
class MethodNode extends CallableNode {
|
||||
MethodNode() { super.asCallableAstNode() instanceof MethodBase }
|
||||
|
||||
/** Gets the underlying AST node for this method. */
|
||||
override MethodBase asCallableAstNode() { result = super.asCallableAstNode() }
|
||||
|
||||
/** Gets the name of this method. */
|
||||
string getMethodName() { result = this.asCallableAstNode().getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node corresponding to a block argument.
|
||||
*/
|
||||
class BlockNode extends CallableNode {
|
||||
BlockNode() { super.asCallableAstNode() instanceof Block }
|
||||
|
||||
/** Gets the underlying AST node for this block. */
|
||||
override Block asCallableAstNode() { result = super.asCallableAstNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of a pair such as `K => V` or `K: V`.
|
||||
*
|
||||
* Unlike most expressions, pairs do not evaluate to actual objects at runtime and their nodes
|
||||
* cannot generally be expected to have meaningful data flow edges.
|
||||
* This node simply provides convenient access to the key and value as data flow nodes.
|
||||
*/
|
||||
class PairNode extends ExprNode {
|
||||
PairNode() { this.getExprNode() instanceof CfgNodes::ExprNodes::PairCfgNode }
|
||||
|
||||
/**
|
||||
* Holds if this pair is of form `key => value` or `key: value`.
|
||||
*/
|
||||
predicate hasKeyAndValue(Node key, Node value) {
|
||||
exists(CfgNodes::ExprNodes::PairCfgNode n |
|
||||
this.getExprNode() = n and
|
||||
key = TExprNode(n.getKey()) and
|
||||
value = TExprNode(n.getValue())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the key expression of this pair, such as the `K` in `K => V` or `K: V`. */
|
||||
Node getKey() { this.hasKeyAndValue(result, _) }
|
||||
|
||||
/** Gets the value expression of this pair, such as the `V` in `K => V` or `K: V`. */
|
||||
Node getValue() { this.hasKeyAndValue(_, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that corresponds to a hash literal. Hash literals are desugared
|
||||
* into calls to `Hash.[]`, so this includes both desugared calls as well as
|
||||
* explicit calls.
|
||||
*/
|
||||
class HashLiteralNode extends LocalSourceNode, ExprNode {
|
||||
HashLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode }
|
||||
|
||||
/** Gets a pair in this hash literal. */
|
||||
PairNode getAKeyValuePair() {
|
||||
result.getExprNode() =
|
||||
super.getExprNode().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair()
|
||||
}
|
||||
|
||||
/** Gets the value associated with the constant `key`, if known. */
|
||||
Node getElementFromKey(ConstantValue key) {
|
||||
exists(ExprNode keyNode |
|
||||
this.getAKeyValuePair().hasKeyAndValue(keyNode, result) and
|
||||
keyNode.getConstantValue() = key
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node corresponding to an array literal. Array literals are desugared
|
||||
* into calls to `Array.[]`, so this includes both desugared calls as well as
|
||||
* explicit calls.
|
||||
*/
|
||||
class ArrayLiteralNode extends LocalSourceNode, ExprNode {
|
||||
ArrayLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode }
|
||||
|
||||
/**
|
||||
* Gets an element of the array.
|
||||
*/
|
||||
Node getAnElement() { result = this.(CallNode).getPositionalArgument(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to a constant, such as `C`, `C::D`, or a class or module declaration.
|
||||
*
|
||||
* See `DataFlow::getConstant` for usage example.
|
||||
*/
|
||||
class ConstRef extends LocalSourceNode {
|
||||
private ConstantAccess access;
|
||||
|
||||
ConstRef() { this = getConstantAccessNode(access) }
|
||||
|
||||
/** Gets the underlying constant access AST node. */
|
||||
ConstantAccess asConstantAccess() { result = access }
|
||||
|
||||
/** Gets the underlying module declaration, if any. */
|
||||
Namespace asNamespaceDeclaration() { result = access }
|
||||
|
||||
/** Gets the module defined or re-opened by this constant access, if any. */
|
||||
ModuleNode asModule() { result.getADeclaration() = access }
|
||||
|
||||
/**
|
||||
* Gets the simple name of the constant being referenced, such as
|
||||
* the `B` in `A::B`.
|
||||
*/
|
||||
string getName() { result = access.getName() }
|
||||
|
||||
/**
|
||||
* Holds if this might refer to a top-level constant.
|
||||
*/
|
||||
predicate isPossiblyGlobal() {
|
||||
exists(Module mod |
|
||||
not exists(mod.getParentModule()) and
|
||||
mod.getAnImmediateReference() = access
|
||||
)
|
||||
or
|
||||
not exists(Module mod | mod.getAnImmediateReference() = access) and
|
||||
not exists(access.getScopeExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a module for which this constant is the reference to an ancestor module.
|
||||
*
|
||||
* For example, `M` is the ancestry target of `C` in the following examples:
|
||||
* ```rb
|
||||
* class M < C {}
|
||||
*
|
||||
* module M
|
||||
* include C
|
||||
* end
|
||||
*
|
||||
* module M
|
||||
* prepend C
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
private ModuleNode getAncestryTarget() { result.getAnAncestorExpr() = this }
|
||||
|
||||
/**
|
||||
* Gets the known target module.
|
||||
*
|
||||
* We resolve these differently to prune out infeasible constant lookups.
|
||||
*/
|
||||
private Module getExactTarget() { result.getAnImmediateReference() = access }
|
||||
|
||||
/**
|
||||
* Gets a scope in which a constant lookup may access the contents of the module referenced by this constant.
|
||||
*/
|
||||
cached
|
||||
private TConstLookupScope getATargetScope() {
|
||||
forceCachingInSameStage() and
|
||||
result = MkAncestorLookup(this.getAncestryTarget().getAnImmediateDescendent*())
|
||||
or
|
||||
access = any(ConstantAccess ac).getScopeExpr() and
|
||||
result = MkQualifiedLookup(access)
|
||||
or
|
||||
result = MkNestedLookup(this.getAncestryTarget())
|
||||
or
|
||||
result = MkExactLookup(access.(Namespace).getModule())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scope expression, or the immediately enclosing `Namespace` (skipping over singleton classes).
|
||||
*
|
||||
* Top-levels are not included, since this is only needed for nested constant lookup, and unqualified constants
|
||||
* at the top-level are handled by `DataFlow::getConstant`, never `ConstRef.getConstant`.
|
||||
*/
|
||||
private TConstLookupScope getLookupScope() {
|
||||
result = MkQualifiedLookup(access.getScopeExpr())
|
||||
or
|
||||
not exists(this.getExactTarget()) and
|
||||
not exists(access.getScopeExpr()) and
|
||||
not access.hasGlobalScope() and
|
||||
(
|
||||
result = MkAncestorLookup(access.getEnclosingModule().getNamespaceOrToplevel().getModule())
|
||||
or
|
||||
result = MkNestedLookup(access.getEnclosingModule().getEnclosingModule*().getModule())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this can reference a constant named `name` from `scope`.
|
||||
*/
|
||||
cached
|
||||
private predicate accesses(TConstLookupScope scope, string name) {
|
||||
forceCachingInSameStage() and
|
||||
scope = this.getLookupScope() and
|
||||
name = this.getName()
|
||||
or
|
||||
exists(Module mod |
|
||||
this.getExactTarget() = mod.getNestedModule(name) and
|
||||
scope = MkExactLookup(mod)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a constant reference that may resolve to a member of this node.
|
||||
*
|
||||
* For example `DataFlow::getConstant("A").getConstant("B")` finds the following:
|
||||
* ```rb
|
||||
* A::B # simple reference
|
||||
*
|
||||
* module A
|
||||
* B # in scope
|
||||
* module X
|
||||
* B # in nested scope
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* module X
|
||||
* include A
|
||||
* B # via inclusion
|
||||
* end
|
||||
*
|
||||
* class X < A
|
||||
* B # via subclassing
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
pragma[inline]
|
||||
ConstRef getConstant(string name) {
|
||||
exists(TConstLookupScope scope |
|
||||
pragma[only_bind_into](scope) = pragma[only_bind_out](this).getATargetScope() and
|
||||
result.accesses(pragma[only_bind_out](scope), name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a module that transitively subclasses, includes, or prepends the module referred to by
|
||||
* this constant.
|
||||
*
|
||||
* For example, `DataFlow::getConstant("A").getADescendentModule()` finds `B`, `C`, and `E`:
|
||||
* ```rb
|
||||
* class B < A
|
||||
* end
|
||||
*
|
||||
* class C < B
|
||||
* end
|
||||
*
|
||||
* module E
|
||||
* include C
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
ModuleNode getADescendentModule() { MkAncestorLookup(result) = this.getATargetScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a constant reference that may resolve to the top-level constant `name`.
|
||||
*
|
||||
* To get nested constants, call `getConstant()` one or more times on the result.
|
||||
*
|
||||
* For example `DataFlow::getConstant("A").getConstant("B")` finds the following:
|
||||
* ```rb
|
||||
* A::B # simple reference
|
||||
*
|
||||
* module A
|
||||
* B # in scope
|
||||
* module X
|
||||
* B # in nested scope
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* module X
|
||||
* include A
|
||||
* B # via inclusion
|
||||
* end
|
||||
*
|
||||
* class X < A
|
||||
* B # via subclassing
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
pragma[nomagic]
|
||||
ConstRef getConstant(string name) {
|
||||
result.getName() = name and
|
||||
result.isPossiblyGlobal()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG as Cfg
|
||||
private import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared as ControlFlowGraphImplShared
|
||||
private import codeql.ruby.ast.Variable
|
||||
private import Cfg::CfgNodes::ExprNodes
|
||||
|
||||
@@ -53,6 +54,9 @@ private module SsaInput implements SsaImplCommon::InputSig {
|
||||
or
|
||||
capturedExitRead(bb, i, v) and
|
||||
certain = false
|
||||
or
|
||||
namespaceSelfExitRead(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +98,21 @@ private predicate capturedExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, Local
|
||||
i = bb.length()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a pseudo read of namespace self-variable `v` should be inserted
|
||||
* at index `i` in basic block `bb`. We do this to ensure that namespace
|
||||
* self-variables always get an SSA definition.
|
||||
*/
|
||||
private predicate namespaceSelfExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, SelfVariable v) {
|
||||
exists(Namespace ns, AstNode last |
|
||||
v.getDeclaringScope() = ns and
|
||||
last = ControlFlowGraphImplShared::getAControlFlowExitNode(ns) and
|
||||
if last = ns
|
||||
then bb.getNode(i).getAPredecessor().getNode() = last
|
||||
else bb.getNode(i).getNode() = last
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if captured variable `v` is read directly inside `scope`,
|
||||
* or inside a (transitively) nested scope of `scope`.
|
||||
|
||||
@@ -105,6 +105,8 @@ private module Cached {
|
||||
exists(DataFlow::ContentSet c | readStep(nodeFrom, c, nodeTo) |
|
||||
c.isSingleton(any(DataFlow::Content::ElementContent ec))
|
||||
or
|
||||
c.isKnownOrUnknownElement(_)
|
||||
or
|
||||
c.isAnyElement()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ deprecated class ParamsCall = Rails::ParamsCall;
|
||||
deprecated class CookiesCall = Rails::CookiesCall;
|
||||
|
||||
/**
|
||||
* A `ClassDeclaration` for a class that extends `ActionController::Base`.
|
||||
* A class that extends `ActionController::Base`.
|
||||
* For example,
|
||||
*
|
||||
* ```rb
|
||||
@@ -36,26 +36,61 @@ deprecated class CookiesCall = Rails::CookiesCall;
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class ActionControllerControllerClass extends ClassDeclaration {
|
||||
ActionControllerControllerClass() {
|
||||
this.getSuperclassExpr() =
|
||||
class ActionControllerClass extends DataFlow::ClassNode {
|
||||
ActionControllerClass() {
|
||||
this =
|
||||
[
|
||||
API::getTopLevelMember("ActionController").getMember("Base"),
|
||||
DataFlow::getConstant("ActionController").getConstant("Base"),
|
||||
// In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
|
||||
// treat it separately in case the `ApplicationController` definition is not in the database.
|
||||
API::getTopLevelMember("ApplicationController"),
|
||||
DataFlow::getConstant("ApplicationController"),
|
||||
// ActionController::Metal technically doesn't contain all of the
|
||||
// methods available in Base, such as those for rendering views.
|
||||
// However we prefer to be over-sensitive in this case in order to find
|
||||
// more results.
|
||||
API::getTopLevelMember("ActionController").getMember("Metal")
|
||||
].getASubclass().getAValueReachableFromSource().asExpr().getExpr()
|
||||
DataFlow::getConstant("ActionController").getConstant("Metal")
|
||||
].getADescendentModule()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `ActionControllerActionMethod` defined in this class.
|
||||
*/
|
||||
ActionControllerActionMethod getAnAction() {
|
||||
result = this.getAnInstanceMethod().asCallableAstNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `self` that possibly refers to an instance of this class.
|
||||
*/
|
||||
DataFlow::LocalSourceNode getSelf() {
|
||||
result = this.getAnInstanceSelf()
|
||||
or
|
||||
// Include the module-level `self` to recover some cases where a block at the module level
|
||||
// is invoked with an instance as the `self`, which we currently can't model directly.
|
||||
// Concretely this happens in the block passed to `rescue_from`.
|
||||
// TODO: revisit when we have better infrastructure for handling self in a block
|
||||
result = this.getModuleLevelSelf()
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlow::LocalSourceNode actionControllerInstance() {
|
||||
result = any(ActionControllerClass cls).getSelf()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `ActionControllerClass` instead.
|
||||
*
|
||||
* A `ClassDeclaration` corresponding to an `ActionControllerClass`.
|
||||
*/
|
||||
deprecated class ActionControllerControllerClass extends ClassDeclaration {
|
||||
ActionControllerControllerClass() { this = any(ActionControllerClass cls).getADeclaration() }
|
||||
|
||||
/**
|
||||
* Gets a `ActionControllerActionMethod` defined in this class.
|
||||
*/
|
||||
ActionControllerActionMethod getAnAction() { result = this.getAMethod() }
|
||||
ActionControllerActionMethod getAnAction() {
|
||||
result = this.getAMethod().(Method) and result.isPrivate()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,9 +98,11 @@ class ActionControllerControllerClass extends ClassDeclaration {
|
||||
* This may be the target of a route handler, if such a route is defined.
|
||||
*/
|
||||
class ActionControllerActionMethod extends Method, Http::Server::RequestHandler::Range {
|
||||
private ActionControllerControllerClass controllerClass;
|
||||
private ActionControllerClass controllerClass;
|
||||
|
||||
ActionControllerActionMethod() { this = controllerClass.getAMethod() and not this.isPrivate() }
|
||||
ActionControllerActionMethod() {
|
||||
this = controllerClass.getAnInstanceMethod().asCallableAstNode() and not this.isPrivate()
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a mapping between a method within the file
|
||||
@@ -91,7 +128,7 @@ class ActionControllerActionMethod extends Method, Http::Server::RequestHandler:
|
||||
/**
|
||||
* Gets the controller class containing this method.
|
||||
*/
|
||||
ActionControllerControllerClass getControllerClass() {
|
||||
ActionControllerClass getControllerClass() {
|
||||
// TODO: model the implicit render call when a path through the method does
|
||||
// not end at an explicit render or redirect
|
||||
result = controllerClass
|
||||
@@ -102,37 +139,23 @@ class ActionControllerActionMethod extends Method, Http::Server::RequestHandler:
|
||||
* May return multiple results.
|
||||
*/
|
||||
ActionDispatch::Routing::Route getARoute() {
|
||||
exists(string name |
|
||||
exists(string name, DataFlow::MethodNode m |
|
||||
isRoute(result, name, controllerClass) and
|
||||
isActionControllerMethod(this, name, controllerClass)
|
||||
m = controllerClass.getInstanceMethod(name) and
|
||||
this = m.asCallableAstNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isRoute(
|
||||
ActionDispatch::Routing::Route route, string name, ActionControllerControllerClass controllerClass
|
||||
ActionDispatch::Routing::Route route, string name, ActionControllerClass controllerClass
|
||||
) {
|
||||
route.getController() + "_controller" =
|
||||
ActionDispatch::Routing::underscore(controllerClass.getAQualifiedName()) and
|
||||
ActionDispatch::Routing::underscore(controllerClass.getQualifiedName()) and
|
||||
name = route.getAction()
|
||||
}
|
||||
|
||||
// A method call with a `self` receiver from within a controller class
|
||||
private class ActionControllerContextCall extends MethodCall {
|
||||
private ActionControllerControllerClass controllerClass;
|
||||
|
||||
ActionControllerContextCall() {
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getEnclosingModule() = controllerClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller class containing this method.
|
||||
*/
|
||||
ActionControllerControllerClass getControllerClass() { result = controllerClass }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `RemoteFlowSource::Range` to represent accessing the
|
||||
* ActionController parameters available via the `params` method.
|
||||
@@ -158,13 +181,17 @@ class CookiesSource extends Http::Server::RequestInputAccess::Range {
|
||||
}
|
||||
|
||||
/** A call to `cookies` from within a controller. */
|
||||
private class ActionControllerCookiesCall extends ActionControllerContextCall, CookiesCallImpl {
|
||||
ActionControllerCookiesCall() { this.getMethodName() = "cookies" }
|
||||
private class ActionControllerCookiesCall extends CookiesCallImpl {
|
||||
ActionControllerCookiesCall() {
|
||||
this = actionControllerInstance().getAMethodCall("cookies").asExpr().getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `params` from within a controller. */
|
||||
private class ActionControllerParamsCall extends ActionControllerContextCall, ParamsCallImpl {
|
||||
ActionControllerParamsCall() { this.getMethodName() = "params" }
|
||||
private class ActionControllerParamsCall extends ParamsCallImpl {
|
||||
ActionControllerParamsCall() {
|
||||
this = actionControllerInstance().getAMethodCall("params").asExpr().getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/** Modeling for `ActionDispatch::Request`. */
|
||||
@@ -174,10 +201,7 @@ private module Request {
|
||||
* `ActionDispatch::Request`.
|
||||
*/
|
||||
private class RequestNode extends DataFlow::CallNode {
|
||||
RequestNode() {
|
||||
this.asExpr().getExpr() instanceof ActionControllerContextCall and
|
||||
this.getMethodName() = "request"
|
||||
}
|
||||
RequestNode() { this = actionControllerInstance().getAMethodCall("request") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,7 +258,7 @@ private module Request {
|
||||
// Request headers are prefixed with `HTTP_` to distinguish them from
|
||||
// "headers" supplied by Rack middleware.
|
||||
this.getMethodName() = ["get_header", "fetch_header"] and
|
||||
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
@@ -290,9 +314,8 @@ private module Request {
|
||||
*/
|
||||
private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range {
|
||||
EnvHttpAccess() {
|
||||
any(EnvCall c).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) and
|
||||
this.getMethodName() = "[]" and
|
||||
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
this = any(EnvCall c).getAMethodCall("[]") and
|
||||
this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+")
|
||||
}
|
||||
|
||||
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
|
||||
@@ -302,21 +325,32 @@ private module Request {
|
||||
}
|
||||
|
||||
/** A call to `render` from within a controller. */
|
||||
private class ActionControllerRenderCall extends ActionControllerContextCall, RenderCallImpl {
|
||||
ActionControllerRenderCall() { this.getMethodName() = "render" }
|
||||
private class ActionControllerRenderCall extends RenderCallImpl {
|
||||
ActionControllerRenderCall() {
|
||||
this = actionControllerInstance().getAMethodCall("render").asExpr().getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `render_to` from within a controller. */
|
||||
private class ActionControllerRenderToCall extends ActionControllerContextCall, RenderToCallImpl {
|
||||
ActionControllerRenderToCall() { this.getMethodName() = ["render_to_body", "render_to_string"] }
|
||||
private class ActionControllerRenderToCall extends RenderToCallImpl {
|
||||
ActionControllerRenderToCall() {
|
||||
this =
|
||||
actionControllerInstance()
|
||||
.getAMethodCall(["render_to_body", "render_to_string"])
|
||||
.asExpr()
|
||||
.getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `html_escape` from within a controller. */
|
||||
private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl {
|
||||
ActionControllerHtmlEscapeCall() {
|
||||
// "h" is aliased to "html_escape" in ActiveSupport
|
||||
this.getMethodName() = ["html_escape", "html_escape_once", "h", "sanitize"] and
|
||||
this.getEnclosingModule() instanceof ActionControllerControllerClass
|
||||
this =
|
||||
actionControllerInstance()
|
||||
.getAMethodCall(["html_escape", "html_escape_once", "h", "sanitize"])
|
||||
.asExpr()
|
||||
.getExpr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,9 +358,16 @@ private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl {
|
||||
* A call to the `redirect_to` method, used in an action to redirect to a
|
||||
* specific URL/path or to a different action in this controller.
|
||||
*/
|
||||
class RedirectToCall extends ActionControllerContextCall {
|
||||
class RedirectToCall extends MethodCall {
|
||||
private ActionControllerClass controller;
|
||||
|
||||
RedirectToCall() {
|
||||
this.getMethodName() = ["redirect_to", "redirect_back", "redirect_back_or_to"]
|
||||
this =
|
||||
controller
|
||||
.getSelf()
|
||||
.getAMethodCall(["redirect_to", "redirect_back", "redirect_back_or_to"])
|
||||
.asExpr()
|
||||
.getExpr()
|
||||
}
|
||||
|
||||
/** Gets the `Expr` representing the URL to redirect to, if any */
|
||||
@@ -338,8 +379,10 @@ class RedirectToCall extends ActionControllerContextCall {
|
||||
|
||||
/** Gets the `ActionControllerActionMethod` to redirect to, if any */
|
||||
ActionControllerActionMethod getRedirectActionMethod() {
|
||||
this.getKeywordArgument("action").getConstantValue().isStringlikeValue(result.getName()) and
|
||||
result.getEnclosingModule() = this.getControllerClass()
|
||||
exists(string name |
|
||||
this.getKeywordArgument("action").getConstantValue().isStringlikeValue(name) and
|
||||
result = controller.getInstanceMethod(name).asCallableAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,18 +416,8 @@ class ActionControllerRedirectResponse extends Http::Server::HttpRedirectRespons
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isActionControllerMethod(Method m, string name, ActionControllerControllerClass c) {
|
||||
m.getName() = name and
|
||||
m.getEnclosingModule() = c
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate actionControllerHasHelperMethodCall(ActionControllerControllerClass c, string name) {
|
||||
exists(MethodCall mc |
|
||||
mc.getMethodName() = "helper_method" and
|
||||
mc.getAnArgument().getConstantValue().isStringlikeValue(name) and
|
||||
mc.getEnclosingModule() = c
|
||||
)
|
||||
private predicate actionControllerHasHelperMethodCall(ActionControllerClass c, string name) {
|
||||
c.getAModuleLevelCall("helper_method").getArgument(_).getConstantValue().isStringlikeValue(name)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,27 +437,28 @@ private predicate actionControllerHasHelperMethodCall(ActionControllerController
|
||||
* See also https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method
|
||||
*/
|
||||
class ActionControllerHelperMethod extends Method {
|
||||
private ActionControllerControllerClass controllerClass;
|
||||
private ActionControllerClass controllerClass;
|
||||
|
||||
ActionControllerHelperMethod() {
|
||||
exists(string name |
|
||||
isActionControllerMethod(this, name, controllerClass) and
|
||||
actionControllerHasHelperMethodCall(controllerClass, name)
|
||||
exists(DataFlow::MethodNode m, string name |
|
||||
m = controllerClass.getInstanceMethod(name) and
|
||||
actionControllerHasHelperMethodCall(controllerClass, name) and
|
||||
this = m.asCallableAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the class containing this helper method. */
|
||||
ActionControllerControllerClass getControllerClass() { result = controllerClass }
|
||||
ActionControllerClass getControllerClass() { result = controllerClass }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `ActionControllerControllerClass` associated with the given `ErbFile`
|
||||
* Gets an `ActionControllerClass` associated with the given `ErbFile`
|
||||
* according to Rails path conventions.
|
||||
* For instance, a template file at `app/views/foo/bar/baz.html.erb` will be
|
||||
* mapped to a controller class in `app/controllers/foo/bar/baz_controller.rb`,
|
||||
* if such a controller class exists.
|
||||
*/
|
||||
ActionControllerControllerClass getAssociatedControllerClass(ErbFile f) {
|
||||
ActionControllerClass getAssociatedControllerClass(ErbFile f) {
|
||||
// There is a direct mapping from template file to controller class
|
||||
controllerTemplateFile(result, f)
|
||||
or
|
||||
@@ -442,13 +476,13 @@ ActionControllerControllerClass getAssociatedControllerClass(ErbFile f) {
|
||||
// TODO: improve layout support, e.g. for `layout` method
|
||||
// https://guides.rubyonrails.org/layouts_and_rendering.html
|
||||
/**
|
||||
* Holds if `templatesFile` is a viable file "belonging" to the given
|
||||
* Holds if `templateFile` is a viable file "belonging" to the given
|
||||
* `ActionControllerControllerClass`, according to Rails conventions.
|
||||
*
|
||||
* This handles mappings between controllers in `app/controllers/`, and
|
||||
* templates in `app/views/` and `app/views/layouts/`.
|
||||
*/
|
||||
predicate controllerTemplateFile(ActionControllerControllerClass cls, ErbFile templateFile) {
|
||||
predicate controllerTemplateFile(ActionControllerClass cls, ErbFile templateFile) {
|
||||
exists(string templatesPath, string sourcePrefix, string subPath, string controllerPath |
|
||||
controllerPath = cls.getLocation().getFile().getRelativePath() and
|
||||
templatesPath = templateFile.getParentContainer().getRelativePath() and
|
||||
@@ -484,16 +518,14 @@ class ActionControllerSkipForgeryProtectionCall extends CsrfProtectionSetting::R
|
||||
/**
|
||||
* A call to `protect_from_forgery`.
|
||||
*/
|
||||
private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetting::Range {
|
||||
private ActionControllerContextCall callExpr;
|
||||
|
||||
private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetting::Range,
|
||||
DataFlow::CallNode {
|
||||
ActionControllerProtectFromForgeryCall() {
|
||||
callExpr = this.asExpr().getExpr() and
|
||||
callExpr.getMethodName() = "protect_from_forgery"
|
||||
this = actionControllerInstance().getAMethodCall("protect_from_forgery")
|
||||
}
|
||||
|
||||
private string getWithValueText() {
|
||||
result = callExpr.getKeywordArgument("with").getConstantValue().getSymbol()
|
||||
result = this.getKeywordArgument("with").getConstantValue().getSymbol()
|
||||
}
|
||||
|
||||
// Calls without `with: :exception` can allow for bypassing CSRF protection
|
||||
@@ -508,11 +540,7 @@ private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetti
|
||||
*/
|
||||
private class SendFile extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
SendFile() {
|
||||
this.getMethodName() = "send_file" and
|
||||
(
|
||||
this.asExpr().getExpr() instanceof ActionControllerContextCall or
|
||||
this.getReceiver().asExpr().getExpr() instanceof Response::ResponseCall
|
||||
)
|
||||
this = [actionControllerInstance(), Response::response()].getAMethodCall("send_file")
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
@@ -522,21 +550,13 @@ private module ParamsSummaries {
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
|
||||
/**
|
||||
* An instance of `ActionController::Parameters`, including those returned
|
||||
* Gets an instance of `ActionController::Parameters`, including those returned
|
||||
* from method calls on other instances.
|
||||
*/
|
||||
private class ParamsInstance extends DataFlow::Node {
|
||||
ParamsInstance() {
|
||||
this.asExpr().getExpr() instanceof Rails::ParamsCall
|
||||
or
|
||||
this =
|
||||
any(DataFlow::CallNode call |
|
||||
call.getReceiver() instanceof ParamsInstance and
|
||||
call.getMethodName() = paramsMethodReturningParamsInstance()
|
||||
)
|
||||
or
|
||||
exists(ParamsInstance prev | prev.(DataFlow::LocalSourceNode).flowsTo(this))
|
||||
}
|
||||
private DataFlow::LocalSourceNode paramsInstance() {
|
||||
result.asExpr().getExpr() instanceof Rails::ParamsCall
|
||||
or
|
||||
result = paramsInstance().getAMethodCall(paramsMethodReturningParamsInstance())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -578,8 +598,7 @@ private module ParamsSummaries {
|
||||
MethodsReturningParamsInstanceSummary() { this = "ActionController::Parameters#<various>" }
|
||||
|
||||
override MethodCall getACall() {
|
||||
any(ParamsInstance i).asExpr().getExpr() = result.getReceiver() and
|
||||
result.getMethodName() = methodReturnsTaintFromSelf()
|
||||
result = paramsInstance().getAMethodCall(methodReturnsTaintFromSelf()).asExpr().getExpr()
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -601,9 +620,8 @@ private module ParamsSummaries {
|
||||
|
||||
override MethodCall getACall() {
|
||||
result.getMethodName() = ["merge", "reverse_merge", "with_defaults"] and
|
||||
exists(ParamsInstance i |
|
||||
i.asExpr().getExpr() = [result.getReceiver(), result.getArgument(0)]
|
||||
)
|
||||
paramsInstance().getALocalUse().asExpr().getExpr() =
|
||||
[result.getReceiver(), result.getArgument(0)]
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -626,9 +644,8 @@ private module ParamsSummaries {
|
||||
|
||||
override MethodCall getACall() {
|
||||
result.getMethodName() = ["merge!", "reverse_merge!", "with_defaults!", "reverse_update"] and
|
||||
exists(ParamsInstance i |
|
||||
i.asExpr().getExpr() = [result.getReceiver(), result.getArgument(0)]
|
||||
)
|
||||
paramsInstance().getALocalUse().asExpr().getExpr() =
|
||||
[result.getReceiver(), result.getArgument(0)]
|
||||
}
|
||||
|
||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||
@@ -644,15 +661,12 @@ private module ParamsSummaries {
|
||||
* response.
|
||||
*/
|
||||
private module Response {
|
||||
class ResponseCall extends ActionControllerContextCall {
|
||||
ResponseCall() { this.getMethodName() = "response" }
|
||||
DataFlow::LocalSourceNode response() {
|
||||
result = actionControllerInstance().getAMethodCall("response")
|
||||
}
|
||||
|
||||
class BodyWrite extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
|
||||
BodyWrite() {
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = "body="
|
||||
}
|
||||
BodyWrite() { this = response().getAMethodCall("body=") }
|
||||
|
||||
override DataFlow::Node getBody() { result = this.getArgument(0) }
|
||||
|
||||
@@ -662,10 +676,7 @@ private module Response {
|
||||
}
|
||||
|
||||
class SendFileCall extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
|
||||
SendFileCall() {
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = "send_file"
|
||||
}
|
||||
SendFileCall() { this = response().getAMethodCall("send_file") }
|
||||
|
||||
override DataFlow::Node getBody() { result = this.getArgument(0) }
|
||||
|
||||
@@ -678,19 +689,12 @@ private module Response {
|
||||
HeaderWrite() {
|
||||
// response.header[key] = val
|
||||
// response.headers[key] = val
|
||||
exists(MethodCall headerCall |
|
||||
headerCall.getMethodName() = ["header", "headers"] and
|
||||
headerCall.getReceiver() instanceof ResponseCall
|
||||
|
|
||||
this.getReceiver().asExpr().getExpr() = headerCall and
|
||||
this.getMethodName() = "[]="
|
||||
)
|
||||
this = response().getAMethodCall(["header", "headers"]).getAMethodCall("[]=")
|
||||
or
|
||||
// response.set_header(key) = val
|
||||
// response[header] = val
|
||||
// response.add_header(key, val)
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() = ["set_header", "[]=", "add_header"]
|
||||
this = response().getAMethodCall(["set_header", "[]=", "add_header"])
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
@@ -703,12 +707,12 @@ private module Response {
|
||||
class SpecificHeaderWrite extends DataFlow::CallNode, Http::Server::HeaderWriteAccess::Range {
|
||||
SpecificHeaderWrite() {
|
||||
// response.<method> = val
|
||||
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
|
||||
this.getMethodName() =
|
||||
[
|
||||
"location=", "cache_control=", "_cache_control=", "etag=", "charset=", "content_type=",
|
||||
"date=", "last_modified=", "weak_etag=", "strong_etag="
|
||||
]
|
||||
this =
|
||||
response()
|
||||
.getAMethodCall([
|
||||
"location=", "cache_control=", "_cache_control=", "etag=", "charset=",
|
||||
"content_type=", "date=", "last_modified=", "weak_etag=", "strong_etag="
|
||||
])
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
|
||||
@@ -571,9 +571,7 @@ class ActiveRecordAssociation extends DataFlow::CallNode {
|
||||
* For example, in `has_many :posts`, this is `post`.
|
||||
*/
|
||||
string getTargetModelName() {
|
||||
exists(string s |
|
||||
s = this.getArgument(0).asExpr().getExpr().getConstantValue().getStringlikeValue()
|
||||
|
|
||||
exists(string s | s = this.getArgument(0).getConstantValue().getStringlikeValue() |
|
||||
// has_one :profile
|
||||
// belongs_to :user
|
||||
this.isSingular() and
|
||||
|
||||
@@ -92,102 +92,63 @@ module Rails {
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to either `Rails::Railtie`, `Rails::Engine`, or `Rails::Application`.
|
||||
* Gets a reference to the `Rails` constant.
|
||||
*/
|
||||
private DataFlow::ConstRef rails() { result = DataFlow::getConstant("Rails") }
|
||||
|
||||
/**
|
||||
* Gets a reference to either `Rails::Railtie`, `Rails::Engine`, or `Rails::Application`.
|
||||
* `Engine` and `Application` extend `Railtie`, but may not have definitions present in the database.
|
||||
*/
|
||||
private class RailtieClassAccess extends ConstantReadAccess {
|
||||
RailtieClassAccess() {
|
||||
this.getScopeExpr().(ConstantAccess).getName() = "Rails" and
|
||||
this.getName() = ["Railtie", "Engine", "Application"]
|
||||
}
|
||||
private DataFlow::ConstRef railtie() {
|
||||
result = rails().getConstant(["Railtie", "Engine", "Application"])
|
||||
}
|
||||
|
||||
// A `ClassDeclaration` that (transitively) extends `Rails::Railtie`
|
||||
private class RailtieClass extends ClassDeclaration {
|
||||
RailtieClass() {
|
||||
this.getSuperclassExpr() instanceof RailtieClassAccess or
|
||||
exists(RailtieClass other |
|
||||
other.getModule() = this.getSuperclassExpr().(ConstantReadAccess).getModule()
|
||||
)
|
||||
}
|
||||
}
|
||||
/** Gets a class that transitively extends `Rails::Railtie` */
|
||||
private DataFlow::ClassNode railtieClass() { result = railtie().getADescendentModule() }
|
||||
|
||||
private DataFlow::CallNode getAConfigureCallNode() {
|
||||
// `Rails.application.configure`
|
||||
result = API::getTopLevelMember("Rails").getReturn("application").getAMethodCall("configure")
|
||||
/**
|
||||
* Gets a reference to `Rails::Application` or `Rails.application`.
|
||||
*/
|
||||
private DataFlow::LocalSourceNode railsApp() {
|
||||
result = rails().getAMethodCall("application")
|
||||
or
|
||||
// `Rails::Application.configure`
|
||||
exists(ConstantReadAccess read, RailtieClass cls |
|
||||
read = result.getReceiver().asExpr().getExpr() and
|
||||
read.getModule() = cls.getModule() and
|
||||
result.asExpr().getExpr().(MethodCall).getMethodName() = "configure"
|
||||
)
|
||||
result = rails().getConstant("Application")
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes representing accesses to the Rails config object.
|
||||
*/
|
||||
private module Config {
|
||||
/**
|
||||
* An access to a Rails config object.
|
||||
*/
|
||||
private class SourceNode extends DataFlow::LocalSourceNode {
|
||||
SourceNode() {
|
||||
// `Foo < Rails::Application ... config ...`
|
||||
exists(MethodCall configCall | this.asExpr().getExpr() = configCall |
|
||||
configCall.getMethodName() = "config" and
|
||||
configCall.getEnclosingModule() instanceof RailtieClass
|
||||
)
|
||||
or
|
||||
// `Rails.application.config`
|
||||
this = API::getTopLevelMember("Rails").getReturn("application").getReturn("config").asSource()
|
||||
or
|
||||
// `Rails.application.configure { ... config ... }`
|
||||
// `Rails::Application.configure { ... config ... }`
|
||||
exists(DataFlow::CallNode configureCallNode, Block block, MethodCall configCall |
|
||||
configCall = this.asExpr().getExpr()
|
||||
|
|
||||
configureCallNode = getAConfigureCallNode() and
|
||||
block = configureCallNode.asExpr().getExpr().(MethodCall).getBlock() and
|
||||
configCall.getParent+() = block and
|
||||
configCall.getMethodName() = "config"
|
||||
)
|
||||
}
|
||||
DataFlow::LocalSourceNode configSource() {
|
||||
// `Foo < Rails::Application ... config ...`
|
||||
result = railtieClass().getAnOwnModuleSelf().getAMethodCall("config")
|
||||
or
|
||||
// `Rails.application.config`
|
||||
result = railsApp().getAMethodCall("config")
|
||||
or
|
||||
// TODO: move away from getParent+() when have better infrastructure for overridden 'self' in blocks
|
||||
// `Rails.application.configure { ... config ... }`
|
||||
// `Rails::Application.configure { ... config ... }`
|
||||
exists(Block block, MethodCall configCall | configCall = result.asExpr().getExpr() |
|
||||
block = railsApp().getAMethodCall("configure").getBlock().asExpr().getExpr() and
|
||||
configCall.getParent+() = block and
|
||||
configCall.getMethodName() = "config"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the Rails config object.
|
||||
* Gets a reference to the ActionController config object.
|
||||
*/
|
||||
class Node extends DataFlow::Node {
|
||||
Node() { exists(SourceNode src | src.flowsTo(this)) }
|
||||
DataFlow::LocalSourceNode actionController() {
|
||||
result = configSource().getAMethodCall("action_controller")
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the ActionController config object.
|
||||
* Gets a reference to the ActionDispatch config object.
|
||||
*/
|
||||
class ActionControllerNode extends DataFlow::Node {
|
||||
ActionControllerNode() {
|
||||
exists(DataFlow::CallNode source |
|
||||
source.getReceiver() instanceof Node and
|
||||
source.getMethodName() = "action_controller"
|
||||
|
|
||||
source.flowsTo(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the ActionDispatch config object.
|
||||
*/
|
||||
class ActionDispatchNode extends DataFlow::Node {
|
||||
ActionDispatchNode() {
|
||||
exists(DataFlow::CallNode source |
|
||||
source.getReceiver() instanceof Node and
|
||||
source.getMethodName() = "action_dispatch"
|
||||
|
|
||||
source.flowsTo(this)
|
||||
)
|
||||
}
|
||||
DataFlow::LocalSourceNode actionDispatch() {
|
||||
result = configSource().getAMethodCall("action_dispatch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,24 +161,18 @@ private module Settings {
|
||||
loc.getFile().getStem() = "test"
|
||||
}
|
||||
|
||||
private class Setting extends DataFlow::CallNode {
|
||||
private class Setting extends DataFlow::SetterCallNode {
|
||||
Setting() {
|
||||
// exclude some test configuration
|
||||
not isInTestConfiguration(this.getLocation()) and
|
||||
this.getReceiver+() instanceof Config::Node and
|
||||
this.asExpr().getExpr() instanceof SetterMethodCall
|
||||
this = Config::configSource().getAMethodCall+()
|
||||
}
|
||||
}
|
||||
|
||||
private class LiteralSetting extends Setting {
|
||||
ConstantValue value;
|
||||
|
||||
LiteralSetting() {
|
||||
exists(DataFlow::LocalSourceNode lsn |
|
||||
lsn.asExpr().getConstantValue() = value and
|
||||
lsn.flowsTo(this.getArgument(0))
|
||||
)
|
||||
}
|
||||
LiteralSetting() { value = this.getArgument(0).getALocalSource().getConstantValue() }
|
||||
|
||||
string getValueText() { result = value.toString() }
|
||||
|
||||
@@ -262,8 +217,7 @@ private module Settings {
|
||||
private class AllowForgeryProtectionSetting extends Settings::BooleanSetting,
|
||||
CsrfProtectionSetting::Range {
|
||||
AllowForgeryProtectionSetting() {
|
||||
this.getReceiver() instanceof Config::ActionControllerNode and
|
||||
this.getMethodName() = "allow_forgery_protection="
|
||||
this = Config::actionController().getAMethodCall("allow_forgery_protection=")
|
||||
}
|
||||
|
||||
override boolean getVerificationSetting() { result = this.getValue() }
|
||||
@@ -277,8 +231,7 @@ private class AllowForgeryProtectionSetting extends Settings::BooleanSetting,
|
||||
private class EncryptedCookieCipherSetting extends Settings::StringlikeSetting,
|
||||
CookieSecurityConfigurationSetting::Range {
|
||||
EncryptedCookieCipherSetting() {
|
||||
this.getReceiver() instanceof Config::ActionDispatchNode and
|
||||
this.getMethodName() = "encrypted_cookie_cipher="
|
||||
this = Config::actionDispatch().getAMethodCall("encrypted_cookie_cipher=")
|
||||
}
|
||||
|
||||
OpenSslCipher getCipher() { this.getValueText() = result.getName() }
|
||||
@@ -298,8 +251,7 @@ private class EncryptedCookieCipherSetting extends Settings::StringlikeSetting,
|
||||
private class UseAuthenticatedCookieEncryptionSetting extends Settings::BooleanSetting,
|
||||
CookieSecurityConfigurationSetting::Range {
|
||||
UseAuthenticatedCookieEncryptionSetting() {
|
||||
this.getReceiver() instanceof Config::ActionDispatchNode and
|
||||
this.getMethodName() = "use_authenticated_cookie_encryption="
|
||||
this = Config::actionDispatch().getAMethodCall("use_authenticated_cookie_encryption=")
|
||||
}
|
||||
|
||||
boolean getDefaultValue() { result = true }
|
||||
@@ -321,8 +273,7 @@ private class UseAuthenticatedCookieEncryptionSetting extends Settings::BooleanS
|
||||
private class CookiesSameSiteProtectionSetting extends Settings::NillableStringlikeSetting,
|
||||
CookieSecurityConfigurationSetting::Range {
|
||||
CookiesSameSiteProtectionSetting() {
|
||||
this.getReceiver() instanceof Config::ActionDispatchNode and
|
||||
this.getMethodName() = "cookies_same_site_protection="
|
||||
this = Config::actionDispatch().getAMethodCall("cookies_same_site_protection=")
|
||||
}
|
||||
|
||||
string getDefaultValue() { result = "lax" }
|
||||
|
||||
@@ -12,26 +12,15 @@ private import codeql.ruby.DataFlow
|
||||
* Modeling for `railties`.
|
||||
*/
|
||||
module Railties {
|
||||
private class IncludeOrPrependCall extends MethodCall {
|
||||
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
|
||||
private DataFlow::ConstRef generatorsActionsConst() {
|
||||
result = DataFlow::getConstant("Rails").getConstant("Generators").getConstant("Actions")
|
||||
}
|
||||
|
||||
/**
|
||||
* A class which `include`s `Rails::Generators::Actions`.
|
||||
* Gets a class which is a descendent of `Rails::Generators::Actions`.
|
||||
*/
|
||||
private class GeneratorsActionsContext extends ClassDeclaration {
|
||||
GeneratorsActionsContext() {
|
||||
exists(IncludeOrPrependCall i |
|
||||
i.getEnclosingModule() = this and
|
||||
i.getArgument(0) =
|
||||
API::getTopLevelMember("Rails")
|
||||
.getMember("Generators")
|
||||
.getMember("Actions")
|
||||
.getAValueReachableFromSource()
|
||||
.asExpr()
|
||||
.getExpr()
|
||||
)
|
||||
}
|
||||
private DataFlow::ClassNode generatorsActionsClass() {
|
||||
result = generatorsActionsConst().getADescendentModule()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,8 +29,7 @@ module Railties {
|
||||
*/
|
||||
private class ExecuteCommandCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
ExecuteCommandCall() {
|
||||
this.asExpr().getExpr().getEnclosingModule() instanceof GeneratorsActionsContext and
|
||||
this.getMethodName() = "execute_command"
|
||||
this = generatorsActionsClass().getAnInstanceSelf().getAMethodCall("execute_command")
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument([0, 1]) }
|
||||
@@ -54,8 +42,10 @@ module Railties {
|
||||
*/
|
||||
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
ExecuteCommandWrapperCall() {
|
||||
this.asExpr().getExpr().getEnclosingModule() instanceof GeneratorsActionsContext and
|
||||
this.getMethodName() = ["rake", "rails_command", "git"]
|
||||
this =
|
||||
generatorsActionsClass()
|
||||
.getAnInstanceSelf()
|
||||
.getAMethodCall(["rake", "rails_command", "git"])
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }
|
||||
|
||||
@@ -88,11 +88,7 @@ module UnsafeDeserialization {
|
||||
|
||||
private predicate isOjModePair(CfgNodes::ExprNodes::PairCfgNode p, string modeValue) {
|
||||
p.getKey().getConstantValue().isStringlikeValue("mode") and
|
||||
exists(DataFlow::LocalSourceNode symbolLiteral, DataFlow::Node value |
|
||||
symbolLiteral.asExpr().getExpr().getConstantValue().isSymbol(modeValue) and
|
||||
symbolLiteral.flowsTo(value) and
|
||||
value.asExpr() = p.getValue()
|
||||
)
|
||||
DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().isSymbol(modeValue)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -180,11 +180,10 @@ private module Shared {
|
||||
private predicate isFlowFromLocals0(
|
||||
CfgNodes::ExprNodes::ElementReferenceCfgNode refNode, string hashKey, ErbFile erb
|
||||
) {
|
||||
exists(DataFlow::Node argNode, CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
|
||||
exists(DataFlow::Node argNode |
|
||||
argNode.asExpr() = refNode.getArgument(0) and
|
||||
refNode.getReceiver().getExpr().(MethodCall).getMethodName() = "local_assigns" and
|
||||
argNode.getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
strNode.getExpr().getConstantValue().isStringlikeValue(hashKey) and
|
||||
argNode.getALocalSource().getConstantValue().isStringlikeValue(hashKey) and
|
||||
erb = refNode.getFile()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,18 +17,11 @@ import codeql.ruby.frameworks.ActionController
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A call to `request` in an ActionController controller class.
|
||||
* Gets a call to `request` in an ActionController controller class.
|
||||
* This probably refers to the incoming HTTP request object.
|
||||
*/
|
||||
class ActionControllerRequest extends DataFlow::Node {
|
||||
ActionControllerRequest() {
|
||||
exists(DataFlow::CallNode c |
|
||||
c.asExpr().getExpr().getEnclosingModule() instanceof ActionControllerControllerClass and
|
||||
c.getMethodName() = "request"
|
||||
|
|
||||
c.flowsTo(this)
|
||||
)
|
||||
}
|
||||
DataFlow::LocalSourceNode request() {
|
||||
result = any(ActionControllerClass cls).getSelf().getAMethodCall("request")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +29,11 @@ class ActionControllerRequest extends DataFlow::Node {
|
||||
*/
|
||||
class WeakParams extends DataFlow::CallNode {
|
||||
WeakParams() {
|
||||
this.getReceiver() instanceof ActionControllerRequest and
|
||||
this.getMethodName() =
|
||||
["path_parameters", "query_parameters", "request_parameters", "GET", "POST"]
|
||||
this =
|
||||
request()
|
||||
.getAMethodCall([
|
||||
"path_parameters", "query_parameters", "request_parameters", "GET", "POST"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import codeql.ruby.ast.Literal
|
||||
from AmbiguousPathCall call
|
||||
where
|
||||
// there is not a constant string argument
|
||||
not exists(call.getPathArgument().asExpr().getExpr().getConstantValue()) and
|
||||
not exists(call.getPathArgument().getConstantValue()) and
|
||||
// if it's a format string, then the first argument is not a constant string
|
||||
not call.getPathArgument().getALocalSource().asExpr().getExpr().(StringLiteral).getComponent(0)
|
||||
instanceof StringTextComponent
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
| array_flow.rb:180:28:180:46 | # $ hasValueFlow=19 | Missing result:hasValueFlow=19 |
|
||||
| array_flow.rb:226:10:226:13 | ...[...] | Unexpected result: hasValueFlow=25 |
|
||||
| array_flow.rb:242:14:242:14 | x | Unexpected result: hasValueFlow=27.2 |
|
||||
| array_flow.rb:255:16:255:56 | # $ hasValueFlow=28.1 $ hasValueFlow=28.2 | Missing result:hasValueFlow=28.1 |
|
||||
| array_flow.rb:319:10:319:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
|
||||
| array_flow.rb:320:10:320:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
|
||||
| array_flow.rb:321:10:321:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
|
||||
@@ -26,7 +25,6 @@
|
||||
| array_flow.rb:490:10:490:13 | ...[...] | Unexpected result: hasValueFlow=54.5 |
|
||||
| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.2 |
|
||||
| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.3 |
|
||||
| array_flow.rb:564:16:564:56 | # $ hasValueFlow=62.1 $ hasValueFlow=62.2 | Missing result:hasValueFlow=62.1 |
|
||||
| array_flow.rb:575:16:575:34 | # $ hasValueFlow=63 | Missing result:hasValueFlow=63 |
|
||||
| array_flow.rb:580:19:580:37 | # $ hasValueFlow=64 | Missing result:hasValueFlow=64 |
|
||||
| array_flow.rb:582:16:582:34 | # $ hasValueFlow=64 | Missing result:hasValueFlow=64 |
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
failures
|
||||
edges
|
||||
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
|
||||
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
|
||||
| captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:1:24:1:24 | x : |
|
||||
| captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:1:24:1:24 | x : |
|
||||
| captured_variables.rb:21:33:21:33 | x : | captured_variables.rb:23:14:23:14 | x |
|
||||
| captured_variables.rb:21:33:21:33 | x : | captured_variables.rb:23:14:23:14 | x |
|
||||
| captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:21:33:21:33 | x : |
|
||||
| captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:21:33:21:33 | x : |
|
||||
| captured_variables.rb:32:31:32:31 | x : | captured_variables.rb:34:14:34:14 | x |
|
||||
| captured_variables.rb:32:31:32:31 | x : | captured_variables.rb:34:14:34:14 | x |
|
||||
| captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:32:31:32:31 | x : |
|
||||
| captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:32:31:32:31 | x : |
|
||||
| instance_variables.rb:10:19:10:19 | x : | instance_variables.rb:11:18:11:18 | x : |
|
||||
| instance_variables.rb:10:19:10:19 | x : | instance_variables.rb:11:18:11:18 | x : |
|
||||
| instance_variables.rb:11:18:11:18 | x : | instance_variables.rb:11:9:11:14 | [post] self [@field] : |
|
||||
@@ -152,6 +164,24 @@ edges
|
||||
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:84:6:84:20 | call to get_field |
|
||||
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:84:6:84:20 | call to get_field |
|
||||
nodes
|
||||
| captured_variables.rb:1:24:1:24 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:1:24:1:24 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:2:20:2:20 | x | semmle.label | x |
|
||||
| captured_variables.rb:2:20:2:20 | x | semmle.label | x |
|
||||
| captured_variables.rb:5:20:5:30 | call to source : | semmle.label | call to source : |
|
||||
| captured_variables.rb:5:20:5:30 | call to source : | semmle.label | call to source : |
|
||||
| captured_variables.rb:21:33:21:33 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:21:33:21:33 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:23:14:23:14 | x | semmle.label | x |
|
||||
| captured_variables.rb:23:14:23:14 | x | semmle.label | x |
|
||||
| captured_variables.rb:27:29:27:39 | call to source : | semmle.label | call to source : |
|
||||
| captured_variables.rb:27:29:27:39 | call to source : | semmle.label | call to source : |
|
||||
| captured_variables.rb:32:31:32:31 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:32:31:32:31 | x : | semmle.label | x : |
|
||||
| captured_variables.rb:34:14:34:14 | x | semmle.label | x |
|
||||
| captured_variables.rb:34:14:34:14 | x | semmle.label | x |
|
||||
| captured_variables.rb:38:27:38:37 | call to source : | semmle.label | call to source : |
|
||||
| captured_variables.rb:38:27:38:37 | call to source : | semmle.label | call to source : |
|
||||
| instance_variables.rb:10:19:10:19 | x : | semmle.label | x : |
|
||||
| instance_variables.rb:10:19:10:19 | x : | semmle.label | x : |
|
||||
| instance_variables.rb:11:9:11:14 | [post] self [@field] : | semmle.label | [post] self [@field] : |
|
||||
@@ -335,6 +365,9 @@ subpaths
|
||||
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:84:6:84:20 | call to get_field |
|
||||
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:84:6:84:20 | call to get_field |
|
||||
#select
|
||||
| captured_variables.rb:2:20:2:20 | x | captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:2:20:2:20 | x | $@ | captured_variables.rb:5:20:5:30 | call to source : | call to source : |
|
||||
| captured_variables.rb:23:14:23:14 | x | captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:23:14:23:14 | x | $@ | captured_variables.rb:27:29:27:39 | call to source : | call to source : |
|
||||
| captured_variables.rb:34:14:34:14 | x | captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:34:14:34:14 | x | $@ | captured_variables.rb:38:27:38:37 | call to source : | call to source : |
|
||||
| instance_variables.rb:20:10:20:13 | @foo | instance_variables.rb:19:12:19:21 | call to taint : | instance_variables.rb:20:10:20:13 | @foo | $@ | instance_variables.rb:19:12:19:21 | call to taint : | call to taint : |
|
||||
| instance_variables.rb:25:6:25:18 | call to get_field | instance_variables.rb:24:15:24:23 | call to taint : | instance_variables.rb:25:6:25:18 | call to get_field | $@ | instance_variables.rb:24:15:24:23 | call to taint : | call to taint : |
|
||||
| instance_variables.rb:29:6:29:18 | call to inc_field | instance_variables.rb:28:15:28:22 | call to taint : | instance_variables.rb:29:6:29:18 | call to inc_field | $@ | instance_variables.rb:28:15:28:22 | call to taint : | call to taint : |
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
| captured_variables.rb:9:14:9:14 | x | Fixed missing result:hasValueFlow=1.2 |
|
||||
| captured_variables.rb:16:14:16:14 | x | Fixed missing result:hasValueFlow=1.3 |
|
||||
| instance_variables.rb:20:16:20:33 | # $ hasValueFlow=7 | Missing result:hasValueFlow=7 |
|
||||
| instance_variables.rb:25:21:25:39 | # $ hasValueFlow=42 | Missing result:hasValueFlow=42 |
|
||||
| instance_variables.rb:37:22:37:40 | # $ hasValueFlow=21 | Missing result:hasValueFlow=21 |
|
||||
| instance_variables.rb:41:18:41:36 | # $ hasValueFlow=22 | Missing result:hasValueFlow=22 |
|
||||
| instance_variables.rb:49:22:49:40 | # $ hasValueFlow=24 | Missing result:hasValueFlow=24 |
|
||||
| instance_variables.rb:53:22:53:40 | # $ hasValueFlow=22 | Missing result:hasValueFlow=22 |
|
||||
| instance_variables.rb:54:22:54:40 | # $ hasValueFlow=24 | Missing result:hasValueFlow=24 |
|
||||
| instance_variables.rb:55:22:55:40 | # $ hasValueFlow=25 | Missing result:hasValueFlow=25 |
|
||||
| instance_variables.rb:60:22:60:40 | # $ hasValueFlow=26 | Missing result:hasValueFlow=26 |
|
||||
| instance_variables.rb:61:22:61:40 | # $ hasValueFlow=26 | Missing result:hasValueFlow=26 |
|
||||
| instance_variables.rb:66:22:66:40 | # $ hasValueFlow=27 | Missing result:hasValueFlow=27 |
|
||||
| instance_variables.rb:67:23:67:41 | # $ hasValueFlow=27 | Missing result:hasValueFlow=27 |
|
||||
| instance_variables.rb:75:23:75:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |
|
||||
| instance_variables.rb:79:23:79:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |
|
||||
| instance_variables.rb:84:23:84:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |
|
||||
@@ -0,0 +1 @@
|
||||
import TestUtilities.InlineTypeTrackingFlowTest
|
||||
@@ -0,0 +1,38 @@
|
||||
def capture_local_call x
|
||||
fn = -> { sink(x) } # $ hasValueFlow=1.1
|
||||
fn.call
|
||||
end
|
||||
capture_local_call source(1.1)
|
||||
|
||||
def capture_escape_return1 x
|
||||
-> {
|
||||
sink(x) # $ MISSING: hasValueFlow=1.2
|
||||
}
|
||||
end
|
||||
(capture_escape_return1 source(1.2)).call
|
||||
|
||||
def capture_escape_return2 x
|
||||
-> {
|
||||
sink(x) # $ MISSING: hasValueFlow=1.3
|
||||
}
|
||||
end
|
||||
Something.unknownMethod(capture_escape_return2 source(1.3))
|
||||
|
||||
def capture_escape_unknown_call x
|
||||
fn = -> {
|
||||
sink(x) # $ hasValueFlow=1.4
|
||||
}
|
||||
Something.unknownMethod(fn)
|
||||
end
|
||||
capture_escape_unknown_call source(1.4)
|
||||
|
||||
def call_it fn
|
||||
fn.call
|
||||
end
|
||||
def capture_escape_known_call x
|
||||
fn = -> {
|
||||
sink(x) # $ hasValueFlow=1.5
|
||||
}
|
||||
call_it fn
|
||||
end
|
||||
capture_escape_known_call source(1.5)
|
||||
234
ruby/ql/test/library-tests/dataflow/helpers/dataflow.expected
Normal file
234
ruby/ql/test/library-tests/dataflow/helpers/dataflow.expected
Normal file
@@ -0,0 +1,234 @@
|
||||
getAnAncestorExpr
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:8:12:8:13 | C1 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:27:12:27:13 | C2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:28:13:28:17 | Mixin |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:29:13:29:18 | Mixin2 |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:17:41:20 | Y |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:21:44:24 | Y |
|
||||
| tst.rb:49:1:51:3 | N2 | tst.rb:50:13:50:13 | X |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:17:53:17 | Y |
|
||||
getAnAncestor
|
||||
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Array |
|
||||
| file://:0:0:0:0 | Array | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | BasicObject | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Class | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Class |
|
||||
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Module |
|
||||
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Complex |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | FalseClass |
|
||||
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Float | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Float |
|
||||
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Hash |
|
||||
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer |
|
||||
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Kernel | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Module | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Module |
|
||||
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | NilClass |
|
||||
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Object | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Object | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Object | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Proc | file://:0:0:0:0 | Proc |
|
||||
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Numeric |
|
||||
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Rational |
|
||||
| file://:0:0:0:0 | String | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | String | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | String | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | String | file://:0:0:0:0 | String |
|
||||
| file://:0:0:0:0 | Symbol | file://:0:0:0:0 | Symbol |
|
||||
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | BasicObject |
|
||||
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | Kernel |
|
||||
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | Object |
|
||||
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | TrueClass |
|
||||
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:1:1:6:3 | C1 | tst.rb:1:1:6:3 | C1 |
|
||||
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:1:1:6:3 | C1 |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:8:1:11:3 | C2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | tst.rb:13:1:18:3 | Mixin |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:20:1:25:3 | Mixin2 |
|
||||
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:1:1:6:3 | C1 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:8:1:11:3 | C2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:13:1:18:3 | Mixin |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:20:1:25:3 | Mixin2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:27:1:35:3 | C3 |
|
||||
| tst.rb:40:1:47:3 | N1 | tst.rb:40:1:47:3 | N1 |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:5:42:7 | N1::XY1 |
|
||||
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:43:5:46:7 | N1::N2 |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:9:45:11 | N1::N2::XY2 |
|
||||
| tst.rb:49:1:51:3 | N2 | tst.rb:49:1:51:3 | N2 |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | Object |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:5:54:7 | N2::XY3 |
|
||||
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | BasicObject |
|
||||
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | Kernel |
|
||||
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | Object |
|
||||
| tst.rb:57:1:62:3 | Nodes | tst.rb:57:1:62:3 | Nodes |
|
||||
getModuleLevelSelf
|
||||
| tst.rb:1:1:6:3 | C1 | tst.rb:1:1:6:3 | self (C1) |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:8:1:11:3 | self (C2) |
|
||||
| tst.rb:13:1:18:3 | Mixin | tst.rb:13:1:18:3 | self (Mixin) |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:20:1:25:3 | self (Mixin2) |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:27:1:35:3 | self (C3) |
|
||||
| tst.rb:40:1:47:3 | N1 | tst.rb:40:1:47:3 | self (N1) |
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:5:42:7 | self (XY1) |
|
||||
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:43:5:46:7 | self (N2) |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:9:45:11 | self (XY2) |
|
||||
| tst.rb:49:1:51:3 | N2 | tst.rb:49:1:51:3 | self (N2) |
|
||||
| tst.rb:49:1:51:3 | N2 | tst.rb:52:1:55:3 | self (N2) |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:5:54:7 | self (XY3) |
|
||||
| tst.rb:57:1:62:3 | Nodes | tst.rb:57:1:62:3 | self (Nodes) |
|
||||
getAnImmediateReference
|
||||
| file://:0:0:0:0 | Array | tst.rb:59:15:59:21 | Array |
|
||||
| file://:0:0:0:0 | Hash | tst.rb:60:14:60:45 | Hash |
|
||||
| tst.rb:1:1:6:3 | C1 | tst.rb:8:12:8:13 | C1 |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:27:12:27:13 | C2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | tst.rb:28:13:28:17 | Mixin |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:29:13:29:18 | Mixin2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:37:5:37:6 | C3 |
|
||||
getOwnInstanceMethod
|
||||
| tst.rb:1:1:6:3 | C1 | c1 | tst.rb:2:5:5:7 | c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | c2 | tst.rb:9:5:10:7 | c2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | m1 | tst.rb:14:5:15:7 | m1 |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | m2 | tst.rb:21:5:22:7 | m2 |
|
||||
| tst.rb:57:1:62:3 | Nodes | m1 | tst.rb:58:5:61:7 | m1 |
|
||||
getInstanceMethod
|
||||
| tst.rb:1:1:6:3 | C1 | c1 | tst.rb:2:5:5:7 | c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | c1 | tst.rb:2:5:5:7 | c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | c2 | tst.rb:9:5:10:7 | c2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | m1 | tst.rb:14:5:15:7 | m1 |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | m2 | tst.rb:21:5:22:7 | m2 |
|
||||
| tst.rb:27:1:35:3 | C3 | c1 | tst.rb:2:5:5:7 | c1 |
|
||||
| tst.rb:27:1:35:3 | C3 | c2 | tst.rb:9:5:10:7 | c2 |
|
||||
| tst.rb:27:1:35:3 | C3 | m1 | tst.rb:14:5:15:7 | m1 |
|
||||
| tst.rb:27:1:35:3 | C3 | m2 | tst.rb:21:5:22:7 | m2 |
|
||||
| tst.rb:57:1:62:3 | Nodes | m1 | tst.rb:58:5:61:7 | m1 |
|
||||
getAnOwnInstanceSelf
|
||||
| tst.rb:1:1:6:3 | C1 | tst.rb:2:5:5:7 | self in c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:9:5:10:7 | self in c2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | tst.rb:14:5:15:7 | self in m1 |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:21:5:22:7 | self in m2 |
|
||||
| tst.rb:57:1:62:3 | Nodes | tst.rb:58:5:61:7 | self in m1 |
|
||||
getAnInstanceSelf
|
||||
| tst.rb:1:1:6:3 | C1 | tst.rb:2:5:5:7 | self in c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:2:5:5:7 | self in c1 |
|
||||
| tst.rb:8:1:11:3 | C2 | tst.rb:9:5:10:7 | self in c2 |
|
||||
| tst.rb:13:1:18:3 | Mixin | tst.rb:14:5:15:7 | self in m1 |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:21:5:22:7 | self in m2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:2:5:5:7 | self in c1 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:9:5:10:7 | self in c2 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:14:5:15:7 | self in m1 |
|
||||
| tst.rb:27:1:35:3 | C3 | tst.rb:21:5:22:7 | self in m2 |
|
||||
| tst.rb:57:1:62:3 | Nodes | tst.rb:58:5:61:7 | self in m1 |
|
||||
getOwnSingletonMethod
|
||||
| tst.rb:13:1:18:3 | Mixin | m1s | tst.rb:16:5:17:7 | m1s |
|
||||
| tst.rb:20:1:25:3 | Mixin2 | m2s | tst.rb:23:5:24:7 | m2s |
|
||||
| tst.rb:27:1:35:3 | C3 | c3_self1 | tst.rb:32:9:33:11 | c3_self1 |
|
||||
| tst.rb:27:1:35:3 | C3 | c3_self2 | tst.rb:37:1:38:3 | c3_self2 |
|
||||
getAnOwnInstanceVariableRead
|
||||
| tst.rb:1:1:6:3 | C1 | @field | tst.rb:4:9:4:14 | @field |
|
||||
getAnOwnInstanceVariableWriteValue
|
||||
| tst.rb:1:1:6:3 | C1 | @field | tst.rb:3:18:3:18 | 1 |
|
||||
getParentModule
|
||||
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:40:1:47:3 | N1 |
|
||||
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:40:1:47:3 | N1 |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:43:5:46:7 | N1::N2 |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:49:1:51:3 | N2 |
|
||||
getNestedModule
|
||||
| tst.rb:40:1:47:3 | N1 | N2 | tst.rb:43:5:46:7 | N1::N2 |
|
||||
| tst.rb:40:1:47:3 | N1 | XY1 | tst.rb:41:5:42:7 | N1::XY1 |
|
||||
| tst.rb:43:5:46:7 | N1::N2 | XY2 | tst.rb:44:9:45:11 | N1::N2::XY2 |
|
||||
| tst.rb:49:1:51:3 | N2 | XY3 | tst.rb:53:5:54:7 | N2::XY3 |
|
||||
getTopLevelConst
|
||||
| Array | tst.rb:59:15:59:21 | Array |
|
||||
| C1 | tst.rb:1:1:6:3 | self (C1) |
|
||||
| C1 | tst.rb:8:12:8:13 | C1 |
|
||||
| C2 | tst.rb:8:1:11:3 | self (C2) |
|
||||
| C2 | tst.rb:27:12:27:13 | C2 |
|
||||
| C3 | tst.rb:27:1:35:3 | self (C3) |
|
||||
| C3 | tst.rb:37:5:37:6 | C3 |
|
||||
| Hash | tst.rb:60:14:60:45 | Hash |
|
||||
| Mixin | tst.rb:13:1:18:3 | self (Mixin) |
|
||||
| Mixin | tst.rb:28:13:28:17 | Mixin |
|
||||
| Mixin2 | tst.rb:20:1:25:3 | self (Mixin2) |
|
||||
| Mixin2 | tst.rb:29:13:29:18 | Mixin2 |
|
||||
| N1 | tst.rb:40:1:47:3 | self (N1) |
|
||||
| N2 | tst.rb:43:5:46:7 | self (N2) |
|
||||
| N2 | tst.rb:49:1:51:3 | self (N2) |
|
||||
| N2 | tst.rb:52:1:55:3 | self (N2) |
|
||||
| Nodes | tst.rb:57:1:62:3 | self (Nodes) |
|
||||
| X | tst.rb:41:17:41:17 | X |
|
||||
| X | tst.rb:44:21:44:21 | X |
|
||||
| X | tst.rb:50:13:50:13 | X |
|
||||
| XY1 | tst.rb:41:5:42:7 | self (XY1) |
|
||||
| XY2 | tst.rb:44:9:45:11 | self (XY2) |
|
||||
| XY3 | tst.rb:53:5:54:7 | self (XY3) |
|
||||
| Y | tst.rb:53:17:53:17 | Y |
|
||||
getConstant
|
||||
| tst.rb:41:17:41:17 | X | Y | tst.rb:41:17:41:20 | Y |
|
||||
| tst.rb:44:21:44:21 | X | Y | tst.rb:44:21:44:24 | Y |
|
||||
| tst.rb:50:13:50:13 | X | X | tst.rb:50:13:50:13 | X |
|
||||
| tst.rb:50:13:50:13 | X | XY3 | tst.rb:53:5:54:7 | self (XY3) |
|
||||
| tst.rb:50:13:50:13 | X | Y | tst.rb:53:17:53:17 | Y |
|
||||
getXYClasses
|
||||
| tst.rb:41:5:42:7 | N1::XY1 |
|
||||
| tst.rb:44:9:45:11 | N1::N2::XY2 |
|
||||
| tst.rb:53:5:54:7 | N2::XY3 |
|
||||
hashLiteralNode
|
||||
| tst.rb:60:14:60:45 | call to [] |
|
||||
hashLiteralKey
|
||||
| tst.rb:60:14:60:45 | call to [] | bar | tst.rb:60:36:60:36 | 2 |
|
||||
| tst.rb:60:14:60:45 | call to [] | baz | tst.rb:60:44:60:44 | 3 |
|
||||
| tst.rb:60:14:60:45 | call to [] | foo | tst.rb:60:24:60:24 | 1 |
|
||||
arrayLiteralNode
|
||||
| tst.rb:59:15:59:21 | call to [] |
|
||||
arrayLiteralElement
|
||||
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:16:59:16 | 1 |
|
||||
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:18:59:18 | 2 |
|
||||
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:20:59:20 | 3 |
|
||||
73
ruby/ql/test/library-tests/dataflow/helpers/dataflow.ql
Normal file
73
ruby/ql/test/library-tests/dataflow/helpers/dataflow.ql
Normal file
@@ -0,0 +1,73 @@
|
||||
import ruby
|
||||
|
||||
query DataFlow::Node getAnAncestorExpr(DataFlow::ModuleNode mod) {
|
||||
result = mod.getAnAncestorExpr()
|
||||
}
|
||||
|
||||
query DataFlow::ModuleNode getAnAncestor(DataFlow::ModuleNode mod) { result = mod.getAnAncestor() }
|
||||
|
||||
query DataFlow::Node getModuleLevelSelf(DataFlow::ModuleNode mod) {
|
||||
result = mod.getModuleLevelSelf()
|
||||
}
|
||||
|
||||
query DataFlow::Node getAnImmediateReference(DataFlow::ModuleNode mod) {
|
||||
result = mod.getAnImmediateReference()
|
||||
}
|
||||
|
||||
query DataFlow::MethodNode getOwnInstanceMethod(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getOwnInstanceMethod(name)
|
||||
}
|
||||
|
||||
query DataFlow::MethodNode getInstanceMethod(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getInstanceMethod(name)
|
||||
}
|
||||
|
||||
query DataFlow::Node getAnOwnInstanceSelf(DataFlow::ModuleNode mod) {
|
||||
result = mod.getAnOwnInstanceSelf()
|
||||
}
|
||||
|
||||
query DataFlow::Node getAnInstanceSelf(DataFlow::ModuleNode mod) {
|
||||
result = mod.getAnInstanceSelf()
|
||||
}
|
||||
|
||||
query DataFlow::Node getOwnSingletonMethod(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getOwnSingletonMethod(name)
|
||||
}
|
||||
|
||||
query DataFlow::Node getAnOwnInstanceVariableRead(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getAnOwnInstanceVariableRead(name)
|
||||
}
|
||||
|
||||
query DataFlow::Node getAnOwnInstanceVariableWriteValue(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getAnOwnInstanceVariableWriteValue(name)
|
||||
}
|
||||
|
||||
query DataFlow::ModuleNode getParentModule(DataFlow::ModuleNode mod) {
|
||||
result = mod.getParentModule()
|
||||
}
|
||||
|
||||
query DataFlow::ModuleNode getNestedModule(DataFlow::ModuleNode mod, string name) {
|
||||
result = mod.getNestedModule(name)
|
||||
}
|
||||
|
||||
query DataFlow::Node getTopLevelConst(string name) { result = DataFlow::getConstant(name) }
|
||||
|
||||
query DataFlow::Node getConstant(DataFlow::ConstRef base, string name) {
|
||||
result = base.getConstant(name)
|
||||
}
|
||||
|
||||
query DataFlow::ModuleNode getXYClasses() {
|
||||
result = DataFlow::getConstant("X").getConstant("Y").getADescendentModule()
|
||||
}
|
||||
|
||||
query DataFlow::HashLiteralNode hashLiteralNode() { any() }
|
||||
|
||||
query DataFlow::Node hashLiteralKey(DataFlow::HashLiteralNode node, string key) {
|
||||
result = node.getElementFromKey(Ast::ConstantValue::fromStringlikeValue(key))
|
||||
}
|
||||
|
||||
query DataFlow::ArrayLiteralNode arrayLiteralNode() { any() }
|
||||
|
||||
query DataFlow::Node arrayLiteralElement(DataFlow::ArrayLiteralNode node) {
|
||||
result = node.getAnElement()
|
||||
}
|
||||
62
ruby/ql/test/library-tests/dataflow/helpers/tst.rb
Normal file
62
ruby/ql/test/library-tests/dataflow/helpers/tst.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
module C1
|
||||
def c1
|
||||
@field = 1
|
||||
@field
|
||||
end
|
||||
end
|
||||
|
||||
class C2 < C1
|
||||
def c2
|
||||
end
|
||||
end
|
||||
|
||||
module Mixin
|
||||
def m1
|
||||
end
|
||||
def self.m1s
|
||||
end
|
||||
end
|
||||
|
||||
module Mixin2
|
||||
def m2
|
||||
end
|
||||
def self.m2s
|
||||
end
|
||||
end
|
||||
|
||||
class C3 < C2
|
||||
include Mixin
|
||||
prepend Mixin2
|
||||
|
||||
class << self
|
||||
def c3_self1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def C3.c3_self2
|
||||
end
|
||||
|
||||
module N1
|
||||
class XY1 < X::Y
|
||||
end
|
||||
module N2
|
||||
class XY2 < X::Y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module N2
|
||||
include X
|
||||
end
|
||||
module N2
|
||||
class XY3 < Y
|
||||
end
|
||||
end
|
||||
|
||||
class Nodes
|
||||
def m1
|
||||
array=[1,2,3]
|
||||
hash={'foo' => 1, 'bar' => 2, baz: 3}
|
||||
end
|
||||
end
|
||||
@@ -26,7 +26,7 @@
|
||||
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
|
||||
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x |
|
||||
| local_dataflow.rb:10:5:13:3 | <captured> | local_dataflow.rb:11:1:11:2 | self |
|
||||
| local_dataflow.rb:10:5:13:3 | <captured> self | local_dataflow.rb:11:1:11:2 | self |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
|
||||
@@ -65,7 +65,7 @@
|
||||
| local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return |
|
||||
| local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self |
|
||||
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self |
|
||||
| local_dataflow.rb:49:3:53:3 | <captured> | local_dataflow.rb:50:18:50:18 | x |
|
||||
| local_dataflow.rb:49:3:53:3 | <captured> x | local_dataflow.rb:50:18:50:18 | x |
|
||||
| local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next |
|
||||
| local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x |
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
|
||||
@@ -264,7 +264,7 @@
|
||||
| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self |
|
||||
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
|
||||
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
|
||||
| local_dataflow.rb:118:17:118:31 | <captured> | local_dataflow.rb:118:23:118:29 | self |
|
||||
| local_dataflow.rb:118:17:118:31 | <captured> self | local_dataflow.rb:118:23:118:29 | self |
|
||||
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
|
||||
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
|
||||
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
|
||||
@@ -278,4 +278,4 @@
|
||||
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup |
|
||||
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
|
||||
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
|
||||
| local_dataflow.rb:123:26:123:45 | <captured> | local_dataflow.rb:123:32:123:43 | self |
|
||||
| local_dataflow.rb:123:26:123:45 | <captured> self | local_dataflow.rb:123:32:123:43 | self |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| file://:0:0:0:0 | [summary] read: argument position 0.any element in Hash[] | file://:0:0:0:0 | [summary] read: argument position 0.any element.element 1 or unknown in Hash[] |
|
||||
| file://:0:0:0:0 | parameter any of ;Pathname;Method[join] | file://:0:0:0:0 | [summary] to write: return (return) in ;Pathname;Method[join] |
|
||||
| file://:0:0:0:0 | parameter position 0 of & | file://:0:0:0:0 | [summary] read: argument position 0.any element in & |
|
||||
| file://:0:0:0:0 | parameter position 0 of + | file://:0:0:0:0 | [summary] read: argument position 0.any element in + |
|
||||
@@ -78,7 +79,7 @@
|
||||
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
|
||||
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x |
|
||||
| local_dataflow.rb:10:5:13:3 | <captured> | local_dataflow.rb:11:1:11:2 | self |
|
||||
| local_dataflow.rb:10:5:13:3 | <captured> self | local_dataflow.rb:11:1:11:2 | self |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
|
||||
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
|
||||
@@ -123,7 +124,7 @@
|
||||
| local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return |
|
||||
| local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self |
|
||||
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self |
|
||||
| local_dataflow.rb:49:3:53:3 | <captured> | local_dataflow.rb:50:18:50:18 | x |
|
||||
| local_dataflow.rb:49:3:53:3 | <captured> x | local_dataflow.rb:50:18:50:18 | x |
|
||||
| local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next |
|
||||
| local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x |
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... |
|
||||
@@ -338,7 +339,7 @@
|
||||
| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self |
|
||||
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
|
||||
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
|
||||
| local_dataflow.rb:118:17:118:31 | <captured> | local_dataflow.rb:118:23:118:29 | self |
|
||||
| local_dataflow.rb:118:17:118:31 | <captured> self | local_dataflow.rb:118:23:118:29 | self |
|
||||
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
|
||||
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
|
||||
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
|
||||
@@ -352,4 +353,4 @@
|
||||
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup |
|
||||
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
|
||||
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
|
||||
| local_dataflow.rb:123:26:123:45 | <captured> | local_dataflow.rb:123:32:123:43 | self |
|
||||
| local_dataflow.rb:123:26:123:45 | <captured> self | local_dataflow.rb:123:32:123:43 | self |
|
||||
|
||||
@@ -112,7 +112,7 @@ private class TypeFromCodeQL extends ModelInput::TypeModel {
|
||||
override DataFlow::Node getASource(string package, string type) {
|
||||
package = "test" and
|
||||
type = "FooOrBar" and
|
||||
result.asExpr().getExpr().getConstantValue().getString() = "magic_string"
|
||||
result.getConstantValue().getString() = "magic_string"
|
||||
}
|
||||
|
||||
override API::Node getAnApiNode(string package, string type) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
track
|
||||
| type_tracker.rb:1:1:10:3 | self (Container) | type tracker without call steps | type_tracker.rb:1:1:10:3 | self (Container) |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self in positional |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
@@ -18,13 +19,19 @@ track
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
@@ -189,20 +196,33 @@ track
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker with call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
@@ -337,6 +357,7 @@ track
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
trackEnd
|
||||
| type_tracker.rb:1:1:10:3 | self (Container) | type_tracker.rb:1:1:10:3 | self (Container) |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:1:1:10:3 | self (type_tracker.rb) |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self in positional |
|
||||
@@ -370,19 +391,24 @@ trackEnd
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:8:9:8:14 | self |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
@@ -565,6 +591,7 @@ trackEnd
|
||||
| type_tracker.rb:34:1:53:3 | self in throughArray | type_tracker.rb:34:1:53:3 | self in throughArray |
|
||||
| type_tracker.rb:34:1:53:3 | throughArray | type_tracker.rb:34:1:53:3 | throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
|
||||
@@ -22,7 +22,7 @@ query predicate trackEnd(LocalSourceNode src, DataFlow::Node dst) {
|
||||
|
||||
predicate backtrack(LocalSourceNode sink, TypeBackTracker t, LocalSourceNode src) {
|
||||
t.start() and
|
||||
sink = src
|
||||
sink.getALocalSource() = src
|
||||
or
|
||||
exists(TypeBackTracker t2, LocalSourceNode mid |
|
||||
backtrack(sink, t2, mid) and
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
actionControllerControllerClasses
|
||||
| action_controller/input_access.rb:1:1:50:3 | UsersController |
|
||||
| action_controller/params_flow.rb:1:1:160:3 | MyController |
|
||||
| action_controller/params_flow.rb:1:1:162:3 | MyController |
|
||||
| action_controller/params_flow.rb:170:1:178:3 | Subclass |
|
||||
| active_record/ActiveRecord.rb:23:1:39:3 | FooController |
|
||||
| active_record/ActiveRecord.rb:41:1:64:3 | BarController |
|
||||
| active_record/ActiveRecord.rb:66:1:98:3 | BazController |
|
||||
| active_record/ActiveRecord.rb:100:1:108:3 | AnnotatedController |
|
||||
| active_storage/active_storage.rb:39:1:45:3 | PostsController |
|
||||
| active_storage/active_storage.rb:39:1:45:3 | PostsController2 |
|
||||
| app/controllers/comments_controller.rb:1:1:40:3 | CommentsController |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:46:3 | BarsController |
|
||||
| app/controllers/photos_controller.rb:1:1:4:3 | PhotosController |
|
||||
| app/controllers/posts_controller.rb:1:1:10:3 | PostsController |
|
||||
| app/controllers/tags_controller.rb:1:1:2:3 | TagsController |
|
||||
| app/controllers/users/notifications_controller.rb:2:3:5:5 | NotificationsController |
|
||||
| app/controllers/users/notifications_controller.rb:2:3:5:5 | Users::NotificationsController |
|
||||
actionControllerActionMethods
|
||||
| action_controller/input_access.rb:2:3:49:5 | index |
|
||||
| action_controller/params_flow.rb:2:3:4:5 | m1 |
|
||||
@@ -48,6 +49,7 @@ actionControllerActionMethods
|
||||
| action_controller/params_flow.rb:134:3:141:5 | m31 |
|
||||
| action_controller/params_flow.rb:143:3:150:5 | m32 |
|
||||
| action_controller/params_flow.rb:152:3:159:5 | m33 |
|
||||
| action_controller/params_flow.rb:171:3:173:5 | m34 |
|
||||
| active_record/ActiveRecord.rb:27:3:38:5 | some_request_handler |
|
||||
| active_record/ActiveRecord.rb:42:3:47:5 | some_other_request_handler |
|
||||
| active_record/ActiveRecord.rb:49:3:63:5 | safe_paths |
|
||||
@@ -121,6 +123,9 @@ paramsCalls
|
||||
| action_controller/params_flow.rb:153:10:153:15 | call to params |
|
||||
| action_controller/params_flow.rb:154:32:154:37 | call to params |
|
||||
| action_controller/params_flow.rb:157:22:157:27 | call to params |
|
||||
| action_controller/params_flow.rb:166:10:166:15 | call to params |
|
||||
| action_controller/params_flow.rb:172:10:172:15 | call to params |
|
||||
| action_controller/params_flow.rb:176:10:176:15 | call to params |
|
||||
| action_mailer/mailer.rb:3:10:3:15 | call to params |
|
||||
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
|
||||
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
|
||||
@@ -199,6 +204,9 @@ paramsSources
|
||||
| action_controller/params_flow.rb:153:10:153:15 | call to params |
|
||||
| action_controller/params_flow.rb:154:32:154:37 | call to params |
|
||||
| action_controller/params_flow.rb:157:22:157:27 | call to params |
|
||||
| action_controller/params_flow.rb:166:10:166:15 | call to params |
|
||||
| action_controller/params_flow.rb:172:10:172:15 | call to params |
|
||||
| action_controller/params_flow.rb:176:10:176:15 | call to params |
|
||||
| action_mailer/mailer.rb:3:10:3:15 | call to params |
|
||||
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
|
||||
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
|
||||
@@ -316,6 +324,9 @@ httpInputAccesses
|
||||
| action_controller/params_flow.rb:153:10:153:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:154:32:154:37 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:157:22:157:27 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:166:10:166:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:172:10:172:15 | call to params | ActionController::Metal#params |
|
||||
| action_controller/params_flow.rb:176:10:176:15 | call to params | ActionController::Metal#params |
|
||||
| action_mailer/mailer.rb:3:10:3:15 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:28:30:28:35 | call to params | ActionController::Metal#params |
|
||||
| active_record/ActiveRecord.rb:29:29:29:34 | call to params | ActionController::Metal#params |
|
||||
|
||||
@@ -5,7 +5,7 @@ private import codeql.ruby.frameworks.ActionView
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
query predicate actionControllerControllerClasses(ActionControllerControllerClass cls) { any() }
|
||||
query predicate actionControllerControllerClasses(ActionControllerClass cls) { any() }
|
||||
|
||||
query predicate actionControllerActionMethods(ActionControllerActionMethod m) { any() }
|
||||
|
||||
@@ -25,11 +25,11 @@ query predicate redirectToCalls(RedirectToCall c) { any() }
|
||||
|
||||
query predicate actionControllerHelperMethods(ActionControllerHelperMethod m) { any() }
|
||||
|
||||
query predicate getAssociatedControllerClasses(ActionControllerControllerClass cls, ErbFile f) {
|
||||
query predicate getAssociatedControllerClasses(ActionControllerClass cls, ErbFile f) {
|
||||
cls = getAssociatedControllerClass(f)
|
||||
}
|
||||
|
||||
query predicate controllerTemplateFiles(ActionControllerControllerClass cls, ErbFile templateFile) {
|
||||
query predicate controllerTemplateFiles(ActionControllerClass cls, ErbFile templateFile) {
|
||||
controllerTemplateFile(cls, templateFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ edges
|
||||
| params_flow.rb:154:32:154:37 | call to params : | params_flow.rb:154:10:154:38 | call to reverse_update |
|
||||
| params_flow.rb:157:5:157:5 | [post] p : | params_flow.rb:158:10:158:10 | p |
|
||||
| params_flow.rb:157:22:157:27 | call to params : | params_flow.rb:157:5:157:5 | [post] p : |
|
||||
| params_flow.rb:166:10:166:15 | call to params : | params_flow.rb:166:10:166:19 | ...[...] |
|
||||
| params_flow.rb:172:10:172:15 | call to params : | params_flow.rb:172:10:172:19 | ...[...] |
|
||||
| params_flow.rb:176:10:176:15 | call to params : | params_flow.rb:176:10:176:19 | ...[...] |
|
||||
nodes
|
||||
| params_flow.rb:3:10:3:15 | call to params : | semmle.label | call to params : |
|
||||
| params_flow.rb:3:10:3:19 | ...[...] | semmle.label | ...[...] |
|
||||
@@ -141,6 +144,12 @@ nodes
|
||||
| params_flow.rb:157:5:157:5 | [post] p : | semmle.label | [post] p : |
|
||||
| params_flow.rb:157:22:157:27 | call to params : | semmle.label | call to params : |
|
||||
| params_flow.rb:158:10:158:10 | p | semmle.label | p |
|
||||
| params_flow.rb:166:10:166:15 | call to params : | semmle.label | call to params : |
|
||||
| params_flow.rb:166:10:166:19 | ...[...] | semmle.label | ...[...] |
|
||||
| params_flow.rb:172:10:172:15 | call to params : | semmle.label | call to params : |
|
||||
| params_flow.rb:172:10:172:19 | ...[...] | semmle.label | ...[...] |
|
||||
| params_flow.rb:176:10:176:15 | call to params : | semmle.label | call to params : |
|
||||
| params_flow.rb:176:10:176:19 | ...[...] | semmle.label | ...[...] |
|
||||
subpaths
|
||||
#select
|
||||
| params_flow.rb:3:10:3:19 | ...[...] | params_flow.rb:3:10:3:15 | call to params : | params_flow.rb:3:10:3:19 | ...[...] | $@ | params_flow.rb:3:10:3:15 | call to params : | call to params : |
|
||||
@@ -187,3 +196,6 @@ subpaths
|
||||
| params_flow.rb:153:10:153:44 | call to reverse_update | params_flow.rb:153:10:153:15 | call to params : | params_flow.rb:153:10:153:44 | call to reverse_update | $@ | params_flow.rb:153:10:153:15 | call to params : | call to params : |
|
||||
| params_flow.rb:154:10:154:38 | call to reverse_update | params_flow.rb:154:32:154:37 | call to params : | params_flow.rb:154:10:154:38 | call to reverse_update | $@ | params_flow.rb:154:32:154:37 | call to params : | call to params : |
|
||||
| params_flow.rb:158:10:158:10 | p | params_flow.rb:157:22:157:27 | call to params : | params_flow.rb:158:10:158:10 | p | $@ | params_flow.rb:157:22:157:27 | call to params : | call to params : |
|
||||
| params_flow.rb:166:10:166:19 | ...[...] | params_flow.rb:166:10:166:15 | call to params : | params_flow.rb:166:10:166:19 | ...[...] | $@ | params_flow.rb:166:10:166:15 | call to params : | call to params : |
|
||||
| params_flow.rb:172:10:172:19 | ...[...] | params_flow.rb:172:10:172:15 | call to params : | params_flow.rb:172:10:172:19 | ...[...] | $@ | params_flow.rb:172:10:172:15 | call to params : | call to params : |
|
||||
| params_flow.rb:176:10:176:19 | ...[...] | params_flow.rb:176:10:176:15 | call to params : | params_flow.rb:176:10:176:19 | ...[...] | $@ | params_flow.rb:176:10:176:15 | call to params : | call to params : |
|
||||
|
||||
@@ -157,4 +157,22 @@ class MyController < ActionController::Base
|
||||
p.reverse_update(params)
|
||||
sink p # $hasTaintFlow
|
||||
end
|
||||
|
||||
include Mixin
|
||||
end
|
||||
|
||||
module Mixin
|
||||
def m33
|
||||
sink params[:x] # $hasTaintFlow
|
||||
end
|
||||
end
|
||||
|
||||
class Subclass < MyController
|
||||
def m34
|
||||
sink params[:x] # $hasTaintFlow
|
||||
end
|
||||
|
||||
rescue_from 'Foo::Bar' do |err|
|
||||
sink params[:x] # $hasTaintFlow
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ ActiveStorage.video_preview_arguments = custom_preview_args
|
||||
|
||||
ActiveStorage.variant_processor = custom_processor
|
||||
|
||||
class PostsController < ActionController::Base
|
||||
class PostsController2 < ActionController::Base
|
||||
def create
|
||||
post = Post.new(params[:post])
|
||||
post.images.attach(params[:images])
|
||||
|
||||
@@ -4,6 +4,8 @@ definition
|
||||
| class_variables.rb:9:1:16:3 | self (X) | class_variables.rb:9:1:16:3 | self |
|
||||
| class_variables.rb:10:3:12:5 | self (b) | class_variables.rb:10:3:12:5 | self |
|
||||
| class_variables.rb:13:3:15:5 | self (s) | class_variables.rb:13:3:15:5 | self |
|
||||
| class_variables.rb:18:1:20:3 | self (Y) | class_variables.rb:18:1:20:3 | self |
|
||||
| class_variables.rb:22:1:24:3 | self (M) | class_variables.rb:22:1:24:3 | self |
|
||||
| class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self |
|
||||
| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self |
|
||||
| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self |
|
||||
@@ -13,9 +15,9 @@ definition
|
||||
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self |
|
||||
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self |
|
||||
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self |
|
||||
| instance_variables.rb:31:1:33:3 | self (bar) | instance_variables.rb:31:1:33:3 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self |
|
||||
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self |
|
||||
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self |
|
||||
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self |
|
||||
@@ -32,8 +34,8 @@ definition
|
||||
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a |
|
||||
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self |
|
||||
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a |
|
||||
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self |
|
||||
@@ -41,7 +43,7 @@ definition
|
||||
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a |
|
||||
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d |
|
||||
| parameters.rb:1:1:1:1 | self (parameters.rb) | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x |
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y |
|
||||
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self |
|
||||
@@ -49,7 +51,7 @@ definition
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas |
|
||||
| parameters.rb:15:1:19:3 | self (print_map) | parameters.rb:15:1:19:3 | self |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map |
|
||||
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self |
|
||||
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block |
|
||||
@@ -76,8 +78,8 @@ definition
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b |
|
||||
| parameters.rb:53:1:53:6 | ... = ... | parameters.rb:53:1:53:1 | x |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:53:1:53:1 | x |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> x | parameters.rb:53:1:53:1 | x |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y |
|
||||
| parameters.rb:54:19:54:23 | ... = ... | parameters.rb:53:1:53:1 | x |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x |
|
||||
@@ -86,11 +88,11 @@ definition
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a |
|
||||
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b |
|
||||
@@ -98,9 +100,12 @@ definition
|
||||
| scopes.rb:13:11:13:11 | ... = ... | scopes.rb:13:11:13:11 | c |
|
||||
| scopes.rb:13:14:13:14 | ... = ... | scopes.rb:13:14:13:14 | d |
|
||||
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 |
|
||||
| scopes.rb:26:1:26:12 | self (A) | scopes.rb:26:1:26:12 | self |
|
||||
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x |
|
||||
| scopes.rb:28:1:30:3 | self (B) | scopes.rb:28:1:30:3 | self |
|
||||
| scopes.rb:29:3:29:7 | ... = ... | scopes.rb:29:3:29:3 | x |
|
||||
| scopes.rb:32:3:32:7 | ... = ... | scopes.rb:32:3:32:3 | x |
|
||||
| scopes.rb:34:1:36:3 | self (C) | scopes.rb:34:1:36:3 | self |
|
||||
| scopes.rb:35:3:35:7 | ... = ... | scopes.rb:35:3:35:3 | x |
|
||||
| scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self |
|
||||
| scopes.rb:42:2:42:9 | ... = ... | scopes.rb:42:2:42:4 | var |
|
||||
@@ -120,11 +125,11 @@ definition
|
||||
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements |
|
||||
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem |
|
||||
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self |
|
||||
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self |
|
||||
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
|
||||
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem |
|
||||
| ssa.rb:32:1:36:3 | self (m3) | ssa.rb:32:1:36:3 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self |
|
||||
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 |
|
||||
@@ -147,19 +152,19 @@ definition
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a |
|
||||
| ssa.rb:65:3:65:15 | ... = ... | ssa.rb:65:3:65:10 | captured |
|
||||
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a |
|
||||
| ssa.rb:69:5:69:17 | ... = ... | ssa.rb:65:3:65:10 | captured |
|
||||
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self |
|
||||
| ssa.rb:75:3:75:14 | ... = ... | ssa.rb:75:3:75:10 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self |
|
||||
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self |
|
||||
| ssa.rb:82:3:82:14 | ... = ... | ssa.rb:82:3:82:10 | captured |
|
||||
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured |
|
||||
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured |
|
||||
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self |
|
||||
read
|
||||
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
|
||||
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
|
||||
@@ -179,8 +184,8 @@ read
|
||||
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
|
||||
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
|
||||
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
|
||||
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self |
|
||||
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:4:42:7 | self |
|
||||
@@ -202,8 +207,8 @@ read
|
||||
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
|
||||
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
|
||||
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self |
|
||||
@@ -211,8 +216,8 @@ read
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
|
||||
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
|
||||
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
|
||||
@@ -222,7 +227,7 @@ read
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
@@ -246,8 +251,8 @@ read
|
||||
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
|
||||
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
|
||||
@@ -255,19 +260,19 @@ read
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
|
||||
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
|
||||
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
|
||||
@@ -308,10 +313,10 @@ read
|
||||
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
|
||||
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
|
||||
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
|
||||
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
|
||||
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self |
|
||||
@@ -331,18 +336,18 @@ read
|
||||
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
|
||||
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
|
||||
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
|
||||
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
firstRead
|
||||
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
|
||||
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
|
||||
@@ -358,8 +363,8 @@ firstRead
|
||||
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
|
||||
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
|
||||
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
|
||||
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self |
|
||||
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self |
|
||||
@@ -376,15 +381,15 @@ firstRead
|
||||
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
|
||||
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
|
||||
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self |
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
|
||||
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
|
||||
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
|
||||
@@ -393,7 +398,7 @@ firstRead
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
@@ -416,7 +421,7 @@ firstRead
|
||||
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
|
||||
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
|
||||
@@ -424,11 +429,11 @@ firstRead
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
|
||||
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
|
||||
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
|
||||
@@ -451,10 +456,10 @@ firstRead
|
||||
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
|
||||
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
|
||||
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
|
||||
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
|
||||
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self |
|
||||
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 |
|
||||
@@ -472,16 +477,16 @@ firstRead
|
||||
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
|
||||
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
|
||||
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
|
||||
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
lastRead
|
||||
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
|
||||
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
|
||||
@@ -498,8 +503,8 @@ lastRead
|
||||
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
|
||||
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
|
||||
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
|
||||
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
|
||||
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
|
||||
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:6:42:7 | self |
|
||||
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self |
|
||||
@@ -516,15 +521,15 @@ lastRead
|
||||
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
|
||||
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
|
||||
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
|
||||
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
|
||||
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:16:28:16 | self |
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
|
||||
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
|
||||
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
|
||||
@@ -534,7 +539,7 @@ lastRead
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
@@ -556,7 +561,7 @@ lastRead
|
||||
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
|
||||
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
|
||||
@@ -564,11 +569,11 @@ lastRead
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
|
||||
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
|
||||
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
|
||||
@@ -592,10 +597,10 @@ lastRead
|
||||
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
|
||||
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
|
||||
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
|
||||
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
|
||||
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:41:3:41:13 | self |
|
||||
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 |
|
||||
@@ -613,16 +618,16 @@ lastRead
|
||||
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
|
||||
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
|
||||
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
|
||||
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
|
||||
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
|
||||
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
|
||||
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
|
||||
adjacentReads
|
||||
| class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | class_variables.rb:28:3:28:7 | self |
|
||||
| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | instance_variables.rb:11:1:11:9 | self |
|
||||
@@ -636,19 +641,19 @@ adjacentReads
|
||||
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a |
|
||||
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | nested_scopes.rb:28:16:28:16 | self |
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:30:16:30:19 | self | nested_scopes.rb:32:11:32:16 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
|
||||
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:13:10:13:15 | ... = ... | scopes.rb:13:10:13:15 | __synth__0__1 | scopes.rb:13:11:13:11 | __synth__0__1 | scopes.rb:13:14:13:14 | __synth__0__1 |
|
||||
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:4:13:4 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 |
|
||||
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 | scopes.rb:13:10:13:15 | __synth__0 |
|
||||
@@ -671,14 +676,14 @@ adjacentReads
|
||||
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | ssa.rb:39:8:39:9 | self |
|
||||
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | ssa.rb:41:3:41:13 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self |
|
||||
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured |
|
||||
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self |
|
||||
phi
|
||||
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | <uninitialized> |
|
||||
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... |
|
||||
| parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | <uninitialized> |
|
||||
| parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:19 | ... = ... |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | <captured> |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | <captured> x |
|
||||
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:19:54:23 | ... = ... |
|
||||
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:6:5:6:9 | ... = ... |
|
||||
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... |
|
||||
|
||||
9
swift/actions/print-unextracted/action.yml
Normal file
9
swift/actions/print-unextracted/action.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
name: Print unextracted entities
|
||||
description: Prints all AST and Type entities that we do not extract yet. Must be run after `setup-env`
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Print unextracted entities
|
||||
shell: bash
|
||||
run: |
|
||||
bazel run //swift/extractor/print_unextracted
|
||||
@@ -10,6 +10,7 @@ swift_cc_binary(
|
||||
visibility = ["//swift:__pkg__"],
|
||||
deps = [
|
||||
"//swift/extractor/infra",
|
||||
"//swift/extractor/invocation",
|
||||
"//swift/extractor/remapping",
|
||||
"//swift/extractor/translators",
|
||||
"//swift/third_party/swift-llvm-support",
|
||||
|
||||
23
swift/extractor/infra/SwiftDiagnosticKind.h
Normal file
23
swift/extractor/infra/SwiftDiagnosticKind.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <swift/AST/DiagnosticConsumer.h>
|
||||
|
||||
namespace codeql {
|
||||
|
||||
inline int translateDiagnosticsKind(swift::DiagnosticKind kind) {
|
||||
using Kind = swift::DiagnosticKind;
|
||||
switch (kind) {
|
||||
case Kind::Error:
|
||||
return 1;
|
||||
case Kind::Warning:
|
||||
return 2;
|
||||
case Kind::Note:
|
||||
return 3;
|
||||
case Kind::Remark:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace codeql
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "swift/extractor/trap/TrapDomain.h"
|
||||
#include "swift/extractor/infra/SwiftTagTraits.h"
|
||||
#include "swift/extractor/trap/generated/TrapClasses.h"
|
||||
#include "swift/extractor/infra/file/PathHash.h"
|
||||
#include "swift/extractor/infra/SwiftLocationExtractor.h"
|
||||
|
||||
namespace codeql {
|
||||
|
||||
@@ -29,8 +29,7 @@ class SwiftDispatcher {
|
||||
const swift::Expr*,
|
||||
const swift::Pattern*,
|
||||
const swift::TypeRepr*,
|
||||
const swift::TypeBase*,
|
||||
std::filesystem::path>;
|
||||
const swift::TypeBase*>;
|
||||
|
||||
template <typename E>
|
||||
static constexpr bool IsStorable = std::is_constructible_v<Store::Handle, const E&>;
|
||||
@@ -48,10 +47,11 @@ class SwiftDispatcher {
|
||||
: sourceManager{sourceManager},
|
||||
trap{trap},
|
||||
currentModule{currentModule},
|
||||
currentPrimarySourceFile{currentPrimarySourceFile} {
|
||||
currentPrimarySourceFile{currentPrimarySourceFile},
|
||||
locationExtractor(trap) {
|
||||
if (currentPrimarySourceFile) {
|
||||
// we make sure the file is in the trap output even if the source is empty
|
||||
fetchLabel(getFilePath(currentPrimarySourceFile->getFilename()));
|
||||
locationExtractor.emitFile(currentPrimarySourceFile->getFilename());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,20 +325,7 @@ class SwiftDispatcher {
|
||||
void attachLocation(swift::SourceLoc start,
|
||||
swift::SourceLoc end,
|
||||
TrapLabel<LocatableTag> locatableLabel) {
|
||||
if (!start.isValid() || !end.isValid()) {
|
||||
// invalid locations seem to come from entities synthesized by the compiler
|
||||
return;
|
||||
}
|
||||
auto file = getFilePath(sourceManager.getDisplayNameForLoc(start));
|
||||
DbLocation entry{{}};
|
||||
entry.file = fetchLabel(file);
|
||||
std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
|
||||
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
|
||||
entry.id = trap.createLabel<DbLocationTag>('{', entry.file, "}:", entry.start_line, ':',
|
||||
entry.start_column, ':', entry.end_line, ':',
|
||||
entry.end_column);
|
||||
emit(entry);
|
||||
emit(LocatableLocationsTrap{locatableLabel, entry.id});
|
||||
locationExtractor.attachLocation(sourceManager, start, end, locatableLabel);
|
||||
}
|
||||
|
||||
template <typename Tag, typename... Ts>
|
||||
@@ -391,12 +378,6 @@ class SwiftDispatcher {
|
||||
virtual void visit(const swift::TypeRepr* typeRepr, swift::Type type) = 0;
|
||||
virtual void visit(const swift::TypeBase* type) = 0;
|
||||
|
||||
void visit(const std::filesystem::path& file) {
|
||||
auto entry = createEntry(file, file.string());
|
||||
entry.name = file.string();
|
||||
emit(entry);
|
||||
}
|
||||
|
||||
const swift::SourceManager& sourceManager;
|
||||
TrapDomain& trap;
|
||||
Store store;
|
||||
@@ -404,6 +385,7 @@ class SwiftDispatcher {
|
||||
swift::ModuleDecl& currentModule;
|
||||
swift::SourceFile* currentPrimarySourceFile;
|
||||
std::unordered_set<swift::ModuleDecl*> encounteredModules;
|
||||
SwiftLocationExtractor locationExtractor;
|
||||
};
|
||||
|
||||
} // namespace codeql
|
||||
|
||||
59
swift/extractor/infra/SwiftLocationExtractor.cpp
Normal file
59
swift/extractor/infra/SwiftLocationExtractor.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <swift/AST/SourceFile.h>
|
||||
#include <swift/Basic/SourceManager.h>
|
||||
|
||||
#include "swift/extractor/trap/TrapDomain.h"
|
||||
#include "swift/extractor/trap/generated/TrapEntries.h"
|
||||
#include "swift/extractor/trap/generated/TrapClasses.h"
|
||||
#include "swift/extractor/infra/SwiftLocationExtractor.h"
|
||||
|
||||
using namespace codeql;
|
||||
|
||||
static std::filesystem::path getFilePath(std::string_view path) {
|
||||
// TODO: this needs more testing
|
||||
// TODO: check canonicalization of names on a case insensitive filesystems
|
||||
// TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true
|
||||
std::error_code ec;
|
||||
auto ret = std::filesystem::canonical(path, ec);
|
||||
if (ec) {
|
||||
std::cerr << "Cannot get real path: " << std::quoted(path) << ": " << ec.message() << "\n";
|
||||
return {};
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
|
||||
swift::SourceLoc start,
|
||||
swift::SourceLoc end,
|
||||
TrapLabel<LocatableTag> locatableLabel) {
|
||||
if (!start.isValid() || !end.isValid()) {
|
||||
// invalid locations seem to come from entities synthesized by the compiler
|
||||
return;
|
||||
}
|
||||
auto file = getFilePath(sourceManager.getDisplayNameForLoc(start));
|
||||
DbLocation entry{{}};
|
||||
entry.file = fetchFileLabel(file);
|
||||
std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
|
||||
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
|
||||
entry.id = trap.createLabel<DbLocationTag>('{', entry.file, "}:", entry.start_line, ':',
|
||||
entry.start_column, ':', entry.end_line, ':',
|
||||
entry.end_column);
|
||||
trap.emit(entry);
|
||||
trap.emit(LocatableLocationsTrap{locatableLabel, entry.id});
|
||||
}
|
||||
|
||||
void SwiftLocationExtractor::emitFile(llvm::StringRef path) {
|
||||
fetchFileLabel(getFilePath(path));
|
||||
}
|
||||
|
||||
TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem::path& file) {
|
||||
if (store.count(file)) {
|
||||
return store[file];
|
||||
}
|
||||
|
||||
DbFile entry({});
|
||||
entry.id = trap.createLabel<DbFileTag>(file.string());
|
||||
entry.name = file.string();
|
||||
trap.emit(entry);
|
||||
store[file] = entry.id;
|
||||
return entry.id;
|
||||
}
|
||||
31
swift/extractor/infra/SwiftLocationExtractor.h
Normal file
31
swift/extractor/infra/SwiftLocationExtractor.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <swift/Basic/SourceManager.h>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
|
||||
#include "swift/extractor/trap/generated/TrapEntries.h"
|
||||
#include "swift/extractor/infra/file/PathHash.h"
|
||||
|
||||
namespace codeql {
|
||||
|
||||
class TrapDomain;
|
||||
|
||||
class SwiftLocationExtractor {
|
||||
public:
|
||||
explicit SwiftLocationExtractor(TrapDomain& trap) : trap(trap) {}
|
||||
|
||||
void attachLocation(const swift::SourceManager& sourceManager,
|
||||
swift::SourceLoc start,
|
||||
swift::SourceLoc end,
|
||||
TrapLabel<LocatableTag> locatableLabel);
|
||||
|
||||
void emitFile(llvm::StringRef path);
|
||||
|
||||
private:
|
||||
TrapLabel<FileTag> fetchFileLabel(const std::filesystem::path& file);
|
||||
TrapDomain& trap;
|
||||
std::unordered_map<std::filesystem::path, TrapLabel<FileTag>> store;
|
||||
};
|
||||
|
||||
} // namespace codeql
|
||||
11
swift/extractor/invocation/BUILD.bazel
Normal file
11
swift/extractor/invocation/BUILD.bazel
Normal file
@@ -0,0 +1,11 @@
|
||||
load("//swift:rules.bzl", "swift_cc_library")
|
||||
|
||||
swift_cc_library(
|
||||
name = "invocation",
|
||||
srcs = glob(["*.cpp"]),
|
||||
hdrs = glob(["*.h"]),
|
||||
visibility = ["//swift:__subpackages__"],
|
||||
deps = [
|
||||
"//swift/extractor/infra",
|
||||
],
|
||||
)
|
||||
31
swift/extractor/invocation/SwiftDiagnosticsConsumer.cpp
Normal file
31
swift/extractor/invocation/SwiftDiagnosticsConsumer.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "swift/extractor/invocation/SwiftDiagnosticsConsumer.h"
|
||||
#include "swift/extractor/trap/generated/TrapEntries.h"
|
||||
#include "swift/extractor/trap/TrapDomain.h"
|
||||
#include "swift/extractor/infra/SwiftDiagnosticKind.h"
|
||||
|
||||
#include <swift/AST/DiagnosticEngine.h>
|
||||
#include <swift/Basic/SourceManager.h>
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <string>
|
||||
|
||||
using namespace codeql;
|
||||
|
||||
void SwiftDiagnosticsConsumer::handleDiagnostic(swift::SourceManager& sourceManager,
|
||||
const swift::DiagnosticInfo& diagInfo) {
|
||||
auto message = getDiagMessage(sourceManager, diagInfo);
|
||||
DiagnosticsTrap diag{};
|
||||
diag.id = trap.createLabel<DiagnosticsTag>();
|
||||
diag.kind = translateDiagnosticsKind(diagInfo.Kind);
|
||||
diag.text = message;
|
||||
trap.emit(diag);
|
||||
locationExtractor.attachLocation(sourceManager, diagInfo.Loc, diagInfo.Loc, diag.id);
|
||||
}
|
||||
|
||||
std::string SwiftDiagnosticsConsumer::getDiagMessage(swift::SourceManager& sourceManager,
|
||||
const swift::DiagnosticInfo& diagInfo) {
|
||||
llvm::SmallString<256> text;
|
||||
llvm::raw_svector_ostream out(text);
|
||||
swift::DiagnosticEngine::formatDiagnosticText(out, diagInfo.FormatString, diagInfo.FormatArgs);
|
||||
return text.str().str();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user