diff --git a/.github/actions/cache-query-compilation/action.yml b/.github/actions/cache-query-compilation/action.yml new file mode 100644 index 00000000000..c071aa204d9 --- /dev/null +++ b/.github/actions/cache-query-compilation/action.yml @@ -0,0 +1,60 @@ +name: Cache query compilation +description: Caches CodeQL compilation caches - should be run both on PRs and pushes to main. + +inputs: + key: + description: 'The cache key to use - should be unique to the workflow' + required: true + +outputs: + cache-dir: + description: "The directory where the cache was stored" + value: ${{ steps.fill-compilation-dir.outputs.compdir }} + +runs: + using: composite + steps: + # Cache the query compilation caches. + # calculate the merge-base with main, in a way that works both on PRs and pushes to main. + - name: Calculate merge-base + shell: bash + if: ${{ github.event_name == 'pull_request' }} + env: + BASE_BRANCH: ${{ github.base_ref }} + run: | + MERGE_BASE=$(git cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ") + echo "merge_base=$MERGE_BASE" >> $GITHUB_ENV + - name: Read CodeQL query compilation - PR + if: ${{ github.event_name == 'pull_request' }} + uses: actions/cache@v3 + with: + path: '**/.cache' + key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }} # deliberately not using the `compile-compile-main` keys here. + restore-keys: | + codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }} + codeql-compile-${{ inputs.key }}-${{ github.base_ref }}- + codeql-compile-${{ inputs.key }}-main- + - name: Fill CodeQL query compilation cache - main + if: ${{ github.event_name != 'pull_request' }} + uses: actions/cache@v3 + with: + path: '**/.cache' + key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main + restore-keys: | # restore from another random commit, to speed up compilation. + codeql-compile-${{ inputs.key }}-${{ github.ref_name }}- + codeql-compile-${{ inputs.key }}-main- + - name: Fill compilation cache directory + id: fill-compilation-dir + shell: bash + run: | + # Move all the existing cache into another folder, so we only preserve the cache for the current queries. + mkdir -p ${COMBINED_CACHE_DIR} + rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty. + # copy the contents of the .cache folders into the combined cache folder. + cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files + # clean up the .cache folders + rm -rf **/.cache/* + + echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT + env: + COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir \ No newline at end of file diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml index 94378250c85..ee6d48c45ea 100644 --- a/.github/workflows/compile-queries.yml +++ b/.github/workflows/compile-queries.yml @@ -14,58 +14,26 @@ jobs: steps: - uses: actions/checkout@v3 - # 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 cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ") - echo "merge-base=$MERGE_BASE" >> $GITHUB_ENV - - name: Read CodeQL query compilation - PR - if: ${{ github.event_name == 'pull_request' }} - uses: actions/cache@v3 - with: - path: '*/ql/src/.cache' - key: codeql-compile-pr-${{ github.sha }} # deliberately not using the `compile-compile-main` keys here. - restore-keys: | - 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: channel: 'release' + - name: Cache compilation cache + id: query-cache + uses: ./.github/actions/cache-query-compilation + with: + key: all-queries - name: check formatting run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --check-only - name: compile queries - check-only # run with --check-only if running in a PR (github.sha != main) if : ${{ github.event_name == 'pull_request' }} shell: bash - run: codeql query compile -j0 */ql/src --keep-going --warnings=error --check-only + run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" - name: compile queries - full # do full compile if running on main - this populates the cache if : ${{ github.event_name != 'pull_request' }} shell: bash - run: | - # Move all the existing cache into another folder, so we only preserve the cache for the current queries. - mkdir -p ${COMBINED_CACHE_DIR} - rm */ql/src/.cache/{lock,size} - # copy the contents of the .cache folders into the combined cache folder. - cp -r */ql/src/.cache/* ${COMBINED_CACHE_DIR}/ - # clean up the .cache folders - rm -rf */ql/src/.cache/* - - # compile the queries - codeql query compile -j0 */ql/src --keep-going --warnings=error --compilation-cache ${COMBINED_CACHE_DIR} + run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" env: COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir \ No newline at end of file diff --git a/.github/workflows/ql-for-ql-tests.yml b/.github/workflows/ql-for-ql-tests.yml index b820d00a3e4..ce7963e8f79 100644 --- a/.github/workflows/ql-for-ql-tests.yml +++ b/.github/workflows/ql-for-ql-tests.yml @@ -47,8 +47,3 @@ jobs: find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only env: CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} - - name: Check QL compilation - run: | - "${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples" - env: - CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} diff --git a/.github/workflows/ruby-build.yml b/.github/workflows/ruby-build.yml index f7ec215a44a..784a7db3dc9 100644 --- a/.github/workflows/ruby-build.yml +++ b/.github/workflows/ruby-build.yml @@ -86,19 +86,23 @@ jobs: ruby/target/release/ruby-extractor.exe retention-days: 1 compile-queries: - runs-on: ubuntu-latest - env: - CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI + runs-on: ubuntu-latest-xl steps: - uses: actions/checkout@v3 - name: Fetch CodeQL uses: ./.github/actions/fetch-codeql + - name: Cache compilation cache + id: query-cache + uses: ./.github/actions/cache-query-compilation + with: + key: ruby-build - name: Build Query Pack run: | codeql pack create ../shared/ssa --output target/packs codeql pack create ../misc/suite-helpers --output target/packs + codeql pack create ../shared/regex --output target/packs codeql pack create ql/lib --output target/packs - codeql pack create ql/src --output target/packs + codeql pack create -j0 ql/src --output target/packs --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*) codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src (cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;) diff --git a/.github/workflows/ruby-qltest.yml b/.github/workflows/ruby-qltest.yml index 125e2694fb0..d8af552c8c6 100644 --- a/.github/workflows/ruby-qltest.yml +++ b/.github/workflows/ruby-qltest.yml @@ -4,7 +4,7 @@ on: push: paths: - "ruby/**" - - .github/workflows/ruby-qltest.yml + - .github/workflows/ruby-build.yml - .github/actions/fetch-codeql/action.yml - codeql-workspace.yml branches: @@ -28,16 +28,6 @@ defaults: working-directory: ruby jobs: - qlcompile: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: ./.github/actions/fetch-codeql - - name: Check QL compilation - run: | - codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples" - env: - GITHUB_TOKEN: ${{ github.token }} qlupgrade: runs-on: ubuntu-latest steps: @@ -58,17 +48,20 @@ jobs: xargs codeql execute upgrades testdb diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme qltest: - runs-on: ubuntu-latest + runs-on: ubuntu-latest-xl strategy: fail-fast: false - matrix: - slice: ["1/2", "2/2"] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/fetch-codeql - uses: ./ruby/actions/create-extractor-pack + - name: Cache compilation cache + id: query-cache + uses: ./.github/actions/cache-query-compilation + with: + key: ruby-qltest - name: Run QL tests run: | - codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test + codeql test run --threads=0 --ram 52000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" env: GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 797d950ee57..99579421adf 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -39,6 +39,7 @@ jobs: - 'swift/ql/lib/codeql/swift/elements/**' - 'swift/ql/lib/codeql/swift/generated/**' - 'swift/ql/test/extractor-tests/generated/**' + - 'swift/ql/.generated.list' ql: - 'github/workflows/swift.yml' - 'swift/**/*.ql' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14845337b36..5f35c2c183b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: - id: swift-codegen name: Run Swift checked in code generation - files: ^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)) + files: ^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)|ql/\.generated.list) language: system entry: bazel run //swift/codegen -- --quiet pass_filenames: false diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index 0a7a31b8db9..30a996fdba6 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.4 + +No user-facing changes. + ## 0.4.3 ### Minor Analysis Improvements diff --git a/cpp/ql/lib/change-notes/2022-11-14-deprecate-ast-gvn.md b/cpp/ql/lib/change-notes/2022-11-14-deprecate-ast-gvn.md new file mode 100644 index 00000000000..eb6bd755c2b --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-11-14-deprecate-ast-gvn.md @@ -0,0 +1,6 @@ +--- +category: deprecated +--- + + +* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/2022-11-16-must-flow.md b/cpp/ql/lib/change-notes/2022-11-16-must-flow.md new file mode 100644 index 00000000000..0f87b8d8bcd --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-11-16-must-flow.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes. diff --git a/cpp/ql/lib/change-notes/2022-11-17-deleted-deps.md b/cpp/ql/lib/change-notes/2022-11-17-deleted-deps.md new file mode 100644 index 00000000000..bf2d5a07de6 --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-11-17-deleted-deps.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/released/0.4.4.md b/cpp/ql/lib/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..33e1c91255d --- /dev/null +++ b/cpp/ql/lib/change-notes/released/0.4.4.md @@ -0,0 +1,3 @@ +## 0.4.4 + +No user-facing changes. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index ef1fd2099a3..4e0b86be561 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.4.4-dev +version: 0.4.5-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/lib/semmle/code/cpp/File.qll b/cpp/ql/lib/semmle/code/cpp/File.qll index e58467fac20..b2e4e0a41a5 100644 --- a/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/cpp/ql/lib/semmle/code/cpp/File.qll @@ -189,18 +189,6 @@ class Folder extends Container, @folder { * Gets the URL of this folder. */ deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - - /** - * DEPRECATED: use `getAbsolutePath` instead. - * Gets the name of this folder. - */ - deprecated string getName() { folders(underlyingElement(this), result) } - - /** - * DEPRECATED: use `getBaseName` instead. - * Gets the last part of the folder name. - */ - deprecated string getShortName() { result = this.getBaseName() } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll index 08ee06acdda..904701144ca 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll @@ -5,7 +5,6 @@ */ private import cpp -import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.IR /** @@ -25,18 +24,18 @@ abstract class MustFlowConfiguration extends string { /** * Holds if `source` is a relevant data flow source. */ - abstract predicate isSource(DataFlow::Node source); + abstract predicate isSource(Instruction source); /** * Holds if `sink` is a relevant data flow sink. */ - abstract predicate isSink(DataFlow::Node sink); + abstract predicate isSink(Operand sink); /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. */ - predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() } /** Holds if this configuration allows flow from arguments to parameters. */ predicate allowInterproceduralFlow() { any() } @@ -48,17 +47,17 @@ abstract class MustFlowConfiguration extends string { * included in the module `PathGraph`. */ final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) { - this.isSource(source.getNode()) and + this.isSource(source.getInstruction()) and source.getASuccessor+() = sink } } /** Holds if `node` flows from a source. */ pragma[nomagic] -private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration config) { +private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) { config.isSource(node) or - exists(DataFlow::Node mid | + exists(Instruction mid | step(mid, node, config) and flowsFromSource(mid, pragma[only_bind_into](config)) ) @@ -66,12 +65,12 @@ private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration con /** Holds if `node` flows to a sink. */ pragma[nomagic] -private predicate flowsToSink(DataFlow::Node node, MustFlowConfiguration config) { +private predicate flowsToSink(Instruction node, MustFlowConfiguration config) { flowsFromSource(node, pragma[only_bind_into](config)) and ( - config.isSink(node) + config.isSink(node.getAUse()) or - exists(DataFlow::Node mid | + exists(Instruction mid | step(node, mid, config) and flowsToSink(mid, pragma[only_bind_into](config)) ) @@ -198,12 +197,13 @@ private module Cached { } cached - predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - instructionToOperandStep(nodeFrom.asInstruction(), nodeTo.asOperand()) + predicate step(Instruction nodeFrom, Instruction nodeTo) { + exists(Operand mid | + instructionToOperandStep(nodeFrom, mid) and + operandToInstructionStep(mid, nodeTo) + ) or - flowThroughCallable(nodeFrom.asInstruction(), nodeTo.asInstruction()) - or - operandToInstructionStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + flowThroughCallable(nodeFrom, nodeTo) } } @@ -213,12 +213,12 @@ private module Cached { * way around. */ pragma[inline] -private Declaration getEnclosingCallable(DataFlow::Node n) { - pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingCallable() +private IRFunction getEnclosingCallable(Instruction n) { + pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction() } /** Holds if `nodeFrom` flows to `nodeTo`. */ -private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) { +private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) { exists(config) and Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and ( @@ -227,37 +227,37 @@ private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowC getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo) ) or - config.isAdditionalFlowStep(nodeFrom, nodeTo) + config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo) } private newtype TLocalPathNode = - MkLocalPathNode(DataFlow::Node n, MustFlowConfiguration config) { + MkLocalPathNode(Instruction n, MustFlowConfiguration config) { flowsToSink(n, config) and ( config.isSource(n) or - exists(MustFlowPathNode mid | step(mid.getNode(), n, config)) + exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config)) ) } /** A `Node` that is in a path from a source to a sink. */ class MustFlowPathNode extends TLocalPathNode { - DataFlow::Node n; + Instruction n; MustFlowPathNode() { this = MkLocalPathNode(n, _) } /** Gets the underlying node. */ - DataFlow::Node getNode() { result = n } + Instruction getInstruction() { result = n } /** Gets a textual representation of this node. */ - string toString() { result = n.toString() } + string toString() { result = n.getAst().toString() } /** Gets the location of this element. */ Location getLocation() { result = n.getLocation() } /** Gets a successor node, if any. */ MustFlowPathNode getASuccessor() { - step(this.getNode(), result.getNode(), this.getConfiguration()) + step(this.getInstruction(), result.getInstruction(), this.getConfiguration()) } /** Gets the associated configuration. */ @@ -265,7 +265,7 @@ class MustFlowPathNode extends TLocalPathNode { } private class MustFlowPathSink extends MustFlowPathNode { - MustFlowPathSink() { this.getConfiguration().isSink(this.getNode()) } + MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll b/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll index 7dd55dbfde3..10e3d3ba1c2 100644 --- a/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll @@ -1,4 +1,8 @@ /** + * DEPRECATED: This library has been replaced with a newer version which + * provides better performance and precision. Use + * `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead. + * * Provides an implementation of Global Value Numbering. * See https://en.wikipedia.org/wiki/Global_value_numbering * @@ -221,7 +225,7 @@ private newtype GvnBase = * expression with this `GVN` and using its `toString` and `getLocation` * methods. */ -class GVN extends GvnBase { +deprecated class GVN extends GvnBase { GVN() { this instanceof GvnBase } /** Gets an expression that has this GVN. */ @@ -503,7 +507,7 @@ private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceE /** Gets the global value number of expression `e`. */ cached -GVN globalValueNumber(Expr e) { +deprecated GVN globalValueNumber(Expr e) { exists(int val, Type t | mk_IntConst(val, t, e) and result = GVN_IntConst(val, t) diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index f32f416b540..5546105176e 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.4 + +No user-facing changes. + ## 0.4.3 ### Minor Analysis Improvements diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql index 26c8ae4c258..af4bd8c61a3 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql @@ -26,11 +26,11 @@ predicate intentionallyReturnsStackPointer(Function f) { class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" } - override predicate isSource(DataFlow::Node source) { + override predicate isSource(Instruction source) { // Holds if `source` is a node that represents the use of a stack variable exists(VariableAddressInstruction var, Function func | - var = source.asInstruction() and - func = var.getEnclosingFunction() and + var = source and + func = source.getEnclosingFunction() and var.getAstVariable() instanceof StackVariable and // Pointer-to-member types aren't properly handled in the dbscheme. not var.getResultType() instanceof PointerToMemberType and @@ -40,7 +40,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { ) } - override predicate isSink(DataFlow::Node sink) { + override predicate isSink(Operand sink) { // Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in // a `ReturnValueInstruction`. // We use the `StoreInstruction` instead of the instruction that defines the @@ -48,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { exists(StoreInstruction store | store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof IRReturnVariable and - sink.asOperand() = store.getSourceValueOperand() + sink = store.getSourceValueOperand() ) } @@ -77,10 +77,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { * } * ``` */ - override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - node2.asInstruction().(FieldAddressInstruction).getObjectAddressOperand() = node1.asOperand() + override predicate isAdditionalFlowStep(Operand node1, Instruction node2) { + node2.(FieldAddressInstruction).getObjectAddressOperand() = node1 or - node2.asInstruction().(PointerOffsetInstruction).getLeftOperand() = node1.asOperand() + node2.(PointerOffsetInstruction).getLeftOperand() = node1 } } @@ -89,6 +89,6 @@ from ReturnStackAllocatedMemoryConfig conf where conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and - source.getNode().asInstruction() = var -select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(), - var.getAst().toString() + source.getInstruction() = var +select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.", + var.getAst(), var.getAst().toString() diff --git a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql index db1816f7a72..bb62cfc1755 100644 --- a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql +++ b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql @@ -22,37 +22,40 @@ import PathGraph class UnsafeUseOfThisConfig extends MustFlowConfiguration { UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" } - override predicate isSource(DataFlow::Node source) { isSource(source, _, _) } + override predicate isSource(Instruction source) { isSource(source, _, _) } - override predicate isSink(DataFlow::Node sink) { isSink(sink, _) } + override predicate isSink(Operand sink) { isSink(sink, _) } } -/** Holds if `instr` is a `this` pointer used by the call instruction `call`. */ -predicate isSink(DataFlow::Node sink, CallInstruction call) { +/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */ +predicate isSink(Operand sink, CallInstruction call) { exists(PureVirtualFunction func | call.getStaticCallTarget() = func and - call.getThisArgument() = sink.asInstruction() and + call.getThisArgumentOperand() = sink and // Weed out implicit calls to destructors of a base class not func instanceof Destructor ) } -/** Holds if `init` initializes the `this` pointer in class `c`. */ -predicate isSource(DataFlow::Node source, string msg, Class c) { - exists(InitializeParameterInstruction init | init = source.asInstruction() | - ( - exists(Constructor func | - not func instanceof CopyConstructor and - not func instanceof MoveConstructor and - func = init.getEnclosingFunction() and - msg = "construction" - ) - or - init.getEnclosingFunction() instanceof Destructor and msg = "destruction" - ) and - init.getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction().getDeclaringType() = c - ) +/** + * Holds if `source` initializes the `this` pointer in class `c`. + * + * The string `msg` describes whether the enclosing function is a + * constructor or destructor. + */ +predicate isSource(InitializeParameterInstruction source, string msg, Class c) { + ( + exists(Constructor func | + not func instanceof CopyConstructor and + not func instanceof MoveConstructor and + func = source.getEnclosingFunction() and + msg = "construction" + ) + or + source.getEnclosingFunction() instanceof Destructor and msg = "destruction" + ) and + source.getIRVariable() instanceof IRThisVariable and + source.getEnclosingFunction().getDeclaringType() = c } /** @@ -68,8 +71,8 @@ predicate flows( ) { exists(UnsafeUseOfThisConfig conf | conf.hasFlowPath(source, sink) and - isSource(source.getNode(), msg, sourceClass) and - isSink(sink.getNode(), call) + isSource(source.getInstruction(), msg, sourceClass) and + isSink(sink.getInstruction().getAUse(), call) ) } diff --git a/cpp/ql/src/change-notes/released/0.4.4.md b/cpp/ql/src/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..33e1c91255d --- /dev/null +++ b/cpp/ql/src/change-notes/released/0.4.4.md @@ -0,0 +1,3 @@ +## 0.4.4 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 3a44ef8b743..75602332e29 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.4.4-dev +version: 0.4.5-dev groups: - cpp - queries diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected index d5d46ee0b72..69c21b5e0b1 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_gvn.expected @@ -1,3 +1,4 @@ +WARNING: Type GVN has been deprecated and may be removed in future (ast_gvn.ql:4,6-9) | test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 | | test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 | | test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 | diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected index e69de29bb2d..d94d58ad5ea 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ast_uniqueness.expected @@ -0,0 +1,3 @@ +WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:7,13-30) +WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:8,30-47) +WARNING: Type GVN has been deprecated and may be removed in future (ast_uniqueness.ql:8,18-21) diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected index b838a13d5af..810c83f197f 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected @@ -1,3 +1,4 @@ +WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (diff_ir_expr.ql:8,29-51) | test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only | | test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only | | test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only | diff --git a/cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/UnsafeUseOfThis.expected b/cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/UnsafeUseOfThis.expected index 067ba7ab4fc..7f1ee1356ab 100644 --- a/cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/UnsafeUseOfThis.expected +++ b/cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/UnsafeUseOfThis.expected @@ -1,103 +1,61 @@ edges -| test.cpp:7:3:7:3 | this | test.cpp:8:12:8:15 | Load | -| test.cpp:8:12:8:15 | Load | test.cpp:8:12:8:15 | this | +| test.cpp:7:3:7:3 | B | test.cpp:8:12:8:15 | this | | test.cpp:8:12:8:15 | this | test.cpp:34:16:34:16 | x | -| test.cpp:11:8:11:8 | b | test.cpp:12:5:12:5 | Load | -| test.cpp:12:5:12:5 | (reference dereference) | test.cpp:12:5:12:5 | Unary | -| test.cpp:12:5:12:5 | Load | test.cpp:12:5:12:5 | b | -| test.cpp:12:5:12:5 | Unary | test.cpp:12:5:12:5 | (A)... | -| test.cpp:12:5:12:5 | Unary | test.cpp:12:5:12:5 | (reference dereference) | -| test.cpp:12:5:12:5 | b | test.cpp:12:5:12:5 | Unary | -| test.cpp:15:3:15:4 | this | test.cpp:16:5:16:5 | Load | -| test.cpp:16:5:16:5 | Load | test.cpp:16:5:16:5 | this | -| test.cpp:16:5:16:5 | Unary | file://:0:0:0:0 | (A *)... | -| test.cpp:16:5:16:5 | this | test.cpp:16:5:16:5 | Unary | -| test.cpp:21:3:21:3 | Unary | test.cpp:21:13:21:13 | ConvertToNonVirtualBase | -| test.cpp:21:3:21:3 | this | test.cpp:21:3:21:3 | Unary | -| test.cpp:21:3:21:3 | this | test.cpp:22:12:22:15 | Load | -| test.cpp:21:3:21:3 | this | test.cpp:25:7:25:10 | Load | -| test.cpp:21:13:21:13 | ConvertToNonVirtualBase | test.cpp:7:3:7:3 | this | +| test.cpp:11:8:11:8 | b | test.cpp:12:5:12:5 | b | +| test.cpp:12:5:12:5 | (reference dereference) | test.cpp:12:5:12:5 | (A)... | +| test.cpp:12:5:12:5 | b | test.cpp:12:5:12:5 | (reference dereference) | +| test.cpp:15:3:15:4 | ~B | test.cpp:16:5:16:5 | this | +| test.cpp:16:5:16:5 | this | file://:0:0:0:0 | (A *)... | +| test.cpp:21:3:21:3 | C | test.cpp:21:13:21:13 | call to B | +| test.cpp:21:3:21:3 | C | test.cpp:22:12:22:15 | this | +| test.cpp:21:3:21:3 | C | test.cpp:25:7:25:10 | this | +| test.cpp:21:13:21:13 | call to B | test.cpp:7:3:7:3 | B | | test.cpp:22:12:22:15 | (B *)... | test.cpp:34:16:34:16 | x | -| test.cpp:22:12:22:15 | Load | test.cpp:22:12:22:15 | this | -| test.cpp:22:12:22:15 | Unary | test.cpp:22:12:22:15 | (B *)... | -| test.cpp:22:12:22:15 | this | test.cpp:22:12:22:15 | Unary | -| test.cpp:25:7:25:10 | (B *)... | test.cpp:25:7:25:10 | Unary | -| test.cpp:25:7:25:10 | Load | test.cpp:25:7:25:10 | this | -| test.cpp:25:7:25:10 | Unary | test.cpp:25:7:25:10 | (A *)... | -| test.cpp:25:7:25:10 | Unary | test.cpp:25:7:25:10 | (B *)... | -| test.cpp:25:7:25:10 | this | test.cpp:25:7:25:10 | Unary | -| test.cpp:31:3:31:3 | this | test.cpp:31:12:31:15 | Load | -| test.cpp:31:11:31:15 | (B)... | test.cpp:31:11:31:15 | Unary | +| test.cpp:22:12:22:15 | this | test.cpp:22:12:22:15 | (B *)... | +| test.cpp:25:7:25:10 | (B *)... | test.cpp:25:7:25:10 | (A *)... | +| test.cpp:25:7:25:10 | this | test.cpp:25:7:25:10 | (B *)... | +| test.cpp:31:3:31:3 | D | test.cpp:31:12:31:15 | this | +| test.cpp:31:11:31:15 | (B)... | test.cpp:31:11:31:15 | (reference to) | | test.cpp:31:11:31:15 | (reference to) | test.cpp:11:8:11:8 | b | -| test.cpp:31:11:31:15 | * ... | test.cpp:31:11:31:15 | Unary | -| test.cpp:31:11:31:15 | Unary | test.cpp:31:11:31:15 | (B)... | -| test.cpp:31:11:31:15 | Unary | test.cpp:31:11:31:15 | (reference to) | -| test.cpp:31:12:31:15 | Load | test.cpp:31:12:31:15 | this | -| test.cpp:31:12:31:15 | Unary | test.cpp:31:11:31:15 | * ... | -| test.cpp:31:12:31:15 | this | test.cpp:31:12:31:15 | Unary | -| test.cpp:34:16:34:16 | x | test.cpp:35:3:35:3 | Load | -| test.cpp:35:3:35:3 | Load | test.cpp:35:3:35:3 | x | -| test.cpp:35:3:35:3 | Unary | test.cpp:35:3:35:3 | (A *)... | -| test.cpp:35:3:35:3 | x | test.cpp:35:3:35:3 | Unary | -| test.cpp:47:3:47:3 | this | test.cpp:48:10:48:13 | Load | -| test.cpp:48:10:48:13 | (E *)... | test.cpp:48:10:48:13 | Unary | -| test.cpp:48:10:48:13 | Load | test.cpp:48:10:48:13 | this | -| test.cpp:48:10:48:13 | Unary | test.cpp:48:6:48:13 | (A *)... | -| test.cpp:48:10:48:13 | Unary | test.cpp:48:10:48:13 | (E *)... | -| test.cpp:48:10:48:13 | this | test.cpp:48:10:48:13 | Unary | +| test.cpp:31:11:31:15 | * ... | test.cpp:31:11:31:15 | (B)... | +| test.cpp:31:12:31:15 | this | test.cpp:31:11:31:15 | * ... | +| test.cpp:34:16:34:16 | x | test.cpp:35:3:35:3 | x | +| test.cpp:35:3:35:3 | x | test.cpp:35:3:35:3 | (A *)... | +| test.cpp:47:3:47:3 | F | test.cpp:48:10:48:13 | this | +| test.cpp:48:10:48:13 | (E *)... | test.cpp:48:6:48:13 | (A *)... | +| test.cpp:48:10:48:13 | this | test.cpp:48:10:48:13 | (E *)... | nodes | file://:0:0:0:0 | (A *)... | semmle.label | (A *)... | -| test.cpp:7:3:7:3 | this | semmle.label | this | -| test.cpp:8:12:8:15 | Load | semmle.label | Load | +| test.cpp:7:3:7:3 | B | semmle.label | B | | test.cpp:8:12:8:15 | this | semmle.label | this | | test.cpp:11:8:11:8 | b | semmle.label | b | | test.cpp:12:5:12:5 | (A)... | semmle.label | (A)... | | test.cpp:12:5:12:5 | (reference dereference) | semmle.label | (reference dereference) | -| test.cpp:12:5:12:5 | Load | semmle.label | Load | -| test.cpp:12:5:12:5 | Unary | semmle.label | Unary | -| test.cpp:12:5:12:5 | Unary | semmle.label | Unary | | test.cpp:12:5:12:5 | b | semmle.label | b | -| test.cpp:15:3:15:4 | this | semmle.label | this | -| test.cpp:16:5:16:5 | Load | semmle.label | Load | -| test.cpp:16:5:16:5 | Unary | semmle.label | Unary | +| test.cpp:15:3:15:4 | ~B | semmle.label | ~B | | test.cpp:16:5:16:5 | this | semmle.label | this | -| test.cpp:21:3:21:3 | Unary | semmle.label | Unary | -| test.cpp:21:3:21:3 | this | semmle.label | this | -| test.cpp:21:13:21:13 | ConvertToNonVirtualBase | semmle.label | ConvertToNonVirtualBase | +| test.cpp:21:3:21:3 | C | semmle.label | C | +| test.cpp:21:13:21:13 | call to B | semmle.label | call to B | | test.cpp:22:12:22:15 | (B *)... | semmle.label | (B *)... | -| test.cpp:22:12:22:15 | Load | semmle.label | Load | -| test.cpp:22:12:22:15 | Unary | semmle.label | Unary | | test.cpp:22:12:22:15 | this | semmle.label | this | | test.cpp:25:7:25:10 | (A *)... | semmle.label | (A *)... | | test.cpp:25:7:25:10 | (B *)... | semmle.label | (B *)... | -| test.cpp:25:7:25:10 | Load | semmle.label | Load | -| test.cpp:25:7:25:10 | Unary | semmle.label | Unary | -| test.cpp:25:7:25:10 | Unary | semmle.label | Unary | | test.cpp:25:7:25:10 | this | semmle.label | this | -| test.cpp:31:3:31:3 | this | semmle.label | this | +| test.cpp:31:3:31:3 | D | semmle.label | D | | test.cpp:31:11:31:15 | (B)... | semmle.label | (B)... | | test.cpp:31:11:31:15 | (reference to) | semmle.label | (reference to) | | test.cpp:31:11:31:15 | * ... | semmle.label | * ... | -| test.cpp:31:11:31:15 | Unary | semmle.label | Unary | -| test.cpp:31:11:31:15 | Unary | semmle.label | Unary | -| test.cpp:31:12:31:15 | Load | semmle.label | Load | -| test.cpp:31:12:31:15 | Unary | semmle.label | Unary | | test.cpp:31:12:31:15 | this | semmle.label | this | | test.cpp:34:16:34:16 | x | semmle.label | x | | test.cpp:35:3:35:3 | (A *)... | semmle.label | (A *)... | -| test.cpp:35:3:35:3 | Load | semmle.label | Load | -| test.cpp:35:3:35:3 | Unary | semmle.label | Unary | | test.cpp:35:3:35:3 | x | semmle.label | x | -| test.cpp:47:3:47:3 | this | semmle.label | this | +| test.cpp:47:3:47:3 | F | semmle.label | F | | test.cpp:48:6:48:13 | (A *)... | semmle.label | (A *)... | | test.cpp:48:10:48:13 | (E *)... | semmle.label | (E *)... | -| test.cpp:48:10:48:13 | Load | semmle.label | Load | -| test.cpp:48:10:48:13 | Unary | semmle.label | Unary | -| test.cpp:48:10:48:13 | Unary | semmle.label | Unary | | test.cpp:48:10:48:13 | this | semmle.label | this | #select -| test.cpp:12:7:12:7 | call to f | test.cpp:31:3:31:3 | this | test.cpp:12:5:12:5 | (A)... | Call to pure virtual function during construction. | -| test.cpp:16:5:16:5 | call to f | test.cpp:15:3:15:4 | this | file://:0:0:0:0 | (A *)... | Call to pure virtual function during destruction. | -| test.cpp:25:13:25:13 | call to f | test.cpp:21:3:21:3 | this | test.cpp:25:7:25:10 | (A *)... | Call to pure virtual function during construction. | -| test.cpp:35:6:35:6 | call to f | test.cpp:7:3:7:3 | this | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. | -| test.cpp:35:6:35:6 | call to f | test.cpp:21:3:21:3 | this | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. | +| test.cpp:12:7:12:7 | call to f | test.cpp:31:3:31:3 | D | test.cpp:12:5:12:5 | (A)... | Call to pure virtual function during construction. | +| test.cpp:16:5:16:5 | call to f | test.cpp:15:3:15:4 | ~B | file://:0:0:0:0 | (A *)... | Call to pure virtual function during destruction. | +| test.cpp:25:13:25:13 | call to f | test.cpp:21:3:21:3 | C | test.cpp:25:7:25:10 | (A *)... | Call to pure virtual function during construction. | +| test.cpp:35:6:35:6 | call to f | test.cpp:7:3:7:3 | B | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. | +| test.cpp:35:6:35:6 | call to f | test.cpp:21:3:21:3 | C | test.cpp:35:3:35:3 | (A *)... | Call to pure virtual function during construction. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected index 8f9d91fc1ad..b7b598a13c5 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected @@ -1,231 +1,117 @@ edges -| test.cpp:17:9:17:11 | & ... | test.cpp:17:9:17:11 | StoreValue | -| test.cpp:17:10:17:11 | Unary | test.cpp:17:9:17:11 | & ... | -| test.cpp:17:10:17:11 | mc | test.cpp:17:10:17:11 | Unary | -| test.cpp:23:17:23:19 | & ... | test.cpp:23:17:23:19 | StoreValue | -| test.cpp:23:17:23:19 | Store | test.cpp:25:9:25:11 | Load | -| test.cpp:23:17:23:19 | StoreValue | test.cpp:23:17:23:19 | Store | -| test.cpp:23:18:23:19 | Unary | test.cpp:23:17:23:19 | & ... | -| test.cpp:23:18:23:19 | mc | test.cpp:23:18:23:19 | Unary | -| test.cpp:25:9:25:11 | Load | test.cpp:25:9:25:11 | ptr | -| test.cpp:25:9:25:11 | ptr | test.cpp:25:9:25:11 | StoreValue | -| test.cpp:39:17:39:18 | (reference to) | test.cpp:39:17:39:18 | StoreValue | -| test.cpp:39:17:39:18 | Store | test.cpp:41:10:41:12 | Load | -| test.cpp:39:17:39:18 | StoreValue | test.cpp:39:17:39:18 | Store | -| test.cpp:39:17:39:18 | Unary | test.cpp:39:17:39:18 | (reference to) | -| test.cpp:39:17:39:18 | mc | test.cpp:39:17:39:18 | Unary | -| test.cpp:41:9:41:12 | & ... | test.cpp:41:9:41:12 | StoreValue | -| test.cpp:41:10:41:12 | (reference dereference) | test.cpp:41:10:41:12 | Unary | -| test.cpp:41:10:41:12 | Load | test.cpp:41:10:41:12 | ref | -| test.cpp:41:10:41:12 | Unary | test.cpp:41:9:41:12 | & ... | -| test.cpp:41:10:41:12 | Unary | test.cpp:41:10:41:12 | (reference dereference) | -| test.cpp:41:10:41:12 | ref | test.cpp:41:10:41:12 | Unary | -| test.cpp:47:9:47:10 | (reference to) | test.cpp:47:9:47:10 | StoreValue | -| test.cpp:47:9:47:10 | Unary | test.cpp:47:9:47:10 | (reference to) | -| test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | Unary | -| test.cpp:54:9:54:15 | & ... | test.cpp:54:9:54:15 | StoreValue | -| test.cpp:54:11:54:12 | Unary | test.cpp:54:14:54:14 | a | -| test.cpp:54:11:54:12 | mc | test.cpp:54:11:54:12 | Unary | -| test.cpp:54:14:54:14 | Unary | test.cpp:54:9:54:15 | & ... | -| test.cpp:54:14:54:14 | a | test.cpp:54:14:54:14 | Unary | -| test.cpp:89:3:89:11 | Store | test.cpp:92:9:92:11 | Load | -| test.cpp:89:9:89:11 | & ... | test.cpp:89:9:89:11 | StoreValue | -| test.cpp:89:9:89:11 | StoreValue | test.cpp:89:3:89:11 | Store | -| test.cpp:89:10:89:11 | Unary | test.cpp:89:9:89:11 | & ... | -| test.cpp:89:10:89:11 | mc | test.cpp:89:10:89:11 | Unary | -| test.cpp:92:9:92:11 | Load | test.cpp:92:9:92:11 | ptr | -| test.cpp:92:9:92:11 | ptr | test.cpp:92:9:92:11 | StoreValue | -| test.cpp:112:9:112:11 | Unary | test.cpp:112:9:112:11 | array to pointer conversion | -| test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | Unary | -| test.cpp:112:9:112:11 | array to pointer conversion | test.cpp:112:9:112:11 | StoreValue | -| test.cpp:119:9:119:18 | & ... | test.cpp:119:9:119:18 | StoreValue | -| test.cpp:119:11:119:13 | Left | test.cpp:119:11:119:17 | access to array | -| test.cpp:119:11:119:13 | Unary | test.cpp:119:11:119:13 | array to pointer conversion | -| test.cpp:119:11:119:13 | arr | test.cpp:119:11:119:13 | Unary | -| test.cpp:119:11:119:13 | array to pointer conversion | test.cpp:119:11:119:13 | Left | -| test.cpp:119:11:119:17 | Unary | test.cpp:119:9:119:18 | & ... | -| test.cpp:119:11:119:17 | access to array | test.cpp:119:11:119:17 | Unary | -| test.cpp:134:2:134:14 | Store | test.cpp:135:2:135:4 | Load | -| test.cpp:134:8:134:10 | Left | test.cpp:134:8:134:14 | ... + ... | -| test.cpp:134:8:134:10 | Unary | test.cpp:134:8:134:10 | array to pointer conversion | -| test.cpp:134:8:134:10 | arr | test.cpp:134:8:134:10 | Unary | -| test.cpp:134:8:134:10 | array to pointer conversion | test.cpp:134:8:134:10 | Left | -| test.cpp:134:8:134:14 | ... + ... | test.cpp:134:8:134:14 | StoreValue | -| test.cpp:134:8:134:14 | StoreValue | test.cpp:134:2:134:14 | Store | -| test.cpp:135:2:135:4 | Left | test.cpp:135:2:135:6 | PointerAdd | -| test.cpp:135:2:135:4 | Load | test.cpp:135:2:135:4 | ptr | -| test.cpp:135:2:135:4 | ptr | test.cpp:135:2:135:4 | Left | -| test.cpp:135:2:135:6 | PointerAdd | test.cpp:135:2:135:6 | StoreValue | -| test.cpp:135:2:135:6 | Store | test.cpp:137:9:137:11 | Load | -| test.cpp:135:2:135:6 | StoreValue | test.cpp:135:2:135:6 | Store | -| test.cpp:137:9:137:11 | Load | test.cpp:137:9:137:11 | ptr | -| test.cpp:137:9:137:11 | ptr | test.cpp:137:9:137:11 | StoreValue | -| test.cpp:170:26:170:41 | (void *)... | test.cpp:170:26:170:41 | StoreValue | -| test.cpp:170:26:170:41 | Store | test.cpp:171:10:171:23 | Load | -| test.cpp:170:26:170:41 | StoreValue | test.cpp:170:26:170:41 | Store | -| test.cpp:170:34:170:41 | & ... | test.cpp:170:34:170:41 | Unary | -| test.cpp:170:34:170:41 | Unary | test.cpp:170:26:170:41 | (void *)... | -| test.cpp:170:35:170:41 | Unary | test.cpp:170:34:170:41 | & ... | -| test.cpp:170:35:170:41 | myLocal | test.cpp:170:35:170:41 | Unary | -| test.cpp:171:10:171:23 | Load | test.cpp:171:10:171:23 | pointerToLocal | -| test.cpp:171:10:171:23 | pointerToLocal | test.cpp:171:10:171:23 | StoreValue | -| test.cpp:176:25:176:34 | Store | test.cpp:177:10:177:23 | Load | -| test.cpp:176:25:176:34 | StoreValue | test.cpp:176:25:176:34 | Store | -| test.cpp:176:25:176:34 | Unary | test.cpp:176:25:176:34 | array to pointer conversion | -| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:176:25:176:34 | StoreValue | -| test.cpp:176:25:176:34 | localArray | test.cpp:176:25:176:34 | Unary | -| test.cpp:177:10:177:23 | (void *)... | test.cpp:177:10:177:23 | StoreValue | -| test.cpp:177:10:177:23 | Load | test.cpp:177:10:177:23 | pointerToLocal | -| test.cpp:177:10:177:23 | Unary | test.cpp:177:10:177:23 | (void *)... | -| test.cpp:177:10:177:23 | pointerToLocal | test.cpp:177:10:177:23 | Unary | -| test.cpp:182:21:182:27 | (reference to) | test.cpp:182:21:182:27 | StoreValue | -| test.cpp:182:21:182:27 | Store | test.cpp:183:10:183:19 | Load | -| test.cpp:182:21:182:27 | StoreValue | test.cpp:182:21:182:27 | Store | -| test.cpp:182:21:182:27 | Unary | test.cpp:182:21:182:27 | (reference to) | -| test.cpp:182:21:182:27 | myLocal | test.cpp:182:21:182:27 | Unary | -| test.cpp:183:10:183:19 | (reference dereference) | test.cpp:183:10:183:19 | Unary | -| test.cpp:183:10:183:19 | (reference to) | test.cpp:183:10:183:19 | StoreValue | -| test.cpp:183:10:183:19 | Load | test.cpp:183:10:183:19 | refToLocal | -| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference dereference) | -| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference to) | -| test.cpp:183:10:183:19 | refToLocal | test.cpp:183:10:183:19 | Unary | -| test.cpp:189:16:189:16 | (reference to) | test.cpp:189:16:189:16 | StoreValue | -| test.cpp:189:16:189:16 | Store | test.cpp:190:10:190:13 | Load | -| test.cpp:189:16:189:16 | StoreValue | test.cpp:189:16:189:16 | Store | -| test.cpp:189:16:189:16 | Unary | test.cpp:189:16:189:16 | (reference to) | -| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | Unary | -| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | Unary | -| test.cpp:190:10:190:13 | (reference to) | test.cpp:190:10:190:13 | StoreValue | -| test.cpp:190:10:190:13 | Load | test.cpp:190:10:190:13 | pRef | -| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference dereference) | -| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference to) | -| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | Unary | +| test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | +| test.cpp:23:17:23:19 | & ... | test.cpp:23:17:23:19 | & ... | +| test.cpp:23:17:23:19 | & ... | test.cpp:25:9:25:11 | ptr | +| test.cpp:23:18:23:19 | mc | test.cpp:23:17:23:19 | & ... | +| test.cpp:39:17:39:18 | (reference to) | test.cpp:39:17:39:18 | (reference to) | +| test.cpp:39:17:39:18 | (reference to) | test.cpp:41:10:41:12 | ref | +| test.cpp:39:17:39:18 | mc | test.cpp:39:17:39:18 | (reference to) | +| test.cpp:41:10:41:12 | (reference dereference) | test.cpp:41:9:41:12 | & ... | +| test.cpp:41:10:41:12 | ref | test.cpp:41:10:41:12 | (reference dereference) | +| test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | (reference to) | +| test.cpp:54:11:54:12 | mc | test.cpp:54:14:54:14 | a | +| test.cpp:54:14:54:14 | a | test.cpp:54:9:54:15 | & ... | +| test.cpp:89:3:89:11 | ... = ... | test.cpp:92:9:92:11 | ptr | +| test.cpp:89:9:89:11 | & ... | test.cpp:89:3:89:11 | ... = ... | +| test.cpp:89:10:89:11 | mc | test.cpp:89:9:89:11 | & ... | +| test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | array to pointer conversion | +| test.cpp:119:11:119:13 | arr | test.cpp:119:11:119:13 | array to pointer conversion | +| test.cpp:119:11:119:13 | array to pointer conversion | test.cpp:119:11:119:17 | access to array | +| test.cpp:119:11:119:17 | access to array | test.cpp:119:9:119:18 | & ... | +| test.cpp:134:2:134:14 | ... = ... | test.cpp:135:2:135:4 | ptr | +| test.cpp:134:8:134:10 | arr | test.cpp:134:8:134:10 | array to pointer conversion | +| test.cpp:134:8:134:10 | array to pointer conversion | test.cpp:134:8:134:14 | ... + ... | +| test.cpp:134:8:134:14 | ... + ... | test.cpp:134:2:134:14 | ... = ... | +| test.cpp:135:2:135:4 | ptr | test.cpp:135:2:135:6 | ... ++ | +| test.cpp:135:2:135:6 | ... ++ | test.cpp:135:2:135:6 | ... ++ | +| test.cpp:135:2:135:6 | ... ++ | test.cpp:137:9:137:11 | ptr | +| test.cpp:170:26:170:41 | (void *)... | test.cpp:170:26:170:41 | (void *)... | +| test.cpp:170:26:170:41 | (void *)... | test.cpp:171:10:171:23 | pointerToLocal | +| test.cpp:170:34:170:41 | & ... | test.cpp:170:26:170:41 | (void *)... | +| test.cpp:170:35:170:41 | myLocal | test.cpp:170:34:170:41 | & ... | +| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:176:25:176:34 | array to pointer conversion | +| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:177:10:177:23 | pointerToLocal | +| test.cpp:176:25:176:34 | localArray | test.cpp:176:25:176:34 | array to pointer conversion | +| test.cpp:177:10:177:23 | pointerToLocal | test.cpp:177:10:177:23 | (void *)... | +| test.cpp:182:21:182:27 | (reference to) | test.cpp:182:21:182:27 | (reference to) | +| test.cpp:182:21:182:27 | (reference to) | test.cpp:183:10:183:19 | refToLocal | +| test.cpp:182:21:182:27 | myLocal | test.cpp:182:21:182:27 | (reference to) | +| test.cpp:183:10:183:19 | (reference dereference) | test.cpp:183:10:183:19 | (reference to) | +| test.cpp:183:10:183:19 | refToLocal | test.cpp:183:10:183:19 | (reference dereference) | +| test.cpp:189:16:189:16 | (reference to) | test.cpp:189:16:189:16 | (reference to) | +| test.cpp:189:16:189:16 | (reference to) | test.cpp:190:10:190:13 | pRef | +| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) | +| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) | +| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) | nodes | test.cpp:17:9:17:11 | & ... | semmle.label | & ... | -| test.cpp:17:9:17:11 | StoreValue | semmle.label | StoreValue | -| test.cpp:17:10:17:11 | Unary | semmle.label | Unary | | test.cpp:17:10:17:11 | mc | semmle.label | mc | | test.cpp:23:17:23:19 | & ... | semmle.label | & ... | -| test.cpp:23:17:23:19 | Store | semmle.label | Store | -| test.cpp:23:17:23:19 | StoreValue | semmle.label | StoreValue | -| test.cpp:23:18:23:19 | Unary | semmle.label | Unary | +| test.cpp:23:17:23:19 | & ... | semmle.label | & ... | | test.cpp:23:18:23:19 | mc | semmle.label | mc | -| test.cpp:25:9:25:11 | Load | semmle.label | Load | -| test.cpp:25:9:25:11 | StoreValue | semmle.label | StoreValue | | test.cpp:25:9:25:11 | ptr | semmle.label | ptr | | test.cpp:39:17:39:18 | (reference to) | semmle.label | (reference to) | -| test.cpp:39:17:39:18 | Store | semmle.label | Store | -| test.cpp:39:17:39:18 | StoreValue | semmle.label | StoreValue | -| test.cpp:39:17:39:18 | Unary | semmle.label | Unary | +| test.cpp:39:17:39:18 | (reference to) | semmle.label | (reference to) | | test.cpp:39:17:39:18 | mc | semmle.label | mc | | test.cpp:41:9:41:12 | & ... | semmle.label | & ... | -| test.cpp:41:9:41:12 | StoreValue | semmle.label | StoreValue | | test.cpp:41:10:41:12 | (reference dereference) | semmle.label | (reference dereference) | -| test.cpp:41:10:41:12 | Load | semmle.label | Load | -| test.cpp:41:10:41:12 | Unary | semmle.label | Unary | -| test.cpp:41:10:41:12 | Unary | semmle.label | Unary | | test.cpp:41:10:41:12 | ref | semmle.label | ref | | test.cpp:47:9:47:10 | (reference to) | semmle.label | (reference to) | -| test.cpp:47:9:47:10 | StoreValue | semmle.label | StoreValue | -| test.cpp:47:9:47:10 | Unary | semmle.label | Unary | | test.cpp:47:9:47:10 | mc | semmle.label | mc | | test.cpp:54:9:54:15 | & ... | semmle.label | & ... | -| test.cpp:54:9:54:15 | StoreValue | semmle.label | StoreValue | -| test.cpp:54:11:54:12 | Unary | semmle.label | Unary | | test.cpp:54:11:54:12 | mc | semmle.label | mc | -| test.cpp:54:14:54:14 | Unary | semmle.label | Unary | | test.cpp:54:14:54:14 | a | semmle.label | a | -| test.cpp:89:3:89:11 | Store | semmle.label | Store | +| test.cpp:89:3:89:11 | ... = ... | semmle.label | ... = ... | | test.cpp:89:9:89:11 | & ... | semmle.label | & ... | -| test.cpp:89:9:89:11 | StoreValue | semmle.label | StoreValue | -| test.cpp:89:10:89:11 | Unary | semmle.label | Unary | | test.cpp:89:10:89:11 | mc | semmle.label | mc | -| test.cpp:92:9:92:11 | Load | semmle.label | Load | -| test.cpp:92:9:92:11 | StoreValue | semmle.label | StoreValue | | test.cpp:92:9:92:11 | ptr | semmle.label | ptr | -| test.cpp:112:9:112:11 | StoreValue | semmle.label | StoreValue | -| test.cpp:112:9:112:11 | Unary | semmle.label | Unary | | test.cpp:112:9:112:11 | arr | semmle.label | arr | | test.cpp:112:9:112:11 | array to pointer conversion | semmle.label | array to pointer conversion | | test.cpp:119:9:119:18 | & ... | semmle.label | & ... | -| test.cpp:119:9:119:18 | StoreValue | semmle.label | StoreValue | -| test.cpp:119:11:119:13 | Left | semmle.label | Left | -| test.cpp:119:11:119:13 | Unary | semmle.label | Unary | | test.cpp:119:11:119:13 | arr | semmle.label | arr | | test.cpp:119:11:119:13 | array to pointer conversion | semmle.label | array to pointer conversion | -| test.cpp:119:11:119:17 | Unary | semmle.label | Unary | | test.cpp:119:11:119:17 | access to array | semmle.label | access to array | -| test.cpp:134:2:134:14 | Store | semmle.label | Store | -| test.cpp:134:8:134:10 | Left | semmle.label | Left | -| test.cpp:134:8:134:10 | Unary | semmle.label | Unary | +| test.cpp:134:2:134:14 | ... = ... | semmle.label | ... = ... | | test.cpp:134:8:134:10 | arr | semmle.label | arr | | test.cpp:134:8:134:10 | array to pointer conversion | semmle.label | array to pointer conversion | | test.cpp:134:8:134:14 | ... + ... | semmle.label | ... + ... | -| test.cpp:134:8:134:14 | StoreValue | semmle.label | StoreValue | -| test.cpp:135:2:135:4 | Left | semmle.label | Left | -| test.cpp:135:2:135:4 | Load | semmle.label | Load | | test.cpp:135:2:135:4 | ptr | semmle.label | ptr | -| test.cpp:135:2:135:6 | PointerAdd | semmle.label | PointerAdd | -| test.cpp:135:2:135:6 | Store | semmle.label | Store | -| test.cpp:135:2:135:6 | StoreValue | semmle.label | StoreValue | -| test.cpp:137:9:137:11 | Load | semmle.label | Load | -| test.cpp:137:9:137:11 | StoreValue | semmle.label | StoreValue | +| test.cpp:135:2:135:6 | ... ++ | semmle.label | ... ++ | +| test.cpp:135:2:135:6 | ... ++ | semmle.label | ... ++ | | test.cpp:137:9:137:11 | ptr | semmle.label | ptr | | test.cpp:170:26:170:41 | (void *)... | semmle.label | (void *)... | -| test.cpp:170:26:170:41 | Store | semmle.label | Store | -| test.cpp:170:26:170:41 | StoreValue | semmle.label | StoreValue | +| test.cpp:170:26:170:41 | (void *)... | semmle.label | (void *)... | | test.cpp:170:34:170:41 | & ... | semmle.label | & ... | -| test.cpp:170:34:170:41 | Unary | semmle.label | Unary | -| test.cpp:170:35:170:41 | Unary | semmle.label | Unary | | test.cpp:170:35:170:41 | myLocal | semmle.label | myLocal | -| test.cpp:171:10:171:23 | Load | semmle.label | Load | -| test.cpp:171:10:171:23 | StoreValue | semmle.label | StoreValue | | test.cpp:171:10:171:23 | pointerToLocal | semmle.label | pointerToLocal | -| test.cpp:176:25:176:34 | Store | semmle.label | Store | -| test.cpp:176:25:176:34 | StoreValue | semmle.label | StoreValue | -| test.cpp:176:25:176:34 | Unary | semmle.label | Unary | +| test.cpp:176:25:176:34 | array to pointer conversion | semmle.label | array to pointer conversion | | test.cpp:176:25:176:34 | array to pointer conversion | semmle.label | array to pointer conversion | | test.cpp:176:25:176:34 | localArray | semmle.label | localArray | | test.cpp:177:10:177:23 | (void *)... | semmle.label | (void *)... | -| test.cpp:177:10:177:23 | Load | semmle.label | Load | -| test.cpp:177:10:177:23 | StoreValue | semmle.label | StoreValue | -| test.cpp:177:10:177:23 | Unary | semmle.label | Unary | | test.cpp:177:10:177:23 | pointerToLocal | semmle.label | pointerToLocal | | test.cpp:182:21:182:27 | (reference to) | semmle.label | (reference to) | -| test.cpp:182:21:182:27 | Store | semmle.label | Store | -| test.cpp:182:21:182:27 | StoreValue | semmle.label | StoreValue | -| test.cpp:182:21:182:27 | Unary | semmle.label | Unary | +| test.cpp:182:21:182:27 | (reference to) | semmle.label | (reference to) | | test.cpp:182:21:182:27 | myLocal | semmle.label | myLocal | | test.cpp:183:10:183:19 | (reference dereference) | semmle.label | (reference dereference) | | test.cpp:183:10:183:19 | (reference to) | semmle.label | (reference to) | -| test.cpp:183:10:183:19 | Load | semmle.label | Load | -| test.cpp:183:10:183:19 | StoreValue | semmle.label | StoreValue | -| test.cpp:183:10:183:19 | Unary | semmle.label | Unary | -| test.cpp:183:10:183:19 | Unary | semmle.label | Unary | | test.cpp:183:10:183:19 | refToLocal | semmle.label | refToLocal | | test.cpp:189:16:189:16 | (reference to) | semmle.label | (reference to) | -| test.cpp:189:16:189:16 | Store | semmle.label | Store | -| test.cpp:189:16:189:16 | StoreValue | semmle.label | StoreValue | -| test.cpp:189:16:189:16 | Unary | semmle.label | Unary | +| test.cpp:189:16:189:16 | (reference to) | semmle.label | (reference to) | | test.cpp:189:16:189:16 | p | semmle.label | p | | test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) | | test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) | -| test.cpp:190:10:190:13 | Load | semmle.label | Load | -| test.cpp:190:10:190:13 | StoreValue | semmle.label | StoreValue | -| test.cpp:190:10:190:13 | Unary | semmle.label | Unary | -| test.cpp:190:10:190:13 | Unary | semmle.label | Unary | | test.cpp:190:10:190:13 | pRef | semmle.label | pRef | #select -| test.cpp:17:9:17:11 | StoreValue | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc | -| test.cpp:25:9:25:11 | StoreValue | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc | -| test.cpp:41:9:41:12 | StoreValue | test.cpp:39:17:39:18 | mc | test.cpp:41:9:41:12 | StoreValue | May return stack-allocated memory from $@. | test.cpp:39:17:39:18 | mc | mc | -| test.cpp:47:9:47:10 | StoreValue | test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | StoreValue | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc | -| test.cpp:54:9:54:15 | StoreValue | test.cpp:54:11:54:12 | mc | test.cpp:54:9:54:15 | StoreValue | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc | -| test.cpp:92:9:92:11 | StoreValue | test.cpp:89:10:89:11 | mc | test.cpp:92:9:92:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc | -| test.cpp:112:9:112:11 | StoreValue | test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr | -| test.cpp:119:9:119:18 | StoreValue | test.cpp:119:11:119:13 | arr | test.cpp:119:9:119:18 | StoreValue | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr | -| test.cpp:137:9:137:11 | StoreValue | test.cpp:134:8:134:10 | arr | test.cpp:137:9:137:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:134:8:134:10 | arr | arr | -| test.cpp:171:10:171:23 | StoreValue | test.cpp:170:35:170:41 | myLocal | test.cpp:171:10:171:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal | -| test.cpp:177:10:177:23 | StoreValue | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray | -| test.cpp:183:10:183:19 | StoreValue | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | StoreValue | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal | -| test.cpp:190:10:190:13 | StoreValue | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | StoreValue | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p | +| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc | +| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc | +| test.cpp:41:9:41:12 | CopyValue: & ... | test.cpp:39:17:39:18 | mc | test.cpp:41:9:41:12 | & ... | May return stack-allocated memory from $@. | test.cpp:39:17:39:18 | mc | mc | +| test.cpp:47:9:47:10 | CopyValue: (reference to) | test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | (reference to) | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc | +| test.cpp:54:9:54:15 | CopyValue: & ... | test.cpp:54:11:54:12 | mc | test.cpp:54:9:54:15 | & ... | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc | +| test.cpp:92:9:92:11 | Load: ptr | test.cpp:89:10:89:11 | mc | test.cpp:92:9:92:11 | ptr | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc | +| test.cpp:112:9:112:11 | Convert: array to pointer conversion | test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | array to pointer conversion | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr | +| test.cpp:119:9:119:18 | CopyValue: & ... | test.cpp:119:11:119:13 | arr | test.cpp:119:9:119:18 | & ... | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr | +| test.cpp:137:9:137:11 | Load: ptr | test.cpp:134:8:134:10 | arr | test.cpp:137:9:137:11 | ptr | May return stack-allocated memory from $@. | test.cpp:134:8:134:10 | arr | arr | +| test.cpp:171:10:171:23 | Load: pointerToLocal | test.cpp:170:35:170:41 | myLocal | test.cpp:171:10:171:23 | pointerToLocal | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal | +| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray | +| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal | +| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p | diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 98c13dfaa77..4aa822f9369 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.4 + +No user-facing changes. + ## 1.3.3 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.3.4.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.3.4.md new file mode 100644 index 00000000000..5073aca7222 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.3.4.md @@ -0,0 +1,3 @@ +## 1.3.4 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index eb1f7dabc84..8263ddf2c8b 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.3.3 +lastReleaseVersion: 1.3.4 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index ccab1b3a8b8..3b918b3442d 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.3.4-dev +version: 1.3.5-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 98c13dfaa77..4aa822f9369 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.4 + +No user-facing changes. + ## 1.3.3 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.3.4.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.3.4.md new file mode 100644 index 00000000000..5073aca7222 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.3.4.md @@ -0,0 +1,3 @@ +## 1.3.4 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index eb1f7dabc84..8263ddf2c8b 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.3.3 +lastReleaseVersion: 1.3.4 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 209538a2014..18101db5518 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.3.4-dev +version: 1.3.5-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 2fff5e72443..265b1a3183d 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.4.4 + +### Minor Analysis Improvements + +* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead. + ## 0.4.3 No user-facing changes. diff --git a/csharp/ql/lib/change-notes/2022-11-17-deleted-deps.md b/csharp/ql/lib/change-notes/2022-11-17-deleted-deps.md new file mode 100644 index 00000000000..da5a8d8cd9b --- /dev/null +++ b/csharp/ql/lib/change-notes/2022-11-17-deleted-deps.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `getNameWithoutBrackets` predicate from the `ValueOrRefType` class in `Type.qll`. \ No newline at end of file diff --git a/csharp/ql/lib/change-notes/2022-11-09-modelsasdataextensions.md b/csharp/ql/lib/change-notes/released/0.4.4.md similarity index 72% rename from csharp/ql/lib/change-notes/2022-11-09-modelsasdataextensions.md rename to csharp/ql/lib/change-notes/released/0.4.4.md index 1c9bb14754d..b3d7e2c3be1 100644 --- a/csharp/ql/lib/change-notes/2022-11-09-modelsasdataextensions.md +++ b/csharp/ql/lib/change-notes/released/0.4.4.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- -* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead. \ No newline at end of file +## 0.4.4 + +### Minor Analysis Improvements + +* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index a43762f9433..5103c8f0ab7 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.4.4-dev +version: 0.4.5-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index dfabea580a4..d475442f886 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -56,13 +56,6 @@ private predicate isObjectClass(Class c) { c instanceof ObjectType } * Either a value type (`ValueType`) or a reference type (`RefType`). */ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_or_ref_type { - /** - * DEPRECATED: use `getUndecoratedName()` instead. - * - * Gets the name of this type without `<...>` brackets, in case it is a generic type. - */ - deprecated string getNameWithoutBrackets() { types(this, _, result) } - /** * Holds if this type has the qualified name `qualifier`.`name`. * diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll index dbd90ba0ae1..5039d09ff22 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll @@ -907,9 +907,13 @@ module TestOutput { query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) { attr = "semmle.label" and - exists(SuccessorType t | succ = getASuccessor(pred, t) | - if successorTypeIsSimple(t) then val = "" else val = t.toString() - ) + val = + strictconcat(SuccessorType t, string s | + succ = getASuccessor(pred, t) and + if successorTypeIsSimple(t) then s = "" else s = t.toString() + | + s, ", " order by s + ) or attr = "semmle.order" and val = diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index 46be24580ef..486c21a1125 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.4 + +No user-facing changes. + ## 0.4.3 No user-facing changes. diff --git a/csharp/ql/src/change-notes/released/0.4.4.md b/csharp/ql/src/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..33e1c91255d --- /dev/null +++ b/csharp/ql/src/change-notes/released/0.4.4.md @@ -0,0 +1,3 @@ +## 0.4.4 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 7f537bcae49..e455b240f04 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.4.4-dev +version: 0.4.5-dev groups: - csharp - queries diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index acabdc1835a..d5c2e78587d 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -2775,7 +2775,7 @@ Assert.cs: #-----| true -> access to parameter b2 # 140| [assertion failure] access to parameter b2 -#-----| false -> [assertion failure] access to parameter b3 +#-----| false, true -> [assertion failure] access to parameter b3 # 140| access to parameter b2 #-----| false -> [assertion success] access to parameter b3 @@ -4924,7 +4924,7 @@ ExitMethods.cs: #-----| -> ...; # 22| call to method ErrorAlways -#-----| exception(Exception) -> exit M3 (abnormal) +#-----| exception(ArgumentException), exception(Exception) -> exit M3 (abnormal) # 22| ...; #-----| -> true diff --git a/docs/codeql/codeql-cli/analyzing-databases-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/analyzing-databases-with-the-codeql-cli.rst index 72fb979c563..bc9924b740a 100644 --- a/docs/codeql/codeql-cli/analyzing-databases-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/analyzing-databases-with-the-codeql-cli.rst @@ -312,7 +312,7 @@ For more information, see "`Using CodeQL query packs in the CodeQL action `_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,,, `Apache Commons IO `_,``org.apache.commons.io``,,556,106,91,,,,,,15 - `Apache Commons Lang `_,``org.apache.commons.lang3``,,424,,,,,,,, + `Apache Commons Lang `_,``org.apache.commons.lang3``,,424,6,,,,,,, `Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,, `Apache HttpComponents `_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25 `Apache Log4j 2 `_,``org.apache.logging.log4j``,,8,359,,,,,,, `Google Guava `_,``com.google.common.*``,,728,39,,6,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,,, `JSON-java `_,``org.json``,,236,,,,,,,, - Java Standard Library,``java.*``,3,589,130,28,,,7,,,10 + Java Standard Library,``java.*``,3,591,130,28,,,7,,,10 Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1835,12,10,,,,,,2 `Spring `_,``org.springframework.*``,29,477,101,,,,19,14,,29 Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",60,300,269,,,,14,18,,3 - Totals,,217,8432,1524,129,6,10,107,33,1,86 + Totals,,217,8434,1530,129,6,10,107,33,1,86 diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 511b97fd4d0..489d1b85743 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -3395,6 +3395,23 @@ open class KotlinFileExtractor( extractExprContext(it, locId, callable, enclosingStmt) } + private fun escapeCharForQuotedLiteral(c: Char) = + when (c) { + '\r' -> "\\r" + '\n' -> "\\n" + '\t' -> "\\t" + '\\' -> "\\\\" + '"' -> "\\\"" + else -> c.toString() + } + + // Render a string literal as it might occur in Kotlin source. Note this is a reasonable guess; the real source + // could use other escape sequences to describe the same String. Importantly, this is the same guess the Java + // extractor makes regarding string literals occurring within annotations, which we need to coincide with to ensure + // database consistency. + private fun toQuotedLiteral(s: String) = + s.toCharArray().joinToString(separator = "", prefix = "\"", postfix = "\"") { c -> escapeCharForQuotedLiteral(c) } + private fun extractExpression(e: IrExpression, callable: Label, parent: StmtExprParent) { with("expression", e) { when(e) { @@ -3602,7 +3619,7 @@ open class KotlinFileExtractor( tw.writeExprs_stringliteral(id, type.javaResult.id, exprParent.parent, exprParent.idx) tw.writeExprsKotlinType(id, type.kotlinResult.id) extractExprContext(id, locId, callable, exprParent.enclosingStmt) - tw.writeNamestrings(v.toString(), v.toString(), id) + tw.writeNamestrings(toQuotedLiteral(v.toString()), v.toString(), id) } v == null -> { extractNull(e.type, tw.getLocation(e), exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt) diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/PrintAst.expected b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/PrintAst.expected index ae23298c033..4f056c3c4fb 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/PrintAst.expected +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/PrintAst.expected @@ -180,15 +180,15 @@ app/src/main/kotlin/testProject/App.kt: # 0| 5: [BlockStmt] { ... } # 0| 0: [ReturnStmt] return ... # 0| 0: [StringTemplateExpr] "..." -# 0| 0: [StringLiteral] Project( -# 0| 1: [StringLiteral] name= +# 0| 0: [StringLiteral] "Project(" +# 0| 1: [StringLiteral] "name=" # 0| 2: [VarAccess] this.name # 0| -1: [ThisAccess] this -# 0| 3: [StringLiteral] , -# 0| 4: [StringLiteral] language= +# 0| 3: [StringLiteral] ", " +# 0| 4: [StringLiteral] "language=" # 0| 5: [VarAccess] this.language # 0| -1: [ThisAccess] this -# 0| 6: [StringLiteral] ) +# 0| 6: [StringLiteral] ")" # 0| 9: [Method] write$Self # 0| 3: [TypeAccess] Unit #-----| 4: (Parameters) @@ -405,19 +405,19 @@ app/src/main/kotlin/testProject/App.kt: # 7| 1: [LocalVariableDeclExpr] tmp0_serialDesc # 7| 0: [ClassInstanceExpr] new PluginGeneratedSerialDescriptor(...) # 7| -3: [TypeAccess] PluginGeneratedSerialDescriptor -# 7| 0: [StringLiteral] testProject.Project +# 7| 0: [StringLiteral] "testProject.Project" # 7| 1: [ThisAccess] $serializer.this # 7| 0: [TypeAccess] $serializer # 7| 2: [IntegerLiteral] 2 # 7| 1: [ExprStmt] ; # 7| 0: [MethodAccess] addElement(...) # 7| -1: [VarAccess] tmp0_serialDesc -# 7| 0: [StringLiteral] name +# 7| 0: [StringLiteral] "name" # 7| 1: [BooleanLiteral] false # 7| 2: [ExprStmt] ; # 7| 0: [MethodAccess] addElement(...) # 7| -1: [VarAccess] tmp0_serialDesc -# 7| 0: [StringLiteral] language +# 7| 0: [StringLiteral] "language" # 7| 1: [BooleanLiteral] false # 7| 3: [ExprStmt] ; # 7| 0: [AssignExpr] ...=... @@ -520,7 +520,7 @@ app/src/main/kotlin/testProject/App.kt: # 14| 0: [VarAccess] X.this.id # 14| -1: [ThisAccess] X.this # 14| 0: [TypeAccess] X -# 16| 1: [StringLiteral] X +# 16| 1: [StringLiteral] "X" # 14| 1: [WhenBranch] ... -> ... # 14| 0: [BooleanLiteral] true # 14| 1: [ExprStmt] ; @@ -556,7 +556,7 @@ app/src/main/kotlin/testProject/App.kt: # 14| 0: [ValueNEExpr] ... (value not-equals) ... # 14| 0: [MethodAccess] getId(...) # 14| -1: [VarAccess] self -# 16| 1: [StringLiteral] X +# 16| 1: [StringLiteral] "X" # 14| 1: [ExprStmt] ; # 14| 0: [MethodAccess] encodeStringElement(...) # 14| -1: [VarAccess] output @@ -720,14 +720,14 @@ app/src/main/kotlin/testProject/App.kt: # 14| 1: [LocalVariableDeclExpr] tmp0_serialDesc # 14| 0: [ClassInstanceExpr] new PluginGeneratedSerialDescriptor(...) # 14| -3: [TypeAccess] PluginGeneratedSerialDescriptor -# 14| 0: [StringLiteral] testProject.X +# 14| 0: [StringLiteral] "testProject.X" # 14| 1: [ThisAccess] $serializer.this # 14| 0: [TypeAccess] $serializer # 14| 2: [IntegerLiteral] 1 # 14| 1: [ExprStmt] ; # 14| 0: [MethodAccess] addElement(...) # 14| -1: [VarAccess] tmp0_serialDesc -# 14| 0: [StringLiteral] id +# 14| 0: [StringLiteral] "id" # 14| 1: [BooleanLiteral] true # 14| 2: [ExprStmt] ; # 14| 0: [AssignExpr] ...=... @@ -764,7 +764,7 @@ app/src/main/kotlin/testProject/App.kt: # 16| 0: [VarAccess] id # 16| 6: [FieldDeclaration] String id; # 16| -1: [TypeAccess] String -# 16| 0: [StringLiteral] X +# 16| 0: [StringLiteral] "X" # 16| 7: [Method] getId # 16| 3: [TypeAccess] String # 16| 5: [BlockStmt] { ... } diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/test.expected b/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/test.expected index 3581a178422..9f16308bdfc 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/test.expected +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/test.expected @@ -1,26 +1,26 @@ edges | hasFields.kt:5:5:5:34 | constField : String | ReadsFields.java:5:10:5:29 | HasFields.constField | -| hasFields.kt:5:28:5:34 | taint : String | hasFields.kt:5:5:5:34 | constField : String | +| hasFields.kt:5:28:5:34 | "taint" : String | hasFields.kt:5:5:5:34 | constField : String | | hasFields.kt:7:5:7:38 | lateinitField : String | ReadsFields.java:6:10:6:32 | HasFields.lateinitField | | hasFields.kt:7:14:7:38 | : String | hasFields.kt:7:5:7:38 | lateinitField : String | | hasFields.kt:7:14:7:38 | : String | hasFields.kt:7:14:7:38 | : String | | hasFields.kt:9:5:9:50 | jvmFieldAnnotatedField : String | ReadsFields.java:7:10:7:41 | HasFields.jvmFieldAnnotatedField | -| hasFields.kt:9:44:9:50 | taint : String | hasFields.kt:9:5:9:50 | jvmFieldAnnotatedField : String | -| hasFields.kt:14:22:14:26 | taint : String | hasFields.kt:7:14:7:38 | : String | +| hasFields.kt:9:44:9:50 | "taint" : String | hasFields.kt:9:5:9:50 | jvmFieldAnnotatedField : String | +| hasFields.kt:14:22:14:26 | "taint" : String | hasFields.kt:7:14:7:38 | : String | nodes | ReadsFields.java:5:10:5:29 | HasFields.constField | semmle.label | HasFields.constField | | ReadsFields.java:6:10:6:32 | HasFields.lateinitField | semmle.label | HasFields.lateinitField | | ReadsFields.java:7:10:7:41 | HasFields.jvmFieldAnnotatedField | semmle.label | HasFields.jvmFieldAnnotatedField | | hasFields.kt:5:5:5:34 | constField : String | semmle.label | constField : String | -| hasFields.kt:5:28:5:34 | taint : String | semmle.label | taint : String | +| hasFields.kt:5:28:5:34 | "taint" : String | semmle.label | "taint" : String | | hasFields.kt:7:5:7:38 | lateinitField : String | semmle.label | lateinitField : String | | hasFields.kt:7:14:7:38 | : String | semmle.label | : String | | hasFields.kt:7:14:7:38 | : String | semmle.label | : String | | hasFields.kt:9:5:9:50 | jvmFieldAnnotatedField : String | semmle.label | jvmFieldAnnotatedField : String | -| hasFields.kt:9:44:9:50 | taint : String | semmle.label | taint : String | -| hasFields.kt:14:22:14:26 | taint : String | semmle.label | taint : String | +| hasFields.kt:9:44:9:50 | "taint" : String | semmle.label | "taint" : String | +| hasFields.kt:14:22:14:26 | "taint" : String | semmle.label | "taint" : String | subpaths #select -| hasFields.kt:5:28:5:34 | taint : String | hasFields.kt:5:28:5:34 | taint : String | ReadsFields.java:5:10:5:29 | HasFields.constField | flow path | -| hasFields.kt:9:44:9:50 | taint : String | hasFields.kt:9:44:9:50 | taint : String | ReadsFields.java:7:10:7:41 | HasFields.jvmFieldAnnotatedField | flow path | -| hasFields.kt:14:22:14:26 | taint : String | hasFields.kt:14:22:14:26 | taint : String | ReadsFields.java:6:10:6:32 | HasFields.lateinitField | flow path | +| hasFields.kt:5:28:5:34 | "taint" : String | hasFields.kt:5:28:5:34 | "taint" : String | ReadsFields.java:5:10:5:29 | HasFields.constField | flow path | +| hasFields.kt:9:44:9:50 | "taint" : String | hasFields.kt:9:44:9:50 | "taint" : String | ReadsFields.java:7:10:7:41 | HasFields.jvmFieldAnnotatedField | flow path | +| hasFields.kt:14:22:14:26 | "taint" : String | hasFields.kt:14:22:14:26 | "taint" : String | ReadsFields.java:6:10:6:32 | HasFields.lateinitField | flow path | diff --git a/java/ql/integration-tests/all-platforms/kotlin/nested_generic_types/test.expected b/java/ql/integration-tests/all-platforms/kotlin/nested_generic_types/test.expected index 27db355f838..94ec21eca1a 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/nested_generic_types/test.expected +++ b/java/ql/integration-tests/all-platforms/kotlin/nested_generic_types/test.expected @@ -76,7 +76,7 @@ callArgs | KotlinUser.kt:10:34:10:65 | new InnerGeneric(...) | KotlinUser.kt:10:14:10:32 | new OuterGeneric(...) | -2 | | KotlinUser.kt:10:34:10:65 | new InnerGeneric(...) | KotlinUser.kt:10:34:10:65 | InnerGeneric | -3 | | KotlinUser.kt:10:34:10:65 | new InnerGeneric(...) | KotlinUser.kt:10:47:10:49 | a | 0 | -| KotlinUser.kt:10:34:10:65 | new InnerGeneric(...) | KotlinUser.kt:10:53:10:63 | hello world | 1 | +| KotlinUser.kt:10:34:10:65 | new InnerGeneric(...) | KotlinUser.kt:10:53:10:63 | "hello world" | 1 | | KotlinUser.kt:11:13:11:31 | new OuterGeneric(...) | KotlinUser.kt:11:13:11:31 | OuterGeneric | -3 | | KotlinUser.kt:11:33:11:49 | new InnerNotGeneric<>(...) | KotlinUser.kt:11:13:11:31 | new OuterGeneric(...) | -2 | | KotlinUser.kt:11:33:11:49 | new InnerNotGeneric<>(...) | KotlinUser.kt:11:33:11:49 | InnerNotGeneric<> | -3 | @@ -88,10 +88,10 @@ callArgs | KotlinUser.kt:13:31:13:52 | new InnerGeneric(...) | KotlinUser.kt:13:31:13:52 | InnerGeneric | -3 | | KotlinUser.kt:14:26:14:63 | new InnerStaticGeneric(...) | KotlinUser.kt:14:26:14:63 | InnerStaticGeneric | -3 | | KotlinUser.kt:14:26:14:63 | new InnerStaticGeneric(...) | KotlinUser.kt:14:45:14:47 | a | 0 | -| KotlinUser.kt:14:26:14:63 | new InnerStaticGeneric(...) | KotlinUser.kt:14:51:14:61 | hello world | 1 | +| KotlinUser.kt:14:26:14:63 | new InnerStaticGeneric(...) | KotlinUser.kt:14:51:14:61 | "hello world" | 1 | | KotlinUser.kt:15:13:15:39 | new OuterManyParams(...) | KotlinUser.kt:15:13:15:39 | OuterManyParams | -3 | | KotlinUser.kt:15:13:15:39 | new OuterManyParams(...) | KotlinUser.kt:15:29:15:29 | 1 | 0 | -| KotlinUser.kt:15:13:15:39 | new OuterManyParams(...) | KotlinUser.kt:15:33:15:37 | hello | 1 | +| KotlinUser.kt:15:13:15:39 | new OuterManyParams(...) | KotlinUser.kt:15:33:15:37 | "hello" | 1 | | KotlinUser.kt:15:41:15:67 | new MiddleManyParams(...) | KotlinUser.kt:15:13:15:39 | new OuterManyParams(...) | -2 | | KotlinUser.kt:15:41:15:67 | new MiddleManyParams(...) | KotlinUser.kt:15:41:15:67 | MiddleManyParams | -3 | | KotlinUser.kt:15:41:15:67 | new MiddleManyParams(...) | KotlinUser.kt:15:58:15:61 | 1.0 | 0 | @@ -103,23 +103,23 @@ callArgs | KotlinUser.kt:15:89:15:99 | shortValue(...) | KotlinUser.kt:15:89:15:89 | 1 | -1 | | KotlinUser.kt:17:19:17:44 | returnsecond(...) | KotlinUser.kt:17:19:17:19 | a | -1 | | KotlinUser.kt:17:19:17:44 | returnsecond(...) | KotlinUser.kt:17:34:17:34 | 0 | 0 | -| KotlinUser.kt:17:19:17:44 | returnsecond(...) | KotlinUser.kt:17:38:17:42 | hello | 1 | +| KotlinUser.kt:17:19:17:44 | returnsecond(...) | KotlinUser.kt:17:38:17:42 | "hello" | 1 | | KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:20:18:20 | a | -1 | | KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:20:18:50 | Character | -2 | | KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:35:18:35 | 0 | 0 | -| KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:39:18:43 | hello | 1 | +| KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:39:18:43 | "hello" | 1 | | KotlinUser.kt:18:20:18:50 | returnsecond(...) | KotlinUser.kt:18:47:18:49 | a | 2 | | KotlinUser.kt:19:19:19:31 | identity(...) | KotlinUser.kt:19:19:19:19 | b | -1 | | KotlinUser.kt:19:19:19:31 | identity(...) | KotlinUser.kt:19:30:19:30 | 5 | 0 | | KotlinUser.kt:20:20:20:39 | identity(...) | KotlinUser.kt:20:20:20:21 | b2 | -1 | -| KotlinUser.kt:20:20:20:39 | identity(...) | KotlinUser.kt:20:33:20:37 | hello | 0 | +| KotlinUser.kt:20:20:20:39 | identity(...) | KotlinUser.kt:20:33:20:37 | "hello" | 0 | | KotlinUser.kt:21:19:21:37 | identity(...) | KotlinUser.kt:21:19:21:19 | c | -1 | -| KotlinUser.kt:21:19:21:37 | identity(...) | KotlinUser.kt:21:31:21:35 | world | 0 | +| KotlinUser.kt:21:19:21:37 | identity(...) | KotlinUser.kt:21:31:21:35 | "world" | 0 | | KotlinUser.kt:22:19:22:39 | identity(...) | KotlinUser.kt:22:19:22:19 | d | -1 | -| KotlinUser.kt:22:19:22:39 | identity(...) | KotlinUser.kt:22:31:22:37 | goodbye | 0 | +| KotlinUser.kt:22:19:22:39 | identity(...) | KotlinUser.kt:22:31:22:37 | "goodbye" | 0 | | KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:19:23:19 | e | -1 | | KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:33:23:33 | 1 | 0 | -| KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:37:23:41 | hello | 1 | +| KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:37:23:41 | "hello" | 1 | | KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:45:23:48 | 1.0 | 2 | | KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:51:23:53 | 1.0 | 3 | | KotlinUser.kt:23:19:23:71 | returnSixth(...) | KotlinUser.kt:23:56:23:57 | 1 | 4 | diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected index 51186ef7b15..6921b7541ad 100644 --- a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected @@ -50,7 +50,7 @@ d.kt: # 1| 1: [Class] D # 0| 2: [FieldDeclaration] String bar; # 0| -1: [TypeAccess] String -# 0| 0: [StringLiteral] Foobar +# 0| 0: [StringLiteral] "Foobar" # 1| 3: [Constructor] D # 1| 5: [BlockStmt] { ... } # 1| 0: [SuperConstructorInvocationStmt] super(...) diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected index 606bbd3f338..092e8241a3d 100644 --- a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected @@ -1 +1 @@ -| d.kt:0:0:0:0 | bar | d.kt:0:0:0:0 | Foobar | +| d.kt:0:0:0:0 | bar | d.kt:0:0:0:0 | "Foobar" | diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 696c3097fac..32632d9ea68 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.4.4 + +### New Features + +* Kotlin support is now in beta. This means that Java analyses will also include Kotlin code by default. Kotlin support can be disabled by setting `CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN` to `true` in the environment. +* The new `string Compilation.getInfo(string)` predicate provides access to some information about compilations. + +### Minor Analysis Improvements + +* The ReDoS libraries in `semmle.code.java.security.regexp` has been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. +* Added data flow summaries for tainted Android intents sent to activities via `Activity.startActivities`. + ## 0.4.3 No user-facing changes. diff --git a/java/ql/lib/change-notes/2022-10-19-android-startactivities-summaries.md b/java/ql/lib/change-notes/2022-10-19-android-startactivities-summaries.md deleted file mode 100644 index 4716fb2ac41..00000000000 --- a/java/ql/lib/change-notes/2022-10-19-android-startactivities-summaries.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added data flow summaries for tainted Android intents sent to activities via `Activity.startActivities`. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-10-31-shared-redos-pack.md b/java/ql/lib/change-notes/2022-10-31-shared-redos-pack.md deleted file mode 100644 index 405ddd1108c..00000000000 --- a/java/ql/lib/change-notes/2022-10-31-shared-redos-pack.md +++ /dev/null @@ -1,4 +0,0 @@ ---- - category: minorAnalysis ---- - * The ReDoS libraries in `semmle.code.java.security.regexp` has been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-11-10-getInfo.md b/java/ql/lib/change-notes/2022-11-10-getInfo.md deleted file mode 100644 index 7a113ca3459..00000000000 --- a/java/ql/lib/change-notes/2022-11-10-getInfo.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* The new `string Compilation.getInfo(string)` provides access to some information about compilations. diff --git a/java/ql/lib/change-notes/2022-11-10-kotlin-default.md b/java/ql/lib/change-notes/2022-11-10-kotlin-default.md deleted file mode 100644 index d411c58173c..00000000000 --- a/java/ql/lib/change-notes/2022-11-10-kotlin-default.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* Kotlin support is now in beta. This means that Java analyses will also include Kotlin code by default. Kotlin support can be disabled by setting `CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN` to `true` in the environment. diff --git a/java/ql/lib/change-notes/2022-11-17-deleted-deps.md b/java/ql/lib/change-notes/2022-11-17-deleted-deps.md new file mode 100644 index 00000000000..014b4ff23eb --- /dev/null +++ b/java/ql/lib/change-notes/2022-11-17-deleted-deps.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `LocalClassDeclStmtNode` and `LocalClassDeclStmt` classes from `PrintAst.qll` and `Statement.qll` respectively. +* Deleted the deprecated `getLocalClass` predicate from `LocalTypeDeclStmt`, and the deprecated `getLocalClassDeclStmt` predicate from `LocalClassOrInterface`. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2022-11-21-paths-get-fix.md b/java/ql/lib/change-notes/2022-11-21-paths-get-fix.md new file mode 100644 index 00000000000..a586cecf04b --- /dev/null +++ b/java/ql/lib/change-notes/2022-11-21-paths-get-fix.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added a taint model for the method `java.nio.file.Path.getParent`. +* Fixed a problem in the taint model for the method `java.nio.file.Paths.get`. diff --git a/java/ql/lib/change-notes/released/0.4.4.md b/java/ql/lib/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..ca76975d283 --- /dev/null +++ b/java/ql/lib/change-notes/released/0.4.4.md @@ -0,0 +1,11 @@ +## 0.4.4 + +### New Features + +* Kotlin support is now in beta. This means that Java analyses will also include Kotlin code by default. Kotlin support can be disabled by setting `CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN` to `true` in the environment. +* The new `string Compilation.getInfo(string)` predicate provides access to some information about compilations. + +### Minor Analysis Improvements + +* The ReDoS libraries in `semmle.code.java.security.regexp` has been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. +* Added data flow summaries for tainted Android intents sent to activities via `Activity.startActivities`. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 4b103c629a2..dfab979e9bd 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.4.4-dev +version: 0.4.5-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/lib/semmle/code/java/PrintAst.qll b/java/ql/lib/semmle/code/java/PrintAst.qll index 4df23f4ec14..d6420f2e4ca 100644 --- a/java/ql/lib/semmle/code/java/PrintAst.qll +++ b/java/ql/lib/semmle/code/java/PrintAst.qll @@ -393,12 +393,6 @@ final class LocalTypeDeclStmtNode extends ExprStmtNode { } } -/** - * DEPRECATED: Renamed `LocalTypeDeclStmtNode` to reflect the fact that - * as of Java 16 interfaces can also be declared locally, not just classes. - */ -deprecated class LocalClassDeclStmtNode = LocalTypeDeclStmtNode; - /** * A node representing a `ForStmt`. */ diff --git a/java/ql/lib/semmle/code/java/Statement.qll b/java/ql/lib/semmle/code/java/Statement.qll index 2c8cff3c217..fe0ba23093a 100644 --- a/java/ql/lib/semmle/code/java/Statement.qll +++ b/java/ql/lib/semmle/code/java/Statement.qll @@ -781,12 +781,6 @@ class LocalTypeDeclStmt extends Stmt, @localtypedeclstmt { /** Gets the local type declared by this statement. */ LocalClassOrInterface getLocalType() { isLocalClassOrInterface(result, this) } - /** - * DEPRECATED: Renamed `getLocalType` to reflect the fact that - * as of Java 16 interfaces can also be declared locally, not just classes. - */ - deprecated LocalClassOrInterface getLocalClass() { result = this.getLocalType() } - private string getDeclKeyword() { result = "class" and this.getLocalType() instanceof Class or @@ -802,12 +796,6 @@ class LocalTypeDeclStmt extends Stmt, @localtypedeclstmt { override string getAPrimaryQlClass() { result = "LocalTypeDeclStmt" } } -/** - * DEPRECATED: Renamed `LocalTypeDeclStmt` to reflect the fact that - * as of Java 16 interfaces can also be declared locally, not just classes. - */ -deprecated class LocalClassDeclStmt = LocalTypeDeclStmt; - /** An explicit `this(...)` constructor invocation. */ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructorinvocationstmt { /** Gets an argument of this constructor invocation. */ diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index 63df6feef42..eff61ed0fde 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -828,12 +828,6 @@ class LocalClassOrInterface extends NestedType, ClassOrInterface { /** Gets the statement that declares this local class. */ LocalTypeDeclStmt getLocalTypeDeclStmt() { isLocalClassOrInterface(this, result) } - /** - * DEPRECATED: renamed `getLocalTypeDeclStmt` to reflect the fact that - * as of Java 16 interfaces can also be declared locally. - */ - deprecated LocalTypeDeclStmt getLocalClassDeclStmt() { result = this.getLocalTypeDeclStmt() } - override string getAPrimaryQlClass() { result = "LocalClassOrInterface" } } diff --git a/java/ql/lib/semmle/code/java/frameworks/Regex.qll b/java/ql/lib/semmle/code/java/frameworks/Regex.qll index 4e83981d857..790255c9703 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Regex.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Regex.qll @@ -2,6 +2,27 @@ private import semmle.code.java.dataflow.ExternalFlow +/** The class `java.util.regex.Pattern`. */ +class TypeRegexPattern extends Class { + TypeRegexPattern() { this.hasQualifiedName("java.util.regex", "Pattern") } +} + +/** The `quote` method of the `java.util.regex.Pattern` class. */ +class PatternQuoteMethod extends Method { + PatternQuoteMethod() { + this.getDeclaringType() instanceof TypeRegexPattern and + this.hasName("quote") + } +} + +/** The `LITERAL` field of the `java.util.regex.Pattern` class. */ +class PatternLiteralField extends Field { + PatternLiteralField() { + this.getDeclaringType() instanceof TypeRegexPattern and + this.hasName("LITERAL") + } +} + private class RegexModel extends SummaryModelCsv { override predicate row(string s) { s = diff --git a/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll b/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll index de0b5465fe4..20ba2c14dc8 100644 --- a/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll +++ b/java/ql/lib/semmle/code/java/regex/RegexFlowModels.qll @@ -27,6 +27,12 @@ private class RegexSinkCsv extends SinkModelCsv { "com.google.common.base;Splitter;false;split;(CharSequence);;Argument[-1];regex-use[0];manual", "com.google.common.base;Splitter;false;splitToList;(CharSequence);;Argument[-1];regex-use[0];manual", "com.google.common.base;Splitter$MapSplitter;false;split;(CharSequence);;Argument[-1];regex-use[0];manual", + "org.apache.commons.lang3;RegExUtils;false;removeAll;(String,String);;Argument[1];regex-use;manual", + "org.apache.commons.lang3;RegExUtils;false;removeFirst;(String,String);;Argument[1];regex-use;manual", + "org.apache.commons.lang3;RegExUtils;false;removePattern;(String,String);;Argument[1];regex-use;manual", + "org.apache.commons.lang3;RegExUtils;false;replaceAll;(String,String,String);;Argument[1];regex-use;manual", + "org.apache.commons.lang3;RegExUtils;false;replaceFirst;(String,String,String);;Argument[1];regex-use;manual", + "org.apache.commons.lang3;RegExUtils;false;replacePattern;(String,String,String);;Argument[1];regex-use;manual", ] } } diff --git a/java/ql/lib/semmle/code/java/security/Files.qll b/java/ql/lib/semmle/code/java/security/Files.qll index 2cc55a1076f..52ea86bc5b7 100644 --- a/java/ql/lib/semmle/code/java/security/Files.qll +++ b/java/ql/lib/semmle/code/java/security/Files.qll @@ -84,13 +84,15 @@ private class FileSummaryModels extends SummaryModelCsv { "java.io;File;true;toPath;;;Argument[-1];ReturnValue;taint;manual", "java.io;File;true;toString;;;Argument[-1];ReturnValue;taint;manual", "java.io;File;true;toURI;;;Argument[-1];ReturnValue;taint;manual", + "java.nio.file;Path;true;getParent;;;Argument[-1];ReturnValue;taint;manual", "java.nio.file;Path;true;normalize;;;Argument[-1];ReturnValue;taint;manual", "java.nio.file;Path;true;resolve;;;Argument[-1..0];ReturnValue;taint;manual", "java.nio.file;Path;true;toAbsolutePath;;;Argument[-1];ReturnValue;taint;manual", "java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint;manual", "java.nio.file;Path;true;toString;;;Argument[-1];ReturnValue;taint;manual", "java.nio.file;Path;true;toUri;;;Argument[-1];ReturnValue;taint;manual", - "java.nio.file;Paths;true;get;;;Argument[0..1];ReturnValue;taint;manual", + "java.nio.file;Paths;true;get;;;Argument[0];ReturnValue;taint;manual", + "java.nio.file;Paths;true;get;;;Argument[1].ArrayElement;ReturnValue;taint;manual", "java.nio.file;FileSystem;true;getPath;;;Argument[0];ReturnValue;taint;manual", "java.nio.file;FileSystem;true;getRootDirectories;;;Argument[0];ReturnValue;taint;manual" ] diff --git a/java/ql/lib/semmle/code/java/security/regexp/RegexInjection.qll b/java/ql/lib/semmle/code/java/security/regexp/RegexInjection.qll new file mode 100644 index 00000000000..3c1e2e98229 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/regexp/RegexInjection.qll @@ -0,0 +1,48 @@ +/** Provides classes and predicates related to regex injection in Java. */ + +import java +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.frameworks.Regex +private import semmle.code.java.regex.RegexFlowModels + +/** A data flow sink for untrusted user input used to construct regular expressions. */ +abstract class RegexInjectionSink extends DataFlow::ExprNode { } + +/** A sanitizer for untrusted user input used to construct regular expressions. */ +abstract class RegexInjectionSanitizer extends DataFlow::ExprNode { } + +/** A method call that takes a regular expression as an argument. */ +private class DefaultRegexInjectionSink extends RegexInjectionSink { + DefaultRegexInjectionSink() { + // we only select sinks where there is direct regex creation, not regex uses + sinkNode(this, ["regex-use[]", "regex-use[f1]", "regex-use[f-1]", "regex-use[-1]", "regex-use"]) + } +} + +/** + * A call to the `Pattern.quote` method, which gives metacharacters or escape sequences + * no special meaning. + */ +private class PatternQuoteCall extends RegexInjectionSanitizer { + PatternQuoteCall() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + ma.getArgument(0) = this.asExpr() and + m instanceof PatternQuoteMethod + ) + } +} + +/** + * Use of the `Pattern.LITERAL` flag with `Pattern.compile`, which gives metacharacters + * or escape sequences no special meaning. + */ +private class PatternLiteralFlag extends RegexInjectionSanitizer { + PatternLiteralFlag() { + exists(MethodAccess ma, Method m, PatternLiteralField field | m = ma.getMethod() | + ma.getArgument(0) = this.asExpr() and + m.getDeclaringType() instanceof TypeRegexPattern and + m.hasName("compile") and + ma.getArgument(1) = field.getAnAccess() + ) + } +} diff --git a/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll new file mode 100644 index 00000000000..e2453c08dca --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll @@ -0,0 +1,17 @@ +/** Provides configurations to be used in queries related to regex injection. */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.security.regexp.RegexInjection + +/** A taint-tracking configuration for untrusted user input used to construct regular expressions. */ +class RegexInjectionConfiguration extends TaintTracking::Configuration { + RegexInjectionConfiguration() { this = "RegexInjection" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof RegexInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof RegexInjectionSanitizer } +} diff --git a/java/ql/lib/semmle/code/xml/MavenPom.qll b/java/ql/lib/semmle/code/xml/MavenPom.qll index 8af6e6f0128..612c1468259 100644 --- a/java/ql/lib/semmle/code/xml/MavenPom.qll +++ b/java/ql/lib/semmle/code/xml/MavenPom.qll @@ -381,6 +381,15 @@ class DeclaredRepository extends PomElement { * be the string contents of that tag. */ string getRepositoryUrl() { result = this.getAChild("url").(PomElement).getValue() } + + /** + * Holds if this repository is disabled in both the `releases` and `snapshots` policies. + */ + predicate isDisabled() { + forex(PomElement policy | policy = this.getAChild(["releases", "snapshots"]) | + policy.getAChild("enabled").(PomElement).getValue() = "false" + ) + } } /** diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index 61b4170ca74..8bbe06cf3fe 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.4.4 + +### New Queries + +* 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). +* Added a new query, `java/android/sensitive-keyboard-cache`, to detect instances of sensitive information possibly being saved to the Android keyboard cache. + ## 0.4.3 No user-facing changes. diff --git a/java/ql/src/Security/CWE/CWE-730/RegexInjection.java b/java/ql/src/Security/CWE/CWE-730/RegexInjection.java new file mode 100644 index 00000000000..673d5a2fa40 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/RegexInjection.java @@ -0,0 +1,22 @@ +import java.util.regex.Pattern; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; + +public class RegexInjectionDemo extends HttpServlet { + + public boolean badExample(javax.servlet.http.HttpServletRequest request) { + String regex = request.getParameter("regex"); + String input = request.getParameter("input"); + + // BAD: Unsanitized user input is used to construct a regular expression + return input.matches(regex); + } + + public boolean goodExample(javax.servlet.http.HttpServletRequest request) { + String regex = request.getParameter("regex"); + String input = request.getParameter("input"); + + // GOOD: User input is sanitized before constructing the regex + return input.matches(Pattern.quote(regex)); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.qhelp b/java/ql/src/Security/CWE/CWE-730/RegexInjection.qhelp similarity index 67% rename from java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.qhelp rename to java/ql/src/Security/CWE/CWE-730/RegexInjection.qhelp index 6cd80b52f75..3e239d07107 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.qhelp +++ b/java/ql/src/Security/CWE/CWE-730/RegexInjection.qhelp @@ -15,25 +15,25 @@ perform a Denial of Service attack.

Before embedding user input into a regular expression, use a sanitization function -to escape meta-characters that have special meaning. +such as Pattern.quote to escape meta-characters that have special meaning.

-The following example shows a HTTP request parameter that is used to construct a regular expression: +The following example shows an HTTP request parameter that is used to construct a regular expression.

-

In the first case the user-provided regex is not escaped. -If a malicious user provides a regex that has exponential worst case performance, +If a malicious user provides a regex whose worst-case performance is exponential, then this could lead to a Denial of Service.

-In the second case, the user input is escaped using escapeSpecialRegexChars before being included +In the second case, the user input is escaped using Pattern.quote before being included in the regular expression. This ensures that the user cannot insert characters which have a special meaning in regular expressions.

+
@@ -44,5 +44,8 @@ OWASP:
  • Wikipedia: ReDoS.
  • +
  • +Java API Specification: Pattern.quote. +
  • diff --git a/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql b/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql new file mode 100644 index 00000000000..820e0949d22 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-730/RegexInjection.ql @@ -0,0 +1,23 @@ +/** + * @name Regular expression injection + * @description User input should not be used in regular expressions without first being escaped, + * otherwise a malicious user may be able to provide a regex that could require + * exponential time on certain inputs. + * @kind path-problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id java/regex-injection + * @tags security + * external/cwe/cwe-730 + * external/cwe/cwe-400 + */ + +import java +import semmle.code.java.security.regexp.RegexInjectionQuery +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql b/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql index ede03c50b00..dca1a9cc4b7 100644 --- a/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql +++ b/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql @@ -17,7 +17,8 @@ import java import semmle.code.xml.MavenPom predicate isInsecureRepositoryUsage(DeclaredRepository repository) { - repository.getRepositoryUrl().regexpMatch("(?i)^(http|ftp)://(?!localhost[:/]).*") + repository.getRepositoryUrl().regexpMatch("(?i)^(http|ftp)://(?!localhost[:/]).*") and + not repository.isDisabled() } from DeclaredRepository repository diff --git a/java/ql/src/change-notes/2022-10-07-sensitive-keyboard-cache.md b/java/ql/src/change-notes/2022-10-07-sensitive-keyboard-cache.md deleted file mode 100644 index 21a1652cc93..00000000000 --- a/java/ql/src/change-notes/2022-10-07-sensitive-keyboard-cache.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: newQuery ---- -* Added a new query, `java/android/sensitive-keyboard-cache`, to detect instances of sensitive information possibly being saved to the keyboard cache. \ No newline at end of file diff --git a/java/ql/src/change-notes/2022-11-03-regex-injection.md b/java/ql/src/change-notes/2022-11-03-regex-injection.md new file mode 100644 index 00000000000..759aa2a86e1 --- /dev/null +++ b/java/ql/src/change-notes/2022-11-03-regex-injection.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* The query, `java/regex-injection`, 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 @edvraa](https://github.com/github/codeql/pull/5704). diff --git a/java/ql/src/change-notes/2022-11-21-disabled-maven-repositories.md b/java/ql/src/change-notes/2022-11-21-disabled-maven-repositories.md new file mode 100644 index 00000000000..5d060b06076 --- /dev/null +++ b/java/ql/src/change-notes/2022-11-21-disabled-maven-repositories.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query `java/maven/non-https-url` no longer alerts about disabled repositories. diff --git a/java/ql/src/change-notes/2022-10-19-insufficient-key-size.md b/java/ql/src/change-notes/released/0.4.4.md similarity index 58% rename from java/ql/src/change-notes/2022-10-19-insufficient-key-size.md rename to java/ql/src/change-notes/released/0.4.4.md index e117b5b5941..849452aa9c0 100644 --- a/java/ql/src/change-notes/2022-10-19-insufficient-key-size.md +++ b/java/ql/src/change-notes/released/0.4.4.md @@ -1,4 +1,6 @@ ---- -category: newQuery ---- +## 0.4.4 + +### New Queries + * 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). +* Added a new query, `java/android/sensitive-keyboard-cache`, to detect instances of sensitive information possibly being saved to the Android keyboard cache. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.java b/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.java deleted file mode 100644 index 387648a443e..00000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.demo; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class DemoApplication { - - @GetMapping("/string1") - public String string1(@RequestParam(value = "input", defaultValue = "test") String input, - @RequestParam(value = "pattern", defaultValue = ".*") String pattern) { - // BAD: Unsanitized user input is used to construct a regular expression - if (input.matches("^" + pattern + "=.*$")) - return "match!"; - - return "doesn't match!"; - } - - @GetMapping("/string2") - public String string2(@RequestParam(value = "input", defaultValue = "test") String input, - @RequestParam(value = "pattern", defaultValue = ".*") String pattern) { - // GOOD: User input is sanitized before constructing the regex - if (input.matches("^" + escapeSpecialRegexChars(pattern) + "=.*$")) - return "match!"; - - return "doesn't match!"; - } - - Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\]><-=!.+*?^$\\\\|]"); - - String escapeSpecialRegexChars(String str) { - return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); - } -} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.ql deleted file mode 100644 index f60e5d9070b..00000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-730/RegexInjection.ql +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @name Regular expression injection - * @description User input should not be used in regular expressions without first being sanitized, - * otherwise a malicious user may be able to provide a regex that could require - * exponential time on certain inputs. - * @kind path-problem - * @problem.severity error - * @precision high - * @id java/regex-injection - * @tags security - * external/cwe/cwe-730 - * external/cwe/cwe-400 - */ - -import java -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking -import DataFlow::PathGraph - -/** - * A data flow sink for untrusted user input used to construct regular expressions. - */ -class RegexSink extends DataFlow::ExprNode { - RegexSink() { - exists(MethodAccess ma, Method m | m = ma.getMethod() | - ( - m.getDeclaringType() instanceof TypeString and - ( - ma.getArgument(0) = this.asExpr() and - m.hasName(["matches", "split", "replaceFirst", "replaceAll"]) - ) - or - m.getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and - ( - ma.getArgument(0) = this.asExpr() and - m.hasName(["compile", "matches"]) - ) - or - m.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "RegExUtils") and - ( - ma.getArgument(1) = this.asExpr() and - m.getParameterType(1) instanceof TypeString and - m.hasName([ - "removeAll", "removeFirst", "removePattern", "replaceAll", "replaceFirst", - "replacePattern" - ]) - ) - ) - ) - } -} - -abstract class Sanitizer extends DataFlow::ExprNode { } - -/** - * A call to a function whose name suggests that it escapes regular - * expression meta-characters. - */ -class RegExpSanitizationCall extends Sanitizer { - RegExpSanitizationCall() { - exists(string calleeName, string sanitize, string regexp | - calleeName = this.asExpr().(Call).getCallee().getName() and - sanitize = "(?:escape|saniti[sz]e)" and - regexp = "regexp?" - | - calleeName - .regexpMatch("(?i)(" + sanitize + ".*" + regexp + ".*)" + "|(" + regexp + ".*" + sanitize + - ".*)") - ) - } -} - -/** - * A taint-tracking configuration for untrusted user input used to construct regular expressions. - */ -class RegexInjectionConfiguration extends TaintTracking::Configuration { - RegexInjectionConfiguration() { this = "RegexInjectionConfiguration" } - - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof RegexSink } - - override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c -where c.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", - source.getNode(), "user-provided value" diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index 87267893413..50d76873114 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.4.4-dev +version: 0.4.5-dev groups: - java - queries diff --git a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.expected deleted file mode 100644 index a795f1591ad..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.expected +++ /dev/null @@ -1,73 +0,0 @@ -edges -| RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... | -| RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern | -| RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern | -| RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern | -| RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern | -| RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern | -| RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern | -| RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:36:68:42 | pattern : String | -| RegexInjection.java:68:32:68:43 | foo(...) : String | RegexInjection.java:68:26:68:52 | ... + ... | -| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:68:32:68:43 | foo(...) : String | -| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:71:14:71:23 | str : String | -| RegexInjection.java:71:14:71:23 | str : String | RegexInjection.java:72:12:72:14 | str : String | -| RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... | -| RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern | -| RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern | -| RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern | -| RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern | -| RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern | -| RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern | -nodes -| RegexInjection.java:13:22:13:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:16:26:16:47 | ... + ... | semmle.label | ... + ... | -| RegexInjection.java:20:22:20:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:23:24:23:30 | pattern | semmle.label | pattern | -| RegexInjection.java:27:22:27:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:30:31:30:37 | pattern | semmle.label | pattern | -| RegexInjection.java:34:22:34:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:37:29:37:35 | pattern | semmle.label | pattern | -| RegexInjection.java:41:22:41:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:44:34:44:40 | pattern | semmle.label | pattern | -| RegexInjection.java:51:22:51:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:54:28:54:34 | pattern | semmle.label | pattern | -| RegexInjection.java:58:22:58:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:61:28:61:34 | pattern | semmle.label | pattern | -| RegexInjection.java:65:22:65:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:68:26:68:52 | ... + ... | semmle.label | ... + ... | -| RegexInjection.java:68:32:68:43 | foo(...) : String | semmle.label | foo(...) : String | -| RegexInjection.java:68:36:68:42 | pattern : String | semmle.label | pattern : String | -| RegexInjection.java:71:14:71:23 | str : String | semmle.label | str : String | -| RegexInjection.java:72:12:72:14 | str : String | semmle.label | str : String | -| RegexInjection.java:84:22:84:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:90:26:90:47 | ... + ... | semmle.label | ... + ... | -| RegexInjection.java:100:22:100:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:103:40:103:46 | pattern | semmle.label | pattern | -| RegexInjection.java:107:22:107:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:110:42:110:48 | pattern | semmle.label | pattern | -| RegexInjection.java:114:22:114:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:117:44:117:50 | pattern | semmle.label | pattern | -| RegexInjection.java:121:22:121:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:124:41:124:47 | pattern | semmle.label | pattern | -| RegexInjection.java:128:22:128:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:131:43:131:49 | pattern | semmle.label | pattern | -| RegexInjection.java:143:22:143:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| RegexInjection.java:146:45:146:51 | pattern | semmle.label | pattern | -subpaths -| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:71:14:71:23 | str : String | RegexInjection.java:72:12:72:14 | str : String | RegexInjection.java:68:32:68:43 | foo(...) : String | -#select -| RegexInjection.java:16:26:16:47 | ... + ... | RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:13:22:13:52 | getParameter(...) | user-provided value | -| RegexInjection.java:23:24:23:30 | pattern | RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:20:22:20:52 | getParameter(...) | user-provided value | -| RegexInjection.java:30:31:30:37 | pattern | RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:27:22:27:52 | getParameter(...) | user-provided value | -| RegexInjection.java:37:29:37:35 | pattern | RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:34:22:34:52 | getParameter(...) | user-provided value | -| RegexInjection.java:44:34:44:40 | pattern | RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:41:22:41:52 | getParameter(...) | user-provided value | -| RegexInjection.java:54:28:54:34 | pattern | RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:51:22:51:52 | getParameter(...) | user-provided value | -| RegexInjection.java:61:28:61:34 | pattern | RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:58:22:58:52 | getParameter(...) | user-provided value | -| RegexInjection.java:68:26:68:52 | ... + ... | RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:26:68:52 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:65:22:65:52 | getParameter(...) | user-provided value | -| RegexInjection.java:90:26:90:47 | ... + ... | RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:84:22:84:52 | getParameter(...) | user-provided value | -| RegexInjection.java:103:40:103:46 | pattern | RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:100:22:100:52 | getParameter(...) | user-provided value | -| RegexInjection.java:110:42:110:48 | pattern | RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:107:22:107:52 | getParameter(...) | user-provided value | -| RegexInjection.java:117:44:117:50 | pattern | RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:114:22:114:52 | getParameter(...) | user-provided value | -| RegexInjection.java:124:41:124:47 | pattern | RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:121:22:121:52 | getParameter(...) | user-provided value | -| RegexInjection.java:131:43:131:49 | pattern | RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:128:22:128:52 | getParameter(...) | user-provided value | -| RegexInjection.java:146:45:146:51 | pattern | RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:143:22:143:52 | getParameter(...) | user-provided value | diff --git a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.qlref deleted file mode 100644 index dca594b38d2..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-730/RegexInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-730/options b/java/ql/test/experimental/query-tests/security/CWE-730/options deleted file mode 100644 index 73f1b5a3c3e..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-730/options +++ /dev/null @@ -1 +0,0 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/apache-commons-lang3-3.7 \ No newline at end of file diff --git a/java/ql/test/kotlin/library-tests/classes/PrintAst.expected b/java/ql/test/kotlin/library-tests/classes/PrintAst.expected index 698a4f874c9..6f19fb37fee 100644 --- a/java/ql/test/kotlin/library-tests/classes/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/classes/PrintAst.expected @@ -138,14 +138,14 @@ classes.kt: # 39| 0: [ExprStmt] ; # 39| 0: [MethodAccess] f(...) # 39| -1: [TypeAccess] ClassesKt -# 39| 0: [StringLiteral] init1 +# 39| 0: [StringLiteral] "init1" # 42| 1: [ExprStmt] ; # 42| 0: [KtInitializerAssignExpr] ...=... # 42| 0: [VarAccess] x # 45| 2: [ExprStmt] ; # 45| 0: [MethodAccess] f(...) # 45| -1: [TypeAccess] ClassesKt -# 45| 0: [StringLiteral] init2 +# 45| 0: [StringLiteral] "init2" # 36| 2: [ExprStmt] ; # 36| 0: [MethodAccess] f(...) # 36| -1: [TypeAccess] ClassesKt @@ -1119,7 +1119,7 @@ local_anonymous.kt: # 40| 1: [BlockStmt] { ... } # 42| 0: [LocalVariableDeclStmt] var ...; # 42| 1: [LocalVariableDeclExpr] answer -# 42| 0: [StringLiteral] 42 +# 42| 0: [StringLiteral] "42" # 40| 1: [ExprStmt] ; # 40| 0: [ClassInstanceExpr] new (...) # 40| -3: [TypeAccess] Interface2 diff --git a/java/ql/test/kotlin/library-tests/collection-literals/PrintAst.expected b/java/ql/test/kotlin/library-tests/collection-literals/PrintAst.expected index 99312685a0e..5a81043964b 100644 --- a/java/ql/test/kotlin/library-tests/collection-literals/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/collection-literals/PrintAst.expected @@ -39,8 +39,8 @@ test.kt: # 1| 0: [VarAccess] p0 # 0| 1: [ArrayCreationExpr] new String[] # 0| -2: [ArrayInit] {...} -# 0| 0: [StringLiteral] hello -# 0| 1: [StringLiteral] world +# 0| 0: [StringLiteral] "hello" +# 0| 1: [StringLiteral] "world" # 0| -1: [TypeAccess] String # 0| 0: [IntegerLiteral] 2 # 1| 1: [IfStmt] if (...) diff --git a/java/ql/test/kotlin/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test/kotlin/library-tests/controlflow/basic/bbStmts.expected index 4e0724fca1f..b3f3c19341f 100644 --- a/java/ql/test/kotlin/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test/kotlin/library-tests/controlflow/basic/bbStmts.expected @@ -155,7 +155,7 @@ | Test.kt:105:5:109:5 | ; | 5 | Test.kt:105:9:105:17 | ... (value not-equals) ... | | Test.kt:105:20:107:5 | { ... } | 0 | Test.kt:105:20:107:5 | { ... } | | Test.kt:105:20:107:5 | { ... } | 1 | Test.kt:106:9:106:29 | ; | -| Test.kt:105:20:107:5 | { ... } | 2 | Test.kt:106:18:106:27 | x not null | +| Test.kt:105:20:107:5 | { ... } | 2 | Test.kt:106:18:106:27 | "x not null" | | Test.kt:105:20:107:5 | { ... } | 3 | Test.kt:106:9:106:29 | println(...) | | Test.kt:107:16:109:5 | ... -> ... | 0 | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:107:16:109:5 | ... -> ... | 1 | Test.kt:107:16:107:16 | y | @@ -163,7 +163,7 @@ | Test.kt:107:16:109:5 | ... -> ... | 3 | Test.kt:107:16:107:24 | ... (value not-equals) ... | | Test.kt:107:27:109:5 | { ... } | 0 | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:27:109:5 | { ... } | 1 | Test.kt:108:9:108:29 | ; | -| Test.kt:107:27:109:5 | { ... } | 2 | Test.kt:108:18:108:27 | y not null | +| Test.kt:107:27:109:5 | { ... } | 2 | Test.kt:108:18:108:27 | "y not null" | | Test.kt:107:27:109:5 | { ... } | 3 | Test.kt:108:9:108:29 | println(...) | | Test.kt:112:1:116:1 | fn | 0 | Test.kt:112:1:116:1 | fn | | Test.kt:112:32:116:1 | { ... } | 0 | Test.kt:112:32:116:1 | { ... } | diff --git a/java/ql/test/kotlin/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test/kotlin/library-tests/controlflow/basic/getASuccessor.expected index bba6e9cbae7..ddd54d10b7b 100644 --- a/java/ql/test/kotlin/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test/kotlin/library-tests/controlflow/basic/getASuccessor.expected @@ -207,20 +207,20 @@ missingSuccessor | Test.kt:105:9:107:5 | ... -> ... | WhenBranch | Test.kt:105:9:105:9 | x | VarAccess | | Test.kt:105:14:105:17 | null | NullLiteral | Test.kt:105:9:105:17 | ... (value not-equals) ... | ValueNEExpr | | Test.kt:105:20:107:5 | { ... } | BlockStmt | Test.kt:106:9:106:29 | ; | ExprStmt | -| Test.kt:106:9:106:29 | ; | ExprStmt | Test.kt:106:18:106:27 | x not null | StringLiteral | +| Test.kt:106:9:106:29 | ; | ExprStmt | Test.kt:106:18:106:27 | "x not null" | StringLiteral | | Test.kt:106:9:106:29 | ConsoleKt | TypeAccess | file://:0:0:0:0 | | | | Test.kt:106:9:106:29 | println(...) | MethodAccess | Test.kt:100:1:110:1 | fn | Method | -| Test.kt:106:18:106:27 | x not null | StringLiteral | Test.kt:106:9:106:29 | println(...) | MethodAccess | +| Test.kt:106:18:106:27 | "x not null" | StringLiteral | Test.kt:106:9:106:29 | println(...) | MethodAccess | | Test.kt:107:16:107:16 | y | VarAccess | Test.kt:107:21:107:24 | null | NullLiteral | | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:100:1:110:1 | fn | Method | | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | Test.kt:107:27:109:5 | { ... } | BlockStmt | | Test.kt:107:16:109:5 | ... -> ... | WhenBranch | Test.kt:107:16:107:16 | y | VarAccess | | Test.kt:107:21:107:24 | null | NullLiteral | Test.kt:107:16:107:24 | ... (value not-equals) ... | ValueNEExpr | | Test.kt:107:27:109:5 | { ... } | BlockStmt | Test.kt:108:9:108:29 | ; | ExprStmt | -| Test.kt:108:9:108:29 | ; | ExprStmt | Test.kt:108:18:108:27 | y not null | StringLiteral | +| Test.kt:108:9:108:29 | ; | ExprStmt | Test.kt:108:18:108:27 | "y not null" | StringLiteral | | Test.kt:108:9:108:29 | ConsoleKt | TypeAccess | file://:0:0:0:0 | | | | Test.kt:108:9:108:29 | println(...) | MethodAccess | Test.kt:100:1:110:1 | fn | Method | -| Test.kt:108:18:108:27 | y not null | StringLiteral | Test.kt:108:9:108:29 | println(...) | MethodAccess | +| Test.kt:108:18:108:27 | "y not null" | StringLiteral | Test.kt:108:9:108:29 | println(...) | MethodAccess | | Test.kt:112:1:116:1 | Unit | TypeAccess | file://:0:0:0:0 | | | | Test.kt:112:1:116:1 | fn | Method | file://:0:0:0:0 | | | | Test.kt:112:8:112:17 | boolean | TypeAccess | file://:0:0:0:0 | | | diff --git a/java/ql/test/kotlin/library-tests/data-classes/PrintAst.expected b/java/ql/test/kotlin/library-tests/data-classes/PrintAst.expected index d52888544dc..7ea9b169c7c 100644 --- a/java/ql/test/kotlin/library-tests/data-classes/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/data-classes/PrintAst.expected @@ -145,19 +145,19 @@ dc.kt: # 0| 5: [BlockStmt] { ... } # 0| 0: [ReturnStmt] return ... # 0| 0: [StringTemplateExpr] "..." -# 0| 0: [StringLiteral] ProtoMapValue( -# 0| 1: [StringLiteral] bytes= +# 0| 0: [StringLiteral] "ProtoMapValue(" +# 0| 1: [StringLiteral] "bytes=" # 0| 2: [MethodAccess] toString(...) # 0| -1: [TypeAccess] Arrays # 0| 0: [VarAccess] this.bytes # 0| -1: [ThisAccess] this -# 0| 3: [StringLiteral] , -# 0| 4: [StringLiteral] strs= +# 0| 3: [StringLiteral] ", " +# 0| 4: [StringLiteral] "strs=" # 0| 5: [MethodAccess] toString(...) # 0| -1: [TypeAccess] Arrays # 0| 0: [VarAccess] this.strs # 0| -1: [ThisAccess] this -# 0| 6: [StringLiteral] ) +# 0| 6: [StringLiteral] ")" # 1| 8: [Constructor] ProtoMapValue #-----| 4: (Parameters) # 1| 0: [Parameter] bytes diff --git a/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected index f204c12ebe2..7c7b382a9ad 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected +++ b/java/ql/test/kotlin/library-tests/dataflow/foreach/test.expected @@ -2,7 +2,7 @@ | C1.java:10:44:10:46 | "a" | C1.java:12:17:12:20 | ...[...] | | C1.java:10:44:10:46 | "a" | C1.java:15:20:15:23 | ...[...] | | C1.java:10:44:10:46 | "a" | C1.java:19:20:19:20 | s | -| C2.kt:8:32:8:32 | a | C2.kt:9:14:9:14 | l | -| C2.kt:8:32:8:32 | a | C2.kt:10:14:10:17 | ...[...] | -| C2.kt:8:32:8:32 | a | C2.kt:12:18:12:21 | ...[...] | -| C2.kt:8:32:8:32 | a | C2.kt:15:18:15:18 | s | +| C2.kt:8:32:8:32 | "a" | C2.kt:9:14:9:14 | l | +| C2.kt:8:32:8:32 | "a" | C2.kt:10:14:10:17 | ...[...] | +| C2.kt:8:32:8:32 | "a" | C2.kt:12:18:12:21 | ...[...] | +| C2.kt:8:32:8:32 | "a" | C2.kt:15:18:15:18 | s | diff --git a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected index f821bdadd5b..78bf583ec0d 100644 --- a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected @@ -171,7 +171,7 @@ delegatedProperties.kt: # 7| 0: [ExprStmt] ; # 7| 0: [MethodAccess] println(...) # 7| -1: [TypeAccess] ConsoleKt -# 7| 0: [StringLiteral] init +# 7| 0: [StringLiteral] "init" # 8| 1: [ReturnStmt] return ... # 8| 0: [IntegerLiteral] 5 # 6| -3: [TypeAccess] Function0 @@ -2459,10 +2459,10 @@ exprs.kt: # 123| 0: [CharacterLiteral] x # 124| 106: [LocalVariableDeclStmt] var ...; # 124| 1: [LocalVariableDeclExpr] str -# 124| 0: [StringLiteral] string lit +# 124| 0: [StringLiteral] "string lit" # 125| 107: [LocalVariableDeclStmt] var ...; # 125| 1: [LocalVariableDeclExpr] strWithQuote -# 125| 0: [StringLiteral] string " lit +# 125| 0: [StringLiteral] "string \" lit" # 126| 108: [LocalVariableDeclStmt] var ...; # 126| 1: [LocalVariableDeclExpr] b6 # 126| 0: [InstanceOfExpr] ...instanceof... @@ -2480,34 +2480,34 @@ exprs.kt: # 128| 1: [VarAccess] b7 # 129| 111: [LocalVariableDeclStmt] var ...; # 129| 1: [LocalVariableDeclExpr] str1 -# 129| 0: [StringLiteral] string lit +# 129| 0: [StringLiteral] "string lit" # 130| 112: [LocalVariableDeclStmt] var ...; # 130| 1: [LocalVariableDeclExpr] str2 -# 130| 0: [StringLiteral] string lit +# 130| 0: [StringLiteral] "string lit" # 131| 113: [LocalVariableDeclStmt] var ...; # 131| 1: [LocalVariableDeclExpr] str3 # 131| 0: [NullLiteral] null # 132| 114: [LocalVariableDeclStmt] var ...; # 132| 1: [LocalVariableDeclExpr] str4 # 132| 0: [StringTemplateExpr] "..." -# 132| 0: [StringLiteral] foo +# 132| 0: [StringLiteral] "foo " # 132| 1: [VarAccess] str1 -# 132| 2: [StringLiteral] bar +# 132| 2: [StringLiteral] " bar " # 132| 3: [VarAccess] str2 -# 132| 4: [StringLiteral] baz +# 132| 4: [StringLiteral] " baz" # 133| 115: [LocalVariableDeclStmt] var ...; # 133| 1: [LocalVariableDeclExpr] str5 # 133| 0: [StringTemplateExpr] "..." -# 133| 0: [StringLiteral] foo +# 133| 0: [StringLiteral] "foo " # 133| 1: [AddExpr] ... + ... # 133| 0: [VarAccess] str1 # 133| 1: [VarAccess] str2 -# 133| 2: [StringLiteral] bar +# 133| 2: [StringLiteral] " bar " # 133| 3: [MethodAccess] stringPlus(...) # 133| -1: [TypeAccess] Intrinsics # 133| 0: [VarAccess] str2 # 133| 1: [VarAccess] str1 -# 133| 4: [StringLiteral] baz +# 133| 4: [StringLiteral] " baz" # 134| 116: [LocalVariableDeclStmt] var ...; # 134| 1: [LocalVariableDeclExpr] str6 # 134| 0: [AddExpr] ... + ... @@ -3531,12 +3531,12 @@ exprs.kt: # 215| 1: [LocalVariableDeclExpr] d0 # 215| 0: [MethodAccess] valueOf(...) # 215| -1: [TypeAccess] Color -# 215| 0: [StringLiteral] GREEN +# 215| 0: [StringLiteral] "GREEN" # 216| 8: [LocalVariableDeclStmt] var ...; # 216| 1: [LocalVariableDeclExpr] d1 # 216| 0: [MethodAccess] valueOf(...) # 216| -1: [TypeAccess] Color -# 216| 0: [StringLiteral] GREEN +# 216| 0: [StringLiteral] "GREEN" # 224| 11: [Class] SomeClass1 # 224| 1: [Constructor] SomeClass1 # 224| 5: [BlockStmt] { ... } @@ -4468,7 +4468,7 @@ funcExprs.kt: # 36| 0: [TypeAccess] int # 36| 5: [BlockStmt] { ... } # 36| 0: [ReturnStmt] return ... -# 36| 0: [StringLiteral] +# 36| 0: [StringLiteral] "" # 36| -3: [TypeAccess] FunctionN # 36| 0: [TypeAccess] String # 38| 14: [ExprStmt] ; @@ -5316,7 +5316,7 @@ funcExprs.kt: # 90| 0: [TypeAccess] int # 90| 5: [BlockStmt] { ... } # 90| 0: [ReturnStmt] return ... -# 90| 0: [StringLiteral] +# 90| 0: [StringLiteral] "" # 90| -3: [TypeAccess] FunctionN # 90| 0: [TypeAccess] String # 91| 5: [ExprStmt] ; @@ -5407,7 +5407,7 @@ funcExprs.kt: # 94| 0: [TypeAccess] int # 94| 5: [BlockStmt] { ... } # 94| 0: [ReturnStmt] return ... -# 94| 0: [StringLiteral] +# 94| 0: [StringLiteral] "" # 94| -3: [TypeAccess] Function22 # 94| 0: [TypeAccess] Integer # 94| 1: [TypeAccess] Integer @@ -5599,7 +5599,7 @@ funcExprs.kt: # 70| 0: [TypeAccess] int # 70| 5: [BlockStmt] { ... } # 70| 0: [ReturnStmt] return ... -# 70| 0: [StringLiteral] +# 70| 0: [StringLiteral] "" # 73| 4: [Class] Class3 # 73| 3: [Constructor] Class3 # 73| 5: [BlockStmt] { ... } @@ -5625,7 +5625,7 @@ funcExprs.kt: # 75| 0: [TypeAccess] Integer # 75| 5: [BlockStmt] { ... } # 75| 0: [ReturnStmt] return ... -# 75| 0: [StringLiteral] a +# 75| 0: [StringLiteral] "a" # 75| -3: [TypeAccess] Function1>,String> # 75| 0: [TypeAccess] Generic> # 75| 0: [TypeAccess] Generic @@ -6014,7 +6014,7 @@ samConversion.kt: # 7| 0: [ReturnStmt] return ... # 7| 0: [ValueEQExpr] ... (value equals) ... # 7| 0: [ExtensionReceiverAccess] this -# 7| 1: [StringLiteral] +# 7| 1: [StringLiteral] "" # 7| -3: [TypeAccess] Function2 # 7| 0: [TypeAccess] String # 7| 1: [TypeAccess] Integer @@ -7058,7 +7058,7 @@ whenExpr.kt: # 6| 1: [ThrowStmt] throw ... # 6| 0: [ClassInstanceExpr] new Exception(...) # 6| -3: [TypeAccess] Exception -# 6| 0: [StringLiteral] No threes please +# 6| 0: [StringLiteral] "No threes please" # 7| 4: [WhenBranch] ... -> ... # 7| 0: [BooleanLiteral] true # 7| 1: [ExprStmt] ; diff --git a/java/ql/test/kotlin/library-tests/exprs/binop.expected b/java/ql/test/kotlin/library-tests/exprs/binop.expected index 4c08b123a68..f69701028d5 100644 --- a/java/ql/test/kotlin/library-tests/exprs/binop.expected +++ b/java/ql/test/kotlin/library-tests/exprs/binop.expected @@ -127,7 +127,7 @@ | localFunctionCalls.kt:5:25:5:29 | ... + ... | localFunctionCalls.kt:5:25:5:25 | i | localFunctionCalls.kt:5:29:5:29 | x | | samConversion.kt:2:33:2:38 | ... % ... | samConversion.kt:2:33:2:34 | it | samConversion.kt:2:38:2:38 | 2 | | samConversion.kt:2:33:2:43 | ... (value equals) ... | samConversion.kt:2:33:2:38 | ... % ... | samConversion.kt:2:43:2:43 | 0 | -| samConversion.kt:7:36:7:45 | ... (value equals) ... | samConversion.kt:7:36:7:39 | this | samConversion.kt:7:44:7:45 | | +| samConversion.kt:7:36:7:45 | ... (value equals) ... | samConversion.kt:7:36:7:39 | this | samConversion.kt:7:44:7:45 | "" | | samConversion.kt:10:18:10:22 | ... % ... | samConversion.kt:10:18:10:18 | j | samConversion.kt:10:22:10:22 | 2 | | samConversion.kt:10:18:10:27 | ... (value equals) ... | samConversion.kt:10:18:10:22 | ... % ... | samConversion.kt:10:27:10:27 | 0 | | samConversion.kt:12:18:12:22 | ... % ... | samConversion.kt:12:18:12:18 | j | samConversion.kt:12:22:12:22 | 2 | diff --git a/java/ql/test/kotlin/library-tests/exprs/exprs.expected b/java/ql/test/kotlin/library-tests/exprs/exprs.expected index 08a9891f64b..4b8d200a1d7 100644 --- a/java/ql/test/kotlin/library-tests/exprs/exprs.expected +++ b/java/ql/test/kotlin/library-tests/exprs/exprs.expected @@ -51,7 +51,7 @@ | delegatedProperties.kt:6:32:9:9 | int | file://:0:0:0:0 | | TypeAccess | | delegatedProperties.kt:7:13:7:27 | ConsoleKt | delegatedProperties.kt:6:32:9:9 | invoke | TypeAccess | | delegatedProperties.kt:7:13:7:27 | println(...) | delegatedProperties.kt:6:32:9:9 | invoke | MethodAccess | -| delegatedProperties.kt:7:22:7:25 | init | delegatedProperties.kt:6:32:9:9 | invoke | StringLiteral | +| delegatedProperties.kt:7:22:7:25 | "init" | delegatedProperties.kt:6:32:9:9 | invoke | StringLiteral | | delegatedProperties.kt:8:13:8:13 | 5 | delegatedProperties.kt:6:32:9:9 | invoke | IntegerLiteral | | delegatedProperties.kt:10:9:10:22 | ConsoleKt | delegatedProperties.kt:5:5:12:5 | fn | TypeAccess | | delegatedProperties.kt:10:9:10:22 | println(...) | delegatedProperties.kt:5:5:12:5 | fn | MethodAccess | @@ -1337,9 +1337,9 @@ | exprs.kt:123:5:123:15 | c | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:123:13:123:15 | x | exprs.kt:4:1:142:1 | topLevelMethod | CharacterLiteral | | exprs.kt:124:5:124:26 | str | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | -| exprs.kt:124:16:124:25 | string lit | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:124:16:124:25 | "string lit" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:125:5:125:38 | strWithQuote | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | -| exprs.kt:125:25:125:37 | string " lit | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:125:25:125:37 | "string \\" lit" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:126:5:126:22 | b6 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:126:14:126:15 | i1 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | | exprs.kt:126:14:126:22 | ...instanceof... | exprs.kt:4:1:142:1 | topLevelMethod | InstanceOfExpr | @@ -1353,30 +1353,30 @@ | exprs.kt:128:14:128:26 | (...)... | exprs.kt:4:1:142:1 | topLevelMethod | CastExpr | | exprs.kt:128:14:128:26 | boolean | exprs.kt:4:1:142:1 | topLevelMethod | TypeAccess | | exprs.kt:129:5:129:35 | str1 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | -| exprs.kt:129:25:129:34 | string lit | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:129:25:129:34 | "string lit" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:130:5:130:36 | str2 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | -| exprs.kt:130:26:130:35 | string lit | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:130:26:130:35 | "string lit" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:131:5:131:28 | str3 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:131:25:131:28 | null | exprs.kt:4:1:142:1 | topLevelMethod | NullLiteral | | exprs.kt:132:5:132:48 | str4 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:132:24:132:48 | "..." | exprs.kt:4:1:142:1 | topLevelMethod | StringTemplateExpr | -| exprs.kt:132:25:132:28 | foo | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:132:25:132:28 | "foo " | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:132:30:132:33 | str1 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | -| exprs.kt:132:34:132:38 | bar | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:132:34:132:38 | " bar " | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:132:40:132:43 | str2 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | -| exprs.kt:132:44:132:47 | baz | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:132:44:132:47 | " baz" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:133:5:133:66 | str5 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:133:24:133:66 | "..." | exprs.kt:4:1:142:1 | topLevelMethod | StringTemplateExpr | -| exprs.kt:133:25:133:28 | foo | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:133:25:133:28 | "foo " | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:133:31:133:34 | str1 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | | exprs.kt:133:31:133:41 | ... + ... | exprs.kt:4:1:142:1 | topLevelMethod | AddExpr | | exprs.kt:133:38:133:41 | str2 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | -| exprs.kt:133:43:133:47 | bar | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:133:43:133:47 | " bar " | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:133:50:133:53 | str2 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | | exprs.kt:133:50:133:60 | Intrinsics | exprs.kt:4:1:142:1 | topLevelMethod | TypeAccess | | exprs.kt:133:50:133:60 | stringPlus(...) | exprs.kt:4:1:142:1 | topLevelMethod | MethodAccess | | exprs.kt:133:57:133:60 | str1 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | -| exprs.kt:133:62:133:65 | baz | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | +| exprs.kt:133:62:133:65 | " baz" | exprs.kt:4:1:142:1 | topLevelMethod | StringLiteral | | exprs.kt:134:5:134:26 | str6 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr | | exprs.kt:134:16:134:19 | str1 | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess | | exprs.kt:134:16:134:26 | ... + ... | exprs.kt:4:1:142:1 | topLevelMethod | AddExpr | @@ -1605,11 +1605,11 @@ | exprs.kt:215:9:215:44 | d0 | exprs.kt:206:5:217:5 | x | LocalVariableDeclExpr | | exprs.kt:215:18:215:44 | Color | exprs.kt:206:5:217:5 | x | TypeAccess | | exprs.kt:215:18:215:44 | valueOf(...) | exprs.kt:206:5:217:5 | x | MethodAccess | -| exprs.kt:215:38:215:42 | GREEN | exprs.kt:206:5:217:5 | x | StringLiteral | +| exprs.kt:215:38:215:42 | "GREEN" | exprs.kt:206:5:217:5 | x | StringLiteral | | exprs.kt:216:9:216:39 | d1 | exprs.kt:206:5:217:5 | x | LocalVariableDeclExpr | | exprs.kt:216:24:216:39 | Color | exprs.kt:206:5:217:5 | x | TypeAccess | | exprs.kt:216:24:216:39 | valueOf(...) | exprs.kt:206:5:217:5 | x | MethodAccess | -| exprs.kt:216:33:216:37 | GREEN | exprs.kt:206:5:217:5 | x | StringLiteral | +| exprs.kt:216:33:216:37 | "GREEN" | exprs.kt:206:5:217:5 | x | StringLiteral | | exprs.kt:220:1:222:1 | Unit | file://:0:0:0:0 | | TypeAccess | | exprs.kt:221:5:221:10 | StandardKt | exprs.kt:220:1:222:1 | todo | TypeAccess | | exprs.kt:221:5:221:10 | TODO(...) | exprs.kt:220:1:222:1 | todo | MethodAccess | @@ -2730,7 +2730,7 @@ | funcExprs.kt:36:100:36:102 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:36:104:36:106 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:36:108:36:110 | int | file://:0:0:0:0 | | TypeAccess | -| funcExprs.kt:36:115:36:116 | | funcExprs.kt:36:29:36:117 | invoke | StringLiteral | +| funcExprs.kt:36:115:36:116 | "" | funcExprs.kt:36:29:36:117 | invoke | StringLiteral | | funcExprs.kt:38:5:38:39 | FuncExprsKt | funcExprs.kt:21:1:52:1 | call | TypeAccess | | funcExprs.kt:38:5:38:39 | functionExpression0a(...) | funcExprs.kt:21:1:52:1 | call | MethodAccess | | funcExprs.kt:38:26:38:34 | FuncRef | funcExprs.kt:21:1:52:1 | call | TypeAccess | @@ -3231,7 +3231,7 @@ | funcExprs.kt:70:102:70:109 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:70:112:70:119 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:70:122:70:129 | int | file://:0:0:0:0 | | TypeAccess | -| funcExprs.kt:70:134:70:135 | | funcExprs.kt:69:5:70:135 | f23 | StringLiteral | +| funcExprs.kt:70:134:70:135 | "" | funcExprs.kt:69:5:70:135 | f23 | StringLiteral | | funcExprs.kt:74:5:76:5 | Unit | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:75:9:75:22 | fn(...) | funcExprs.kt:74:5:76:5 | call | MethodAccess | | funcExprs.kt:75:9:75:22 | this | funcExprs.kt:74:5:76:5 | call | ThisAccess | @@ -3245,7 +3245,7 @@ | funcExprs.kt:75:14:75:14 | Generic> | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:75:14:75:14 | Generic | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:75:14:75:14 | Integer | file://:0:0:0:0 | | TypeAccess | -| funcExprs.kt:75:20:75:20 | a | funcExprs.kt:75:12:75:22 | invoke | StringLiteral | +| funcExprs.kt:75:20:75:20 | "a" | funcExprs.kt:75:12:75:22 | invoke | StringLiteral | | funcExprs.kt:77:13:77:60 | Unit | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:77:20:77:55 | ? ... | file://:0:0:0:0 | | WildcardTypeAccess | | funcExprs.kt:77:20:77:55 | Function1>,String> | file://:0:0:0:0 | | TypeAccess | @@ -3427,7 +3427,7 @@ | funcExprs.kt:90:57:90:57 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:90:59:90:59 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:90:61:90:61 | int | file://:0:0:0:0 | | TypeAccess | -| funcExprs.kt:90:67:90:68 | | funcExprs.kt:90:15:90:69 | invoke | StringLiteral | +| funcExprs.kt:90:67:90:68 | "" | funcExprs.kt:90:15:90:69 | invoke | StringLiteral | | funcExprs.kt:91:5:91:6 | l3 | funcExprs.kt:82:9:96:1 | fn | VarAccess | | funcExprs.kt:91:5:91:60 | 23 | funcExprs.kt:82:9:96:1 | fn | IntegerLiteral | | funcExprs.kt:91:5:91:60 | Object | funcExprs.kt:82:9:96:1 | fn | TypeAccess | @@ -3508,7 +3508,7 @@ | funcExprs.kt:94:55:94:55 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:94:57:94:57 | int | file://:0:0:0:0 | | TypeAccess | | funcExprs.kt:94:59:94:59 | int | file://:0:0:0:0 | | TypeAccess | -| funcExprs.kt:94:65:94:66 | | funcExprs.kt:94:15:94:67 | invoke | StringLiteral | +| funcExprs.kt:94:65:94:66 | "" | funcExprs.kt:94:15:94:67 | invoke | StringLiteral | | funcExprs.kt:95:5:95:6 | l4 | funcExprs.kt:82:9:96:1 | fn | VarAccess | | funcExprs.kt:95:5:95:58 | invoke(...) | funcExprs.kt:82:9:96:1 | fn | MethodAccess | | funcExprs.kt:95:8:95:58 | | funcExprs.kt:82:9:96:1 | fn | ImplicitCoercionToUnitExpr | @@ -3724,7 +3724,7 @@ | samConversion.kt:7:31:7:31 | int | file://:0:0:0:0 | | TypeAccess | | samConversion.kt:7:36:7:39 | this | samConversion.kt:7:29:7:46 | invoke | ExtensionReceiverAccess | | samConversion.kt:7:36:7:45 | ... (value equals) ... | samConversion.kt:7:29:7:46 | invoke | ValueEQExpr | -| samConversion.kt:7:44:7:45 | | samConversion.kt:7:29:7:46 | invoke | StringLiteral | +| samConversion.kt:7:44:7:45 | "" | samConversion.kt:7:29:7:46 | invoke | StringLiteral | | samConversion.kt:9:5:13:6 | x | samConversion.kt:1:1:14:1 | main | LocalVariableDeclExpr | | samConversion.kt:9:13:13:6 | (...)... | samConversion.kt:1:1:14:1 | main | CastExpr | | samConversion.kt:9:13:13:6 | ...=... | samConversion.kt:9:13:13:6 | | AssignExpr | @@ -4379,6 +4379,6 @@ | whenExpr.kt:6:5:6:5 | tmp0_subject | whenExpr.kt:1:1:9:1 | testWhen | VarAccess | | whenExpr.kt:6:16:6:44 | Exception | whenExpr.kt:1:1:9:1 | testWhen | TypeAccess | | whenExpr.kt:6:16:6:44 | new Exception(...) | whenExpr.kt:1:1:9:1 | testWhen | ClassInstanceExpr | -| whenExpr.kt:6:27:6:42 | No threes please | whenExpr.kt:1:1:9:1 | testWhen | StringLiteral | +| whenExpr.kt:6:27:6:42 | "No threes please" | whenExpr.kt:1:1:9:1 | testWhen | StringLiteral | | whenExpr.kt:7:13:7:15 | 999 | whenExpr.kt:1:1:9:1 | testWhen | IntegerLiteral | | whenExpr.kt:7:13:7:15 | true | whenExpr.kt:1:1:9:1 | testWhen | BooleanLiteral | diff --git a/java/ql/test/kotlin/library-tests/exprs_typeaccess/PrintAst.expected b/java/ql/test/kotlin/library-tests/exprs_typeaccess/PrintAst.expected index 77b2fbb794e..5af83a46a01 100644 --- a/java/ql/test/kotlin/library-tests/exprs_typeaccess/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/exprs_typeaccess/PrintAst.expected @@ -27,7 +27,7 @@ A.kt: # 10| 2: [ExprStmt] ; # 10| 0: [MethodAccess] println(...) # 10| -1: [TypeAccess] ConsoleKt -# 10| 0: [StringLiteral] +# 10| 0: [StringLiteral] "" # 13| 6: [Method] getProp # 13| 3: [TypeAccess] int # 13| 5: [BlockStmt] { ... } diff --git a/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected b/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected index 03322ec3313..4aa35cde90b 100644 --- a/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected +++ b/java/ql/test/kotlin/library-tests/extensions/methodaccesses.expected @@ -1,20 +1,20 @@ | A.java:3:9:3:49 | someFun(...) | A.java:3:9:3:20 | ExtensionsKt | A.java:3:30:3:44 | new SomeClass(...) | | A.java:3:9:3:49 | someFun(...) | A.java:3:9:3:20 | ExtensionsKt | A.java:3:47:3:48 | "" | -| extensions.kt:21:5:21:38 | someClassMethod(...) | extensions.kt:21:5:21:15 | new SomeClass(...) | extensions.kt:21:34:21:36 | foo | +| extensions.kt:21:5:21:38 | someClassMethod(...) | extensions.kt:21:5:21:15 | new SomeClass(...) | extensions.kt:21:34:21:36 | "foo" | | extensions.kt:22:5:22:30 | someFun(...) | extensions.kt:22:5:22:30 | ExtensionsKt | extensions.kt:22:5:22:15 | new SomeClass(...) | -| extensions.kt:22:5:22:30 | someFun(...) | extensions.kt:22:5:22:30 | ExtensionsKt | extensions.kt:22:26:22:28 | foo | +| extensions.kt:22:5:22:30 | someFun(...) | extensions.kt:22:5:22:30 | ExtensionsKt | extensions.kt:22:26:22:28 | "foo" | | extensions.kt:23:5:23:30 | bothFun(...) | extensions.kt:23:5:23:30 | ExtensionsKt | extensions.kt:23:5:23:15 | new SomeClass(...) | -| extensions.kt:23:5:23:30 | bothFun(...) | extensions.kt:23:5:23:30 | ExtensionsKt | extensions.kt:23:26:23:28 | foo | +| extensions.kt:23:5:23:30 | bothFun(...) | extensions.kt:23:5:23:30 | ExtensionsKt | extensions.kt:23:26:23:28 | "foo" | | extensions.kt:24:5:24:35 | bothFunDiffTypes(...) | extensions.kt:24:5:24:35 | ExtensionsKt | extensions.kt:24:5:24:15 | new SomeClass(...) | | extensions.kt:24:5:24:35 | bothFunDiffTypes(...) | extensions.kt:24:5:24:35 | ExtensionsKt | extensions.kt:24:34:24:34 | 1 | -| extensions.kt:25:5:25:44 | anotherClassMethod(...) | extensions.kt:25:5:25:18 | new AnotherClass(...) | extensions.kt:25:40:25:42 | foo | +| extensions.kt:25:5:25:44 | anotherClassMethod(...) | extensions.kt:25:5:25:18 | new AnotherClass(...) | extensions.kt:25:40:25:42 | "foo" | | extensions.kt:26:5:26:36 | anotherFun(...) | extensions.kt:26:5:26:36 | ExtensionsKt | extensions.kt:26:5:26:18 | new AnotherClass(...) | -| extensions.kt:26:5:26:36 | anotherFun(...) | extensions.kt:26:5:26:36 | ExtensionsKt | extensions.kt:26:32:26:34 | foo | +| extensions.kt:26:5:26:36 | anotherFun(...) | extensions.kt:26:5:26:36 | ExtensionsKt | extensions.kt:26:32:26:34 | "foo" | | extensions.kt:27:5:27:33 | bothFun(...) | extensions.kt:27:5:27:33 | ExtensionsKt | extensions.kt:27:5:27:18 | new AnotherClass(...) | -| extensions.kt:27:5:27:33 | bothFun(...) | extensions.kt:27:5:27:33 | ExtensionsKt | extensions.kt:27:29:27:31 | foo | +| extensions.kt:27:5:27:33 | bothFun(...) | extensions.kt:27:5:27:33 | ExtensionsKt | extensions.kt:27:29:27:31 | "foo" | | extensions.kt:28:5:28:42 | bothFunDiffTypes(...) | extensions.kt:28:5:28:42 | ExtensionsKt | extensions.kt:28:5:28:18 | new AnotherClass(...) | -| extensions.kt:28:5:28:42 | bothFunDiffTypes(...) | extensions.kt:28:5:28:42 | ExtensionsKt | extensions.kt:28:38:28:40 | foo | -| extensions.kt:29:6:29:27 | bar(...) | extensions.kt:29:6:29:27 | ExtensionsKt | extensions.kt:29:6:29:15 | someString | -| extensions.kt:29:6:29:27 | bar(...) | extensions.kt:29:6:29:27 | ExtensionsKt | extensions.kt:29:23:29:25 | foo | -| extensions.kt:31:6:31:32 | baz(...) | extensions.kt:31:6:31:32 | new (...) | extensions.kt:31:6:31:15 | someString | -| extensions.kt:31:6:31:32 | baz(...) | extensions.kt:31:6:31:32 | new (...) | extensions.kt:31:23:31:30 | bazParam | +| extensions.kt:28:5:28:42 | bothFunDiffTypes(...) | extensions.kt:28:5:28:42 | ExtensionsKt | extensions.kt:28:38:28:40 | "foo" | +| extensions.kt:29:6:29:27 | bar(...) | extensions.kt:29:6:29:27 | ExtensionsKt | extensions.kt:29:6:29:15 | "someString" | +| extensions.kt:29:6:29:27 | bar(...) | extensions.kt:29:6:29:27 | ExtensionsKt | extensions.kt:29:23:29:25 | "foo" | +| extensions.kt:31:6:31:32 | baz(...) | extensions.kt:31:6:31:32 | new (...) | extensions.kt:31:6:31:15 | "someString" | +| extensions.kt:31:6:31:32 | baz(...) | extensions.kt:31:6:31:32 | new (...) | extensions.kt:31:23:31:30 | "bazParam" | diff --git a/java/ql/test/kotlin/library-tests/extensions/parameters.expected b/java/ql/test/kotlin/library-tests/extensions/parameters.expected index 5cb7e0986d3..65906e57dd2 100644 --- a/java/ql/test/kotlin/library-tests/extensions/parameters.expected +++ b/java/ql/test/kotlin/library-tests/extensions/parameters.expected @@ -1,24 +1,24 @@ parametersWithArgs -| extensions.kt:3:25:3:34 | p1 | 0 | extensions.kt:21:34:21:36 | foo | -| extensions.kt:6:28:6:37 | p1 | 0 | extensions.kt:25:40:25:42 | foo | +| extensions.kt:3:25:3:34 | p1 | 0 | extensions.kt:21:34:21:36 | "foo" | +| extensions.kt:6:28:6:37 | p1 | 0 | extensions.kt:25:40:25:42 | "foo" | | extensions.kt:9:5:9:13 | | 0 | A.java:3:30:3:44 | new SomeClass(...) | | extensions.kt:9:5:9:13 | | 0 | extensions.kt:22:5:22:15 | new SomeClass(...) | | extensions.kt:9:23:9:32 | p1 | 1 | A.java:3:47:3:48 | "" | -| extensions.kt:9:23:9:32 | p1 | 1 | extensions.kt:22:26:22:28 | foo | +| extensions.kt:9:23:9:32 | p1 | 1 | extensions.kt:22:26:22:28 | "foo" | | extensions.kt:10:5:10:16 | | 0 | extensions.kt:26:5:26:18 | new AnotherClass(...) | -| extensions.kt:10:29:10:38 | p1 | 1 | extensions.kt:26:32:26:34 | foo | +| extensions.kt:10:29:10:38 | p1 | 1 | extensions.kt:26:32:26:34 | "foo" | | extensions.kt:12:5:12:13 | | 0 | extensions.kt:23:5:23:15 | new SomeClass(...) | -| extensions.kt:12:23:12:32 | p1 | 1 | extensions.kt:23:26:23:28 | foo | +| extensions.kt:12:23:12:32 | p1 | 1 | extensions.kt:23:26:23:28 | "foo" | | extensions.kt:13:5:13:16 | | 0 | extensions.kt:27:5:27:18 | new AnotherClass(...) | -| extensions.kt:13:26:13:35 | p1 | 1 | extensions.kt:27:29:27:31 | foo | +| extensions.kt:13:26:13:35 | p1 | 1 | extensions.kt:27:29:27:31 | "foo" | | extensions.kt:15:5:15:13 | | 0 | extensions.kt:24:5:24:15 | new SomeClass(...) | | extensions.kt:15:32:15:38 | p1 | 1 | extensions.kt:24:34:24:34 | 1 | | extensions.kt:16:5:16:16 | | 0 | extensions.kt:28:5:28:18 | new AnotherClass(...) | -| extensions.kt:16:35:16:44 | p1 | 1 | extensions.kt:28:38:28:40 | foo | -| extensions.kt:18:5:18:10 | | 0 | extensions.kt:29:6:29:15 | someString | -| extensions.kt:18:16:18:25 | p1 | 1 | extensions.kt:29:23:29:25 | foo | -| extensions.kt:30:9:30:14 | | 0 | extensions.kt:31:6:31:15 | someString | -| extensions.kt:30:20:30:29 | p1 | 1 | extensions.kt:31:23:31:30 | bazParam | +| extensions.kt:16:35:16:44 | p1 | 1 | extensions.kt:28:38:28:40 | "foo" | +| extensions.kt:18:5:18:10 | | 0 | extensions.kt:29:6:29:15 | "someString" | +| extensions.kt:18:16:18:25 | p1 | 1 | extensions.kt:29:23:29:25 | "foo" | +| extensions.kt:30:9:30:14 | | 0 | extensions.kt:31:6:31:15 | "someString" | +| extensions.kt:30:20:30:29 | p1 | 1 | extensions.kt:31:23:31:30 | "bazParam" | extensionParameter | extensions.kt:9:5:9:13 | | | extensions.kt:10:5:10:16 | | diff --git a/java/ql/test/kotlin/library-tests/generic-inner-classes/test.expected b/java/ql/test/kotlin/library-tests/generic-inner-classes/test.expected index deed53a7269..8b6a502898e 100644 --- a/java/ql/test/kotlin/library-tests/generic-inner-classes/test.expected +++ b/java/ql/test/kotlin/library-tests/generic-inner-classes/test.expected @@ -2,11 +2,11 @@ callArgs | KotlinUser.kt:7:13:7:31 | new OuterGeneric(...) | KotlinUser.kt:7:13:7:31 | OuterGeneric | -3 | | KotlinUser.kt:7:33:7:61 | new InnerGeneric(...) | KotlinUser.kt:7:13:7:31 | new OuterGeneric(...) | -2 | | KotlinUser.kt:7:33:7:61 | new InnerGeneric(...) | KotlinUser.kt:7:33:7:61 | InnerGeneric | -3 | -| KotlinUser.kt:7:33:7:61 | new InnerGeneric(...) | KotlinUser.kt:7:55:7:59 | hello | 0 | +| KotlinUser.kt:7:33:7:61 | new InnerGeneric(...) | KotlinUser.kt:7:55:7:59 | "hello" | 0 | | KotlinUser.kt:8:14:8:32 | new OuterGeneric(...) | KotlinUser.kt:8:14:8:32 | OuterGeneric | -3 | | KotlinUser.kt:8:34:8:54 | new InnerGeneric(...) | KotlinUser.kt:8:14:8:32 | new OuterGeneric(...) | -2 | | KotlinUser.kt:8:34:8:54 | new InnerGeneric(...) | KotlinUser.kt:8:34:8:54 | InnerGeneric | -3 | -| KotlinUser.kt:8:34:8:54 | new InnerGeneric(...) | KotlinUser.kt:8:48:8:52 | hello | 0 | +| KotlinUser.kt:8:34:8:54 | new InnerGeneric(...) | KotlinUser.kt:8:48:8:52 | "hello" | 0 | | KotlinUser.kt:9:13:9:31 | new OuterGeneric(...) | KotlinUser.kt:9:13:9:31 | OuterGeneric | -3 | | KotlinUser.kt:9:33:9:49 | new InnerNotGeneric<>(...) | KotlinUser.kt:9:13:9:31 | new OuterGeneric(...) | -2 | | KotlinUser.kt:9:33:9:49 | new InnerNotGeneric<>(...) | KotlinUser.kt:9:33:9:49 | InnerNotGeneric<> | -3 | @@ -15,11 +15,11 @@ callArgs | KotlinUser.kt:10:31:10:52 | new InnerGeneric(...) | KotlinUser.kt:10:31:10:52 | InnerGeneric | -3 | | KotlinUser.kt:12:19:12:44 | returnsecond(...) | KotlinUser.kt:12:19:12:19 | a | -1 | | KotlinUser.kt:12:19:12:44 | returnsecond(...) | KotlinUser.kt:12:34:12:34 | 0 | 0 | -| KotlinUser.kt:12:19:12:44 | returnsecond(...) | KotlinUser.kt:12:38:12:42 | hello | 1 | +| KotlinUser.kt:12:19:12:44 | returnsecond(...) | KotlinUser.kt:12:38:12:42 | "hello" | 1 | | KotlinUser.kt:13:19:13:31 | identity(...) | KotlinUser.kt:13:19:13:19 | b | -1 | | KotlinUser.kt:13:19:13:31 | identity(...) | KotlinUser.kt:13:30:13:30 | 5 | 0 | | KotlinUser.kt:14:19:14:37 | identity(...) | KotlinUser.kt:14:19:14:19 | c | -1 | -| KotlinUser.kt:14:19:14:37 | identity(...) | KotlinUser.kt:14:31:14:35 | world | 0 | +| KotlinUser.kt:14:19:14:37 | identity(...) | KotlinUser.kt:14:31:14:35 | "world" | 0 | genericTypes | OuterGeneric.kt:3:1:21:1 | OuterGeneric | OuterGeneric.kt:3:27:3:27 | T | | OuterGeneric.kt:11:3:19:3 | InnerGeneric | OuterGeneric.kt:11:35:11:35 | S | diff --git a/java/ql/test/kotlin/library-tests/generics/PrintAst.expected b/java/ql/test/kotlin/library-tests/generics/PrintAst.expected index 619ba5f3bcc..2c3b395f4f1 100644 --- a/java/ql/test/kotlin/library-tests/generics/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/generics/PrintAst.expected @@ -45,18 +45,18 @@ generics.kt: # 27| 0: [MethodAccess] f2(...) # 27| -2: [TypeAccess] String # 27| -1: [VarAccess] c1 -# 27| 0: [StringLiteral] +# 27| 0: [StringLiteral] "" # 28| 3: [LocalVariableDeclStmt] var ...; # 28| 1: [LocalVariableDeclExpr] c2 # 28| 0: [ClassInstanceExpr] new C1(...) # 28| -3: [TypeAccess] C1 # 28| 0: [TypeAccess] String # 28| 1: [TypeAccess] Integer -# 28| 0: [StringLiteral] +# 28| 0: [StringLiteral] "" # 29| 4: [ExprStmt] ; # 29| 0: [MethodAccess] f1(...) # 29| -1: [VarAccess] c2 -# 29| 0: [StringLiteral] a +# 29| 0: [StringLiteral] "a" # 30| 5: [LocalVariableDeclStmt] var ...; # 30| 1: [LocalVariableDeclExpr] x2 # 30| 0: [MethodAccess] f2(...) @@ -256,4 +256,4 @@ generics.kt: # 61| -3: [TypeAccess] Local # 61| 0: [TypeAccess] Integer # 61| 0: [VarAccess] t -# 61| 1: [StringLiteral] +# 61| 1: [StringLiteral] "" diff --git a/java/ql/test/kotlin/library-tests/java-map-methods/PrintAst.expected b/java/ql/test/kotlin/library-tests/java-map-methods/PrintAst.expected index 978c4777b09..e356679e208 100644 --- a/java/ql/test/kotlin/library-tests/java-map-methods/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/java-map-methods/PrintAst.expected @@ -45,7 +45,7 @@ test.kt: # 9| 0: [ReturnStmt] return ... # 9| 0: [AddExpr] ... + ... # 9| 0: [VarAccess] s -# 9| 1: [StringLiteral] +# 9| 1: [StringLiteral] "" # 10| 5: [Method] fn2 # 10| 3: [TypeAccess] String #-----| 4: (Parameters) @@ -55,7 +55,7 @@ test.kt: # 10| 0: [ReturnStmt] return ... # 10| 0: [AddExpr] ... + ... # 10| 0: [VarAccess] s -# 10| 1: [StringLiteral] +# 10| 1: [StringLiteral] "" # 12| 6: [Method] fn1 # 12| 3: [TypeAccess] int #-----| 4: (Parameters) diff --git a/java/ql/test/kotlin/library-tests/jvmoverloads-annotation/PrintAst.expected b/java/ql/test/kotlin/library-tests/jvmoverloads-annotation/PrintAst.expected index 6dfd45e83f4..a1d0808d7a9 100644 --- a/java/ql/test/kotlin/library-tests/jvmoverloads-annotation/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/jvmoverloads-annotation/PrintAst.expected @@ -5,7 +5,7 @@ test.kt: # 1| 3: [TypeAccess] String # 1| 5: [BlockStmt] { ... } # 1| 0: [ReturnStmt] return ... -# 1| 0: [StringLiteral] Hello world +# 1| 0: [StringLiteral] "Hello world" # 45| 2: [ExtensionMethod] testExtensionFunction # 45| 3: [TypeAccess] int #-----| 4: (Parameters) @@ -929,7 +929,7 @@ test.kt: # 30| 1: [ExprStmt] ; # 30| 0: [AssignExpr] ...=... # 30| 0: [VarAccess] p2 -# 30| 1: [StringLiteral] Hello world +# 30| 1: [StringLiteral] "Hello world" # 30| 2: [ThisConstructorInvocationStmt] this(...) # 30| 0: [VarAccess] p0 # 30| 1: [VarAccess] p1 @@ -1024,7 +1024,7 @@ test.kt: # 33| 1: [ExprStmt] ; # 33| 0: [AssignExpr] ...=... # 33| 0: [VarAccess] p3 -# 33| 1: [StringLiteral] Hello world +# 33| 1: [StringLiteral] "Hello world" # 33| 2: [ReturnStmt] return ... # 33| 0: [MethodAccess] testMemberFunction(...) # 33| -1: [VarAccess] p0 @@ -1049,7 +1049,7 @@ test.kt: # 37| -1: [VarAccess] spec1 # 37| 0: [IntegerLiteral] 1 # 37| 1: [FloatLiteral] 1.0 -# 37| 2: [StringLiteral] Hello world +# 37| 2: [StringLiteral] "Hello world" # 37| 3: [FloatLiteral] 2.0 # 38| 1: [ExprStmt] ; # 38| 0: [ImplicitCoercionToUnitExpr] @@ -1058,5 +1058,5 @@ test.kt: # 38| -1: [VarAccess] spec2 # 38| 0: [IntegerLiteral] 1 # 38| 1: [DoubleLiteral] 1.0 -# 38| 2: [StringLiteral] Hello world +# 38| 2: [StringLiteral] "Hello world" # 38| 3: [DoubleLiteral] 2.0 diff --git a/java/ql/test/kotlin/library-tests/jvmstatic-annotation/PrintAst.expected b/java/ql/test/kotlin/library-tests/jvmstatic-annotation/PrintAst.expected index 6386ec036fb..1db0b09adc0 100644 --- a/java/ql/test/kotlin/library-tests/jvmstatic-annotation/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/jvmstatic-annotation/PrintAst.expected @@ -81,13 +81,13 @@ test.kt: # 52| 0: [TypeAccess] Unit # 52| 1: [MethodAccess] staticMethod(...) # 52| -1: [VarAccess] Companion -# 52| 0: [StringLiteral] 1 +# 52| 0: [StringLiteral] "1" # 53| 1: [ExprStmt] ; # 53| 0: [ImplicitCoercionToUnitExpr] # 53| 0: [TypeAccess] Unit # 53| 1: [MethodAccess] nonStaticMethod(...) # 53| -1: [VarAccess] Companion -# 53| 0: [StringLiteral] 2 +# 53| 0: [StringLiteral] "2" # 54| 2: [ExprStmt] ; # 54| 0: [MethodAccess] setStaticProp(...) # 54| -1: [VarAccess] Companion @@ -113,13 +113,13 @@ test.kt: # 60| 0: [TypeAccess] Unit # 60| 1: [MethodAccess] staticMethod(...) # 60| -1: [TypeAccess] NonCompanion -# 60| 0: [StringLiteral] 1 +# 60| 0: [StringLiteral] "1" # 61| 7: [ExprStmt] ; # 61| 0: [ImplicitCoercionToUnitExpr] # 61| 0: [TypeAccess] Unit # 61| 1: [MethodAccess] nonStaticMethod(...) # 61| -1: [VarAccess] INSTANCE -# 61| 0: [StringLiteral] 2 +# 61| 0: [StringLiteral] "2" # 62| 8: [ExprStmt] ; # 62| 0: [MethodAccess] setStaticProp(...) # 62| -1: [TypeAccess] NonCompanion @@ -182,7 +182,7 @@ test.kt: # 14| 0: [VarAccess] s # 16| 4: [FieldDeclaration] String staticProp; # 16| -1: [TypeAccess] String -# 16| 0: [StringLiteral] a +# 16| 0: [StringLiteral] "a" # 16| 5: [Method] getStaticProp #-----| 1: (Annotations) # 16| 3: [TypeAccess] String @@ -204,7 +204,7 @@ test.kt: # 16| 1: [VarAccess] # 17| 7: [FieldDeclaration] String nonStaticProp; # 17| -1: [TypeAccess] String -# 17| 0: [StringLiteral] b +# 17| 0: [StringLiteral] "b" # 17| 8: [Method] getNonStaticProp #-----| 1: (Annotations) # 17| 3: [TypeAccess] String @@ -353,7 +353,7 @@ test.kt: # 34| 0: [VarAccess] s # 36| 5: [FieldDeclaration] String staticProp; # 36| -1: [TypeAccess] String -# 36| 0: [StringLiteral] a +# 36| 0: [StringLiteral] "a" # 36| 6: [Method] getStaticProp #-----| 1: (Annotations) # 36| 3: [TypeAccess] String @@ -377,7 +377,7 @@ test.kt: # 36| 1: [VarAccess] # 37| 8: [FieldDeclaration] String nonStaticProp; # 37| -1: [TypeAccess] String -# 37| 0: [StringLiteral] b +# 37| 0: [StringLiteral] "b" # 37| 9: [Method] getNonStaticProp #-----| 1: (Annotations) # 37| 3: [TypeAccess] String diff --git a/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected index c2119ec6123..9f482ab3b71 100644 --- a/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected @@ -30,7 +30,7 @@ test.kt: # 4| 0: [ReturnStmt] return ... # 4| 0: [MethodAccess] println(...) # 4| -1: [TypeAccess] ConsoleKt -# 4| 0: [StringLiteral] a +# 4| 0: [StringLiteral] "a" # 6| 6: [Method] init # 6| 3: [TypeAccess] LateInit # 6| 5: [BlockStmt] { ... } diff --git a/java/ql/test/kotlin/library-tests/literals/literals.expected b/java/ql/test/kotlin/library-tests/literals/literals.expected index 86d23aa0d05..a22709ce194 100644 --- a/java/ql/test/kotlin/library-tests/literals/literals.expected +++ b/java/ql/test/kotlin/library-tests/literals/literals.expected @@ -23,7 +23,7 @@ | literals.kt:25:34:25:39 | -123.4 | DoubleLiteral | | literals.kt:26:30:26:32 | c | CharacterLiteral | | literals.kt:27:30:27:33 | \n | CharacterLiteral | -| literals.kt:28:34:28:35 | | StringLiteral | -| literals.kt:29:35:29:45 | Some string | StringLiteral | -| literals.kt:30:35:30:46 | Some\nstring | StringLiteral | +| literals.kt:28:34:28:35 | "" | StringLiteral | +| literals.kt:29:35:29:45 | "Some string" | StringLiteral | +| literals.kt:30:35:30:46 | "Some\\nstring" | StringLiteral | | literals.kt:31:30:31:33 | null | NullLiteral | diff --git a/java/ql/test/kotlin/library-tests/methods/exprs.expected b/java/ql/test/kotlin/library-tests/methods/exprs.expected index 76a48c189c4..6d2221b5bae 100644 --- a/java/ql/test/kotlin/library-tests/methods/exprs.expected +++ b/java/ql/test/kotlin/library-tests/methods/exprs.expected @@ -17,10 +17,13 @@ | dataClass.kt:0:0:0:0 | 1 | IntegerLiteral | | dataClass.kt:0:0:0:0 | 2 | IntegerLiteral | | dataClass.kt:0:0:0:0 | 31 | IntegerLiteral | +| dataClass.kt:0:0:0:0 | ")" | StringLiteral | +| dataClass.kt:0:0:0:0 | ", " | StringLiteral | | dataClass.kt:0:0:0:0 | "..." | StringTemplateExpr | +| dataClass.kt:0:0:0:0 | "DataClass(" | StringLiteral | +| dataClass.kt:0:0:0:0 | "x=" | StringLiteral | +| dataClass.kt:0:0:0:0 | "y=" | StringLiteral | | dataClass.kt:0:0:0:0 | (...)... | CastExpr | -| dataClass.kt:0:0:0:0 | ) | StringLiteral | -| dataClass.kt:0:0:0:0 | , | StringLiteral | | dataClass.kt:0:0:0:0 | ... !is ... | NotInstanceOfExpr | | dataClass.kt:0:0:0:0 | ... & ... | AndBitwiseExpr | | dataClass.kt:0:0:0:0 | ... & ... | AndBitwiseExpr | @@ -40,7 +43,6 @@ | dataClass.kt:0:0:0:0 | DataClass | TypeAccess | | dataClass.kt:0:0:0:0 | DataClass | TypeAccess | | dataClass.kt:0:0:0:0 | DataClass | TypeAccess | -| dataClass.kt:0:0:0:0 | DataClass( | StringLiteral | | dataClass.kt:0:0:0:0 | Object | TypeAccess | | dataClass.kt:0:0:0:0 | Object | TypeAccess | | dataClass.kt:0:0:0:0 | String | TypeAccess | @@ -105,9 +107,7 @@ | dataClass.kt:0:0:0:0 | when ... | WhenExpr | | dataClass.kt:0:0:0:0 | when ... | WhenExpr | | dataClass.kt:0:0:0:0 | x | VarAccess | -| dataClass.kt:0:0:0:0 | x= | StringLiteral | | dataClass.kt:0:0:0:0 | y | VarAccess | -| dataClass.kt:0:0:0:0 | y= | StringLiteral | | dataClass.kt:1:22:1:31 | ...=... | KtInitializerAssignExpr | | dataClass.kt:1:22:1:31 | int | TypeAccess | | dataClass.kt:1:22:1:31 | int | TypeAccess | @@ -204,7 +204,7 @@ | delegates.kt:8:35:11:5 | | VarAccess | | delegates.kt:8:35:11:5 | String | TypeAccess | | delegates.kt:8:35:11:5 | observable(...) | MethodAccess | -| delegates.kt:8:57:8:62 | | StringLiteral | +| delegates.kt:8:57:8:62 | "" | StringLiteral | | delegates.kt:8:66:11:5 | ...->... | LambdaExpr | | delegates.kt:8:66:11:5 | Function3,String,String,Unit> | TypeAccess | | delegates.kt:8:66:11:5 | KProperty | TypeAccess | @@ -219,9 +219,9 @@ | delegates.kt:10:9:10:37 | ConsoleKt | TypeAccess | | delegates.kt:10:9:10:37 | println(...) | MethodAccess | | delegates.kt:10:17:10:36 | "..." | StringTemplateExpr | -| delegates.kt:10:18:10:21 | Was | StringLiteral | +| delegates.kt:10:18:10:21 | "Was " | StringLiteral | | delegates.kt:10:23:10:25 | old | VarAccess | -| delegates.kt:10:26:10:31 | , now | StringLiteral | +| delegates.kt:10:26:10:31 | ", now " | StringLiteral | | delegates.kt:10:33:10:35 | new | VarAccess | | enumClass.kt:0:0:0:0 | EnumClass | TypeAccess | | enumClass.kt:0:0:0:0 | EnumClass | TypeAccess | diff --git a/java/ql/test/kotlin/library-tests/operator-overloads/PrintAst.expected b/java/ql/test/kotlin/library-tests/operator-overloads/PrintAst.expected index af62c3e412e..46fd70318ad 100644 --- a/java/ql/test/kotlin/library-tests/operator-overloads/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/operator-overloads/PrintAst.expected @@ -59,7 +59,7 @@ test.kt: # 10| 0: [TypeAccess] int # 10| 5: [BlockStmt] { ... } # 10| 0: [ReturnStmt] return ... -# 10| 0: [StringLiteral] +# 10| 0: [StringLiteral] "" # 11| 3: [ExtensionMethod] set # 11| 3: [TypeAccess] String #-----| 4: (Parameters) @@ -73,7 +73,7 @@ test.kt: # 11| 0: [TypeAccess] int # 11| 5: [BlockStmt] { ... } # 11| 0: [ReturnStmt] return ... -# 11| 0: [StringLiteral] +# 11| 0: [StringLiteral] "" # 12| 4: [ExtensionMethod] set # 12| 3: [TypeAccess] String #-----| 4: (Parameters) @@ -85,7 +85,7 @@ test.kt: # 12| 0: [TypeAccess] C # 12| 5: [BlockStmt] { ... } # 12| 0: [ReturnStmt] return ... -# 12| 0: [StringLiteral] +# 12| 0: [StringLiteral] "" # 15| 2: [Class] C # 15| 1: [Constructor] C # 15| 5: [BlockStmt] { ... } @@ -100,4 +100,4 @@ test.kt: # 16| 0: [TypeAccess] int # 16| 5: [BlockStmt] { ... } # 16| 0: [ReturnStmt] return ... -# 16| 0: [StringLiteral] +# 16| 0: [StringLiteral] "" diff --git a/java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected b/java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected index a769bc397ee..972e826cdca 100644 --- a/java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected @@ -56,7 +56,7 @@ test.kt: # 184| 1: [ExprStmt] ; # 184| 0: [AssignExpr] ...=... # 184| 0: [VarAccess] p0 -# 184| 1: [StringLiteral] before-vararg-default sunk +# 184| 1: [StringLiteral] "before-vararg-default sunk" # 184| 1: [IfStmt] if (...) # 184| 0: [EQExpr] ... == ... # 184| 0: [AndBitwiseExpr] ... & ... @@ -68,8 +68,8 @@ test.kt: # 184| 0: [VarAccess] p1 # 184| 1: [ArrayCreationExpr] new String[] # 184| -2: [ArrayInit] {...} -# 184| 0: [StringLiteral] first-vararg-default sunk -# 184| 1: [StringLiteral] second-vararg-default sunk +# 184| 0: [StringLiteral] "first-vararg-default sunk" +# 184| 1: [StringLiteral] "second-vararg-default sunk" # 184| -1: [TypeAccess] String # 184| 0: [IntegerLiteral] 2 # 184| 2: [IfStmt] if (...) @@ -81,7 +81,7 @@ test.kt: # 184| 1: [ExprStmt] ; # 184| 0: [AssignExpr] ...=... # 184| 0: [VarAccess] p2 -# 184| 1: [StringLiteral] after-vararg-default sunk +# 184| 1: [StringLiteral] "after-vararg-default sunk" # 184| 3: [ReturnStmt] return ... # 184| 0: [MethodAccess] varargsTest(...) # 184| -1: [TypeAccess] TestKt @@ -102,7 +102,7 @@ test.kt: # 192| 1: [ExprStmt] ; # 192| 0: [MethodAccess] varargsTest$default(...) # 192| -1: [TypeAccess] TestKt -# 192| 0: [StringLiteral] no-varargs-before, no-z-parameter sunk +# 192| 0: [StringLiteral] "no-varargs-before, no-z-parameter sunk" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -110,32 +110,32 @@ test.kt: # 193| 2: [ExprStmt] ; # 193| 0: [MethodAccess] varargsTest$default(...) # 193| -1: [TypeAccess] TestKt -# 193| 0: [StringLiteral] no-varargs-before sunk +# 193| 0: [StringLiteral] "no-varargs-before sunk" # 1| 1: [NullLiteral] null -# 193| 2: [StringLiteral] no-varargs-after sunk +# 193| 2: [StringLiteral] "no-varargs-after sunk" # 1| 3: [IntegerLiteral] 5 # 1| 4: [NullLiteral] null # 194| 3: [ExprStmt] ; # 194| 0: [MethodAccess] varargsTest(...) # 194| -1: [TypeAccess] TestKt -# 194| 0: [StringLiteral] one-vararg-before sunk -# 194| 1: [StringLiteral] one-vararg sunk -# 194| 2: [StringLiteral] one-vararg-after sunk +# 194| 0: [StringLiteral] "one-vararg-before sunk" +# 194| 1: [StringLiteral] "one-vararg sunk" +# 194| 2: [StringLiteral] "one-vararg-after sunk" # 195| 4: [ExprStmt] ; # 195| 0: [MethodAccess] varargsTest(...) # 195| -1: [TypeAccess] TestKt -# 195| 0: [StringLiteral] two-varargs-before sunk -# 195| 1: [StringLiteral] two-vararg-first sunk -# 195| 2: [StringLiteral] two-vararg-second sunk -# 195| 3: [StringLiteral] two-varargs-after sunk +# 195| 0: [StringLiteral] "two-varargs-before sunk" +# 195| 1: [StringLiteral] "two-vararg-first sunk" +# 195| 2: [StringLiteral] "two-vararg-second sunk" +# 195| 3: [StringLiteral] "two-varargs-after sunk" # 196| 5: [ExprStmt] ; # 196| 0: [MethodAccess] varargsTest$default(...) # 196| -1: [TypeAccess] TestKt -# 196| 0: [StringLiteral] no-z-parmeter sunk +# 196| 0: [StringLiteral] "no-z-parmeter sunk" # 196| 1: [ArrayCreationExpr] new String[] # 196| -2: [ArrayInit] {...} -# 196| 0: [StringLiteral] no-z-parameter first vararg sunk -# 196| 1: [StringLiteral] no-z-parameter second vararg sunk +# 196| 0: [StringLiteral] "no-z-parameter first vararg sunk" +# 196| 1: [StringLiteral] "no-z-parameter second vararg sunk" # 196| -1: [TypeAccess] String # 196| 0: [IntegerLiteral] 2 # 1| 2: [NullLiteral] null @@ -182,7 +182,7 @@ test.kt: # 199| 1: [ExprStmt] ; # 199| 0: [AssignExpr] ...=... # 199| 0: [VarAccess] p0 -# 199| 1: [StringLiteral] before-vararg-default not sunk 2 +# 199| 1: [StringLiteral] "before-vararg-default not sunk 2" # 199| 1: [IfStmt] if (...) # 199| 0: [EQExpr] ... == ... # 199| 0: [AndBitwiseExpr] ... & ... @@ -194,8 +194,8 @@ test.kt: # 199| 0: [VarAccess] p1 # 199| 1: [ArrayCreationExpr] new String[] # 199| -2: [ArrayInit] {...} -# 199| 0: [StringLiteral] first-vararg-default sunk 2 -# 199| 1: [StringLiteral] second-vararg-default sunk 2 +# 199| 0: [StringLiteral] "first-vararg-default sunk 2" +# 199| 1: [StringLiteral] "second-vararg-default sunk 2" # 199| -1: [TypeAccess] String # 199| 0: [IntegerLiteral] 2 # 199| 2: [IfStmt] if (...) @@ -207,7 +207,7 @@ test.kt: # 199| 1: [ExprStmt] ; # 199| 0: [AssignExpr] ...=... # 199| 0: [VarAccess] p2 -# 199| 1: [StringLiteral] after-vararg-default not sunk 2 +# 199| 1: [StringLiteral] "after-vararg-default not sunk 2" # 199| 3: [ReturnStmt] return ... # 199| 0: [MethodAccess] varargsTestOnlySinkVarargs(...) # 199| -1: [TypeAccess] TestKt @@ -228,7 +228,7 @@ test.kt: # 205| 1: [ExprStmt] ; # 205| 0: [MethodAccess] varargsTestOnlySinkVarargs$default(...) # 205| -1: [TypeAccess] TestKt -# 205| 0: [StringLiteral] no-varargs-before, no-z-parameter not sunk 2 +# 205| 0: [StringLiteral] "no-varargs-before, no-z-parameter not sunk 2" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -236,32 +236,32 @@ test.kt: # 206| 2: [ExprStmt] ; # 206| 0: [MethodAccess] varargsTestOnlySinkVarargs$default(...) # 206| -1: [TypeAccess] TestKt -# 206| 0: [StringLiteral] no-varargs-before not sunk 2 +# 206| 0: [StringLiteral] "no-varargs-before not sunk 2" # 1| 1: [NullLiteral] null -# 206| 2: [StringLiteral] no-varargs-after not sunk 2 +# 206| 2: [StringLiteral] "no-varargs-after not sunk 2" # 1| 3: [IntegerLiteral] 5 # 1| 4: [NullLiteral] null # 207| 3: [ExprStmt] ; # 207| 0: [MethodAccess] varargsTestOnlySinkVarargs(...) # 207| -1: [TypeAccess] TestKt -# 207| 0: [StringLiteral] one-vararg-before not sunk 2 -# 207| 1: [StringLiteral] one-vararg sunk 2 -# 207| 2: [StringLiteral] one-vararg-after not sunk 2 +# 207| 0: [StringLiteral] "one-vararg-before not sunk 2" +# 207| 1: [StringLiteral] "one-vararg sunk 2" +# 207| 2: [StringLiteral] "one-vararg-after not sunk 2" # 208| 4: [ExprStmt] ; # 208| 0: [MethodAccess] varargsTestOnlySinkVarargs(...) # 208| -1: [TypeAccess] TestKt -# 208| 0: [StringLiteral] two-varargs-before not sunk 2 -# 208| 1: [StringLiteral] two-vararg-first sunk 2 -# 208| 2: [StringLiteral] two-vararg-second sunk 2 -# 208| 3: [StringLiteral] two-varargs-after not sunk 2 +# 208| 0: [StringLiteral] "two-varargs-before not sunk 2" +# 208| 1: [StringLiteral] "two-vararg-first sunk 2" +# 208| 2: [StringLiteral] "two-vararg-second sunk 2" +# 208| 3: [StringLiteral] "two-varargs-after not sunk 2" # 209| 5: [ExprStmt] ; # 209| 0: [MethodAccess] varargsTestOnlySinkVarargs$default(...) # 209| -1: [TypeAccess] TestKt -# 209| 0: [StringLiteral] no-z-parmeter not sunk 2 +# 209| 0: [StringLiteral] "no-z-parmeter not sunk 2" # 209| 1: [ArrayCreationExpr] new String[] # 209| -2: [ArrayInit] {...} -# 209| 0: [StringLiteral] no-z-parameter first vararg sunk 2 -# 209| 1: [StringLiteral] no-z-parameter second vararg sunk 2 +# 209| 0: [StringLiteral] "no-z-parameter first vararg sunk 2" +# 209| 1: [StringLiteral] "no-z-parameter second vararg sunk 2" # 209| -1: [TypeAccess] String # 209| 0: [IntegerLiteral] 2 # 1| 2: [NullLiteral] null @@ -310,7 +310,7 @@ test.kt: # 212| 1: [ExprStmt] ; # 212| 0: [AssignExpr] ...=... # 212| 0: [VarAccess] p0 -# 212| 1: [StringLiteral] before-vararg-default sunk 3 +# 212| 1: [StringLiteral] "before-vararg-default sunk 3" # 212| 1: [IfStmt] if (...) # 212| 0: [EQExpr] ... == ... # 212| 0: [AndBitwiseExpr] ... & ... @@ -322,8 +322,8 @@ test.kt: # 212| 0: [VarAccess] p1 # 212| 1: [ArrayCreationExpr] new String[] # 212| -2: [ArrayInit] {...} -# 212| 0: [StringLiteral] first-vararg-default not sunk 3 -# 212| 1: [StringLiteral] second-vararg-default not sunk 3 +# 212| 0: [StringLiteral] "first-vararg-default not sunk 3" +# 212| 1: [StringLiteral] "second-vararg-default not sunk 3" # 212| -1: [TypeAccess] String # 212| 0: [IntegerLiteral] 2 # 212| 2: [IfStmt] if (...) @@ -335,7 +335,7 @@ test.kt: # 212| 1: [ExprStmt] ; # 212| 0: [AssignExpr] ...=... # 212| 0: [VarAccess] p2 -# 212| 1: [StringLiteral] after-vararg-default sunk 3 +# 212| 1: [StringLiteral] "after-vararg-default sunk 3" # 212| 3: [ReturnStmt] return ... # 212| 0: [MethodAccess] varargsTestOnlySinkRegularArgs(...) # 212| -1: [TypeAccess] TestKt @@ -356,7 +356,7 @@ test.kt: # 219| 1: [ExprStmt] ; # 219| 0: [MethodAccess] varargsTestOnlySinkRegularArgs$default(...) # 219| -1: [TypeAccess] TestKt -# 219| 0: [StringLiteral] no-varargs-before, no-z-parameter sunk 3 +# 219| 0: [StringLiteral] "no-varargs-before, no-z-parameter sunk 3" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -364,32 +364,32 @@ test.kt: # 220| 2: [ExprStmt] ; # 220| 0: [MethodAccess] varargsTestOnlySinkRegularArgs$default(...) # 220| -1: [TypeAccess] TestKt -# 220| 0: [StringLiteral] no-varargs-before sunk 3 +# 220| 0: [StringLiteral] "no-varargs-before sunk 3" # 1| 1: [NullLiteral] null -# 220| 2: [StringLiteral] no-varargs-after sunk 3 +# 220| 2: [StringLiteral] "no-varargs-after sunk 3" # 1| 3: [IntegerLiteral] 5 # 1| 4: [NullLiteral] null # 221| 3: [ExprStmt] ; # 221| 0: [MethodAccess] varargsTestOnlySinkRegularArgs(...) # 221| -1: [TypeAccess] TestKt -# 221| 0: [StringLiteral] one-vararg-before sunk 3 -# 221| 1: [StringLiteral] one-vararg not sunk 3 -# 221| 2: [StringLiteral] one-vararg-after sunk 3 +# 221| 0: [StringLiteral] "one-vararg-before sunk 3" +# 221| 1: [StringLiteral] "one-vararg not sunk 3" +# 221| 2: [StringLiteral] "one-vararg-after sunk 3" # 222| 4: [ExprStmt] ; # 222| 0: [MethodAccess] varargsTestOnlySinkRegularArgs(...) # 222| -1: [TypeAccess] TestKt -# 222| 0: [StringLiteral] two-varargs-before sunk 3 -# 222| 1: [StringLiteral] two-vararg-first not sunk 3 -# 222| 2: [StringLiteral] two-vararg-second not sunk 3 -# 222| 3: [StringLiteral] two-varargs-after sunk 3 +# 222| 0: [StringLiteral] "two-varargs-before sunk 3" +# 222| 1: [StringLiteral] "two-vararg-first not sunk 3" +# 222| 2: [StringLiteral] "two-vararg-second not sunk 3" +# 222| 3: [StringLiteral] "two-varargs-after sunk 3" # 223| 5: [ExprStmt] ; # 223| 0: [MethodAccess] varargsTestOnlySinkRegularArgs$default(...) # 223| -1: [TypeAccess] TestKt -# 223| 0: [StringLiteral] no-z-parmeter sunk 3 +# 223| 0: [StringLiteral] "no-z-parmeter sunk 3" # 223| 1: [ArrayCreationExpr] new String[] # 223| -2: [ArrayInit] {...} -# 223| 0: [StringLiteral] no-z-parameter first vararg not sunk 3 -# 223| 1: [StringLiteral] no-z-parameter second vararg not sunk 3 +# 223| 0: [StringLiteral] "no-z-parameter first vararg not sunk 3" +# 223| 1: [StringLiteral] "no-z-parameter second vararg not sunk 3" # 223| -1: [TypeAccess] String # 223| 0: [IntegerLiteral] 2 # 1| 2: [NullLiteral] null @@ -403,15 +403,15 @@ test.kt: # 233| 0: [TypeAccess] Unit # 233| 1: [ClassInstanceExpr] new VarargsConstructorTest(...) # 233| -3: [TypeAccess] VarargsConstructorTest -# 233| 0: [StringLiteral] varargs constructor test sunk +# 233| 0: [StringLiteral] "varargs constructor test sunk" # 234| 1: [ExprStmt] ; # 234| 0: [ImplicitCoercionToUnitExpr] # 234| 0: [TypeAccess] Unit # 234| 1: [ClassInstanceExpr] new VarargsConstructorTest(...) # 234| -3: [TypeAccess] VarargsConstructorTest -# 234| 0: [StringLiteral] varargs constructor test sunk 2 -# 234| 1: [StringLiteral] varargs constructor test not sunk 1 -# 234| 2: [StringLiteral] varargs constructor test not sunk 2 +# 234| 0: [StringLiteral] "varargs constructor test sunk 2" +# 234| 1: [StringLiteral] "varargs constructor test not sunk 1" +# 234| 2: [StringLiteral] "varargs constructor test not sunk 2" # 3| 2: [Class] TestMember # 3| 1: [Constructor] TestMember # 3| 5: [BlockStmt] { ... } @@ -466,7 +466,7 @@ test.kt: # 5| 1: [ExprStmt] ; # 5| 0: [AssignExpr] ...=... # 5| 0: [VarAccess] p3 -# 5| 1: [StringLiteral] hello world +# 5| 1: [StringLiteral] "hello world" # 5| 2: [ReturnStmt] return ... # 5| 0: [MethodAccess] f(...) # 5| -1: [VarAccess] p0 @@ -480,7 +480,7 @@ test.kt: # 10| 0: [MethodAccess] f$default(...) # 10| -1: [TypeAccess] TestMember # 10| 0: [ThisAccess] this -# 10| 1: [StringLiteral] member sunk +# 10| 1: [StringLiteral] "member sunk" # 1| 2: [NullLiteral] null # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 1 @@ -489,17 +489,17 @@ test.kt: # 11| 0: [MethodAccess] f$default(...) # 11| -1: [TypeAccess] TestMember # 11| 0: [ThisAccess] this -# 11| 1: [StringLiteral] member sunk fp -# 11| 2: [StringLiteral] member sunk 2 +# 11| 1: [StringLiteral] "member sunk fp" +# 11| 2: [StringLiteral] "member sunk 2" # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 3 # 1| 5: [NullLiteral] null # 12| 2: [ExprStmt] ; # 12| 0: [MethodAccess] f(...) # 12| -1: [ThisAccess] this -# 12| 0: [StringLiteral] not sunk -# 12| 1: [StringLiteral] member sunk 3 -# 12| 2: [StringLiteral] not sunk +# 12| 0: [StringLiteral] "not sunk" +# 12| 1: [StringLiteral] "member sunk 3" +# 12| 2: [StringLiteral] "not sunk" # 17| 3: [Class] TestExtensionMember # 17| 1: [Constructor] TestExtensionMember # 17| 5: [BlockStmt] { ... } @@ -562,7 +562,7 @@ test.kt: # 19| 1: [ExprStmt] ; # 19| 0: [AssignExpr] ...=... # 19| 0: [VarAccess] p4 -# 19| 1: [StringLiteral] hello world +# 19| 1: [StringLiteral] "hello world" # 19| 2: [ReturnStmt] return ... # 19| 0: [MethodAccess] f(...) # 19| -1: [VarAccess] p1 @@ -581,7 +581,7 @@ test.kt: # 25| -1: [TypeAccess] TestExtensionMember # 25| 0: [VarAccess] sunk # 25| 1: [ThisAccess] this -# 25| 2: [StringLiteral] extension sunk +# 25| 2: [StringLiteral] "extension sunk" # 1| 3: [NullLiteral] null # 1| 4: [NullLiteral] null # 1| 5: [IntegerLiteral] 1 @@ -591,8 +591,8 @@ test.kt: # 26| -1: [TypeAccess] TestExtensionMember # 26| 0: [VarAccess] sunk # 26| 1: [ThisAccess] this -# 26| 2: [StringLiteral] extension sunk fp -# 26| 3: [StringLiteral] extension sunk 2 +# 26| 2: [StringLiteral] "extension sunk fp" +# 26| 3: [StringLiteral] "extension sunk 2" # 1| 4: [NullLiteral] null # 1| 5: [IntegerLiteral] 3 # 1| 6: [NullLiteral] null @@ -600,9 +600,9 @@ test.kt: # 27| 0: [MethodAccess] f(...) # 27| -1: [ThisAccess] this # 27| 0: [VarAccess] sunk -# 27| 1: [StringLiteral] not sunk -# 27| 2: [StringLiteral] extension sunk 3 -# 27| 3: [StringLiteral] not sunk +# 27| 1: [StringLiteral] "not sunk" +# 27| 2: [StringLiteral] "extension sunk 3" +# 27| 3: [StringLiteral] "not sunk" # 32| 4: [Class] TestStaticMember # 32| 1: [Constructor] TestStaticMember # 32| 5: [BlockStmt] { ... } @@ -655,7 +655,7 @@ test.kt: # 34| 1: [ExprStmt] ; # 34| 0: [AssignExpr] ...=... # 34| 0: [VarAccess] p2 -# 34| 1: [StringLiteral] hello world +# 34| 1: [StringLiteral] "hello world" # 34| 2: [ReturnStmt] return ... # 34| 0: [MethodAccess] f(...) # 34| -1: [TypeAccess] TestStaticMember @@ -668,7 +668,7 @@ test.kt: # 39| 0: [ExprStmt] ; # 39| 0: [MethodAccess] f$default(...) # 39| -1: [TypeAccess] TestStaticMember -# 39| 0: [StringLiteral] static sunk +# 39| 0: [StringLiteral] "static sunk" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -676,17 +676,17 @@ test.kt: # 40| 1: [ExprStmt] ; # 40| 0: [MethodAccess] f$default(...) # 40| -1: [TypeAccess] TestStaticMember -# 40| 0: [StringLiteral] static sunk fp -# 40| 1: [StringLiteral] static sunk 2 +# 40| 0: [StringLiteral] "static sunk fp" +# 40| 1: [StringLiteral] "static sunk 2" # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 3 # 1| 4: [NullLiteral] null # 41| 2: [ExprStmt] ; # 41| 0: [MethodAccess] f(...) # 41| -1: [TypeAccess] TestStaticMember -# 41| 0: [StringLiteral] not sunk -# 41| 1: [StringLiteral] static sunk 3 -# 41| 2: [StringLiteral] not sunk +# 41| 0: [StringLiteral] "not sunk" +# 41| 1: [StringLiteral] "static sunk 3" +# 41| 2: [StringLiteral] "not sunk" # 46| 5: [Class] ExtendMe # 46| 1: [Constructor] ExtendMe # 46| 5: [BlockStmt] { ... } @@ -770,7 +770,7 @@ test.kt: # 56| 1: [ExprStmt] ; # 56| 0: [AssignExpr] ...=... # 56| 0: [VarAccess] p4 -# 56| 1: [StringLiteral] hello world +# 56| 1: [StringLiteral] "hello world" # 56| 2: [ReturnStmt] return ... # 56| 0: [MethodAccess] test(...) # 56| -1: [VarAccess] p1 @@ -789,7 +789,7 @@ test.kt: # 61| -1: [TypeAccess] TestReceiverReferences # 61| 0: [VarAccess] t # 61| 1: [ThisAccess] this -# 61| 2: [StringLiteral] receiver refs sunk +# 61| 2: [StringLiteral] "receiver refs sunk" # 1| 3: [NullLiteral] null # 1| 4: [NullLiteral] null # 1| 5: [IntegerLiteral] 1 @@ -799,8 +799,8 @@ test.kt: # 62| -1: [TypeAccess] TestReceiverReferences # 62| 0: [VarAccess] t # 62| 1: [ThisAccess] this -# 62| 2: [StringLiteral] receiver refs sunk fp -# 62| 3: [StringLiteral] receiver refs sunk 2 +# 62| 2: [StringLiteral] "receiver refs sunk fp" +# 62| 3: [StringLiteral] "receiver refs sunk 2" # 1| 4: [NullLiteral] null # 1| 5: [IntegerLiteral] 3 # 1| 6: [NullLiteral] null @@ -808,9 +808,9 @@ test.kt: # 63| 0: [MethodAccess] test(...) # 63| -1: [ThisAccess] this # 63| 0: [VarAccess] t -# 63| 1: [StringLiteral] not sunk -# 63| 2: [StringLiteral] receiver refs sunk 3 -# 63| 3: [StringLiteral] not sunk +# 63| 1: [StringLiteral] "not sunk" +# 63| 2: [StringLiteral] "receiver refs sunk 3" +# 63| 3: [StringLiteral] "not sunk" # 68| 7: [Class] TestConstructor # 68| 1: [Constructor] TestConstructor #-----| 4: (Parameters) @@ -859,7 +859,7 @@ test.kt: # 68| 1: [ExprStmt] ; # 68| 0: [AssignExpr] ...=... # 68| 0: [VarAccess] p2 -# 68| 1: [StringLiteral] hello world +# 68| 1: [StringLiteral] "hello world" # 68| 2: [ThisConstructorInvocationStmt] this(...) # 68| 0: [VarAccess] p0 # 68| 1: [VarAccess] p1 @@ -872,7 +872,7 @@ test.kt: # 75| 0: [TypeAccess] Unit # 75| 1: [ClassInstanceExpr] new TestConstructor(...) # 75| -3: [TypeAccess] TestConstructor -# 75| 0: [StringLiteral] constructor sunk +# 75| 0: [StringLiteral] "constructor sunk" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -882,8 +882,8 @@ test.kt: # 76| 0: [TypeAccess] Unit # 76| 1: [ClassInstanceExpr] new TestConstructor(...) # 76| -3: [TypeAccess] TestConstructor -# 76| 0: [StringLiteral] constructor sunk fp -# 76| 1: [StringLiteral] constructor sunk 2 +# 76| 0: [StringLiteral] "constructor sunk fp" +# 76| 1: [StringLiteral] "constructor sunk 2" # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 3 # 1| 4: [NullLiteral] null @@ -892,9 +892,9 @@ test.kt: # 77| 0: [TypeAccess] Unit # 77| 1: [ClassInstanceExpr] new TestConstructor(...) # 77| -3: [TypeAccess] TestConstructor -# 77| 0: [StringLiteral] not sunk -# 77| 1: [StringLiteral] constructor sunk 3 -# 77| 2: [StringLiteral] not sunk +# 77| 0: [StringLiteral] "not sunk" +# 77| 1: [StringLiteral] "constructor sunk 3" +# 77| 2: [StringLiteral] "not sunk" # 82| 8: [Class] TestLocal # 82| 1: [Constructor] TestLocal # 82| 5: [BlockStmt] { ... } @@ -955,7 +955,7 @@ test.kt: # 86| 1: [ExprStmt] ; # 86| 0: [AssignExpr] ...=... # 86| 0: [VarAccess] p2 -# 86| 1: [StringLiteral] hello world +# 86| 1: [StringLiteral] "hello world" # 86| 2: [ReturnStmt] return ... # 86| 0: [MethodAccess] f(...) # 86| -1: [ClassInstanceExpr] new (...) @@ -974,7 +974,7 @@ test.kt: # 91| 0: [ExprStmt] ; # 91| 0: [MethodAccess] f$default(...) # 91| -1: [TypeAccess] -# 91| 0: [StringLiteral] local sunk +# 91| 0: [StringLiteral] "local sunk" # 1| 1: [NullLiteral] null # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 @@ -982,8 +982,8 @@ test.kt: # 92| 1: [ExprStmt] ; # 92| 0: [MethodAccess] f$default(...) # 92| -1: [TypeAccess] -# 92| 0: [StringLiteral] local sunk fp -# 92| 1: [StringLiteral] local sunk 2 +# 92| 0: [StringLiteral] "local sunk fp" +# 92| 1: [StringLiteral] "local sunk 2" # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 3 # 1| 4: [NullLiteral] null @@ -991,9 +991,9 @@ test.kt: # 93| 0: [MethodAccess] f(...) # 93| -1: [ClassInstanceExpr] new (...) # 93| -3: [TypeAccess] Object -# 93| 0: [StringLiteral] not sunk -# 93| 1: [StringLiteral] local sunk 3 -# 93| 2: [StringLiteral] not sunk +# 93| 0: [StringLiteral] "not sunk" +# 93| 1: [StringLiteral] "local sunk 3" +# 93| 2: [StringLiteral] "not sunk" # 100| 9: [Class] TestLocalClass # 100| 1: [Constructor] TestLocalClass # 100| 5: [BlockStmt] { ... } @@ -1057,7 +1057,7 @@ test.kt: # 106| 1: [ExprStmt] ; # 106| 0: [AssignExpr] ...=... # 106| 0: [VarAccess] p3 -# 106| 1: [StringLiteral] hello world +# 106| 1: [StringLiteral] "hello world" # 106| 2: [ReturnStmt] return ... # 106| 0: [MethodAccess] f(...) # 106| -1: [VarAccess] p0 @@ -1071,7 +1071,7 @@ test.kt: # 111| 0: [MethodAccess] f$default(...) # 111| -1: [TypeAccess] EnclosingLocalClass # 111| 0: [ThisAccess] this -# 111| 1: [StringLiteral] local sunk +# 111| 1: [StringLiteral] "local sunk" # 1| 2: [NullLiteral] null # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 1 @@ -1080,17 +1080,17 @@ test.kt: # 112| 0: [MethodAccess] f$default(...) # 112| -1: [TypeAccess] EnclosingLocalClass # 112| 0: [ThisAccess] this -# 112| 1: [StringLiteral] local sunk fp -# 112| 2: [StringLiteral] local sunk 2 +# 112| 1: [StringLiteral] "local sunk fp" +# 112| 2: [StringLiteral] "local sunk 2" # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 3 # 1| 5: [NullLiteral] null # 113| 2: [ExprStmt] ; # 113| 0: [MethodAccess] f(...) # 113| -1: [ThisAccess] this -# 113| 0: [StringLiteral] not sunk -# 113| 1: [StringLiteral] local sunk 3 -# 113| 2: [StringLiteral] not sunk +# 113| 0: [StringLiteral] "not sunk" +# 113| 1: [StringLiteral] "local sunk 3" +# 113| 2: [StringLiteral] "not sunk" # 122| 10: [Class,GenericType,ParameterizedType] TestGeneric #-----| -2: (Generic Parameters) # 122| 0: [TypeVariable] T @@ -1168,7 +1168,7 @@ test.kt: # 129| 0: [MethodAccess] f$default(...) # 129| -1: [TypeAccess] TestGeneric<> # 129| 0: [VarAccess] tgs -# 129| 1: [StringLiteral] generic sunk +# 129| 1: [StringLiteral] "generic sunk" # 1| 2: [NullLiteral] null # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 1 @@ -1177,23 +1177,23 @@ test.kt: # 130| 0: [MethodAccess] f$default(...) # 130| -1: [TypeAccess] TestGeneric<> # 130| 0: [VarAccess] tcs -# 130| 1: [StringLiteral] generic sunk fp -# 130| 2: [StringLiteral] generic sunk 2 +# 130| 1: [StringLiteral] "generic sunk fp" +# 130| 2: [StringLiteral] "generic sunk 2" # 1| 3: [NullLiteral] null # 1| 4: [IntegerLiteral] 3 # 1| 5: [NullLiteral] null # 131| 2: [ExprStmt] ; # 131| 0: [MethodAccess] f(...) # 131| -1: [VarAccess] tgs -# 131| 0: [StringLiteral] not sunk -# 131| 1: [StringLiteral] generic sunk 3 -# 131| 2: [StringLiteral] not sunk +# 131| 0: [StringLiteral] "not sunk" +# 131| 1: [StringLiteral] "generic sunk 3" +# 131| 2: [StringLiteral] "not sunk" # 132| 3: [ExprStmt] ; # 132| 0: [MethodAccess] f(...) # 132| -1: [VarAccess] tcs -# 132| 0: [StringLiteral] not sunk -# 132| 1: [StringLiteral] generic sunk 3 -# 132| 2: [StringLiteral] not sunk +# 132| 0: [StringLiteral] "not sunk" +# 132| 1: [StringLiteral] "generic sunk 3" +# 132| 2: [StringLiteral] "not sunk" # 135| 5: [Method] testReturn # 135| 3: [TypeAccess] T #-----| 4: (Parameters) @@ -1246,7 +1246,7 @@ test.kt: # 138| 0: [MethodAccess] testReturn$default(...) # 138| -1: [TypeAccess] TestGeneric<> # 138| 0: [VarAccess] tgs -# 138| 1: [StringLiteral] sunk return value +# 138| 1: [StringLiteral] "sunk return value" # 1| 2: [NullLiteral] null # 1| 3: [IntegerLiteral] 1 # 1| 4: [NullLiteral] null @@ -1381,7 +1381,7 @@ test.kt: # 150| 0: [MethodAccess] f$default(...) # 150| -1: [TypeAccess] TestGenericFunction<> # 150| 0: [VarAccess] inst -# 150| 1: [StringLiteral] generic function sunk +# 150| 1: [StringLiteral] "generic function sunk" # 1| 2: [NullLiteral] null # 1| 3: [NullLiteral] null # 1| 4: [NullLiteral] null @@ -1393,8 +1393,8 @@ test.kt: # 151| 0: [MethodAccess] f$default(...) # 151| -1: [TypeAccess] TestGenericFunction<> # 151| 0: [VarAccess] inst -# 151| 1: [StringLiteral] generic function sunk fp -# 151| 2: [StringLiteral] generic function sunk 2 +# 151| 1: [StringLiteral] "generic function sunk fp" +# 151| 2: [StringLiteral] "generic function sunk 2" # 1| 3: [NullLiteral] null # 1| 4: [NullLiteral] null # 1| 5: [NullLiteral] null @@ -1612,7 +1612,7 @@ test.kt: # 171| -1: [ClassInstanceExpr] new TestGenericUsedWithinDefaultValue(...) # 171| -3: [TypeAccess] TestGenericUsedWithinDefaultValue # 171| 0: [TypeAccess] String -# 171| 0: [StringLiteral] Hello world +# 171| 0: [StringLiteral] "Hello world" # 171| 1: [ReturnStmt] return ... # 171| 0: [MethodAccess] f(...) # 171| -1: [VarAccess] p0 @@ -1662,7 +1662,7 @@ test.kt: # 179| 1: [ExprStmt] ; # 179| 0: [AssignExpr] ...=... # 179| 0: [VarAccess] p2 -# 179| 1: [StringLiteral] Hello world +# 179| 1: [StringLiteral] "Hello world" # 179| 1: [ReturnStmt] return ... # 179| 0: [MethodAccess] f(...) # 179| -1: [VarAccess] p0 diff --git a/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected b/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected index 64fffd47586..c46be5c7900 100644 --- a/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/reflection/PrintAst.expected @@ -45,7 +45,7 @@ reflection.kt: # 50| -3: [TypeAccess] KProperty1 # 50| 0: [TypeAccess] String # 50| 1: [TypeAccess] Character -# 50| 0: [StringLiteral] abc +# 50| 0: [StringLiteral] "abc" # 51| 1: [ExprStmt] ; # 51| 0: [MethodAccess] println(...) # 51| -1: [TypeAccess] ConsoleKt @@ -78,7 +78,7 @@ reflection.kt: # 51| -1: [ThisAccess] this # 51| -3: [TypeAccess] KProperty0 # 51| 0: [TypeAccess] Character -# 51| 0: [StringLiteral] abcd +# 51| 0: [StringLiteral] "abcd" # 54| 3: [ExtensionMethod] ext1 #-----| 2: (Generic Parameters) # 54| 0: [TypeVariable] T2 @@ -118,7 +118,7 @@ reflection.kt: # 97| 0: [TypeAccess] String # 97| -2: [TypeAccess] String # 97| -1: [TypeAccess] ReflectionKt -# 97| 0: [StringLiteral] +# 97| 0: [StringLiteral] "" # 97| 1: [MemberRefExpr] ...::... # 97| -4: [AnonymousClass] new Function1>(...) { ... } # 97| 1: [Constructor] @@ -143,7 +143,7 @@ reflection.kt: # 98| -3: [TypeAccess] Unit # 98| -2: [TypeAccess] String # 98| -1: [TypeAccess] ReflectionKt -# 98| 0: [StringLiteral] +# 98| 0: [StringLiteral] "" # 98| 1: [MemberRefExpr] ...::... # 98| -4: [AnonymousClass] new Function1(...) { ... } # 98| 1: [Constructor] @@ -169,7 +169,7 @@ reflection.kt: # 99| 1: [TypeAccess] Integer # 99| -2: [TypeAccess] String # 99| -1: [TypeAccess] ReflectionKt -# 99| 0: [StringLiteral] +# 99| 0: [StringLiteral] "" # 99| 1: [MemberRefExpr] ...::... # 99| -4: [AnonymousClass] new Function1>(...) { ... } # 99| 1: [Constructor] @@ -1026,7 +1026,7 @@ reflection.kt: # 24| 0: [ValueEQExpr] ... (value equals) ... # 24| 0: [MethodAccess] getName(...) # 24| -1: [VarAccess] it -# 24| 1: [StringLiteral] p3 +# 24| 1: [StringLiteral] "p3" # 24| -3: [TypeAccess] Function1,Boolean> # 24| 0: [TypeAccess] KCallable # 24| 1: [TypeAccess] Boolean @@ -1534,7 +1534,7 @@ reflection.kt: # 90| 1: [TypeAccess] T # 90| -2: [TypeAccess] String # 90| -1: [TypeAccess] ReflectionKt -# 90| 0: [StringLiteral] +# 90| 0: [StringLiteral] "" # 90| 1: [MemberRefExpr] ...::... # 90| -4: [AnonymousClass] new Function1>(...) { ... } # 90| 1: [Constructor] diff --git a/java/ql/test/kotlin/library-tests/stmts/PrintAst.expected b/java/ql/test/kotlin/library-tests/stmts/PrintAst.expected index 2edcd3755b6..7ab29615bd3 100644 --- a/java/ql/test/kotlin/library-tests/stmts/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/stmts/PrintAst.expected @@ -188,7 +188,7 @@ stmts.kt: # 48| 0: [ThrowStmt] throw ... # 48| 0: [ClassInstanceExpr] new Exception(...) # 48| -3: [TypeAccess] Exception -# 48| 0: [StringLiteral] Foo +# 48| 0: [StringLiteral] "Foo" # 50| 0: [CatchClause] catch (...) #-----| 0: (Single Local Variable Declaration) # 50| 0: [TypeAccess] Exception diff --git a/java/ql/test/kotlin/library-tests/stmts/exprs.expected b/java/ql/test/kotlin/library-tests/stmts/exprs.expected index 01631139da3..9193248487f 100644 --- a/java/ql/test/kotlin/library-tests/stmts/exprs.expected +++ b/java/ql/test/kotlin/library-tests/stmts/exprs.expected @@ -101,7 +101,7 @@ | stmts.kt:46:1:56:1 | int | TypeAccess | | stmts.kt:48:15:48:30 | Exception | TypeAccess | | stmts.kt:48:15:48:30 | new Exception(...) | ClassInstanceExpr | -| stmts.kt:48:26:48:28 | Foo | StringLiteral | +| stmts.kt:48:26:48:28 | "Foo" | StringLiteral | | stmts.kt:50:12:50:23 | Exception | TypeAccess | | stmts.kt:50:12:50:23 | e | LocalVariableDeclExpr | | stmts.kt:51:16:51:16 | 1 | IntegerLiteral | diff --git a/java/ql/test/kotlin/library-tests/trap/diags.expected b/java/ql/test/kotlin/library-tests/trap/diags.expected index 377b7fd0a99..6e145a5e4e0 100644 --- a/java/ql/test/kotlin/library-tests/trap/diags.expected +++ b/java/ql/test/kotlin/library-tests/trap/diags.expected @@ -1,9 +1,11 @@ -| file://:0:0:0:0 | Truncated string of length 1048577 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048577 | DATE TIME Truncated string of length 1048577\nTruncated string of length 1048577, starting '//A03BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDE' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:22:0\n | +| file://:0:0:0:0 | Truncated string of length 1048577 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048577 | DATE TIME Truncated string of length 1048577\nTruncated string of length 1048577, starting '"ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBC"' ...while extracting a expression () at long_string.kt:14:31:14:1048605\n ...while extracting a variable expr (longStringLiteral1) at long_string.kt:14:5:14:1048606\n ...while extracting a variable (longStringLiteral1) at long_string.kt:14:5:14:1048606\n ...while extracting a statement (longStringLiteral1) at long_string.kt:14:5:14:1048606\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 1048577 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048577 | DATE TIME Truncated string of length 1048577\nTruncated string of length 1048577, starting '//A03BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDE' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:24:0\n | | file://:0:0:0:0 | Truncated string of length 1048577 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048577 | DATE TIME Truncated string of length 1048577\nTruncated string of length 1048577, starting 'ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDE' ...while extracting a expression () at long_string.kt:16:31:16:1048607\n ...while extracting a variable expr (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a variable (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a statement (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | -| file://:0:0:0:0 | Truncated string of length 1048577 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048577 | DATE TIME Truncated string of length 1048577\nTruncated string of length 1048577, starting 'ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDE' ...while extracting a expression () at long_string.kt:16:31:16:1048607\n ...while extracting a variable expr (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a variable (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a statement (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | -| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting '//A04BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDEF' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:22:0\n | -| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting '//A05"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""', ending '""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""CDEF' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:22:0\n | -| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting 'A"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""', ending '""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""CDEF' ...while extracting a expression () at long_string.kt:18:31:18:2097181\n ...while extracting a variable expr (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a variable (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a statement (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting '"ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCD"' ...while extracting a expression () at long_string.kt:15:31:15:1048606\n ...while extracting a variable expr (longStringLiteral2) at long_string.kt:15:5:15:1048607\n ...while extracting a variable (longStringLiteral2) at long_string.kt:15:5:15:1048607\n ...while extracting a statement (longStringLiteral2) at long_string.kt:15:5:15:1048607\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting '//A04BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDEF' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:24:0\n | +| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting '//A05"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""', ending '""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""CDEF' ...while extracting a file (long_comments.kt) at long_comments.kt:1:1:24:0\n | | file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting 'A"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""', ending '""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""CDEF' ...while extracting a expression () at long_string.kt:18:31:18:2097181\n ...while extracting a variable expr (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a variable (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a statement (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | | file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting 'ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDEF' ...while extracting a expression () at long_string.kt:17:31:17:1048608\n ...while extracting a variable expr (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a variable (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a statement (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | -| file://:0:0:0:0 | Truncated string of length 1048578 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048578 | DATE TIME Truncated string of length 1048578\nTruncated string of length 1048578, starting 'ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDEF' ...while extracting a expression () at long_string.kt:17:31:17:1048608\n ...while extracting a variable expr (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a variable (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a statement (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 1048579 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048579 | DATE TIME Truncated string of length 1048579\nTruncated string of length 1048579, starting '"ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDE"' ...while extracting a expression () at long_string.kt:16:31:16:1048607\n ...while extracting a variable expr (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a variable (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a statement (longStringLiteral3) at long_string.kt:16:5:16:1048608\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 1048580 | CodeQL Kotlin extractor | 2 | | Truncated string of length 1048580 | DATE TIME Truncated string of length 1048580\nTruncated string of length 1048580, starting '"ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', ending 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDEF"' ...while extracting a expression () at long_string.kt:17:31:17:1048608\n ...while extracting a variable expr (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a variable (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a statement (longStringLiteral4) at long_string.kt:17:5:17:1048609\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | +| file://:0:0:0:0 | Truncated string of length 2097153 | CodeQL Kotlin extractor | 2 | | Truncated string of length 2097153 | DATE TIME Truncated string of length 2097153\nTruncated string of length 2097153, starting '"A\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"', ending '"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"CDEF"' ...while extracting a expression () at long_string.kt:18:31:18:2097181\n ...while extracting a variable expr (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a variable (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a statement (longStringLiteral5) at long_string.kt:18:5:18:2097182\n ...while extracting a block body () at long_string.kt:13:22:19:1\n ...while extracting a body () at long_string.kt:13:22:19:1\n ...while extracting a function (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a declaration (longLiteralFun) at long_string.kt:13:1:19:1\n ...while extracting a file (long_string.kt) at long_string.kt:1:1:21:0\n | diff --git a/java/ql/test/kotlin/library-tests/trap/literals.ql b/java/ql/test/kotlin/library-tests/trap/literals.ql index 1490a21b458..b6dc1dcff6f 100644 --- a/java/ql/test/kotlin/library-tests/trap/literals.ql +++ b/java/ql/test/kotlin/library-tests/trap/literals.ql @@ -1,6 +1,6 @@ import java from Literal l, int len -where len = l.getValue().length() +where len = l.getValue().length() and l.getFile().isSourceFile() select l.getLocation(), len, l.getValue().prefix(5) + "..." + l.getValue().suffix(len - 5), l.getPrimaryQlClasses() diff --git a/java/ql/test/kotlin/library-tests/trap/long_comments.kt b/java/ql/test/kotlin/library-tests/trap/long_comments.kt index 3c5cb1d3764..55db7520f21 100644 --- a/java/ql/test/kotlin/library-tests/trap/long_comments.kt +++ b/java/ql/test/kotlin/library-tests/trap/long_comments.kt @@ -18,4 +18,6 @@ // Diagnostic Matches: %Truncated string of length 1048577% // Diagnostic Matches: %Truncated string of length 1048578% - +// Diagnostic Matches: %Truncated string of length 1048579% +// Diagnostic Matches: %Truncated string of length 1048580% +// Diagnostic Matches: %Truncated string of length 2097153% diff --git a/java/ql/test/kotlin/library-tests/vararg/args.expected b/java/ql/test/kotlin/library-tests/vararg/args.expected index 1e5a60a3545..6f5e0fbc035 100644 --- a/java/ql/test/kotlin/library-tests/vararg/args.expected +++ b/java/ql/test/kotlin/library-tests/vararg/args.expected @@ -53,33 +53,33 @@ implicitVarargsArguments | test.kt:35:5:35:34 | funWithOnlyVarArgs(...) | 0 | test.kt:35:24:35:25 | 20 | | test.kt:35:5:35:34 | funWithOnlyVarArgs(...) | 1 | test.kt:35:28:35:29 | 21 | | test.kt:35:5:35:34 | funWithOnlyVarArgs(...) | 2 | test.kt:35:32:35:33 | 22 | -| test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 0 | test.kt:36:28:36:30 | foo | +| test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 0 | test.kt:36:28:36:30 | "foo" | | test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 1 | test.kt:36:34:36:37 | true | | test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 2 | test.kt:36:40:36:41 | 30 | | test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 3 | test.kt:36:44:36:45 | 31 | | test.kt:36:5:36:50 | funWithArgsAndVarArgs(...) | 4 | test.kt:36:48:36:49 | 32 | -| test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 0 | test.kt:37:27:37:29 | foo | +| test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 0 | test.kt:37:27:37:29 | "foo" | | test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 1 | test.kt:37:33:37:34 | 41 | | test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 2 | test.kt:37:37:37:38 | 42 | | test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 3 | test.kt:37:41:37:42 | 43 | | test.kt:37:5:37:53 | funWithMiddleVarArgs(...) | 4 | test.kt:37:49:37:52 | true | | test.kt:38:5:38:30 | funWithOnlyVarArgs(...) | 0 | test.kt:38:25:38:29 | array | -| test.kt:39:5:39:46 | funWithArgsAndVarArgs(...) | 0 | test.kt:39:28:39:30 | foo | +| test.kt:39:5:39:46 | funWithArgsAndVarArgs(...) | 0 | test.kt:39:28:39:30 | "foo" | | test.kt:39:5:39:46 | funWithArgsAndVarArgs(...) | 1 | test.kt:39:34:39:37 | true | | test.kt:39:5:39:46 | funWithArgsAndVarArgs(...) | 2 | test.kt:39:41:39:45 | array | -| test.kt:40:5:40:49 | funWithMiddleVarArgs(...) | 0 | test.kt:40:27:40:29 | foo | +| test.kt:40:5:40:49 | funWithMiddleVarArgs(...) | 0 | test.kt:40:27:40:29 | "foo" | | test.kt:40:5:40:49 | funWithMiddleVarArgs(...) | 1 | test.kt:40:34:40:38 | array | | test.kt:40:5:40:49 | funWithMiddleVarArgs(...) | 2 | test.kt:40:45:40:48 | true | | test.kt:41:5:41:36 | new HasVarargConstructor(...) | 0 | test.kt:41:26:41:27 | 51 | | test.kt:41:5:41:36 | new HasVarargConstructor(...) | 1 | test.kt:41:30:41:31 | 52 | | test.kt:41:5:41:36 | new HasVarargConstructor(...) | 2 | test.kt:41:34:41:35 | 53 | -| test.kt:42:5:42:43 | new HasVarargConstructor(...) | 0 | test.kt:42:27:42:29 | foo | +| test.kt:42:5:42:43 | new HasVarargConstructor(...) | 0 | test.kt:42:27:42:29 | "foo" | | test.kt:42:5:42:43 | new HasVarargConstructor(...) | 1 | test.kt:42:33:42:34 | 61 | | test.kt:42:5:42:43 | new HasVarargConstructor(...) | 2 | test.kt:42:37:42:38 | 62 | | test.kt:42:5:42:43 | new HasVarargConstructor(...) | 3 | test.kt:42:41:42:42 | 63 | | test.kt:43:5:43:38 | new SuperclassHasVarargConstructor(...) | 0 | test.kt:43:36:43:37 | 91 | | test.kt:44:5:44:32 | new HasVarargConstructor(...) | 0 | test.kt:44:27:44:31 | array | -| test.kt:45:5:45:39 | new HasVarargConstructor(...) | 0 | test.kt:45:27:45:29 | foo | +| test.kt:45:5:45:39 | new HasVarargConstructor(...) | 0 | test.kt:45:27:45:29 | "foo" | | test.kt:45:5:45:39 | new HasVarargConstructor(...) | 1 | test.kt:45:34:45:38 | array | | test.kt:55:13:55:43 | new X(...) | 0 | test.kt:55:42:55:42 | 1 | | test.kt:55:13:55:43 | new X(...) | 1 | test.kt:55:15:55:35 | tmp0_s | diff --git a/java/ql/test/library-tests/paths/Test.java b/java/ql/test/library-tests/paths/Test.java index 3ba4d97ca78..b00a667d823 100644 --- a/java/ql/test/library-tests/paths/Test.java +++ b/java/ql/test/library-tests/paths/Test.java @@ -2,6 +2,7 @@ package generatedtest; import java.io.File; import java.net.URI; +import java.nio.file.FileSystem; import java.nio.file.Path; import java.nio.file.Paths; @@ -13,6 +14,119 @@ public class Test { public void test() throws Exception { + { + // "java.io;File;false;File;;;Argument[0];Argument[-1];taint;manual" + File out = null; + File in = (File)source(); + out = new File(in, (String)null); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;false;File;;;Argument[0];Argument[-1];taint;manual" + File out = null; + String in = (String)source(); + out = new File(in); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;false;File;;;Argument[0];Argument[-1];taint;manual" + File out = null; + String in = (String)source(); + out = new File(in, (String)null); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;false;File;;;Argument[0];Argument[-1];taint;manual" + File out = null; + URI in = (URI)source(); + out = new File(in); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;false;File;;;Argument[1];Argument[-1];taint;manual" + File out = null; + String in = (String)source(); + out = new File((File)null, in); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;false;File;;;Argument[1];Argument[-1];taint;manual" + File out = null; + String in = (String)source(); + out = new File((String)null, in); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;getAbsoluteFile;;;Argument[-1];ReturnValue;taint;manual" + File out = null; + File in = (File)source(); + out = in.getAbsoluteFile(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;getAbsolutePath;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + File in = (File)source(); + out = in.getAbsolutePath(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;getCanonicalFile;;;Argument[-1];ReturnValue;taint;manual" + File out = null; + File in = (File)source(); + out = in.getCanonicalFile(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;getCanonicalPath;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + File in = (File)source(); + out = in.getCanonicalPath(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;toPath;;;Argument[-1];ReturnValue;taint;manual" + Path out = null; + File in = (File)source(); + out = in.toPath(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;toString;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + File in = (File)source(); + out = in.toString(); + sink(out); // $ hasTaintFlow + } + { + // "java.io;File;true;toURI;;;Argument[-1];ReturnValue;taint;manual" + URI out = null; + File in = (File)source(); + out = in.toURI(); + sink(out); // $ hasTaintFlow + } + { + // "java.nio.file;FileSystem;true;getPath;;;Argument[0];ReturnValue;taint;manual" + Path out = null; + String in = (String)source(); + FileSystem instance = null; + out = instance.getPath(in, (String[])null); + sink(out); // $ hasTaintFlow + } + { + // "java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint;manual" + File out = null; + Path in = (Path)source(); + out = in.toFile(); + sink(out); // $ hasTaintFlow + } + { + // "java.nio.file;Path;true;getParent;;;Argument[-1];ReturnValue;taint;manual" + Path out = null; + Path in = (Path)source(); + out = in.getParent(); + sink(out); // $ hasTaintFlow + } { // "java.nio.file;Path;true;normalize;;;Argument[-1];ReturnValue;taint;manual" Path out = null; @@ -51,10 +165,10 @@ public class Test { sink(out); // $ hasTaintFlow } { - // "java.nio.file;Path;true;toFile;;;Argument[-1];ReturnValue;taint;manual" - File out = null; + // "java.nio.file;Path;true;toAbsolutePath;;;Argument[-1];ReturnValue;taint;manual" + Path out = null; Path in = (Path)source(); - out = in.toFile(); + out = in.toAbsolutePath(); sink(out); // $ hasTaintFlow } { @@ -72,26 +186,26 @@ public class Test { sink(out); // $ hasTaintFlow } { - // "java.nio.file;Paths;true;get;;;Argument[0..1];ReturnValue;taint;manual" + // "java.nio.file;Paths;true;get;;;Argument[0];ReturnValue;taint;manual" Path out = null; String in = (String)source(); out = Paths.get(in, (String[])null); sink(out); // $ hasTaintFlow } { - // "java.nio.file;Paths;true;get;;;Argument[0..1];ReturnValue;taint;manual" - Path out = null; - String[] in = (String[])source(); - out = Paths.get((String)null, in); - sink(out); // $ hasTaintFlow - } - { - // "java.nio.file;Paths;true;get;;;Argument[0..1];ReturnValue;taint;manual" + // "java.nio.file;Paths;true;get;;;Argument[0];ReturnValue;taint;manual" Path out = null; URI in = (URI)source(); out = Paths.get(in); sink(out); // $ hasTaintFlow } + { + // "java.nio.file;Paths;true;get;;;Argument[1].ArrayElement;ReturnValue;taint;manual" + Path out = null; + String[] in = (String[])new String[]{(String)source()}; + out = Paths.get((String)null, in); + sink(out); // $ hasTaintFlow + } } diff --git a/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.java b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.java similarity index 65% rename from java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.java rename to java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.java index 2aace93aeb8..5c7a3ca0574 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-730/RegexInjection.java +++ b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.java @@ -7,128 +7,119 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import org.apache.commons.lang3.RegExUtils; +import com.google.common.base.Splitter; -public class RegexInjection extends HttpServlet { +public class RegexInjectionTest extends HttpServlet { public boolean string1(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return input.matches("^" + pattern + "=.*$"); // BAD + return input.matches("^" + pattern + "=.*$"); // $ hasRegexInjection } public boolean string2(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return input.split(pattern).length > 0; // BAD + return input.split(pattern).length > 0; // $ hasRegexInjection } public boolean string3(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return input.replaceFirst(pattern, "").length() > 0; // BAD + return input.split(pattern, 0).length > 0; // $ hasRegexInjection } public boolean string4(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return input.replaceAll(pattern, "").length() > 0; // BAD + return input.replaceFirst(pattern, "").length() > 0; // $ hasRegexInjection + } + + public boolean string5(javax.servlet.http.HttpServletRequest request) { + String pattern = request.getParameter("pattern"); + String input = request.getParameter("input"); + + return input.replaceAll(pattern, "").length() > 0; // $ hasRegexInjection } public boolean pattern1(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - Pattern pt = Pattern.compile(pattern); + Pattern pt = Pattern.compile(pattern); // $ hasRegexInjection Matcher matcher = pt.matcher(input); - return matcher.find(); // BAD + return matcher.find(); } public boolean pattern2(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return Pattern.compile(pattern).matcher(input).matches(); // BAD + return Pattern.compile(pattern).matcher(input).matches(); // $ hasRegexInjection } public boolean pattern3(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return Pattern.matches(pattern, input); // BAD + return Pattern.compile(pattern, 0).matcher(input).matches(); // $ hasRegexInjection } public boolean pattern4(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return input.matches("^" + foo(pattern) + "=.*$"); // BAD - } - - String foo(String str) { - return str; + return Pattern.matches(pattern, input); // $ hasRegexInjection } public boolean pattern5(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - // GOOD: User input is sanitized before constructing the regex - return input.matches("^" + escapeSpecialRegexChars(pattern) + "=.*$"); + return input.matches("^" + foo(pattern) + "=.*$"); // $ hasRegexInjection } - public boolean pattern6(javax.servlet.http.HttpServletRequest request) { - String pattern = request.getParameter("pattern"); - String input = request.getParameter("input"); - - escapeSpecialRegexChars(pattern); - - // BAD: the pattern is not really sanitized - return input.matches("^" + pattern + "=.*$"); - } - - Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\]><-=!.+*?^$\\\\|]"); - - String escapeSpecialRegexChars(String str) { - return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); + String foo(String str) { + return str; } public boolean apache1(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.removeAll(input, pattern).length() > 0; // BAD + return RegExUtils.removeAll(input, pattern).length() > 0; // $ hasRegexInjection } public boolean apache2(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.removeFirst(input, pattern).length() > 0; // BAD + return RegExUtils.removeFirst(input, pattern).length() > 0; // $ hasRegexInjection } public boolean apache3(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.removePattern(input, pattern).length() > 0; // BAD + return RegExUtils.removePattern(input, pattern).length() > 0; // $ hasRegexInjection } public boolean apache4(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.replaceAll(input, pattern, "").length() > 0; // BAD + return RegExUtils.replaceAll(input, pattern, "").length() > 0; // $ hasRegexInjection } public boolean apache5(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.replaceFirst(input, pattern, "").length() > 0; // BAD + return RegExUtils.replaceFirst(input, pattern, "").length() > 0; // $ hasRegexInjection } public boolean apache6(javax.servlet.http.HttpServletRequest request) { @@ -136,13 +127,40 @@ public class RegexInjection extends HttpServlet { String input = request.getParameter("input"); Pattern pt = (Pattern)(Object) pattern; - return RegExUtils.replaceFirst(input, pt, "").length() > 0; // GOOD, Pattern compile is the sink instead + return RegExUtils.replaceFirst(input, pt, "").length() > 0; // Safe: Pattern compile is the sink instead } public boolean apache7(javax.servlet.http.HttpServletRequest request) { String pattern = request.getParameter("pattern"); String input = request.getParameter("input"); - return RegExUtils.replacePattern(input, pattern, "").length() > 0; // BAD + return RegExUtils.replacePattern(input, pattern, "").length() > 0; // $ hasRegexInjection + } + + // test `Pattern.quote` sanitizer + public boolean quoteTest(javax.servlet.http.HttpServletRequest request) { + String pattern = request.getParameter("pattern"); + String input = request.getParameter("input"); + + return input.matches(Pattern.quote(pattern)); // Safe + } + + // test `Pattern.LITERAL` sanitizer + public boolean literalTest(javax.servlet.http.HttpServletRequest request) { + String pattern = request.getParameter("pattern"); + String input = request.getParameter("input"); + + return Pattern.compile(pattern, Pattern.LITERAL).matcher(input).matches(); // Safe + } + + public Splitter guava1(javax.servlet.http.HttpServletRequest request) { + String pattern = request.getParameter("pattern"); + return Splitter.onPattern(pattern); // $ hasRegexInjection + } + + public Splitter guava2(javax.servlet.http.HttpServletRequest request) { + String pattern = request.getParameter("pattern"); + // sink is `Pattern.compile` + return Splitter.on(Pattern.compile(pattern)); // $ hasRegexInjection } } diff --git a/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.ql b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.ql new file mode 100644 index 00000000000..368b5170bfc --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.ql @@ -0,0 +1,20 @@ +import java +import TestUtilities.InlineExpectationsTest +import semmle.code.java.security.regexp.RegexInjectionQuery + +class RegexInjectionTest extends InlineExpectationsTest { + RegexInjectionTest() { this = "RegexInjectionTest" } + + override string getARelevantTag() { result = "hasRegexInjection" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasRegexInjection" and + exists(DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c | + c.hasFlowPath(source, sink) + | + location = sink.getNode().getLocation() and + element = sink.getNode().toString() and + value = "" + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-730/options b/java/ql/test/query-tests/security/CWE-730/options index 2f7d22dc61c..884cb21114c 100644 --- a/java/ql/test/query-tests/security/CWE-730/options +++ b/java/ql/test/query-tests/security/CWE-730/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0 \ No newline at end of file +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7 diff --git a/java/ql/test/query-tests/security/CWE-829/semmle/tests/secure-pom.xml b/java/ql/test/query-tests/security/CWE-829/semmle/tests/secure-pom.xml index 2f96052d584..2dc5709b320 100644 --- a/java/ql/test/query-tests/security/CWE-829/semmle/tests/secure-pom.xml +++ b/java/ql/test/query-tests/security/CWE-829/semmle/tests/secure-pom.xml @@ -61,5 +61,17 @@ https://insecure-repository.example + + disabled-repo + Disabled Repository + + false + + + false + + + http://insecure-repository.example + diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index ac17e9e9f27..7bf9f7f1db0 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.3.4 + +### Major Analysis Improvements + +* Added support for TypeScript 4.9. + ## 0.3.3 No user-facing changes. diff --git a/javascript/ql/lib/change-notes/2022-11-15-typescript-4-9.md b/javascript/ql/lib/change-notes/2022-11-15-typescript-4-9.md deleted file mode 100644 index 723f0a5c65f..00000000000 --- a/javascript/ql/lib/change-notes/2022-11-15-typescript-4-9.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: majorAnalysis ---- -* Added support for TypeScript 4.9. diff --git a/javascript/ql/lib/change-notes/2022-11-17-deleted-deps.md b/javascript/ql/lib/change-notes/2022-11-17-deleted-deps.md new file mode 100644 index 00000000000..eade7244ce1 --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-11-17-deleted-deps.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `Instance` class from the `Vue` module. +* Deleted the deprecated `VHtmlSourceWrite` class from `DomBasedXssQuery.qll`. +* Deleted all the deprecated `[QueryName].qll` files from the `javascript/ql/lib/semmle/javascript/security/dataflow` folder, use the corresponding `[QueryName]Query.qll` files instead. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/released/0.3.4.md b/javascript/ql/lib/change-notes/released/0.3.4.md new file mode 100644 index 00000000000..04b51176020 --- /dev/null +++ b/javascript/ql/lib/change-notes/released/0.3.4.md @@ -0,0 +1,5 @@ +## 0.3.4 + +### Major Analysis Improvements + +* Added support for TypeScript 4.9. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 9da182d3394..5ed15c24b9c 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.3.3 +lastReleaseVersion: 0.3.4 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 0a3a773e368..fed1085652e 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.3.4-dev +version: 0.3.5-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index 95a372025e2..f3eb2e5bb0d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -115,11 +115,6 @@ module Vue { kind = DataFlow::MemberKind::setter() and result = "set" } - /** - * DEPRECATED. This class has been renamed to `Vue::Component`. - */ - deprecated class Instance = Component; - /** * A Vue component, such as a `new Vue({ ... })` call or a `.vue` file. * @@ -383,23 +378,6 @@ module Vue { } } - /** - * DEPRECATED. Use `Vue::Component` instead. - * - * A Vue component from `new Vue({...})`. - */ - deprecated class VueInstance extends Component { - VueInstance() { - // restrict charpred to match original behavior - this = MkComponentInstantiation(vueLibrary().getAnInstantiation()) - } - } - - /** - * DEPRECATED. Use `Vue::ComponentExtension` or `Vue::Component` instead. - */ - deprecated class ExtendedVue = ComponentExtension; - /** * A component created via an explicit call to `Vue.extend({...})` or `CustomComponent.extend({...})`. */ @@ -429,19 +407,6 @@ module Vue { } } - /** - * DEPRECATED. Use `Vue::Component` instead. - * - * An instance of an extended Vue, for example `instance` of `var Ext = Vue.extend({...}); var instance = new Ext({...})`. - */ - deprecated class ExtendedInstance extends Component { - ExtendedInstance() { - // restrict charpred to match original behavior - this = - MkComponentInstantiation(vueLibrary().getMember("extend").getReturn().getAnInstantiation()) - } - } - /** * A Vue component from `Vue.component("my-component", { ... })`. */ @@ -568,9 +533,6 @@ module Vue { } } - /** DEPRECATED. Do not use. */ - deprecated class InstanceHeapStep = PropStep; - /** * A Vue `v-html` attribute. */ @@ -609,11 +571,6 @@ module Vue { } } - /** - * DEPRECATED. Do not use. - */ - deprecated class VHtmlSourceWrite = VHtmlAttributeStep; - /* * Provides classes for working with Vue templates. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithm.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithm.qll deleted file mode 100644 index 43a56b14dbc..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithm.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `BrokenCryptoAlgorithmQuery` instead. */ - -import javascript -private import BrokenCryptoAlgorithmQuery as BrokenCryptoAlgorithmQuery // ignore-query-import - -/** DEPRECATED. Import `BrokenCryptoAlgorithmQuery` instead. */ -deprecated module BrokenCryptoAlgorithm = BrokenCryptoAlgorithmQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/BuildArtifactLeak.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/BuildArtifactLeak.qll deleted file mode 100644 index f4853263d63..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/BuildArtifactLeak.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `BuildArtifactLeakQuery` instead. */ - -import javascript -private import BuildArtifactLeakQuery as BuildArtifactLeakQuery // ignore-query-import - -/** DEPRECATED. Import `BuildArtifactLeakQuery` instead. */ -deprecated module BuildArtifactLeak = BuildArtifactLeakQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLogging.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLogging.qll deleted file mode 100644 index 40f18772fb3..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLogging.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `CleartextLoggingQuery` instead. */ - -import javascript -private import CleartextLoggingQuery as CleartextLoggingQuery // ignore-query-import - -/** DEPRECATED. Import `CleartextLoggingQuery` instead. */ -deprecated module CleartextLogging = CleartextLoggingQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorage.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorage.qll deleted file mode 100644 index ac6bc090d66..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorage.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `CleartextStorageQuery` instead. */ - -import javascript -private import CleartextStorageQuery as CleartextStorageQuery // ignore-query-import - -/** DEPRECATED. Import `CleartextStorageQuery` instead. */ -deprecated module CleartextStorage = CleartextStorageQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll deleted file mode 100644 index 744646e168c..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `ClientSideUrlRedirectQuery` instead. */ - -import javascript -import UrlConcatenation -private import ClientSideUrlRedirectQuery as ClientSideUrlRedirectQuery // ignore-query-import - -/** DEPRECATED. Import `ClientSideUrlRedirectQuery` instead. */ -deprecated module ClientSideUrlRedirect = ClientSideUrlRedirectQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjection.qll deleted file mode 100644 index 6c03cef6cd3..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `CodeInjectionQuery` instead. */ - -import javascript -private import CodeInjectionQuery as CodeInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `CodeInjectionQuery` instead. */ -deprecated module CodeInjection = CodeInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjection.qll deleted file mode 100644 index b424c3695e1..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `CommandInjectionQuery` instead. */ - -import javascript -private import CommandInjectionQuery as CommandInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `CommandInjectionQuery` instead. */ -deprecated module CommandInjection = CommandInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ConditionalBypass.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ConditionalBypass.qll deleted file mode 100644 index 54f1e9418fc..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ConditionalBypass.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ConditionalBypassQuery` instead. */ - -import javascript -private import ConditionalBypassQuery as ConditionalBypassQuery // ignore-query-import - -/** DEPRECATED. Import `ConditionalBypassQuery` instead. */ -deprecated module ConditionalBypass = ConditionalBypassQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentials.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentials.qll deleted file mode 100644 index 06a6378e8ef..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentials.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `CorsMisconfigurationForCredentialsQuery` instead. */ - -import javascript -private import CorsMisconfigurationForCredentialsQuery as CorsMisconfigurationForCredentialsQuery // ignore-query-import - -/** DEPRECATED. Import `CorsMisconfigurationForCredentialsQuery` instead. */ -deprecated module CorsMisconfigurationForCredentials = CorsMisconfigurationForCredentialsQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll deleted file mode 100644 index 82d9f4156a5..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `DeepObjectResourceExhaustionQuery` instead. */ - -import javascript -import semmle.javascript.security.TaintedObject -private import DeepObjectResourceExhaustionQuery as DeepObjectResourceExhaustionQuery // ignore-query-import - -/** DEPRECATED. Import `DeepObjectResourceExhaustionQuery` instead. */ -deprecated module DeepObjectResourceExhaustion = DeepObjectResourceExhaustionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DifferentKindsComparisonBypass.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DifferentKindsComparisonBypass.qll deleted file mode 100644 index e28dc5e34f1..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DifferentKindsComparisonBypass.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `DifferentKindsComparisonBypassQuery` instead. */ - -import javascript -private import DifferentKindsComparisonBypassQuery as DifferentKindsComparisonBypassQuery // ignore-query-import - -/** DEPRECATED. Import `DifferentKindsComparisonBypassQuery` instead. */ -deprecated module DifferentKindsComparisonBypass = DifferentKindsComparisonBypassQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXss.qll deleted file mode 100644 index 9a687eb06a0..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXss.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `DomBasedXssQuery` instead. */ - -import javascript -private import DomBasedXssQuery as DomBasedXssQuery // ignore-query-import - -/** DEPRECATED. Import `DomBasedXssQuery` instead. */ -deprecated module DomBasedXss = DomBasedXssQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll index e8c1a144920..2f920f59604 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll @@ -8,11 +8,6 @@ private import semmle.javascript.security.TaintedUrlSuffix import DomBasedXssCustomizations::DomBasedXss private import Xss::Shared as Shared -/** - * DEPRECATED. Use `Vue::VHtmlSourceWrite` instead. - */ -deprecated class VHtmlSourceWrite = Vue::VHtmlSourceWrite; - /** DEPRECATED. Use `Configuration`. */ deprecated class HtmlInjectionConfiguration = Configuration; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXss.qll deleted file mode 100644 index 7f133319438..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXss.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ExceptionXssQuery` instead. */ - -import javascript -private import ExceptionXssQuery as ExceptionXssQuery // ignore-query-import - -/** DEPRECATED. Import `ExceptionXssQuery` instead. */ -deprecated module ExceptionXss = ExceptionXssQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/FileAccessToHttp.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/FileAccessToHttp.qll deleted file mode 100644 index 7b6e88d0669..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/FileAccessToHttp.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `FileAccessToHttpQuery` instead. */ - -import javascript -private import FileAccessToHttpQuery as FileAccessToHttpQuery // ignore-query-import - -/** DEPRECATED. Import `FileAccessToHttpQuery` instead. */ -deprecated module FileAccessToHttp = FileAccessToHttpQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentials.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentials.qll deleted file mode 100644 index 9fabc93d9ac..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentials.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `HardcodedCredentialsQuery` instead. */ - -import javascript -private import HardcodedCredentialsQuery as HardcodedCredentialsQuery // ignore-query-import - -/** DEPRECATED. Import `HardcodedCredentialsQuery` instead. */ -deprecated module HardcodedCredentials = HardcodedCredentialsQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedDataInterpretedAsCode.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedDataInterpretedAsCode.qll deleted file mode 100644 index e1ca461183a..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedDataInterpretedAsCode.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `HardcodedDataInterpretedAsCodeQuery` instead. */ - -import javascript -private import HardcodedDataInterpretedAsCodeQuery as HardcodedDataInterpretedAsCodeQuery // ignore-query-import - -/** DEPRECATED. Import `HardcodedDataInterpretedAsCodeQuery` instead. */ -deprecated module HardcodedDataInterpretedAsCode = HardcodedDataInterpretedAsCodeQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll deleted file mode 100644 index 18f90400e3d..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HostHeaderPoisoningInEmailGeneration.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `HostHeaderPoisoningInEmailGenerationQuery` instead. */ - -import javascript -private import HostHeaderPoisoningInEmailGenerationQuery as HostHeaderPoisoningInEmailGenerationQuery // ignore-query-import - -/** DEPRECATED. Import `HostHeaderPoisoningInEmailGenerationQuery` instead. */ -deprecated module HostHeaderPoisoningInEmailGeneration = HostHeaderPoisoningInEmailGenerationQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccess.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccess.qll deleted file mode 100644 index 0569ba0e692..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccess.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `HttpToFileAccessQuery` instead. */ - -import javascript -private import HttpToFileAccessQuery as HttpToFileAccessQuery // ignore-query-import - -/** DEPRECATED. Import `HttpToFileAccessQuery` instead. */ -deprecated module HttpToFileAccess = HttpToFileAccessQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll deleted file mode 100644 index 7b221c4edb5..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ImproperCodeSanitizationQuery` instead. */ - -import javascript -private import ImproperCodeSanitizationQuery as ImproperCodeSanitizationQuery // ignore-query-import - -/** DEPRECATED. Import `ImproperCodeSanitizationQuery` instead. */ -deprecated module ImproperCodeSanitization = ImproperCodeSanitizationQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitization.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitization.qll deleted file mode 100644 index f036a3388df..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitization.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `IncompleteHtmlAttributeSanitizationQuery` instead. */ - -import javascript -private import IncompleteHtmlAttributeSanitizationQuery as IncompleteHtmlAttributeSanitizationQuery // ignore-query-import - -/** DEPRECATED. Import `IncompleteHtmlAttributeSanitizationQuery` instead. */ -deprecated module IncompleteHtmlAttributeSanitization = IncompleteHtmlAttributeSanitizationQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjection.qll deleted file mode 100644 index 64e24b9ceba..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `IndirectCommandInjectionQuery` instead. */ - -import javascript -private import IndirectCommandInjectionQuery as IndirectCommandInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `IndirectCommandInjectionQuery` instead. */ -deprecated module IndirectCommandInjection = IndirectCommandInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownload.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownload.qll deleted file mode 100644 index 83c1d179243..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownload.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `InsecureDownloadQuery` instead. */ - -import javascript -private import InsecureDownloadQuery as InsecureDownloadQuery // ignore-query-import - -/** DEPRECATED. Import `InsecureDownloadQuery` instead. */ -deprecated module InsecureDownload = InsecureDownloadQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureRandomness.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureRandomness.qll deleted file mode 100644 index 2672d48bee7..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureRandomness.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `InsecureRandomnessQuery` instead. */ - -import javascript -private import InsecureRandomnessQuery as InsecureRandomnessQuery // ignore-query-import - -/** DEPRECATED. Import `InsecureRandomnessQuery` instead. */ -deprecated module InsecureRandomness = InsecureRandomnessQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHash.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHash.qll deleted file mode 100644 index f3d814e3601..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHash.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `InsufficientPasswordHashQuery` instead. */ - -import javascript -private import InsufficientPasswordHashQuery as InsufficientPasswordHashQuery // ignore-query-import - -/** DEPRECATED. Import `InsufficientPasswordHashQuery` instead. */ -deprecated module InsufficientPasswordHash = InsufficientPasswordHashQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjection.qll deleted file mode 100644 index 95dec6e87fd..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `LogInjectionQuery` instead. */ - -import javascript -private import LogInjectionQuery as LogInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `LogInjectionQuery` instead. */ -deprecated module LogInjection = LogInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/LoopBoundInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/LoopBoundInjection.qll deleted file mode 100644 index ab65fb9705e..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/LoopBoundInjection.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `LoopBoundInjectionQuery` instead. */ - -import javascript -import semmle.javascript.security.TaintedObject -private import LoopBoundInjectionQuery as LoopBoundInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `LoopBoundInjectionQuery` instead. */ -deprecated module LoopBoundInjection = LoopBoundInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjection.qll deleted file mode 100644 index 8534cad9a7e..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjection.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `NosqlInjectionQuery` instead. */ - -import javascript -import semmle.javascript.security.TaintedObject -private import NosqlInjectionQuery as NosqlInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `NosqlInjectionQuery` instead. */ -deprecated module NosqlInjection = NosqlInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStar.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStar.qll deleted file mode 100644 index 392466f32ab..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStar.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `PostMessageStarQuery` instead. */ - -import javascript -private import PostMessageStarQuery as PostMessageStarQuery // ignore-query-import - -/** DEPRECATED. Import `PostMessageStarQuery` instead. */ -deprecated module PostMessageStar = PostMessageStarQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll deleted file mode 100644 index 6663d74e91a..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll +++ /dev/null @@ -1,6 +0,0 @@ -/** DEPRECATED. Import `PrototypePollutingAssignmentQuery` instead. */ - -private import PrototypePollutingAssignmentQuery as PrototypePollutingAssignmentQuery // ignore-query-import - -/** DEPRECATED. Import `PrototypePollutingAssignmentQuery` instead. */ -deprecated module PrototypePollutingAssignment = PrototypePollutingAssignmentQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollution.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollution.qll deleted file mode 100644 index 7783a551775..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollution.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** DEPRECATED. Import `PrototypePollutionQuery` instead. */ - -import javascript -import semmle.javascript.security.TaintedObject -import semmle.javascript.dependencies.Dependencies -import semmle.javascript.dependencies.SemVer -private import PrototypePollutionQuery as PrototypePollutionQuery // ignore-query-import - -/** DEPRECATED. Import `PrototypePollutionQuery` instead. */ -deprecated module PrototypePollution = PrototypePollutionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXss.qll deleted file mode 100644 index 92ffd84fdda..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXss.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ReflectedXssQuery` instead. */ - -import javascript -private import ReflectedXssQuery as ReflectedXssQuery // ignore-query-import - -/** DEPRECATED. Import `ReflectedXssQuery` instead. */ -deprecated module ReflectedXss = ReflectedXssQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjection.qll deleted file mode 100644 index c1a27c66354..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `RegExpInjectionQuery` instead. */ - -import javascript -private import RegExpInjectionQuery as RegExpInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `RegExpInjectionQuery` instead. */ -deprecated module RegExpInjection = RegExpInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjection.qll deleted file mode 100644 index f19b02fdcb3..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `RemotePropertyInjectionQuery` instead. */ - -import javascript -private import RemotePropertyInjectionQuery as RemotePropertyInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `RemotePropertyInjectionQuery` instead. */ -deprecated module RemotePropertyInjection = RemotePropertyInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgery.qll deleted file mode 100644 index a4612bf360d..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgery.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `RequestForgeryQuery` instead. */ - -import javascript -import UrlConcatenation -private import RequestForgeryQuery as RequestForgeryQuery // ignore-query-import - -/** DEPRECATED. Import `RequestForgeryQuery` instead. */ -deprecated module RequestForgery = RequestForgeryQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll deleted file mode 100644 index 25d27e77f2f..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll +++ /dev/null @@ -1,9 +0,0 @@ -/** DEPRECATED. Import `ServerSideUrlRedirectQuery` instead. */ - -import javascript -import RemoteFlowSources -import UrlConcatenation -private import ServerSideUrlRedirectQuery as ServerSideUrlRedirectQuery // ignore-query-import - -/** DEPRECATED. Import `ServerSideUrlRedirectQuery` instead. */ -deprecated module ServerSideUrlRedirect = ServerSideUrlRedirectQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironment.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironment.qll deleted file mode 100644 index af1c0e7a574..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironment.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ShellCommandInjectionFromEnvironmentQuery` instead. */ - -import javascript -private import ShellCommandInjectionFromEnvironmentQuery as ShellCommandInjectionFromEnvironmentQuery // ignore-query-import - -/** DEPRECATED. Import `ShellCommandInjectionFromEnvironmentQuery` instead. */ -deprecated module ShellCommandInjectionFromEnvironment = ShellCommandInjectionFromEnvironmentQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjection.qll deleted file mode 100644 index 32b0d80669b..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ - -import javascript -private import SqlInjectionQuery as SqlInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ -deprecated module SqlInjection = SqlInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposure.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposure.qll deleted file mode 100644 index 4211c6fd633..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposure.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `StackTraceExposureQuery` instead. */ - -import javascript -private import StackTraceExposureQuery as StackTraceExposureQuery // ignore-query-import - -/** DEPRECATED. Import `StackTraceExposureQuery` instead. */ -deprecated module StackTraceExposure = StackTraceExposureQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/StoredXss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/StoredXss.qll deleted file mode 100644 index 65536440bcb..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/StoredXss.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `StoredXssQuery` instead. */ - -import javascript -private import StoredXssQuery as StoredXssQuery // ignore-query-import - -/** DEPRECATED. Import `StoredXssQuery` instead. */ -deprecated module StoredXss = StoredXssQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatString.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatString.qll deleted file mode 100644 index a0660580206..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatString.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `TaintedFormatStringQuery` instead. */ - -import javascript -import semmle.javascript.security.dataflow.DOM -private import TaintedFormatStringQuery as TaintedFormatStringQuery // ignore-query-import - -/** DEPRECATED. Import `TaintedFormatStringQuery` instead. */ -deprecated module TaintedFormatString = TaintedFormatStringQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPath.qll deleted file mode 100644 index ffd7d320684..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPath.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `TaintedPathQuery` instead. */ - -import javascript -private import TaintedPathQuery as TaintedPathQuery // ignore-query-import - -/** DEPRECATED. Import `TaintedPathQuery` instead. */ -deprecated module TaintedPath = TaintedPathQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjection.qll deleted file mode 100644 index 37f3721d600..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjection.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `TemplateObjectInjectionQuery` instead. */ - -import javascript -private import TemplateObjectInjectionQuery as TemplateObjectInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `TemplateObjectInjectionQuery` instead. */ -deprecated module TemplateObjectInjection = TemplateObjectInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTampering.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTampering.qll deleted file mode 100644 index 44744e0efa3..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTampering.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `TypeConfusionThroughParameterTamperingQuery` instead. */ - -import javascript -private import TypeConfusionThroughParameterTamperingQuery as TypeConfusionThroughParameterTamperingQuery // ignore-query-import - -/** DEPRECATED. Import `TypeConfusionThroughParameterTamperingQuery` instead. */ -deprecated module TypeConfusionThroughParameterTampering = - TypeConfusionThroughParameterTamperingQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserialization.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserialization.qll deleted file mode 100644 index 4b1fd4b58ea..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserialization.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */ - -import javascript -private import UnsafeDeserializationQuery as UnsafeDeserializationQuery // ignore-query-import - -/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */ -deprecated module UnsafeDeserialization = UnsafeDeserializationQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDynamicMethodAccess.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDynamicMethodAccess.qll deleted file mode 100644 index c38bb4cdeb8..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDynamicMethodAccess.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `UnsafeDynamicMethodAccessQuery` instead. */ - -import javascript -import PropertyInjectionShared -private import UnsafeDynamicMethodAccessQuery as UnsafeDynamicMethodAccessQuery // ignore-query-import - -/** DEPRECATED. Import `UnsafeDynamicMethodAccessQuery` instead. */ -deprecated module UnsafeDynamicMethodAccess = UnsafeDynamicMethodAccessQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstruction.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstruction.qll deleted file mode 100644 index 8617d3e8724..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstruction.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `UnsafeHtmlConstructionQuery` instead. */ - -import javascript -private import UnsafeHtmlConstructionQuery as UnsafeHtmlConstructionQuery // ignore-query-import - -/** DEPRECATED. Import `UnsafeHtmlConstructionQuery` instead. */ -deprecated module UnsafeHtmlConstruction = UnsafeHtmlConstructionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll deleted file mode 100644 index 634b7d917aa..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeJQueryPlugin.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `UnsafeJQueryPluginQuery` instead. */ - -import javascript -import semmle.javascript.security.dataflow.Xss -private import UnsafeJQueryPluginQuery as UnsafeJQueryPluginQuery // ignore-query-import - -/** DEPRECATED. Import `UnsafeJQueryPluginQuery` instead. */ -deprecated module UnsafeJQueryPlugin = UnsafeJQueryPluginQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll deleted file mode 100644 index 7e9470a7334..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `UnsafeShellCommandConstructionQuery` instead. */ - -import javascript -private import UnsafeShellCommandConstructionQuery as UnsafeShellCommandConstructionQuery // ignore-query-import - -/** DEPRECATED. Import `UnsafeShellCommandConstructionQuery` instead. */ -deprecated module UnsafeShellCommandConstruction = UnsafeShellCommandConstructionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnvalidatedDynamicMethodCall.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnvalidatedDynamicMethodCall.qll deleted file mode 100644 index f5af520e0d7..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnvalidatedDynamicMethodCall.qll +++ /dev/null @@ -1,9 +0,0 @@ -/** DEPRECATED. Import `UnvalidatedDynamicMethodCallQuery` instead. */ - -import javascript -import semmle.javascript.frameworks.Express -import PropertyInjectionShared -private import UnvalidatedDynamicMethodCallQuery as UnvalidatedDynamicMethodCallQuery // ignore-query-import - -/** DEPRECATED. Import `UnvalidatedDynamicMethodCallQuery` instead. */ -deprecated module UnvalidatedDynamicMethodCall = UnvalidatedDynamicMethodCallQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBomb.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBomb.qll deleted file mode 100644 index 45615a92000..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBomb.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `XmlBombQuery` instead. */ - -import javascript -private import XmlBombQuery as XmlBombQuery // ignore-query-import - -/** DEPRECATED. Import `XmlBombQuery` instead. */ -deprecated module XmlBomb = XmlBombQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XpathInjection.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XpathInjection.qll deleted file mode 100644 index 15f5413a620..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XpathInjection.qll +++ /dev/null @@ -1,8 +0,0 @@ -/** DEPRECATED. Import `XpathInjectionQuery` instead. */ - -import javascript -import semmle.javascript.security.dataflow.DOM -private import XpathInjectionQuery as XpathInjectionQuery // ignore-query-import - -/** DEPRECATED. Import `XpathInjectionQuery` instead. */ -deprecated module XpathInjection = XpathInjectionQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDom.qll deleted file mode 100644 index 0d3096d5c1b..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDom.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `XssThroughDomQuery` instead. */ - -import javascript -private import XssThroughDomQuery as XssThroughDomQuery // ignore-query-import - -/** DEPRECATED. Import `XssThroughDomQuery` instead. */ -deprecated module XssThroughDom = XssThroughDomQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/Xxe.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/Xxe.qll deleted file mode 100644 index 5275c96bada..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/Xxe.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `XxeQuery` instead. */ - -import javascript -private import XxeQuery as XxeQuery // ignore-query-import - -/** DEPRECATED. Import `XxeQuery` instead. */ -deprecated module Xxe = XxeQuery; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlip.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlip.qll deleted file mode 100644 index cc3fd8a2f27..00000000000 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlip.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** DEPRECATED. Import `ZipSlipQuery` instead. */ - -import javascript -private import ZipSlipQuery as ZipSlipQuery // ignore-query-import - -/** DEPRECATED. Import `ZipSlipQuery` instead. */ -deprecated module ZipSlip = ZipSlipQuery; diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index bdd74c9a701..fe221bce7d3 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.4.4 + +### Minor Analysis Improvements + +* Added support for `@hapi/glue` and Hapi plugins to the `frameworks/Hapi.qll` library. + +### Bug Fixes + +* Fixed a bug that would cause the extractor to crash when an `import` type is used in + the `extends` clause of an `interface`. +* 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. + ## 0.4.3 ### New Queries diff --git a/javascript/ql/src/change-notes/2022-11-08-hapi-glue.md b/javascript/ql/src/change-notes/2022-11-08-hapi-glue.md deleted file mode 100644 index 18816a2af13..00000000000 --- a/javascript/ql/src/change-notes/2022-11-08-hapi-glue.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added support for @hapi/glue and Hapi plugins to the frameworks/Hapi.qll library. diff --git a/javascript/ql/src/change-notes/2022-11-08-yaml-locations.md b/javascript/ql/src/change-notes/2022-11-08-yaml-locations.md deleted file mode 100644 index 68664780beb..00000000000 --- a/javascript/ql/src/change-notes/2022-11-08-yaml-locations.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -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. diff --git a/javascript/ql/src/change-notes/2022-11-14-dynamic-import-type-expr.md b/javascript/ql/src/change-notes/2022-11-14-dynamic-import-type-expr.md deleted file mode 100644 index 5f975516620..00000000000 --- a/javascript/ql/src/change-notes/2022-11-14-dynamic-import-type-expr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: fix ---- -* Fixed a bug that would cause the extractor to crash when an `import` type is used in - the `extends` clause of an `interface`. diff --git a/javascript/ql/src/change-notes/released/0.4.4.md b/javascript/ql/src/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..90a5df9d9df --- /dev/null +++ b/javascript/ql/src/change-notes/released/0.4.4.md @@ -0,0 +1,12 @@ +## 0.4.4 + +### Minor Analysis Improvements + +* Added support for `@hapi/glue` and Hapi plugins to the `frameworks/Hapi.qll` library. + +### Bug Fixes + +* Fixed a bug that would cause the extractor to crash when an `import` type is used in + the `extends` clause of an `interface`. +* 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. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 0d9eb306ee9..48d1f2353cf 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.4.4-dev +version: 0.4.5-dev groups: - javascript - queries diff --git a/javascript/ql/test/experimental/PoI/CommandInjectionPoIConfiguration.ql b/javascript/ql/test/experimental/PoI/CommandInjectionPoIConfiguration.ql index 4b7e798b226..5ea8c17fc28 100644 --- a/javascript/ql/test/experimental/PoI/CommandInjectionPoIConfiguration.ql +++ b/javascript/ql/test/experimental/PoI/CommandInjectionPoIConfiguration.ql @@ -4,9 +4,9 @@ import javascript import experimental.poi.PoI -import semmle.javascript.security.dataflow.CommandInjection -import semmle.javascript.security.dataflow.IndirectCommandInjection -import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironment +import semmle.javascript.security.dataflow.CommandInjectionQuery as CommandInjection +import semmle.javascript.security.dataflow.IndirectCommandInjectionQuery as IndirectCommandInjection +import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentQuery as ShellCommandInjectionFromEnvironment class MyDataFlowConfigurationPoIs extends DataFlowConfigurationPoI, ActivePoI { } diff --git a/javascript/ql/test/experimental/PoI/TaintedPathPoIConfiguration.ql b/javascript/ql/test/experimental/PoI/TaintedPathPoIConfiguration.ql index e21bc68f68c..784abb7e85b 100644 --- a/javascript/ql/test/experimental/PoI/TaintedPathPoIConfiguration.ql +++ b/javascript/ql/test/experimental/PoI/TaintedPathPoIConfiguration.ql @@ -4,7 +4,7 @@ import javascript import experimental.poi.PoI -import semmle.javascript.security.dataflow.TaintedPath +import semmle.javascript.security.dataflow.TaintedPathQuery as TaintedPath class MyDataflowRelatedPoIs extends DataFlowConfigurationPoI, ActivePoI { } diff --git a/javascript/ql/test/experimental/PoI/XssPoIConfiguration.ql b/javascript/ql/test/experimental/PoI/XssPoIConfiguration.ql index e18b2e96913..05b43a06cd1 100644 --- a/javascript/ql/test/experimental/PoI/XssPoIConfiguration.ql +++ b/javascript/ql/test/experimental/PoI/XssPoIConfiguration.ql @@ -4,10 +4,10 @@ import javascript import experimental.poi.PoI -import semmle.javascript.security.dataflow.ReflectedXss -import semmle.javascript.security.dataflow.StoredXss -import semmle.javascript.security.dataflow.DomBasedXss -import semmle.javascript.security.dataflow.ExceptionXss +import semmle.javascript.security.dataflow.ReflectedXssQuery as ReflectedXss +import semmle.javascript.security.dataflow.StoredXssQuery as StoredXss +import semmle.javascript.security.dataflow.DomBasedXssQuery as DomBasedXss +import semmle.javascript.security.dataflow.ExceptionXssQuery as ExceptionXss class MyDataFlowConfigurationPoIs extends DataFlowConfigurationPoI, ActivePoI { } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/Consistency.ql b/javascript/ql/test/library-tests/frameworks/Nest/Consistency.ql index 787d0a5fdc4..e96cbc4b70f 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/Consistency.ql +++ b/javascript/ql/test/library-tests/frameworks/Nest/Consistency.ql @@ -1,3 +1,3 @@ import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.ReflectedXss -import semmle.javascript.security.dataflow.ServerSideUrlRedirect +import semmle.javascript.security.dataflow.ReflectedXssQuery as ReflectedXss +import semmle.javascript.security.dataflow.ServerSideUrlRedirectQuery as ServerSideUrlRedirect diff --git a/javascript/ql/test/query-tests/Security/CWE-078/Consistency.ql b/javascript/ql/test/query-tests/Security/CWE-078/Consistency.ql index 6ae7fd0a970..c48af1a7971 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/Consistency.ql +++ b/javascript/ql/test/query-tests/Security/CWE-078/Consistency.ql @@ -1,10 +1,10 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.CommandInjection -import semmle.javascript.security.dataflow.IndirectCommandInjection -import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironment -import semmle.javascript.security.dataflow.UnsafeShellCommandConstruction -import semmle.javascript.security.dataflow.SecondOrderCommandInjectionQuery +import semmle.javascript.security.dataflow.CommandInjectionQuery as CommandInjection +import semmle.javascript.security.dataflow.IndirectCommandInjectionQuery as IndirectCommandInjection +import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentQuery as ShellCommandInjectionFromEnvironment +import semmle.javascript.security.dataflow.UnsafeShellCommandConstructionQuery as UnsafeShellCommandConstruction +import semmle.javascript.security.dataflow.SecondOrderCommandInjectionQuery as SecondOrderCommandInjectionQuery class CommandInjectionConsistency extends ConsistencyConfiguration { CommandInjectionConsistency() { this = "ComandInjection" } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ConsistencyExceptionXss.ql b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ConsistencyExceptionXss.ql index 584faa27c11..5b40a626e4a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ConsistencyExceptionXss.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ConsistencyExceptionXss.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.ExceptionXss as ExceptionXss +import semmle.javascript.security.dataflow.ExceptionXssQuery as ExceptionXss diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ConsistencyReflectedXss.ql b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ConsistencyReflectedXss.ql index 76785917fb5..3200271daa6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ConsistencyReflectedXss.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ConsistencyReflectedXss.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.ReflectedXss as ReflectedXss +import semmle.javascript.security.dataflow.ReflectedXssQuery as ReflectedXss diff --git a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/ConsistencyStoredXss.ql b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/ConsistencyStoredXss.ql index 63794389bab..c75dbb17b71 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/ConsistencyStoredXss.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/ConsistencyStoredXss.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.StoredXss as StoredXss +import semmle.javascript.security.dataflow.StoredXssQuery as StoredXss diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/ConsistencyUnsafeHtmlConstruction.ql b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/ConsistencyUnsafeHtmlConstruction.ql index 823644730b2..f09744a4d6c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/ConsistencyUnsafeHtmlConstruction.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/ConsistencyUnsafeHtmlConstruction.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.UnsafeHtmlConstruction as UnsafeHtmlConstruction +import semmle.javascript.security.dataflow.UnsafeHtmlConstructionQuery as UnsafeHtmlConstruction diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin/ConsistencyUnsafeJQueryPlugin.ql b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin/ConsistencyUnsafeJQueryPlugin.ql index 6a16badb37f..b77df2a8d67 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin/ConsistencyUnsafeJQueryPlugin.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin/ConsistencyUnsafeJQueryPlugin.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.UnsafeJQueryPlugin as UnsafeJqueryPlugin +import semmle.javascript.security.dataflow.UnsafeJQueryPluginQuery as UnsafeJqueryPlugin diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/ConsistencyXssThroughDom.ql b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/ConsistencyXssThroughDom.ql index 118a875f15d..75416d5a0dc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/ConsistencyXssThroughDom.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/ConsistencyXssThroughDom.ql @@ -1,3 +1,3 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.XssThroughDom as ThroughDomXss +import semmle.javascript.security.dataflow.XssThroughDomQuery as ThroughDomXss diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.ql b/javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.ql index 0ab292b7b82..bd24059f31c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.ql +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/Consistency.ql @@ -1,4 +1,4 @@ import javascript import testUtilities.ConsistencyChecking -import semmle.javascript.security.dataflow.SqlInjection -import semmle.javascript.security.dataflow.NosqlInjection +import semmle.javascript.security.dataflow.SqlInjectionQuery as SqlInjection +import semmle.javascript.security.dataflow.NosqlInjectionQuery as NosqlInjection diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index e3d9cec6f66..9ee41acc1ec 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4 + +No user-facing changes. + ## 0.3.3 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/0.3.4.md b/misc/suite-helpers/change-notes/released/0.3.4.md new file mode 100644 index 00000000000..5fae94b07c9 --- /dev/null +++ b/misc/suite-helpers/change-notes/released/0.3.4.md @@ -0,0 +1,3 @@ +## 0.3.4 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index 9da182d3394..5ed15c24b9c 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.3.3 +lastReleaseVersion: 0.3.4 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 6a377895b2a..77c5496ea53 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,3 +1,3 @@ name: codeql/suite-helpers -version: 0.3.4-dev +version: 0.3.5-dev groups: shared diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index ee84607f683..fe35f8daf38 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.4 + +### Minor Analysis Improvements + + * The ReDoS libraries in `semmle.code.python.security.regexp` have been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. + ## 0.6.3 No user-facing changes. diff --git a/python/ql/lib/change-notes/2022-10-31-shared-redos-pack.md b/python/ql/lib/change-notes/2022-10-31-shared-redos-pack.md deleted file mode 100644 index 44212066527..00000000000 --- a/python/ql/lib/change-notes/2022-10-31-shared-redos-pack.md +++ /dev/null @@ -1,4 +0,0 @@ ---- - category: minorAnalysis ---- - * The ReDoS libraries in `semmle.code.python.security.regexp` has been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. \ No newline at end of file diff --git a/python/ql/lib/change-notes/2022-11-17-deleted-deps.md b/python/ql/lib/change-notes/2022-11-17-deleted-deps.md new file mode 100644 index 00000000000..6d366b9c114 --- /dev/null +++ b/python/ql/lib/change-notes/2022-11-17-deleted-deps.md @@ -0,0 +1,7 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `importNode` predicate from the `DataFlowUtil.qll` file. +* Deleted the deprecated features from `PEP249.qll` that were not inside the `PEP249` module. +* Deleted the deprecated `werkzeug` from the `Werkzeug` module in `Werkzeug.qll`. +* Deleted the deprecated `methodResult` predicate from `PEP249::Cursor`. \ No newline at end of file diff --git a/python/ql/lib/change-notes/released/0.6.4.md b/python/ql/lib/change-notes/released/0.6.4.md new file mode 100644 index 00000000000..9f12960721c --- /dev/null +++ b/python/ql/lib/change-notes/released/0.6.4.md @@ -0,0 +1,5 @@ +## 0.6.4 + +### Minor Analysis Improvements + + * The ReDoS libraries in `semmle.code.python.security.regexp` have been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index b7dafe32c5d..ced8cf94614 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.3 +lastReleaseVersion: 0.6.4 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index cf9d72aa9d2..2cc69948b1d 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.6.4-dev +version: 0.6.5-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll index fc697d45524..7f1a6464adf 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll @@ -26,67 +26,3 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { */ pragma[inline] predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } - -/** - * DEPRECATED. Use the API graphs library (`semmle.python.ApiGraphs`) instead. - * - * For a drop-in replacement, use `API::moduleImport(name).getAUse()`. - * - * Gets a `Node` that refers to the module referenced by `name`. - * Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a - * reference to the module `pkg`. - * - * This predicate handles (with optional `... as `): - * 1. `import ` - * 2. `from import ` when ` = + "." + ` - * 3. `from import ` when ` = + "." + ` - * - * Finally, in `from import ` we consider the `ImportExpr` corresponding to - * `` to be a reference to that module. - * - * Note: - * While it is technically possible that `import mypkg.foo` and `from mypkg import foo` can give different values, - * it's highly unlikely that this will be a problem in production level code. - * Example: If `mypkg/__init__.py` contains `foo = 42`, then `from mypkg import foo` will not import the module - * `mypkg/foo.py` but the variable `foo` containing `42` -- however, `import mypkg.foo` will always cause `mypkg.foo` - * to refer to the module. - */ -deprecated Node importNode(string name) { - exists(Variable var, Import imp, Alias alias | - alias = imp.getAName() and - alias.getAsname() = var.getAStore() and - ( - name = alias.getValue().(ImportMember).getImportedModuleName() - or - name = alias.getValue().(ImportExpr).getImportedModuleName() - ) and - result.asExpr() = alias.getValue() - ) - or - // Although it may seem superfluous to consider the `foo` part of `from foo import bar as baz` to - // be a reference to a module (since that reference only makes sense locally within the `import` - // statement), it's important for our use of type trackers to consider this local reference to - // also refer to the `foo` module. That way, if one wants to track references to the `bar` - // attribute using a type tracker, one can simply write - // - // ```ql - // DataFlow::Node bar_attr_tracker(TypeTracker t) { - // t.startInAttr("bar") and - // result = foo_module_tracker() - // or - // exists(TypeTracker t2 | result = bar_attr_tracker(t2).track(t2, t)) - // } - // ``` - // - // Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module. - // Because named imports are modeled as `AttrRead`s, the statement `from foo import bar as baz` - // is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a - // reference to `foo.bar`, as desired. - exists(ImportExpr imp_expr | - imp_expr.getName() = name and - result.asCfgNode().getNode() = imp_expr and - // in `import foo.bar` we DON'T want to give a result for `importNode("foo.bar")`, - // only for `importNode("foo")`. We exclude those cases with the following clause. - not exists(Import imp | imp.getAName().getValue() = imp_expr) - ) -} diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index 0c346fa2dd4..e4af21caacc 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -1,14 +1,75 @@ +/** + * INTERNAL. DO NOT USE. + * + * Provides predicates for resolving imports. + */ + private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.dataflow.new.TypeTracker +private import semmle.python.dataflow.new.internal.DataFlowPrivate +/** + * Python modules and the way imports are resolved are... complicated. Here's a crash course in how + * it works, as well as some caveats to bear in mind when looking at the implementation in this + * module. + * + * First, let's consider the humble `import` statement: + * ```python + * import foo + * import bar.baz + * import ham.eggs as spam + * ``` + * + * In the AST, all imports are aliased, as in the last import above. That is, `import foo` becomes + * `import foo as foo`, and `import bar.baz` becomes `import bar as bar`. Note that `import` is + * exclusively used to import modules -- if `eggs` is an attribute of the `ham` module (and not a + * submodule of the `ham` package), then the third line above is an error. + * + * Next, we have the `from` statement. This one is a bit more complicated, but still has the same + * aliasing desugaring as above applied to it. Thus, `from foo import bar` becomes + * `from foo import bar as bar`. + * + * In general, `from foo import bar` can mean two different things: + * + * 1. If `foo` is a module, and `bar` is an attribute of `foo`, then `from foo import bar` imports + * the attribute `bar` into the current module (binding it to the name `bar`). + * 2. If `foo` is a package, and `bar` is already defined in `foo/__init__.py`, + * that value will be imported. If it is not defined, and `bar` is a submodule of `foo`, then + * `bar` is imported to `foo`, and the `bar` submodule imported. + * Note: We don't currently model if the attribute is already defined in `__init__.py` + * and always assume that the submodule will be used. + * + * Now, when it comes to how these imports are represented in the AST, things get a bit complicated. + * First of all, both of the above forms of imports get mapped to the same kind of AST node: + * `Import`. An `Import` node has a sequence of names, each of which is an `Alias` node. This `Alias` + * node represents the `x as y` bit of each imported module. + * + * The same is true for `from` imports. So, how then do we distinguish between the two forms of + * imports? The distinguishing feature is the left hand side of the `as` node. If the left hand side + * is an `ImportExpr`, then it is a plain import. If it is an `ImportMember`, then it is a `from` + * import. (And to confuse matters even more, this `ImportMember` contains another `ImportExpr` for + * the bit between the `from` and `import` keywords.) + * + * Caveats: + * + * - A relative import of the form `from .foo import bar as baz` not only imports `bar` and binds it + * to the name `baz`, but also imports `foo` and binds it to the name `foo`. This only happens with + * relative imports. `from foo import bar as baz` only binds `bar` to `baz`. + * - Modules may also be packages, so e.g. `import foo.bar` may import the `bar` submodule in the `foo` + * package, or the `bar` subpackage of the `foo` package. The practical difference here is the name of + * the module that is imported, as the package `foo.bar` will have the "name" `foo.bar.__init__`, + * corresponding to the fact that the code that is executed is in the `__init__.py` file of the + * `bar` subpackage. + */ module ImportResolution { /** * Holds if the module `m` defines a name `name` by assigning `defn` to it. This is an * overapproximation, as `name` may not in fact be exported (e.g. by defining an `__all__` that does * not include `name`). */ + pragma[nomagic] predicate module_export(Module m, string name, DataFlow::CfgNode defn) { exists(EssaVariable v | v.getName() = name and @@ -18,12 +79,223 @@ module ImportResolution { or defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument() ) - } - - Module getModule(DataFlow::CfgNode node) { - exists(ModuleValue mv | - node.getNode().pointsTo(mv) and - result = mv.getScope() + or + exists(Alias a | + defn.asExpr() = [a.getValue(), a.getValue().(ImportMember).getModule()] and + a.getAsname().(Name).getId() = name and + defn.getScope() = m ) } + + /** + * Holds if the module `m` explicitly exports the name `name` by listing it in `__all__`. Only + * handles simple cases where we can statically tell that this is the case. + */ + private predicate all_mentions_name(Module m, string name) { + exists(DefinitionNode def, SequenceNode n | + def.getValue() = n and + def.(NameNode).getId() = "__all__" and + def.getScope() = m and + any(StrConst s | s.getText() = name) = n.getAnElement().getNode() + ) + } + + /** + * Holds if the module `m` either does not set `__all__` (and so implicitly exports anything that + * doesn't start with an underscore), or sets `__all__` in a way that's too complicated for us to + * handle (in which case we _also_ pretend that it just exports all such names). + */ + private predicate no_or_complicated_all(Module m) { + // No mention of `__all__` in the module + not exists(DefinitionNode def | def.getScope() = m and def.(NameNode).getId() = "__all__") + or + // `__all__` is set to a non-sequence value + exists(DefinitionNode def | + def.(NameNode).getId() = "__all__" and + def.getScope() = m and + not def.getValue() instanceof SequenceNode + ) + or + // `__all__` is used in some way that doesn't involve storing a value in it. This usually means + // it is being mutated through `append` or `extend`, which we don't handle. + exists(NameNode n | n.getId() = "__all__" and n.getScope() = m and n.isLoad()) + } + + private predicate potential_module_export(Module m, string name) { + all_mentions_name(m, name) + or + no_or_complicated_all(m) and + ( + exists(NameNode n | n.getId() = name and n.getScope() = m and name.charAt(0) != "_") + or + exists(Alias a | a.getAsname().(Name).getId() = name and a.getValue().getScope() = m) + ) + } + + /** + * Holds if the module `reexporter` exports the module `reexported` under the name + * `reexported_name`. + */ + private predicate module_reexport(Module reexporter, string reexported_name, Module reexported) { + exists(DataFlow::Node ref | + ref = getImmediateModuleReference(reexported) and + module_export(reexporter, reexported_name, ref) and + potential_module_export(reexporter, reexported_name) + ) + } + + /** + * Gets a reference to `sys.modules`. + */ + private DataFlow::Node sys_modules_reference() { + result = + any(DataFlow::AttrRef a | + a.getAttributeName() = "modules" and a.getObject().asExpr().(Name).getId() = "sys" + ) + } + + /** Gets a module that may have been added to `sys.modules`. */ + private Module sys_modules_module_with_name(string name) { + exists(ControlFlowNode n, DataFlow::Node mod | + exists(SubscriptNode sub | + sub.getObject() = sys_modules_reference().asCfgNode() and + sub.getIndex() = n and + n.getNode().(StrConst).getText() = name and + sub.(DefinitionNode).getValue() = mod.asCfgNode() and + mod = getModuleReference(result) + ) + ) + } + + Module getModuleImportedByImportStar(ImportStar i) { + isPreferredModuleForName(result.getFile(), i.getImportedModuleName()) + } + + /** + * Gets a data-flow node that may be a reference to a module with the name `module_name`. + * + * This is a helper predicate for `getImmediateModuleReference`. It captures the fact that in an + * import such as `import foo`, + * - `foo` may simply be the name of a module, or + * - `foo` may be the name of a package (in which case its name is actually `foo.__init__`), or + * - `foo` may be a module name that has been added to `sys.modules` (in which case its actual name can + * be anything, for instance `os.path` is either `posixpath` or `ntpath`). + */ + private DataFlow::Node getReferenceToModuleName(string module_name) { + // Regular import statements, e.g. + // import foo # implicitly `import foo as foo` + // import foo as foo_alias + exists(Import i, Alias a | a = i.getAName() | + result.asExpr() = a.getAsname() and + module_name = a.getValue().(ImportExpr).getImportedModuleName() + ) + or + // The module part of a `from ... import ...` statement, e.g. the `..foo.bar` in + // from ..foo.bar import baz # ..foo.bar might point to, say, package.subpackage.foo.bar + exists(ImportMember i | result.asExpr() = i.getModule() | + module_name = i.getModule().(ImportExpr).getImportedModuleName() + ) + or + // Modules (not attributes) imported via `from ... import ... statements`, e.g. + // from foo.bar import baz # imports foo.bar.baz as baz + // from foo.bar import baz as baz_alias # imports foo.bar.baz as baz_alias + exists(Import i, Alias a, ImportMember im | a = i.getAName() and im = a.getValue() | + result.asExpr() = a.getAsname() and + module_name = im.getModule().(ImportExpr).getImportedModuleName() + "." + im.getName() + ) + or + // For parity with the points-to based solution, the `ImportExpr` and `ImportMember` bits of the + // above cases should _also_ point to the right modules. + result.asExpr() = any(ImportExpr i | i.getImportedModuleName() = module_name) + or + result.asExpr() = + any(ImportMember i | + i.getModule().(ImportExpr).getImportedModuleName() + "." + i.getName() = module_name + ) + } + + /** + * Gets a dataflow node that is an immediate reference to the module `m`. + * + * Because of attribute lookups, this is mutually recursive with `getModuleReference`. + */ + DataFlow::Node getImmediateModuleReference(Module m) { + exists(string module_name | result = getReferenceToModuleName(module_name) | + // Depending on whether the referenced module is a package or not, we may need to add a + // trailing `.__init__` to the module name. + isPreferredModuleForName(m.getFile(), module_name + ["", ".__init__"]) + or + // Module defined via `sys.modules` + m = sys_modules_module_with_name(module_name) + ) + or + // Reading an attribute on a module may return a submodule (or subpackage). + exists(DataFlow::AttrRead ar, Module p, string attr_name | + ar.accesses(getModuleReference(p), attr_name) and + result = ar + | + isPreferredModuleForName(m.getFile(), p.getPackageName() + "." + attr_name + ["", ".__init__"]) + ) + or + // This is also true for attributes that come from reexports. + exists(Module reexporter, string attr_name | + result.(DataFlow::AttrRead).accesses(getModuleReference(reexporter), attr_name) and + module_reexport(reexporter, attr_name, m) + ) + or + // Submodules that are implicitly defined with relative imports of the form `from .foo import ...`. + // In practice, we create a definition for each module in a package, even if it is not imported. + exists(string submodule, Module package | + SsaSource::init_module_submodule_defn(result.asVar().getSourceVariable(), + package.getEntryNode()) and + isPreferredModuleForName(m.getFile(), + package.getPackageName() + "." + submodule + ["", ".__init__"]) + ) + } + + /** Join-order helper for `getModuleReference`. */ + pragma[nomagic] + private predicate module_reference_in_scope(DataFlow::Node node, Scope s, string name, Module m) { + node.getScope() = s and + node.asExpr().(Name).getId() = name and + pragma[only_bind_into](node) = getImmediateModuleReference(pragma[only_bind_into](m)) + } + + /** Join-order helper for `getModuleReference`. */ + pragma[nomagic] + private predicate module_name_in_scope(DataFlow::Node node, Scope s, string name) { + node.getScope() = s and + exists(Name n | n = node.asExpr() | + n.getId() = name and + pragma[only_bind_into](n).isUse() + ) + } + + /** + * Gets a reference to the module `m` (including through certain kinds of local and global flow). + */ + DataFlow::Node getModuleReference(Module m) { + // Immedate references to the module + result = getImmediateModuleReference(m) + or + // Flow (local or global) forward to a later reference to the module. + exists(DataFlow::Node ref | ref = getModuleReference(m) | + simpleLocalFlowStepForTypetracking(ref, result) + or + exists(DataFlow::ModuleVariableNode mv | + mv.getAWrite() = ref and + result = mv.getARead() + ) + ) + or + // A reference to a name that is bound to a module in an enclosing scope. + exists(DataFlow::Node def, Scope def_scope, Scope use_scope, string name | + module_reference_in_scope(pragma[only_bind_into](def), pragma[only_bind_into](def_scope), + pragma[only_bind_into](name), pragma[only_bind_into](m)) and + module_name_in_scope(result, use_scope, name) and + use_scope.getEnclosingScope*() = def_scope + ) + } + + Module getModule(DataFlow::CfgNode node) { node = getModuleReference(result) } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll index ae115342dba..564630c47db 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll @@ -76,7 +76,7 @@ module ImportStar { exists(ImportStar i, DataFlow::CfgNode imported_module | imported_module.getNode().getNode() = i.getModule() and i.getScope() = m and - result = ImportResolution::getModule(imported_module) + result = ImportResolution::getModuleImportedByImportStar(i) ) } diff --git a/python/ql/lib/semmle/python/frameworks/PEP249.qll b/python/ql/lib/semmle/python/frameworks/PEP249.qll index 6c4e07cd801..594c3e938e2 100644 --- a/python/ql/lib/semmle/python/frameworks/PEP249.qll +++ b/python/ql/lib/semmle/python/frameworks/PEP249.qll @@ -8,29 +8,170 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.Concepts private import semmle.python.ApiGraphs -import semmle.python.frameworks.internal.PEP249Impl /** - * DEPRECATED: Use `PEP249::PEP249ModuleApiNode` instead. + * Provides classes modeling database interfaces following PEP 249. + * See https://www.python.org/dev/peps/pep-0249/. */ -deprecated class PEP249ModuleApiNode = PEP249::PEP249ModuleApiNode; +module PEP249 { + /** + * An API graph node representing a module that implements PEP 249. + */ + abstract class PEP249ModuleApiNode extends API::Node { + /** Gets a string representation of this element. */ + override string toString() { result = this.(API::Node).toString() } + } -/** - * DEPRECATED: Use `PEP249::Connection` instead. - */ -deprecated module Connection = PEP249::Connection; + /** Gets a reference to the `connect` function of a module that implements PEP 249. */ + DataFlow::Node connect() { + result = any(PEP249ModuleApiNode a).getMember("connect").getAValueReachableFromSource() + } -/** - * DEPRECATED: Use `PEP249::Cursor` instead. - */ -deprecated module cursor = PEP249::Cursor; + /** + * Provides models for database connections (following PEP 249). + * + * See https://www.python.org/dev/peps/pep-0249/#connection-objects. + */ + module Connection { + /** + * A source of database connections (following PEP 249), extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by external + * libraries. + * + * Use the predicate `Connection::instance()` to get references to database connections (following PEP 249). + * + * Extend this class if the module implementing PEP 249 offers more direct ways to obtain + * a connection than going through `connect`. + */ + abstract class InstanceSource extends DataFlow::Node { } -/** - * DEPRECATED: Use `PEP249::execute` instead. - */ -deprecated predicate execute = PEP249::execute/0; + /** A call to the `connect` function of a module that implements PEP 249. */ + private class ConnectCall extends InstanceSource, DataFlow::CallCfgNode { + ConnectCall() { this.getFunction() = connect() } + } -/** - * DEPRECATED: Use `PEP249::connect` instead. - */ -deprecated predicate connect = PEP249::connect/0; + /** Gets a reference to a database connection (following PEP 249). */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to a database connection (following PEP 249). */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + } + + /** + * Provides models for database cursors (following PEP 249). + * + * These are returned by the `cursor` method on a database connection. + * See https://www.python.org/dev/peps/pep-0249/#cursor. + */ + module Cursor { + /** + * A source of database cursors (following PEP 249), extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by external + * libraries. + * + * Use the predicate `Cursor::instance()` to get references to database cursors (following PEP 249). + * + * Extend this class if the module implementing PEP 249 offers more direct ways to obtain + * a connection than going through `connect`. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + /** Gets a reference to a database cursor. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to a database cursor. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** Gets a reference to the `cursor` method on a database connection. */ + private DataFlow::TypeTrackingNode methodRef(DataFlow::TypeTracker t) { + t.startInAttr("cursor") and + result = Connection::instance() + or + exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t)) + } + + /** Gets a reference to the `cursor` method on a database connection. */ + DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** A call to the `cursor` method on a database connection */ + private class CursorCall extends InstanceSource, DataFlow::CallCfgNode { + CursorCall() { this.getFunction() = methodRef() } + } + } + + /** + * Gets a reference to the `execute` method on a cursor (or on a connection). + * + * Note: while `execute` method on a connection is not part of PEP249, if it is used, we + * recognize it as an alias for constructing a cursor and calling `execute` on it. + * + * See https://peps.python.org/pep-0249/#execute. + */ + private DataFlow::TypeTrackingNode execute(DataFlow::TypeTracker t) { + t.startInAttr("execute") and + result in [Cursor::instance(), Connection::instance()] + or + exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t)) + } + + /** + * Gets a reference to the `execute` method on a cursor (or on a connection). + * + * Note: while `execute` method on a connection is not part of PEP249, if it is used, we + * recognize it as an alias for constructing a cursor and calling `execute` on it. + * + * See https://peps.python.org/pep-0249/#execute. + */ + DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** + * A call to the `execute` method on a cursor or a connection. + * + * See https://peps.python.org/pep-0249/#execute + * + * Note: While `execute` method on a connection is not part of PEP249, if it is used, we + * recognize it as an alias for constructing a cursor and calling `execute` on it. + */ + private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode { + ExecuteCall() { this.getFunction() = execute() } + + override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] } + } + + private DataFlow::TypeTrackingNode executemany(DataFlow::TypeTracker t) { + t.startInAttr("executemany") and + result in [Cursor::instance(), Connection::instance()] + or + exists(DataFlow::TypeTracker t2 | result = executemany(t2).track(t2, t)) + } + + private DataFlow::Node executemany() { executemany(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** + * A call to the `executemany` method on a cursor or a connection. + * + * See https://peps.python.org/pep-0249/#executemany + * + * Note: While `executemany` method on a connection is not part of PEP249, if it is used, we + * recognize it as an alias for constructing a cursor and calling `executemany` on it. + */ + private class ExecutemanyCall extends SqlExecution::Range, DataFlow::CallCfgNode { + ExecutemanyCall() { this.getFunction() = executemany() } + + override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] } + } +} diff --git a/python/ql/lib/semmle/python/frameworks/Werkzeug.qll b/python/ql/lib/semmle/python/frameworks/Werkzeug.qll index 2867516dcd8..66cea37020e 100644 --- a/python/ql/lib/semmle/python/frameworks/Werkzeug.qll +++ b/python/ql/lib/semmle/python/frameworks/Werkzeug.qll @@ -231,119 +231,4 @@ module Werkzeug { override string getAsyncMethodName() { none() } } } - - import WerkzeugOld -} - -/** - * Old version that contains the deprecated modules. - */ -private module WerkzeugOld { - /** - * DEPRECATED: Use the modeling available directly in the `Werkzeug` module instead. - * - * Provides models for the `werkzeug` module. - */ - deprecated module werkzeug { - /** - * DEPRECATED: Use the modeling available directly in the `Werkzeug` module instead. - * - * Provides models for the `werkzeug.datastructures` module. - */ - deprecated module datastructures { - /** - * DEPRECATED: Use `Werkzeug::MultiDict` instead. - * - * Provides models for the `werkzeug.datastructures.MultiDict` class - * - * See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict. - */ - deprecated module MultiDict { - /** - * DEPRECATED. Use `Werkzeug::MultiDict::InstanceSource` instead. - * - * A source of instances of `werkzeug.datastructures.MultiDict`, extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by an external - * library. - * - * Use the predicate `MultiDict::instance()` to get references to instances of `werkzeug.datastructures.MultiDict`. - */ - abstract deprecated class InstanceSourceApiNode extends API::Node { } - - /** - * DEPRECATED - * - * Gets a reference to the `getlist` method on an instance of `werkzeug.datastructures.MultiDict`. - * - * See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers.getlist - */ - deprecated DataFlow::Node getlist() { - result = any(InstanceSourceApiNode a).getMember("getlist").getAValueReachableFromSource() - } - - private class MultiDictAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { - override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // obj -> obj.getlist - exists(DataFlow::AttrRead read | - read.getObject() = nodeFrom and - nodeTo = read and - nodeTo = getlist() - ) - or - // getlist -> getlist() - nodeFrom = getlist() and - nodeTo.(DataFlow::CallCfgNode).getFunction() = nodeFrom - } - } - } - - /** - * DEPRECATED: Use `Werkzeug::FileStorage` instead. - * - * Provides models for the `werkzeug.datastructures.FileStorage` class - * - * See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage. - */ - deprecated module FileStorage { - /** - * DEPRECATED. Use `Werkzeug::FileStorage::InstanceSource` instead. - * - * A source of instances of `werkzeug.datastructures.FileStorage`, extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by an external - * library. - * - * Use the predicate `FileStorage::instance()` to get references to instances of `werkzeug.datastructures.FileStorage`. - */ - abstract deprecated class InstanceSourceApiNode extends API::Node { } - - /** Gets a reference to an instance of `werkzeug.datastructures.FileStorage`. */ - deprecated DataFlow::Node instance() { - result = any(InstanceSourceApiNode a).getAValueReachableFromSource() - } - - private class FileStorageAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { - override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - nodeFrom = instance() and - exists(DataFlow::AttrRead read | nodeTo = read | - read.getAttributeName() in [ - // str - "filename", "name", "content_type", "mimetype", - // file-like - "stream", - // TODO: werkzeug.datastructures.Headers - "headers", - // dict[str, str] - "mimetype_params" - ] and - read.getObject() = nodeFrom - ) - } - } - } - } - } } diff --git a/python/ql/lib/semmle/python/frameworks/internal/PEP249Impl.qll b/python/ql/lib/semmle/python/frameworks/internal/PEP249Impl.qll deleted file mode 100644 index bf63bbb3731..00000000000 --- a/python/ql/lib/semmle/python/frameworks/internal/PEP249Impl.qll +++ /dev/null @@ -1,204 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides internal implementation of PEP249. This currently resides in a different - * file than `python/ql/src/semmle/python/frameworks/PEP249.qll`, since we used to - * export everything without being encapsulated in a module, and shadowing rules means - * that we can't just add the module directly to that file :( - * - * So once we can remove those deprecated things (Start of July 2022), we can also move - * the core implementation into its' proper place. - * - * Provides classes modeling PEP 249. - * See https://www.python.org/dev/peps/pep-0249/. - */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.Concepts -private import semmle.python.ApiGraphs - -/** - * Provides classes modeling database interfaces following PEP 249. - * See https://www.python.org/dev/peps/pep-0249/. - */ -module PEP249 { - /** - * An API graph node representing a module that implements PEP 249. - */ - abstract class PEP249ModuleApiNode extends API::Node { - /** Gets a string representation of this element. */ - override string toString() { result = this.(API::Node).toString() } - } - - /** Gets a reference to the `connect` function of a module that implements PEP 249. */ - DataFlow::Node connect() { - result = any(PEP249ModuleApiNode a).getMember("connect").getAValueReachableFromSource() - } - - /** - * Provides models for database connections (following PEP 249). - * - * See https://www.python.org/dev/peps/pep-0249/#connection-objects. - */ - module Connection { - /** - * A source of database connections (following PEP 249), extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by external - * libraries. - * - * Use the predicate `Connection::instance()` to get references to database connections (following PEP 249). - * - * Extend this class if the module implementing PEP 249 offers more direct ways to obtain - * a connection than going through `connect`. - */ - abstract class InstanceSource extends DataFlow::Node { } - - /** A call to the `connect` function of a module that implements PEP 249. */ - private class ConnectCall extends InstanceSource, DataFlow::CallCfgNode { - ConnectCall() { this.getFunction() = connect() } - } - - /** Gets a reference to a database connection (following PEP 249). */ - private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { - t.start() and - result instanceof InstanceSource - or - exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) - } - - /** Gets a reference to a database connection (following PEP 249). */ - DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } - } - - /** - * Provides models for database cursors (following PEP 249). - * - * These are returned by the `cursor` method on a database connection. - * See https://www.python.org/dev/peps/pep-0249/#cursor. - */ - module Cursor { - /** - * A source of database cursors (following PEP 249), extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by external - * libraries. - * - * Use the predicate `Cursor::instance()` to get references to database cursors (following PEP 249). - * - * Extend this class if the module implementing PEP 249 offers more direct ways to obtain - * a connection than going through `connect`. - */ - abstract class InstanceSource extends DataFlow::LocalSourceNode { } - - /** Gets a reference to a database cursor. */ - private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { - t.start() and - result instanceof InstanceSource - or - exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) - } - - /** Gets a reference to a database cursor. */ - DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } - - /** Gets a reference to the `cursor` method on a database connection. */ - private DataFlow::TypeTrackingNode methodRef(DataFlow::TypeTracker t) { - t.startInAttr("cursor") and - result = Connection::instance() - or - exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t)) - } - - /** Gets a reference to the `cursor` method on a database connection. */ - DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) } - - /** A call to the `cursor` method on a database connection */ - private class CursorCall extends InstanceSource, DataFlow::CallCfgNode { - CursorCall() { this.getFunction() = methodRef() } - } - - /** Gets a reference to a result of calling the `cursor` method on a database connection. */ - private DataFlow::TypeTrackingNode methodResult(DataFlow::TypeTracker t) { - t.start() and - result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode() - or - exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t)) - } - - /** - * DEPRECATED: Use `Cursor::instance()` to get references to database cursors instead. - * - * Gets a reference to a result of calling the `cursor` method on a database connection. - */ - deprecated DataFlow::Node methodResult() { - methodResult(DataFlow::TypeTracker::end()).flowsTo(result) - } - } - - /** - * Gets a reference to the `execute` method on a cursor (or on a connection). - * - * Note: while `execute` method on a connection is not part of PEP249, if it is used, we - * recognize it as an alias for constructing a cursor and calling `execute` on it. - * - * See https://peps.python.org/pep-0249/#execute. - */ - private DataFlow::TypeTrackingNode execute(DataFlow::TypeTracker t) { - t.startInAttr("execute") and - result in [Cursor::instance(), Connection::instance()] - or - exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t)) - } - - /** - * Gets a reference to the `execute` method on a cursor (or on a connection). - * - * Note: while `execute` method on a connection is not part of PEP249, if it is used, we - * recognize it as an alias for constructing a cursor and calling `execute` on it. - * - * See https://peps.python.org/pep-0249/#execute. - */ - DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) } - - /** - * A call to the `execute` method on a cursor or a connection. - * - * See https://peps.python.org/pep-0249/#execute - * - * Note: While `execute` method on a connection is not part of PEP249, if it is used, we - * recognize it as an alias for constructing a cursor and calling `execute` on it. - */ - private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode { - ExecuteCall() { this.getFunction() = execute() } - - override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] } - } - - private DataFlow::TypeTrackingNode executemany(DataFlow::TypeTracker t) { - t.startInAttr("executemany") and - result in [Cursor::instance(), Connection::instance()] - or - exists(DataFlow::TypeTracker t2 | result = executemany(t2).track(t2, t)) - } - - private DataFlow::Node executemany() { executemany(DataFlow::TypeTracker::end()).flowsTo(result) } - - /** - * A call to the `executemany` method on a cursor or a connection. - * - * See https://peps.python.org/pep-0249/#executemany - * - * Note: While `executemany` method on a connection is not part of PEP249, if it is used, we - * recognize it as an alias for constructing a cursor and calling `executemany` on it. - */ - private class ExecutemanyCall extends SqlExecution::Range, DataFlow::CallCfgNode { - ExecutemanyCall() { this.getFunction() = executemany() } - - override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] } - } -} diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 9e30f0aba2f..8c5b1bbc2ed 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.4 + +No user-facing changes. + ## 0.5.3 No user-facing changes. diff --git a/python/ql/src/change-notes/released/0.5.4.md b/python/ql/src/change-notes/released/0.5.4.md new file mode 100644 index 00000000000..1686ab4354d --- /dev/null +++ b/python/ql/src/change-notes/released/0.5.4.md @@ -0,0 +1,3 @@ +## 0.5.4 + +No user-facing changes. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 2164e038a5d..cd3f72e2513 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.3 +lastReleaseVersion: 0.5.4 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index c5f06d5b464..c907e7ee1d0 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.5.4-dev +version: 0.5.5-dev groups: - python - queries diff --git a/python/ql/test/experimental/dataflow/typetracking_imports/pkg/use.py b/python/ql/test/experimental/dataflow/typetracking_imports/pkg/use.py index 023af8684f2..a23ddc54b2d 100644 --- a/python/ql/test/experimental/dataflow/typetracking_imports/pkg/use.py +++ b/python/ql/test/experimental/dataflow/typetracking_imports/pkg/use.py @@ -6,8 +6,8 @@ test_direct_import() def test_alias_problem(): - from .alias_problem import foo # $ MISSING: tracked - print(foo) # $ MISSING: tracked + from .alias_problem import foo # $ tracked + print(foo) # $ tracked test_alias_problem() @@ -34,8 +34,8 @@ test_alias_only_direct() def test_problem_absolute_import(): - from pkg.problem_absolute_import import foo # $ MISSING: tracked - print(foo) # $ MISSING: tracked + from pkg.problem_absolute_import import foo # $ tracked + print(foo) # $ tracked test_problem_absolute_import() diff --git a/python/ql/test/experimental/import-resolution/attr_clash/__init__.py b/python/ql/test/experimental/import-resolution/attr_clash/__init__.py new file mode 100644 index 00000000000..d210fbd703b --- /dev/null +++ b/python/ql/test/experimental/import-resolution/attr_clash/__init__.py @@ -0,0 +1,6 @@ +from trace import * +enter(__file__) + +clashing_attr = "clashing_attr" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/attr_clash/clashing_attr.py b/python/ql/test/experimental/import-resolution/attr_clash/clashing_attr.py new file mode 100644 index 00000000000..7544594893b --- /dev/null +++ b/python/ql/test/experimental/import-resolution/attr_clash/clashing_attr.py @@ -0,0 +1,4 @@ +from trace import * +enter(__file__) + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/attr_clash/non_clashing_submodule.py b/python/ql/test/experimental/import-resolution/attr_clash/non_clashing_submodule.py new file mode 100644 index 00000000000..7544594893b --- /dev/null +++ b/python/ql/test/experimental/import-resolution/attr_clash/non_clashing_submodule.py @@ -0,0 +1,4 @@ +from trace import * +enter(__file__) + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/bar.py b/python/ql/test/experimental/import-resolution/bar.py new file mode 100644 index 00000000000..5cb6339be17 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/bar.py @@ -0,0 +1,6 @@ +from trace import * +enter(__file__) + +bar_attr = "bar_attr" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/foo.py b/python/ql/test/experimental/import-resolution/foo.py new file mode 100644 index 00000000000..d112007ad03 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/foo.py @@ -0,0 +1,14 @@ +from trace import * +enter(__file__) + +# A simple attribute. Used in main.py +foo_attr = "foo_attr" + +# A private attribute. Accessible from main.py despite this. +__private_foo_attr = "__private_foo_attr" + +# A reexport of bar under a new name. Used in main.py +import bar as bar_reexported #$ imports=bar as=bar_reexported +check("bar_reexported.bar_attr", bar_reexported.bar_attr, "bar_attr", globals()) #$ prints=bar_attr + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/importflow.expected b/python/ql/test/experimental/import-resolution/importflow.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/import-resolution/importflow.ql b/python/ql/test/experimental/import-resolution/importflow.ql new file mode 100644 index 00000000000..6160560a3ee --- /dev/null +++ b/python/ql/test/experimental/import-resolution/importflow.ql @@ -0,0 +1,122 @@ +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.ApiGraphs +import TestUtilities.InlineExpectationsTest +import semmle.python.dataflow.new.internal.ImportResolution + +/** A string that appears on the right hand side of an assignment. */ +private class SourceString extends DataFlow::Node { + string contents; + + SourceString() { + this.asExpr().(StrConst).getText() = contents and + this.asExpr().getParent() instanceof Assign + } + + string getContents() { result = contents } +} + +/** An argument that is checked using the `check` function. */ +private class CheckArgument extends DataFlow::Node { + CheckArgument() { this = API::moduleImport("trace").getMember("check").getACall().getArg(1) } +} + +/** A data-flow node that is a reference to a module. */ +private class ModuleRef extends DataFlow::Node { + Module mod; + + ModuleRef() { + this = ImportResolution::getModuleReference(mod) and + not mod.getName() in ["__future__", "trace"] + } + + string getName() { result = mod.getName() } +} + +/** + * A data-flow node that is guarded by a version check. Only supports checks of the form `if + *sys.version_info[0] == ...` where the right hand side is either `2` or `3`. + */ +private class VersionGuardedNode extends DataFlow::Node { + int version; + + VersionGuardedNode() { + version in [2, 3] and + exists(If parent, CompareNode c | parent.getBody().contains(this.asExpr()) | + c.operands(API::moduleImport("sys") + .getMember("version_info") + .getASubscript() + .asSource() + .asCfgNode(), any(Eq eq), + any(IntegerLiteral lit | lit.getValue() = version).getAFlowNode()) + ) + } + + int getVersion() { result = version } +} + +private class ImportConfiguration extends DataFlow::Configuration { + ImportConfiguration() { this = "ImportConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof SourceString } + + override predicate isSink(DataFlow::Node sink) { + sink = API::moduleImport("trace").getMember("check").getACall().getArg(1) + } +} + +class ResolutionTest extends InlineExpectationsTest { + ResolutionTest() { this = "ResolutionTest" } + + override string getARelevantTag() { result = "prints" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + ( + exists(DataFlow::PathNode source, DataFlow::PathNode sink, ImportConfiguration config | + config.hasFlowPath(source, sink) and + not sink.getNode() instanceof VersionGuardedNode and + tag = "prints" and + location = sink.getNode().getLocation() and + value = source.getNode().(SourceString).getContents() and + element = sink.getNode().toString() + ) + or + exists(ModuleRef ref | + not ref instanceof VersionGuardedNode and + ref instanceof CheckArgument and + tag = "prints" and + location = ref.getLocation() and + value = "\"\"" and + element = ref.toString() + ) + ) + } +} + +class ResolutionTest3 extends InlineExpectationsTest { + ResolutionTest3() { this = "ResolutionTest3" } + + override string getARelevantTag() { result = "prints3" and major_version() = 3 } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + ( + exists(DataFlow::PathNode source, DataFlow::PathNode sink, ImportConfiguration config | + config.hasFlowPath(source, sink) and + sink.getNode().(VersionGuardedNode).getVersion() = 3 and + tag = "prints3" and + location = sink.getNode().getLocation() and + value = source.getNode().(SourceString).getContents() and + element = sink.getNode().toString() + ) + or + exists(ModuleRef ref | + ref.(VersionGuardedNode).getVersion() = 3 and + ref instanceof CheckArgument and + tag = "prints3" and + location = ref.getLocation() and + value = "\"\"" and + element = ref.toString() + ) + ) + } +} diff --git a/python/ql/test/experimental/import-resolution/imports.expected b/python/ql/test/experimental/import-resolution/imports.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/import-resolution/imports.ql b/python/ql/test/experimental/import-resolution/imports.ql new file mode 100644 index 00000000000..e5d357c5ef4 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/imports.ql @@ -0,0 +1,49 @@ +import python +import TestUtilities.InlineExpectationsTest +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.internal.ImportResolution + +private class ImmediateModuleRef extends DataFlow::Node { + Module mod; + string alias; + + ImmediateModuleRef() { + this = ImportResolution::getImmediateModuleReference(mod) and + not mod.getName() in ["__future__", "trace"] and + this.asExpr() = any(Alias a | alias = a.getAsname().(Name).getId()).getAsname() + } + + Module getModule() { result = mod } + + string getAsname() { result = alias } +} + +class ImportTest extends InlineExpectationsTest { + ImportTest() { this = "ImportTest" } + + override string getARelevantTag() { result = "imports" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(ImmediateModuleRef ref | + tag = "imports" and + location = ref.getLocation() and + value = ref.getModule().getName() and + element = ref.toString() + ) + } +} + +class AliasTest extends InlineExpectationsTest { + AliasTest() { this = "AliasTest" } + + override string getARelevantTag() { result = "as" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(ImmediateModuleRef ref | + tag = "as" and + location = ref.getLocation() and + value = ref.getAsname() and + element = ref.toString() + ) + } +} diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py new file mode 100644 index 00000000000..45c84559fb6 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/main.py @@ -0,0 +1,94 @@ +#! /usr/bin/env python3 +""" +A slightly complicated test setup. I wanted to both make sure I captured +the semantics of Python and also the fact that the kinds of global flow +we expect to see are indeed present. + +The code is executable, and prints out both when the execution reaches +certain files, and also what values are assigned to the various +attributes that are referenced throughout the program. These values are +validated in the test as well. + +My original version used introspection to avoid referencing attributes +directly (thus enabling better error diagnostics), but unfortunately +that made it so that the model couldn't follow what was going on. + +The current setup is a bit clunky (and Python's scoping rules makes it +especially so -- cf. the explicit calls to `globals` and `locals`), but +I think it does the job okay. +""" + +from __future__ import print_function +import sys +from trace import * +enter(__file__) + +# A simple import. Binds foo to the foo module +import foo #$ imports=foo as=foo +check("foo.foo_attr", foo.foo_attr, "foo_attr", globals()) #$ prints=foo_attr + +# Private attributes are still accessible. +check("foo.__private_foo_attr", foo.__private_foo_attr, "__private_foo_attr", globals()) #$ prints=__private_foo_attr + +# An aliased import, binding foo to foo_alias +import foo as foo_alias #$ imports=foo as=foo_alias +check("foo_alias.foo_attr", foo_alias.foo_attr, "foo_attr", globals()) #$ prints=foo_attr + +# A reference to a reexported module +check("foo.bar_reexported", foo.bar_reexported, "", globals()) #$ prints="" +check("foo.bar_reexported.bar_attr", foo.bar_reexported.bar_attr, "bar_attr", globals()) #$ prints=bar_attr + +# A simple "import from" statement. +from bar import bar_attr +check("bar_attr", bar_attr, "bar_attr", globals()) #$ prints=bar_attr + +# Importing an attribute from a subpackage of a package. +from package.subpackage import subpackage_attr +check("subpackage_attr", subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr + +# Importing a package attribute under an alias. +from package import package_attr as package_attr_alias +check("package_attr_alias", package_attr_alias, "package_attr", globals()) #$ prints=package_attr + +# Importing a subpackage under an alias. +from package import subpackage as aliased_subpackage #$ imports=package.subpackage.__init__ as=aliased_subpackage +check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr + +def local_import(): + # Same as above, but in a local scope. + import package.subpackage as local_subpackage #$ imports=package.subpackage.__init__ as=local_subpackage + check("local_subpackage.subpackage_attr", local_subpackage.subpackage_attr, "subpackage_attr", locals()) #$ prints=subpackage_attr + +local_import() + +# Importing a subpacking using `import` and binding it to a name. +import package.subpackage as aliased_subpackage #$ imports=package.subpackage.__init__ as=aliased_subpackage +check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr + +# Importing without binding instead binds the top level name. +import package.subpackage #$ imports=package.__init__ as=package +check("package.package_attr", package.package_attr, "package_attr", globals()) #$ prints=package_attr + +# Deep imports +import package.subpackage.submodule #$ imports=package.__init__ as=package +check("package.subpackage.submodule.submodule_attr", package.subpackage.submodule.submodule_attr, "submodule_attr", globals()) #$ prints=submodule_attr + + +if sys.version_info[0] == 3: + # Importing from a namespace module. + from namespace_package.namespace_module import namespace_module_attr + check("namespace_module_attr", namespace_module_attr, "namespace_module_attr", globals()) #$ prints3=namespace_module_attr + + +from attr_clash import clashing_attr, non_clashing_submodule #$ imports=attr_clash.clashing_attr as=clashing_attr imports=attr_clash.non_clashing_submodule as=non_clashing_submodule +check("clashing_attr", clashing_attr, "clashing_attr", globals()) #$ prints=clashing_attr SPURIOUS: prints="" +check("non_clashing_submodule", non_clashing_submodule, "", globals()) #$ prints="" + +exit(__file__) + +print() + +if status() == 0: + print("PASS") +else: + print("FAIL") diff --git a/python/ql/test/experimental/import-resolution/namespace_package/namespace_module.py b/python/ql/test/experimental/import-resolution/namespace_package/namespace_module.py new file mode 100644 index 00000000000..2c831662f47 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/namespace_package/namespace_module.py @@ -0,0 +1,6 @@ +from trace import * +enter(__file__) + +namespace_module_attr = "namespace_module_attr" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/package/__init__.py b/python/ql/test/experimental/import-resolution/package/__init__.py new file mode 100644 index 00000000000..ee2e3211a2c --- /dev/null +++ b/python/ql/test/experimental/import-resolution/package/__init__.py @@ -0,0 +1,7 @@ +from trace import * +enter(__file__) + +attr_used_in_subpackage = "attr_used_in_subpackage" +package_attr = "package_attr" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/package/subpackage/__init__.py b/python/ql/test/experimental/import-resolution/package/subpackage/__init__.py new file mode 100644 index 00000000000..86cc92dd37b --- /dev/null +++ b/python/ql/test/experimental/import-resolution/package/subpackage/__init__.py @@ -0,0 +1,14 @@ +from trace import * +enter(__file__) + +subpackage_attr = "subpackage_attr" + +# Importing an attribute from the parent package. +from .. import attr_used_in_subpackage as imported_attr +check("imported_attr", imported_attr, "attr_used_in_subpackage", globals()) #$ prints=attr_used_in_subpackage + +# Importing an irrelevant attribute from a sibling module binds the name to the module. +from .submodule import irrelevant_attr +check("submodule.submodule_attr", submodule.submodule_attr, "submodule_attr", globals()) #$ prints=submodule_attr + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/package/subpackage/submodule.py b/python/ql/test/experimental/import-resolution/package/subpackage/submodule.py new file mode 100644 index 00000000000..89f9dd497a4 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/package/subpackage/submodule.py @@ -0,0 +1,7 @@ +from trace import * +enter(__file__) + +submodule_attr = "submodule_attr" +irrelevant_attr = "irrelevant_attr" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/trace.py b/python/ql/test/experimental/import-resolution/trace.py new file mode 100644 index 00000000000..90d8efba3fb --- /dev/null +++ b/python/ql/test/experimental/import-resolution/trace.py @@ -0,0 +1,52 @@ +from __future__ import print_function + +_indent_level = 0 + +_print = print + +def print(*args, **kwargs): + _print(" " * _indent_level, end="") + _print(*args, **kwargs) + +def enter(file_name): + global _indent_level + print("Entering {}".format(file_name)) + _indent_level += 1 + +def exit(file_name): + global _indent_level + _indent_level -= 1 + print("Leaving {}".format(file_name)) + +_status = 0 + +def status(): + return _status + +def check(attr_path, actual_value, expected_value, bindings): + global _status + parts = attr_path.split(".") + base, parts = parts[0], parts[1:] + if base not in bindings: + print("Error: {} not in bindings".format(base)) + _status = 1 + return + val = bindings[base] + for part in parts: + if not hasattr(val, part): + print("Error: Unknown attribute {}".format(part)) + _status = 1 + return + val = getattr(val, part) + if val != actual_value: + print("Error: Value at path {} and actual value are out of sync! {} != {}".format(attr_path, val, actual_value)) + _status = 1 + if str(val).startswith("" + if val != expected_value: + print("Error: Expected {} to be {}, got {}".format(attr_path, expected_value, val)) + _status = 1 + return + print("OK: {} = {}".format(attr_path, val)) + +__all__ = ["enter", "exit", "check", "status"] diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index d6a5039a3c7..577fae69947 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -983,6 +983,8 @@ class NewTypeBranch extends TNewTypeBranch, Predicate, TypeDeclaration { override NewTypeBranchType getReturnType() { result.getDeclaration() = this } + override Annotation getAnAnnotation() { toQL(this).getAFieldOrChild() = toQL(result) } + override Type getParameterType(int i) { result = this.getField(i).getType() } override int getArity() { result = count(this.getField(_)) } @@ -2397,6 +2399,8 @@ private class AnnotationArg extends TAnnotationArg, AstNode { } override string toString() { result = this.getValue() } + + override string getAPrimaryQlClass() { result = "AnnotationArg" } } private class NoInlineArg extends AnnotationArg { diff --git a/ql/ql/test/printAst/Foo.qll b/ql/ql/test/printAst/Foo.qll index 17e4a4d636d..461402cd2eb 100644 --- a/ql/ql/test/printAst/Foo.qll +++ b/ql/ql/test/printAst/Foo.qll @@ -25,3 +25,7 @@ predicate calls(Foo f) { or true = false } + +newtype TPathNode = + pragma[assume_small_delta] + TPathNodeMid() diff --git a/ql/ql/test/printAst/printAst.expected b/ql/ql/test/printAst/printAst.expected index 333b42332e7..e53f9112569 100644 --- a/ql/ql/test/printAst/printAst.expected +++ b/ql/ql/test/printAst/printAst.expected @@ -1,8 +1,8 @@ nodes | Foo.qll:1:1:1:17 | Import | semmle.label | [Import] Import | | Foo.qll:1:1:1:17 | Import | semmle.order | 1 | -| Foo.qll:1:1:27:2 | TopLevel | semmle.label | [TopLevel] TopLevel | -| Foo.qll:1:1:27:2 | TopLevel | semmle.order | 1 | +| Foo.qll:1:1:31:17 | TopLevel | semmle.label | [TopLevel] TopLevel | +| Foo.qll:1:1:31:17 | TopLevel | semmle.order | 1 | | Foo.qll:1:8:1:17 | javascript | semmle.label | [ModuleExpr] javascript | | Foo.qll:1:8:1:17 | javascript | semmle.order | 3 | | Foo.qll:3:7:3:9 | Class Foo | semmle.label | [Class] Class Foo | @@ -153,6 +153,14 @@ nodes | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 75 | | Foo.qll:26:10:26:14 | Boolean | semmle.label | [Boolean] Boolean | | Foo.qll:26:10:26:14 | Boolean | semmle.order | 77 | +| Foo.qll:29:9:29:17 | NewType TPathNode | semmle.label | [NewType] NewType TPathNode | +| Foo.qll:29:9:29:17 | NewType TPathNode | semmle.order | 78 | +| Foo.qll:30:3:30:28 | annotation | semmle.label | [Annotation] annotation | +| Foo.qll:30:3:30:28 | annotation | semmle.order | 79 | +| Foo.qll:30:10:30:27 | assume_small_delta | semmle.label | [AnnotationArg] assume_small_delta | +| Foo.qll:30:10:30:27 | assume_small_delta | semmle.order | 80 | +| Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | semmle.label | [NewTypeBranch] NewTypeBranch TPathNodeMid | +| Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | semmle.order | 81 | | file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs | | file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs | | file://:0:0:0:0 | acos | semmle.label | [BuiltinPredicate] acos | @@ -235,22 +243,24 @@ nodes | file://:0:0:0:0 | trim | semmle.label | [BuiltinPredicate] trim | | file://:0:0:0:0 | ulp | semmle.label | [BuiltinPredicate] ulp | | printAst.ql:1:1:1:28 | Import | semmle.label | [Import] Import | -| printAst.ql:1:1:1:28 | Import | semmle.order | 78 | +| printAst.ql:1:1:1:28 | Import | semmle.order | 82 | | printAst.ql:1:1:1:29 | TopLevel | semmle.label | [TopLevel] TopLevel | -| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 78 | +| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 82 | | printAst.ql:1:18:1:28 | printAstAst | semmle.label | [ModuleExpr] printAstAst | -| printAst.ql:1:18:1:28 | printAstAst | semmle.order | 80 | +| printAst.ql:1:18:1:28 | printAstAst | semmle.order | 84 | edges | Foo.qll:1:1:1:17 | Import | Foo.qll:1:8:1:17 | javascript | semmle.label | getModuleExpr() | | Foo.qll:1:1:1:17 | Import | Foo.qll:1:8:1:17 | javascript | semmle.order | 3 | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.label | getAnImport() | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.order | 1 | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:7:3:9 | Class Foo | semmle.label | getAClass() | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:7:3:9 | Class Foo | semmle.order | 4 | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:17:9:19 | ClasslessPredicate foo | semmle.label | getAPredicate() | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:17:9:19 | ClasslessPredicate foo | semmle.order | 16 | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:11:13:15 | ClasslessPredicate calls | semmle.label | getAPredicate() | -| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:11:13:15 | ClasslessPredicate calls | semmle.order | 32 | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.label | getAnImport() | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.order | 1 | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:3:7:3:9 | Class Foo | semmle.label | getAClass() | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:3:7:3:9 | Class Foo | semmle.order | 4 | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:9:17:9:19 | ClasslessPredicate foo | semmle.label | getAPredicate() | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:9:17:9:19 | ClasslessPredicate foo | semmle.order | 16 | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:13:11:13:15 | ClasslessPredicate calls | semmle.label | getAPredicate() | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:13:11:13:15 | ClasslessPredicate calls | semmle.order | 32 | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:29:9:29:17 | NewType TPathNode | semmle.label | getANewType() | +| Foo.qll:1:1:31:17 | TopLevel | Foo.qll:29:9:29:17 | NewType TPathNode | semmle.order | 78 | | Foo.qll:3:7:3:9 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.label | getASuperType() | | Foo.qll:3:7:3:9 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.order | 5 | | Foo.qll:3:7:3:9 | Class Foo | Foo.qll:4:3:4:17 | CharPred Foo | semmle.label | getCharPred() | @@ -393,9 +403,15 @@ edges | Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.order | 75 | | Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.label | getRightOperand() | | Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.order | 77 | +| Foo.qll:29:9:29:17 | NewType TPathNode | Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | semmle.label | getABranch() | +| Foo.qll:29:9:29:17 | NewType TPathNode | Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | semmle.order | 81 | +| Foo.qll:30:3:30:28 | annotation | Foo.qll:30:10:30:27 | assume_small_delta | semmle.label | getArgs(_) | +| Foo.qll:30:3:30:28 | annotation | Foo.qll:30:10:30:27 | assume_small_delta | semmle.order | 80 | +| Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | Foo.qll:30:3:30:28 | annotation | semmle.label | getAnAnnotation() | +| Foo.qll:31:3:31:14 | NewTypeBranch TPathNodeMid | Foo.qll:30:3:30:28 | annotation | semmle.order | 79 | | printAst.ql:1:1:1:28 | Import | printAst.ql:1:18:1:28 | printAstAst | semmle.label | getModuleExpr() | -| printAst.ql:1:1:1:28 | Import | printAst.ql:1:18:1:28 | printAstAst | semmle.order | 80 | +| printAst.ql:1:1:1:28 | Import | printAst.ql:1:18:1:28 | printAstAst | semmle.order | 84 | | printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.label | getAnImport() | -| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 78 | +| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 82 | graphProperties | semmle.graphKind | tree | diff --git a/ruby/actions/create-extractor-pack/action.yml b/ruby/actions/create-extractor-pack/action.yml index b0907eff834..667158c264c 100644 --- a/ruby/actions/create-extractor-pack/action.yml +++ b/ruby/actions/create-extractor-pack/action.yml @@ -3,7 +3,15 @@ description: Builds the Ruby CodeQL pack runs: using: composite steps: - - uses: actions/cache@v3 + - name: Cache entire extractor + id: cache-extractor + uses: actions/cache@v3 + with: + path: ruby/extractor-pack + key: ${{ runner.os }}-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}-${{ hashFiles('ruby/**/*.rs') }}-${{ hashFiles('ruby/codeql-extractor.yml', 'ruby/downgrades', 'ruby/tools', 'ruby/ql/lib/ruby.dbscheme', 'ruby/ql/lib/ruby.dbscheme.stats') }} + - name: Cache cargo + uses: actions/cache@v3 + if: steps.cache-extractor.outputs.cache-hit != 'true' with: path: | ~/.cargo/registry @@ -11,6 +19,7 @@ runs: ruby/target key: ${{ runner.os }}-ruby-qltest-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }} - name: Build Extractor + if: steps.cache-extractor.outputs.cache-hit != 'true' shell: bash run: scripts/create-extractor-pack.sh working-directory: ruby diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index c92874cdbb7..7d0ff13d907 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,17 @@ +## 0.4.4 + +### Minor Analysis Improvements + +* Data flow through the `ActiveSupport` extension `Enumerable#index_by` is now modeled. +* The `codeql.ruby.Concepts` library now has a `SqlConstruction` class, in addition to the existing `SqlExecution` class. +* Calls to `Arel.sql` are now modeled as instances of the new `SqlConstruction` concept. +* Arguments to RPC endpoints (public methods) on subclasses of `ActionCable::Channel::Base` are now recognized as sources of remote user input. +* Taint flow through the `ActiveSupport` extensions `Hash#reverse_merge` and `Hash:reverse_merge!`, and their aliases, is now modeled more generally, where previously it was only modeled in the context of `ActionController` parameters. +* Calls to `logger` in `ActiveSupport` actions are now recognised as logger instances. +* Calls to `send_data` in `ActiveSupport` actions are recognised as HTTP responses. +* Calls to `body_stream` in `ActiveSupport` actions are recognised as HTTP request accesses. +* The `ActiveSupport` extensions `Object#try` and `Object#try!` are now recognised as code executions. + ## 0.4.3 ### Minor Analysis Improvements diff --git a/ruby/ql/lib/change-notes/2022-10-28-try-code-execution.md b/ruby/ql/lib/change-notes/2022-10-28-try-code-execution.md deleted file mode 100644 index af5b1cb59e4..00000000000 --- a/ruby/ql/lib/change-notes/2022-10-28-try-code-execution.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `ActiveSupport` extensions `Object#try` and `Object#try!` are now recognised as code executions. diff --git a/ruby/ql/lib/change-notes/2022-10-31-shared-redos-pack.md b/ruby/ql/lib/change-notes/2022-10-31-shared-redos-pack.md new file mode 100644 index 00000000000..55918160b1f --- /dev/null +++ b/ruby/ql/lib/change-notes/2022-10-31-shared-redos-pack.md @@ -0,0 +1,4 @@ +--- + category: minorAnalysis +--- + * The ReDoS libraries in `codeql.ruby.security.regexp` has been moved to a shared pack inside the `shared/` folder, and the previous location has been deprecated. \ No newline at end of file diff --git a/ruby/ql/lib/change-notes/2022-11-01-actioncontroller-logger.md b/ruby/ql/lib/change-notes/2022-11-01-actioncontroller-logger.md deleted file mode 100644 index 367665ac61a..00000000000 --- a/ruby/ql/lib/change-notes/2022-11-01-actioncontroller-logger.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: minorAnalysis ---- -* Calls to `logger` in `ActiveSupport` actions are now recognised as logger instances. -* Calls to `send_data` in `ActiveSupport` actions are recognised as HTTP responses. -* Calls to `body_stream` in `ActiveSupport` actions are recognised as HTTP request accesses. diff --git a/ruby/ql/lib/change-notes/2022-11-08-activesupport-hash-extensions.md b/ruby/ql/lib/change-notes/2022-11-08-activesupport-hash-extensions.md deleted file mode 100644 index e979c49ce0a..00000000000 --- a/ruby/ql/lib/change-notes/2022-11-08-activesupport-hash-extensions.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Taint flow through the `ActiveSupport` extensions `Hash#reverse_merge` and `Hash:reverse_merge!`, and their aliases, is now modeled more generally, where previously it was only modeled in the context of `ActionController` parameters. diff --git a/ruby/ql/lib/change-notes/2022-11-09-actioncable-channels.md b/ruby/ql/lib/change-notes/2022-11-09-actioncable-channels.md deleted file mode 100644 index 3248fc194e0..00000000000 --- a/ruby/ql/lib/change-notes/2022-11-09-actioncable-channels.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Arguments to RPC endpoints (public methods) on subclasses of `ActionCable::Channel::Base` are now recognized as sources of remote user input. diff --git a/ruby/ql/lib/change-notes/2022-11-10-arel-sql.md b/ruby/ql/lib/change-notes/2022-11-10-arel-sql.md deleted file mode 100644 index e803d0e0895..00000000000 --- a/ruby/ql/lib/change-notes/2022-11-10-arel-sql.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The `codeql.ruby.Concepts` library now has a `SqlConstruction` class, in addition to the existing `SqlExecution` class. -* Calls to `Arel.sql` are now modeled as instances of the new `SqlConstruction` concept. diff --git a/ruby/ql/lib/change-notes/2022-11-14-activesupport-enumerable-index-by.md b/ruby/ql/lib/change-notes/2022-11-14-activesupport-enumerable-index-by.md deleted file mode 100644 index 812c292dd94..00000000000 --- a/ruby/ql/lib/change-notes/2022-11-14-activesupport-enumerable-index-by.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Data flow through the `ActiveSupport` extension `Enumerable#index_by` is now modeled. diff --git a/ruby/ql/lib/change-notes/released/0.4.4.md b/ruby/ql/lib/change-notes/released/0.4.4.md new file mode 100644 index 00000000000..6147687886b --- /dev/null +++ b/ruby/ql/lib/change-notes/released/0.4.4.md @@ -0,0 +1,13 @@ +## 0.4.4 + +### Minor Analysis Improvements + +* Data flow through the `ActiveSupport` extension `Enumerable#index_by` is now modeled. +* The `codeql.ruby.Concepts` library now has a `SqlConstruction` class, in addition to the existing `SqlExecution` class. +* Calls to `Arel.sql` are now modeled as instances of the new `SqlConstruction` concept. +* Arguments to RPC endpoints (public methods) on subclasses of `ActionCable::Channel::Base` are now recognized as sources of remote user input. +* Taint flow through the `ActiveSupport` extensions `Hash#reverse_merge` and `Hash:reverse_merge!`, and their aliases, is now modeled more generally, where previously it was only modeled in the context of `ActionController` parameters. +* Calls to `logger` in `ActiveSupport` actions are now recognised as logger instances. +* Calls to `send_data` in `ActiveSupport` actions are recognised as HTTP responses. +* Calls to `body_stream` in `ActiveSupport` actions are recognised as HTTP request accesses. +* The `ActiveSupport` extensions `Object#try` and `Object#try!` are now recognised as code executions. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 1ec9c4ea5d9..e9b57993a01 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.3 +lastReleaseVersion: 0.4.4 diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll index dbd90ba0ae1..5039d09ff22 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll @@ -907,9 +907,13 @@ module TestOutput { query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) { attr = "semmle.label" and - exists(SuccessorType t | succ = getASuccessor(pred, t) | - if successorTypeIsSimple(t) then val = "" else val = t.toString() - ) + val = + strictconcat(SuccessorType t, string s | + succ = getASuccessor(pred, t) and + if successorTypeIsSimple(t) then s = "" else s = t.toString() + | + s, ", " order by s + ) or attr = "semmle.order" and val = diff --git a/ruby/ql/lib/codeql/ruby/regexp/RegExpTreeView.qll b/ruby/ql/lib/codeql/ruby/regexp/RegExpTreeView.qll index 1ff182e3dcc..ab21512c694 100644 --- a/ruby/ql/lib/codeql/ruby/regexp/RegExpTreeView.qll +++ b/ruby/ql/lib/codeql/ruby/regexp/RegExpTreeView.qll @@ -4,6 +4,16 @@ private import internal.ParseRegExp private import codeql.NumberUtils private import codeql.ruby.ast.Literal as Ast private import codeql.Locations +private import codeql.regex.nfa.NfaUtils as NfaUtils +private import codeql.regex.RegexTreeView +// exporting as RegexTreeView, and in the top-level scope. +import Impl as RegexTreeView +import Impl + +/** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ +RegExpTerm getParsedRegExp(Ast::RegExpLiteral re) { + result.getRegExp() = re and result.isRootTerm() +} /** * An element containing a regular expression term, that is, either @@ -45,1109 +55,1173 @@ private newtype TRegExpParent = re.namedCharacterProperty(start, end, _) } -/** - * An element containing a regular expression term, that is, either - * a string literal (parsed as a regular expression) - * or another regular expression term. - */ -class RegExpParent extends TRegExpParent { - /** Gets a textual representation of this element. */ - string toString() { result = "RegExpParent" } - - /** Gets the `i`th child term. */ - RegExpTerm getChild(int i) { none() } - - /** Gets a child term . */ - final RegExpTerm getAChild() { result = this.getChild(_) } - - /** Gets the number of child terms. */ - int getNumChild() { result = count(this.getAChild()) } - - /** Gets the last child term of this element. */ - RegExpTerm getLastChild() { result = this.getChild(this.getNumChild() - 1) } - +/** An implementation that statisfies the RegexTreeView signature. */ +private module Impl implements RegexTreeViewSig { /** - * Gets the name of a primary CodeQL class to which this regular - * expression term belongs. + * An element containing a regular expression term, that is, either + * a string literal (parsed as a regular expression) + * or another regular expression term. */ - string getAPrimaryQlClass() { result = "RegExpParent" } + class RegExpParent extends TRegExpParent { + /** Gets a textual representation of this element. */ + string toString() { result = "RegExpParent" } - /** - * Gets a comma-separated list of the names of the primary CodeQL classes to - * which this regular expression term belongs. - */ - final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } -} + /** Gets the `i`th child term. */ + RegExpTerm getChild(int i) { none() } -/** A string literal used as a regular expression */ -class RegExpLiteral extends TRegExpLiteral, RegExpParent { - RegExp re; + /** Gets a child term . */ + final RegExpTerm getAChild() { result = this.getChild(_) } - RegExpLiteral() { this = TRegExpLiteral(re) } + /** Gets the number of child terms. */ + int getNumChild() { result = count(this.getAChild()) } - override RegExpTerm getChild(int i) { i = 0 and result.getRegExp() = re and result.isRootTerm() } + /** Gets the last child term of this element. */ + RegExpTerm getLastChild() { result = this.getChild(this.getNumChild() - 1) } - /** Holds if dot, `.`, matches all characters, including newlines. */ - predicate isDotAll() { re.isDotAll() } + /** + * Gets the name of a primary CodeQL class to which this regular + * expression term belongs. + */ + string getAPrimaryQlClass() { result = "RegExpParent" } - /** Holds if this regex matching is case-insensitive for this regex. */ - predicate isIgnoreCase() { re.isIgnoreCase() } + /** + * Gets a comma-separated list of the names of the primary CodeQL classes to + * which this regular expression term belongs. + */ + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } + } - /** Get a string representing all modes for this regex. */ - string getFlags() { result = re.getFlags() } + /** A string literal used as a regular expression */ + class RegExpLiteral extends TRegExpLiteral, RegExpParent { + RegExp re; - /** Gets the primary QL class for this regex. */ - override string getAPrimaryQlClass() { result = "RegExpLiteral" } -} + RegExpLiteral() { this = TRegExpLiteral(re) } -/** - * A regular expression term, that is, a syntactic part of a regular expression. - */ -class RegExpTerm extends RegExpParent { - RegExp re; - int start; - int end; + override RegExpTerm getChild(int i) { + i = 0 and result.getRegExp() = re and result.isRootTerm() + } - RegExpTerm() { - this = TRegExpAlt(re, start, end) - or - this = TRegExpBackRef(re, start, end) - or - this = TRegExpCharacterClass(re, start, end) - or - this = TRegExpCharacterRange(re, start, end) - or - this = TRegExpNormalChar(re, start, end) - or - this = TRegExpGroup(re, start, end) - or - this = TRegExpQuantifier(re, start, end) - or - this = TRegExpSequence(re, start, end) and - exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. - or - this = TRegExpSpecialChar(re, start, end) - or - this = TRegExpNamedCharacterProperty(re, start, end) + /** Holds if dot, `.`, matches all characters, including newlines. */ + predicate isDotAll() { re.isDotAll() } + + /** Holds if this regex matching is case-insensitive for this regex. */ + predicate isIgnoreCase() { re.isIgnoreCase() } + + /** Get a string representing all modes for this regex. */ + string getFlags() { result = re.getFlags() } + + /** Gets the primary QL class for this regex. */ + override string getAPrimaryQlClass() { result = "RegExpLiteral" } } /** - * Gets the outermost term of this regular expression. + * A regular expression term, that is, a syntactic part of a regular expression. */ - RegExpTerm getRootTerm() { - this.isRootTerm() and result = this - or - result = this.getParent().(RegExpTerm).getRootTerm() - } + class RegExpTerm extends RegExpParent { + RegExp re; + int start; + int end; - /** - * Holds if this term is part of a string literal - * that is interpreted as a regular expression. - */ - predicate isUsedAsRegExp() { any() } - - /** - * Holds if this is the root term of a regular expression. - */ - predicate isRootTerm() { start = 0 and end = re.getText().length() } - - override RegExpTerm getChild(int i) { - result = this.(RegExpAlt).getChild(i) - or - result = this.(RegExpBackRef).getChild(i) - or - result = this.(RegExpCharacterClass).getChild(i) - or - result = this.(RegExpCharacterRange).getChild(i) - or - result = this.(RegExpNormalChar).getChild(i) - or - result = this.(RegExpGroup).getChild(i) - or - result = this.(RegExpQuantifier).getChild(i) - or - result = this.(RegExpSequence).getChild(i) - or - result = this.(RegExpSpecialChar).getChild(i) - or - result = this.(RegExpNamedCharacterProperty).getChild(i) - } - - /** - * Gets the parent term of this regular expression term, or the - * regular expression literal if this is the root term. - */ - RegExpParent getParent() { result.getAChild() = this } - - /** Gets the associated `RegExp`. */ - RegExp getRegExp() { result = re } - - /** Gets the offset at which this term starts. */ - int getStart() { result = start } - - /** Gets the offset at which this term ends. */ - int getEnd() { result = end } - - override string toString() { result = re.getText().substring(start, end) } - - /** - * Gets the location of the surrounding regex, as locations inside the regex do not exist. - * To get location information corresponding to the term inside the regex, - * use `hasLocationInfo`. - */ - Location getLocation() { result = re.getLocation() } - - pragma[noinline] - private predicate componentHasLocationInfo( - int i, string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - re.getComponent(i) - .getLocation() - .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Holds if this term is found at the specified location offsets. */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - exists(int re_start, int re_end | - this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and - this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, re_end) and - startcolumn = re_start + start and - endcolumn = re_start + end - 1 - ) - } - - /** Gets the file in which this term is found. */ - File getFile() { result = this.getLocation().getFile() } - - /** Gets the raw source text of this term. */ - string getRawValue() { result = this.toString() } - - /** Gets the string literal in which this term is found. */ - RegExpLiteral getLiteral() { result = TRegExpLiteral(re) } - - /** Gets the regular expression term that is matched (textually) before this one, if any. */ - RegExpTerm getPredecessor() { - exists(RegExpTerm parent | parent = this.getParent() | - result = parent.(RegExpSequence).previousElement(this) + RegExpTerm() { + this = TRegExpAlt(re, start, end) or - not exists(parent.(RegExpSequence).previousElement(this)) and - not parent instanceof RegExpSubPattern and - result = parent.getPredecessor() - ) - } - - /** Gets the regular expression term that is matched (textually) after this one, if any. */ - RegExpTerm getSuccessor() { - exists(RegExpTerm parent | parent = this.getParent() | - result = parent.(RegExpSequence).nextElement(this) + this = TRegExpBackRef(re, start, end) or - not exists(parent.(RegExpSequence).nextElement(this)) and - not parent instanceof RegExpSubPattern and - result = parent.getSuccessor() - ) + this = TRegExpCharacterClass(re, start, end) + or + this = TRegExpCharacterRange(re, start, end) + or + this = TRegExpNormalChar(re, start, end) + or + this = TRegExpGroup(re, start, end) + or + this = TRegExpQuantifier(re, start, end) + or + this = TRegExpSequence(re, start, end) and + exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. + or + this = TRegExpSpecialChar(re, start, end) + or + this = TRegExpNamedCharacterProperty(re, start, end) + } + + /** + * Gets the outermost term of this regular expression. + */ + RegExpTerm getRootTerm() { + this.isRootTerm() and result = this + or + result = this.getParent().(RegExpTerm).getRootTerm() + } + + /** + * Holds if this term is part of a string literal + * that is interpreted as a regular expression. + */ + predicate isUsedAsRegExp() { any() } + + /** + * Holds if this is the root term of a regular expression. + */ + predicate isRootTerm() { start = 0 and end = re.getText().length() } + + override RegExpTerm getChild(int i) { + result = this.(RegExpAlt).getChild(i) + or + result = this.(RegExpBackRef).getChild(i) + or + result = this.(RegExpCharacterClass).getChild(i) + or + result = this.(RegExpCharacterRange).getChild(i) + or + result = this.(RegExpNormalChar).getChild(i) + or + result = this.(RegExpGroup).getChild(i) + or + result = this.(RegExpQuantifier).getChild(i) + or + result = this.(RegExpSequence).getChild(i) + or + result = this.(RegExpSpecialChar).getChild(i) + or + result = this.(RegExpNamedCharacterProperty).getChild(i) + } + + /** + * Gets the parent term of this regular expression term, or the + * regular expression literal if this is the root term. + */ + RegExpParent getParent() { result.getAChild() = this } + + /** Gets the associated `RegExp`. */ + RegExp getRegExp() { result = re } + + /** Gets the offset at which this term starts. */ + int getStart() { result = start } + + /** Gets the offset at which this term ends. */ + int getEnd() { result = end } + + override string toString() { result = re.getText().substring(start, end) } + + /** + * Gets the location of the surrounding regex, as locations inside the regex do not exist. + * To get location information corresponding to the term inside the regex, + * use `hasLocationInfo`. + */ + Location getLocation() { result = re.getLocation() } + + pragma[noinline] + private predicate componentHasLocationInfo( + int i, string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + re.getComponent(i) + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Holds if this term is found at the specified location offsets. */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(int re_start, int re_end | + this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and + this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, + re_end) and + startcolumn = re_start + start and + endcolumn = re_start + end - 1 + ) + } + + /** Gets the file in which this term is found. */ + File getFile() { result = this.getLocation().getFile() } + + /** Gets the raw source text of this term. */ + string getRawValue() { result = this.toString() } + + /** Gets the string literal in which this term is found. */ + RegExpLiteral getLiteral() { result = TRegExpLiteral(re) } + + /** Gets the regular expression term that is matched (textually) before this one, if any. */ + RegExpTerm getPredecessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).previousElement(this) + or + not exists(parent.(RegExpSequence).previousElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getPredecessor() + ) + } + + /** Gets the regular expression term that is matched (textually) after this one, if any. */ + RegExpTerm getSuccessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).nextElement(this) + or + not exists(parent.(RegExpSequence).nextElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getSuccessor() + ) + } + + /** + * Gets the single string this regular-expression term matches. + * + * This predicate is only defined for (sequences/groups of) constant regular + * expressions. In particular, terms involving zero-width assertions like `^` + * or `\b` are not considered to have a constant value. + * + * Note that this predicate does not take flags of the enclosing + * regular-expression literal into account. + */ + string getConstantValue() { none() } + + /** + * Gets a string that is matched by this regular-expression term. + */ + string getAMatchedString() { result = this.getConstantValue() } + + /** Gets the primary QL class for this term. */ + override string getAPrimaryQlClass() { result = "RegExpTerm" } + + /** Holds if this regular expression term can match the empty string. */ + predicate isNullable() { none() } } /** - * Gets the single string this regular-expression term matches. + * A quantified regular expression term. * - * This predicate is only defined for (sequences/groups of) constant regular - * expressions. In particular, terms involving zero-width assertions like `^` - * or `\b` are not considered to have a constant value. + * Example: * - * Note that this predicate does not take flags of the enclosing - * regular-expression literal into account. + * ``` + * ((ECMA|Java)[sS]cript)* + * ``` */ - string getConstantValue() { none() } + class RegExpQuantifier extends RegExpTerm, TRegExpQuantifier { + int part_end; + boolean may_repeat_forever; - /** - * Gets a string that is matched by this regular-expression term. - */ - string getAMatchedString() { result = this.getConstantValue() } + RegExpQuantifier() { + this = TRegExpQuantifier(re, start, end) and + re.qualifiedPart(start, part_end, end, _, may_repeat_forever) + } - /** Gets the primary QL class for this term. */ - override string getAPrimaryQlClass() { result = "RegExpTerm" } - - /** Holds if this regular expression term can match the empty string. */ - predicate isNullable() { none() } -} - -/** - * A quantified regular expression term. - * - * Example: - * - * ``` - * ((ECMA|Java)[sS]cript)* - * ``` - */ -class RegExpQuantifier extends RegExpTerm, TRegExpQuantifier { - int part_end; - boolean may_repeat_forever; - - RegExpQuantifier() { - this = TRegExpQuantifier(re, start, end) and - re.qualifiedPart(start, part_end, end, _, may_repeat_forever) - } - - override RegExpTerm getChild(int i) { - i = 0 and - result.getRegExp() = re and - result.getStart() = start and - result.getEnd() = part_end - } - - /** Hols if this term may match an unlimited number of times. */ - predicate mayRepeatForever() { may_repeat_forever = true } - - /** Gets the qualifier for this term. That is e.g "?" for "a?". */ - string getQualifier() { result = re.getText().substring(part_end, end) } - - override string getAPrimaryQlClass() { result = "RegExpQuantifier" } -} - -/** - * A regular expression term that permits unlimited repetitions. - */ -class InfiniteRepetitionQuantifier extends RegExpQuantifier { - InfiniteRepetitionQuantifier() { this.mayRepeatForever() } - - override string getAPrimaryQlClass() { result = "InfiniteRepetitionQuantifier" } -} - -/** - * A star-quantified term. - * - * Example: - * - * ``` - * \w* - * ``` - */ -class RegExpStar extends InfiniteRepetitionQuantifier { - RegExpStar() { this.getQualifier().charAt(0) = "*" } - - override string getAPrimaryQlClass() { result = "RegExpStar" } - - override predicate isNullable() { any() } -} - -/** - * A plus-quantified term. - * - * Example: - * - * ``` - * \w+ - * ``` - */ -class RegExpPlus extends InfiniteRepetitionQuantifier { - RegExpPlus() { this.getQualifier().charAt(0) = "+" } - - override string getAPrimaryQlClass() { result = "RegExpPlus" } - - override predicate isNullable() { this.getAChild().isNullable() } -} - -/** - * An optional term. - * - * Example: - * - * ``` - * ;? - * ``` - */ -class RegExpOpt extends RegExpQuantifier { - RegExpOpt() { this.getQualifier().charAt(0) = "?" } - - override string getAPrimaryQlClass() { result = "RegExpOpt" } - - override predicate isNullable() { any() } -} - -/** - * A range-quantified term - * - * Examples: - * - * ``` - * \w{2,4} - * \w{2,} - * \w{2} - * ``` - */ -class RegExpRange extends RegExpQuantifier { - string upper; - string lower; - - RegExpRange() { re.multiples(part_end, end, lower, upper) } - - override string getAPrimaryQlClass() { result = "RegExpRange" } - - /** Gets the string defining the upper bound of this range, if any. */ - string getUpper() { result = upper } - - /** Gets the string defining the lower bound of this range, if any. */ - string getLower() { result = lower } - - /** - * Gets the upper bound of the range, if any. - * - * If there is no upper bound, any number of repetitions is allowed. - * For a term of the form `r{lo}`, both the lower and the upper bound - * are `lo`. - */ - int getUpperBound() { result = this.getUpper().toInt() } - - /** Gets the lower bound of the range. */ - int getLowerBound() { result = this.getLower().toInt() } - - override predicate isNullable() { this.getAChild().isNullable() or this.getLowerBound() = 0 } -} - -/** - * A sequence term. - * - * Example: - * - * ``` - * (ECMA|Java)Script - * ``` - * - * This is a sequence with the elements `(ECMA|Java)` and `Script`. - */ -class RegExpSequence extends RegExpTerm, TRegExpSequence { - RegExpSequence() { - this = TRegExpSequence(re, start, end) and - exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. - } - - override RegExpTerm getChild(int i) { result = seqChild(re, start, end, i) } - - /** Gets the element preceding `element` in this sequence. */ - RegExpTerm previousElement(RegExpTerm element) { element = this.nextElement(result) } - - /** Gets the element following `element` in this sequence. */ - RegExpTerm nextElement(RegExpTerm element) { - exists(int i | - element = this.getChild(i) and - result = this.getChild(i + 1) - ) - } - - override string getConstantValue() { result = this.getConstantValue(0) } - - /** - * Gets the single string matched by the `i`th child and all following - * children of this sequence, if any. - */ - private string getConstantValue(int i) { - i = this.getNumChild() and - result = "" - or - result = this.getChild(i).getConstantValue() + this.getConstantValue(i + 1) - } - - override string getAPrimaryQlClass() { result = "RegExpSequence" } - - override predicate isNullable() { - forall(RegExpTerm child | child = this.getAChild() | child.isNullable()) - } -} - -pragma[nomagic] -private int seqChildEnd(RegExp re, int start, int end, int i) { - result = seqChild(re, start, end, i).getEnd() -} - -// moved out so we can use it in the charpred -private RegExpTerm seqChild(RegExp re, int start, int end, int i) { - re.sequence(start, end) and - ( - i = 0 and - result.getRegExp() = re and - result.getStart() = start and - exists(int itemEnd | - re.item(start, itemEnd) and - result.getEnd() = itemEnd - ) - or - i > 0 and - result.getRegExp() = re and - exists(int itemStart | itemStart = seqChildEnd(re, start, end, i - 1) | - result.getStart() = itemStart and - re.item(itemStart, result.getEnd()) - ) - ) -} - -/** - * An alternative term, that is, a term of the form `a|b`. - * - * Example: - * - * ``` - * ECMA|Java - * ``` - */ -class RegExpAlt extends RegExpTerm, TRegExpAlt { - RegExpAlt() { this = TRegExpAlt(re, start, end) } - - override RegExpTerm getChild(int i) { - i = 0 and - result.getRegExp() = re and - result.getStart() = start and - exists(int part_end | - re.alternationOption(start, end, start, part_end) and - result.getEnd() = part_end - ) - or - i > 0 and - result.getRegExp() = re and - exists(int part_start | - part_start = this.getChild(i - 1).getEnd() + 1 // allow for the | - | - result.getStart() = part_start and - re.alternationOption(start, end, part_start, result.getEnd()) - ) - } - - /** Gets an alternative of this term. */ - RegExpTerm getAlternative() { result = this.getAChild() } - - override string getAMatchedString() { result = this.getAlternative().getAMatchedString() } - - override string getAPrimaryQlClass() { result = "RegExpAlt" } - - override predicate isNullable() { this.getAChild().isNullable() } -} - -class RegExpCharEscape = RegExpEscape; - -/** - * An escaped regular expression term, that is, a regular expression - * term starting with a backslash, which is not a backreference. - * - * Example: - * - * ``` - * \. - * \w - * ``` - */ -class RegExpEscape extends RegExpNormalChar { - RegExpEscape() { re.escapedCharacter(start, end) } - - /** - * Gets the name of the escaped; for example, `w` for `\w`. - * TODO: Handle named escapes. - */ - override string getValue() { - not this.isUnicode() and - this.isIdentityEscape() and - result = this.getUnescaped() - or - this.getUnescaped() = "n" and result = "\n" - or - this.getUnescaped() = "r" and result = "\r" - or - this.getUnescaped() = "t" and result = "\t" - or - this.getUnescaped() = "f" and result = 12.toUnicode() - or - this.getUnescaped() = "v" and result = 11.toUnicode() - or - this.isUnicode() and - result = this.getUnicode() - } - - /** Holds if this terms name is given by the part following the escape character. */ - predicate isIdentityEscape() { - not this.getUnescaped() in ["n", "r", "t", "f", "v"] and not this.isUnicode() - } - - override string getAPrimaryQlClass() { result = "RegExpEscape" } - - /** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */ - string getUnescaped() { result = this.getText().suffix(1) } - - /** - * Gets the text for this escape. That is e.g. "\w". - */ - private string getText() { result = re.getText().substring(start, end) } - - /** - * Holds if this is a unicode escape. - */ - private predicate isUnicode() { this.getText().prefix(2) = ["\\u", "\\U"] } - - /** - * Gets the unicode char for this escape. - * E.g. for `\u0061` this returns "a". - */ - private string getUnicode() { - this.isUnicode() and - result = parseHexInt(this.getText().suffix(2)).toUnicode() - } -} - -/** - * A word boundary, that is, a regular expression term of the form `\b`. - */ -class RegExpWordBoundary extends RegExpSpecialChar { - RegExpWordBoundary() { this.getChar() = "\\b" } - - override predicate isNullable() { none() } -} - -/** - * A non-word boundary, that is, a regular expression term of the form `\B`. - */ -class RegExpNonWordBoundary extends RegExpSpecialChar { - RegExpNonWordBoundary() { this.getChar() = "\\B" } - - override string getAPrimaryQlClass() { result = "RegExpNonWordBoundary" } -} - -/** - * A character class escape in a regular expression. - * That is, an escaped character that denotes multiple characters. - * - * Examples: - * - * ``` - * \w - * \S - * ``` - */ -class RegExpCharacterClassEscape extends RegExpEscape { - RegExpCharacterClassEscape() { this.getValue() in ["d", "D", "s", "S", "w", "W", "h", "H"] } - - override RegExpTerm getChild(int i) { none() } - - override string getAPrimaryQlClass() { result = "RegExpCharacterClassEscape" } - - override predicate isNullable() { none() } -} - -/** - * A character class in a regular expression. - * - * Examples: - * - * ```rb - * /[a-fA-F0-9]/ - * /[^abc]/ - * ``` - */ -class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass { - RegExpCharacterClass() { this = TRegExpCharacterClass(re, start, end) } - - /** Holds if this character class is inverted, matching the opposite of its content. */ - predicate isInverted() { re.getChar(start + 1) = "^" } - - /** Holds if this character class can match anything. */ - predicate isUniversalClass() { - // [^] - this.isInverted() and not exists(this.getAChild()) - or - // [\w\W] and similar - not this.isInverted() and - exists(string cce1, string cce2 | - cce1 = this.getAChild().(RegExpCharacterClassEscape).getValue() and - cce2 = this.getAChild().(RegExpCharacterClassEscape).getValue() - | - cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase() - ) - } - - override RegExpTerm getChild(int i) { - i = 0 and - result.getRegExp() = re and - exists(int itemStart, int itemEnd | - result.getStart() = itemStart and - re.charSetStart(start, itemStart) and - re.charSetChild(start, itemStart, itemEnd) and - result.getEnd() = itemEnd - ) - or - i > 0 and - result.getRegExp() = re and - exists(int itemStart | itemStart = this.getChild(i - 1).getEnd() | - result.getStart() = itemStart and - re.charSetChild(start, itemStart, result.getEnd()) - ) - } - - override string getAMatchedString() { - not this.isInverted() and result = this.getAChild().getAMatchedString() - } - - override string getAPrimaryQlClass() { result = "RegExpCharacterClass" } - - override predicate isNullable() { none() } -} - -/** - * A character range in a character class in a regular expression. - * - * Example: - * - * ``` - * a-z - * ``` - */ -class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange { - int lower_end; - int upper_start; - - RegExpCharacterRange() { - this = TRegExpCharacterRange(re, start, end) and - re.charRange(_, start, lower_end, upper_start, end) - } - - /** Holds if this range goes from `lo` to `hi`, in effect is `lo-hi`. */ - predicate isRange(string lo, string hi) { - lo = re.getText().substring(start, lower_end) and - hi = re.getText().substring(upper_start, end) - } - - override RegExpTerm getChild(int i) { - i = 0 and - result.getRegExp() = re and - result.getStart() = start and - result.getEnd() = lower_end - or - i = 1 and - result.getRegExp() = re and - result.getStart() = upper_start and - result.getEnd() = end - } - - override string getAPrimaryQlClass() { result = "RegExpCharacterRange" } - - override predicate isNullable() { none() } -} - -/** - * A normal character in a regular expression, that is, a character - * without special meaning. This includes escaped characters. - * - * Examples: - * ``` - * t - * \t - * ``` - */ -class RegExpNormalChar extends RegExpTerm, TRegExpNormalChar { - RegExpNormalChar() { this = TRegExpNormalChar(re, start, end) } - - /** - * Holds if this constant represents a valid Unicode character (as opposed - * to a surrogate code point that does not correspond to a character by itself.) - */ - predicate isCharacter() { any() } - - /** Gets the string representation of the char matched by this term. */ - string getValue() { result = re.getText().substring(start, end) } - - override RegExpTerm getChild(int i) { none() } - - override string getAPrimaryQlClass() { result = "RegExpNormalChar" } -} - -/** - * A constant regular expression term, that is, a regular expression - * term matching a single string. Currently, this will always be a single character. - * - * Example: - * - * ``` - * a - * ``` - */ -class RegExpConstant extends RegExpTerm { - string value; - - RegExpConstant() { - this = TRegExpNormalChar(re, start, end) and - not this instanceof RegExpCharacterClassEscape and - // exclude chars in qualifiers - // TODO: push this into regex library - not exists(int qstart, int qend | re.qualifiedPart(_, qstart, qend, _, _) | - qstart <= start and end <= qend - ) and - value = this.(RegExpNormalChar).getValue() - or - this = TRegExpSpecialChar(re, start, end) and - re.inCharSet(start) and - value = this.(RegExpSpecialChar).getChar() - } - - /** - * Holds if this constant represents a valid Unicode character (as opposed - * to a surrogate code point that does not correspond to a character by itself.) - */ - predicate isCharacter() { any() } - - /** Gets the string matched by this constant term. */ - string getValue() { result = value } - - override RegExpTerm getChild(int i) { none() } - - override string getConstantValue() { result = this.getValue() } - - override string getAPrimaryQlClass() { result = "RegExpConstant" } - - override predicate isNullable() { none() } -} - -/** - * A grouped regular expression. - * - * Examples: - * - * ``` - * (ECMA|Java) - * (?:ECMA|Java) - * (?['"]) - * ``` - */ -class RegExpGroup extends RegExpTerm, TRegExpGroup { - RegExpGroup() { this = TRegExpGroup(re, start, end) } - - /** - * Gets the index of this capture group within the enclosing regular - * expression literal. - * - * For example, in the regular expression `/((a?).)(?:b)/`, the - * group `((a?).)` has index 1, the group `(a?)` nested inside it - * has index 2, and the group `(?:b)` has no index, since it is - * not a capture group. - */ - int getNumber() { result = re.getGroupNumber(start, end) } - - /** Holds if this is a capture group. */ - predicate isCapture() { exists(this.getNumber()) } - - /** Holds if this is a named capture group. */ - predicate isNamed() { exists(this.getName()) } - - /** Gets the name of this capture group, if any. */ - string getName() { result = re.getGroupName(start, end) } - - override RegExpTerm getChild(int i) { - result.getRegExp() = re and - i = 0 and - re.groupContents(start, end, result.getStart(), result.getEnd()) - } - - override string getConstantValue() { result = this.getAChild().getConstantValue() } - - override string getAMatchedString() { result = this.getAChild().getAMatchedString() } - - override string getAPrimaryQlClass() { result = "RegExpGroup" } - - override predicate isNullable() { this.getAChild().isNullable() } -} - -/** - * A special character in a regular expression. - * - * Examples: - * ``` - * ^ - * $ - * . - * ``` - */ -class RegExpSpecialChar extends RegExpTerm, TRegExpSpecialChar { - string char; - - RegExpSpecialChar() { - this = TRegExpSpecialChar(re, start, end) and - re.specialCharacter(start, end, char) - } - - /** - * Holds if this constant represents a valid Unicode character (as opposed - * to a surrogate code point that does not correspond to a character by itself.) - */ - predicate isCharacter() { any() } - - /** Gets the char for this term. */ - string getChar() { result = char } - - override RegExpTerm getChild(int i) { none() } - - override string getAPrimaryQlClass() { result = "RegExpSpecialChar" } -} - -/** - * A dot regular expression. - * - * Example: - * - * ``` - * . - * ``` - */ -class RegExpDot extends RegExpSpecialChar { - RegExpDot() { this.getChar() = "." } - - override string getAPrimaryQlClass() { result = "RegExpDot" } - - override predicate isNullable() { none() } -} - -/** - * A term that matches a specific position between characters in the string. - * - * Example: - * - * ``` - * \A - * ``` - */ -class RegExpAnchor extends RegExpSpecialChar { - RegExpAnchor() { this.getChar() = ["^", "$", "\\A", "\\Z", "\\z"] } - - override string getAPrimaryQlClass() { result = "RegExpAnchor" } -} - -/** - * A dollar assertion `$` or `\Z` matching the end of a line. - * - * Example: - * - * ``` - * $ - * ``` - */ -class RegExpDollar extends RegExpAnchor { - RegExpDollar() { this.getChar() = ["$", "\\Z", "\\z"] } - - override string getAPrimaryQlClass() { result = "RegExpDollar" } - - override predicate isNullable() { any() } -} - -/** - * A caret assertion `^` or `\A` matching the beginning of a line. - * - * Example: - * - * ``` - * ^ - * ``` - */ -class RegExpCaret extends RegExpAnchor { - RegExpCaret() { this.getChar() = ["^", "\\A"] } - - override string getAPrimaryQlClass() { result = "RegExpCaret" } - - override predicate isNullable() { any() } -} - -/** - * A zero-width match, that is, either an empty group or an assertion. - * - * Examples: - * ``` - * () - * (?=\w) - * ``` - */ -class RegExpZeroWidthMatch extends RegExpGroup { - RegExpZeroWidthMatch() { re.zeroWidthMatch(start, end) } - - override RegExpTerm getChild(int i) { none() } - - override string getAPrimaryQlClass() { result = "RegExpZeroWidthMatch" } - - override predicate isNullable() { any() } -} - -/** - * A zero-width lookahead or lookbehind assertion. - * - * Examples: - * - * ``` - * (?=\w) - * (?!\n) - * (?<=\.) - * (?` - * in a regular expression. - * - * Examples: - * - * ``` - * \1 - * (?P=quote) - * ``` - */ -class RegExpBackRef extends RegExpTerm, TRegExpBackRef { - RegExpBackRef() { this = TRegExpBackRef(re, start, end) } + override string getAPrimaryQlClass() { result = "InfiniteRepetitionQuantifier" } + } /** - * Gets the number of the capture group this back reference refers to, if any. + * A star-quantified term. + * + * Example: + * + * ``` + * \w* + * ``` */ - int getNumber() { result = re.getBackRefNumber(start, end) } + class RegExpStar extends InfiniteRepetitionQuantifier { + RegExpStar() { this.getQualifier().charAt(0) = "*" } + + override string getAPrimaryQlClass() { result = "RegExpStar" } + + override predicate isNullable() { any() } + } /** - * Gets the name of the capture group this back reference refers to, if any. + * A plus-quantified term. + * + * Example: + * + * ``` + * \w+ + * ``` */ - string getName() { result = re.getBackRefName(start, end) } + class RegExpPlus extends InfiniteRepetitionQuantifier { + RegExpPlus() { this.getQualifier().charAt(0) = "+" } - /** Gets the capture group this back reference refers to. */ - RegExpGroup getGroup() { - result.getLiteral() = this.getLiteral() and + override string getAPrimaryQlClass() { result = "RegExpPlus" } + + override predicate isNullable() { this.getAChild().isNullable() } + } + + /** + * An optional term. + * + * Example: + * + * ``` + * ;? + * ``` + */ + class RegExpOpt extends RegExpQuantifier { + RegExpOpt() { this.getQualifier().charAt(0) = "?" } + + override string getAPrimaryQlClass() { result = "RegExpOpt" } + + override predicate isNullable() { any() } + } + + /** + * A range-quantified term + * + * Examples: + * + * ``` + * \w{2,4} + * \w{2,} + * \w{2} + * ``` + */ + class RegExpRange extends RegExpQuantifier { + string upper; + string lower; + + RegExpRange() { re.multiples(part_end, end, lower, upper) } + + override string getAPrimaryQlClass() { result = "RegExpRange" } + + /** Gets the string defining the upper bound of this range, if any. */ + string getUpper() { result = upper } + + /** Gets the string defining the lower bound of this range, if any. */ + string getLower() { result = lower } + + /** + * Gets the upper bound of the range, if any. + * + * If there is no upper bound, any number of repetitions is allowed. + * For a term of the form `r{lo}`, both the lower and the upper bound + * are `lo`. + */ + int getUpperBound() { result = this.getUpper().toInt() } + + /** Gets the lower bound of the range. */ + int getLowerBound() { result = this.getLower().toInt() } + + override predicate isNullable() { this.getAChild().isNullable() or this.getLowerBound() = 0 } + } + + /** + * A sequence term. + * + * Example: + * + * ``` + * (ECMA|Java)Script + * ``` + * + * This is a sequence with the elements `(ECMA|Java)` and `Script`. + */ + class RegExpSequence extends RegExpTerm, TRegExpSequence { + RegExpSequence() { + this = TRegExpSequence(re, start, end) and + exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. + } + + override RegExpTerm getChild(int i) { result = seqChild(re, start, end, i) } + + /** Gets the element preceding `element` in this sequence. */ + RegExpTerm previousElement(RegExpTerm element) { element = this.nextElement(result) } + + /** Gets the element following `element` in this sequence. */ + RegExpTerm nextElement(RegExpTerm element) { + exists(int i | + element = this.getChild(i) and + result = this.getChild(i + 1) + ) + } + + override string getConstantValue() { result = this.getConstantValue(0) } + + /** + * Gets the single string matched by the `i`th child and all following + * children of this sequence, if any. + */ + private string getConstantValue(int i) { + i = this.getNumChild() and + result = "" + or + result = this.getChild(i).getConstantValue() + this.getConstantValue(i + 1) + } + + override string getAPrimaryQlClass() { result = "RegExpSequence" } + + override predicate isNullable() { + forall(RegExpTerm child | child = this.getAChild() | child.isNullable()) + } + } + + pragma[nomagic] + private int seqChildEnd(RegExp re, int start, int end, int i) { + result = seqChild(re, start, end, i).getEnd() + } + + // moved out so we can use it in the charpred + private RegExpTerm seqChild(RegExp re, int start, int end, int i) { + re.sequence(start, end) and ( - result.getNumber() = this.getNumber() or - result.getName() = this.getName() + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + exists(int itemEnd | + re.item(start, itemEnd) and + result.getEnd() = itemEnd + ) + or + i > 0 and + result.getRegExp() = re and + exists(int itemStart | itemStart = seqChildEnd(re, start, end, i - 1) | + result.getStart() = itemStart and + re.item(itemStart, result.getEnd()) + ) ) } - override RegExpTerm getChild(int i) { none() } + /** + * An alternative term, that is, a term of the form `a|b`. + * + * Example: + * + * ``` + * ECMA|Java + * ``` + */ + class RegExpAlt extends RegExpTerm, TRegExpAlt { + RegExpAlt() { this = TRegExpAlt(re, start, end) } - override string getAPrimaryQlClass() { result = "RegExpBackRef" } + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + exists(int part_end | + re.alternationOption(start, end, start, part_end) and + result.getEnd() = part_end + ) + or + i > 0 and + result.getRegExp() = re and + exists(int part_start | + part_start = this.getChild(i - 1).getEnd() + 1 // allow for the | + | + result.getStart() = part_start and + re.alternationOption(start, end, part_start, result.getEnd()) + ) + } - override predicate isNullable() { this.getGroup().isNullable() } -} + /** Gets an alternative of this term. */ + RegExpTerm getAlternative() { result = this.getAChild() } -/** - * A named character property. For example, the POSIX bracket expression - * `[[:digit:]]`. - */ -class RegExpNamedCharacterProperty extends RegExpTerm, TRegExpNamedCharacterProperty { - RegExpNamedCharacterProperty() { this = TRegExpNamedCharacterProperty(re, start, end) } + override string getAMatchedString() { result = this.getAlternative().getAMatchedString() } - override RegExpTerm getChild(int i) { none() } + override string getAPrimaryQlClass() { result = "RegExpAlt" } - override string getAPrimaryQlClass() { result = "RegExpNamedCharacterProperty" } + override predicate isNullable() { this.getAChild().isNullable() } + } + + class RegExpCharEscape = RegExpEscape; /** - * Gets the property name. For example, in `\p{Space}`, the result is - * `"Space"`. + * An escaped regular expression term, that is, a regular expression + * term starting with a backslash, which is not a backreference. + * + * Example: + * + * ``` + * \. + * \w + * ``` */ - string getName() { result = re.getCharacterPropertyName(start, end) } + class RegExpEscape extends RegExpNormalChar { + RegExpEscape() { re.escapedCharacter(start, end) } + + /** + * Gets the name of the escaped; for example, `w` for `\w`. + * TODO: Handle named escapes. + */ + override string getValue() { + not this.isUnicode() and + this.isIdentityEscape() and + result = this.getUnescaped() + or + this.getUnescaped() = "n" and result = "\n" + or + this.getUnescaped() = "r" and result = "\r" + or + this.getUnescaped() = "t" and result = "\t" + or + this.getUnescaped() = "f" and result = 12.toUnicode() + or + this.getUnescaped() = "v" and result = 11.toUnicode() + or + this.isUnicode() and + result = this.getUnicode() + } + + /** Holds if this terms name is given by the part following the escape character. */ + predicate isIdentityEscape() { + not this.getUnescaped() in ["n", "r", "t", "f", "v"] and not this.isUnicode() + } + + override string getAPrimaryQlClass() { result = "RegExpEscape" } + + /** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */ + string getUnescaped() { result = this.getText().suffix(1) } + + /** + * Gets the text for this escape. That is e.g. "\w". + */ + private string getText() { result = re.getText().substring(start, end) } + + /** + * Holds if this is a unicode escape. + */ + private predicate isUnicode() { this.getText().prefix(2) = ["\\u", "\\U"] } + + /** + * Gets the unicode char for this escape. + * E.g. for `\u0061` this returns "a". + */ + private string getUnicode() { + this.isUnicode() and + result = parseHexInt(this.getText().suffix(2)).toUnicode() + } + } /** - * Holds if the property is inverted. For example, it holds for `\p{^Digit}`, - * which matches non-digits. + * A word boundary, that is, a regular expression term of the form `\b`. */ - predicate isInverted() { re.namedCharacterPropertyIsInverted(start, end) } -} + class RegExpWordBoundary extends RegExpSpecialChar { + RegExpWordBoundary() { this.getChar() = "\\b" } -/** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ -RegExpTerm getParsedRegExp(Ast::RegExpLiteral re) { - result.getRegExp() = re and result.isRootTerm() + override predicate isNullable() { none() } + } + + /** + * A non-word boundary, that is, a regular expression term of the form `\B`. + */ + class RegExpNonWordBoundary extends RegExpSpecialChar { + RegExpNonWordBoundary() { this.getChar() = "\\B" } + + override string getAPrimaryQlClass() { result = "RegExpNonWordBoundary" } + } + + /** + * A character class escape in a regular expression. + * That is, an escaped character that denotes multiple characters. + * + * Examples: + * + * ``` + * \w + * \S + * ``` + */ + class RegExpCharacterClassEscape extends RegExpEscape { + RegExpCharacterClassEscape() { this.getValue() in ["d", "D", "s", "S", "w", "W", "h", "H"] } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpCharacterClassEscape" } + + override predicate isNullable() { none() } + } + + /** + * A character class in a regular expression. + * + * Examples: + * + * ```rb + * /[a-fA-F0-9]/ + * /[^abc]/ + * ``` + */ + class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass { + RegExpCharacterClass() { this = TRegExpCharacterClass(re, start, end) } + + /** Holds if this character class is inverted, matching the opposite of its content. */ + predicate isInverted() { re.getChar(start + 1) = "^" } + + /** Holds if this character class can match anything. */ + predicate isUniversalClass() { + // [^] + this.isInverted() and not exists(this.getAChild()) + or + // [\w\W] and similar + not this.isInverted() and + exists(string cce1, string cce2 | + cce1 = this.getAChild().(RegExpCharacterClassEscape).getValue() and + cce2 = this.getAChild().(RegExpCharacterClassEscape).getValue() + | + cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase() + ) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + exists(int itemStart, int itemEnd | + result.getStart() = itemStart and + re.charSetStart(start, itemStart) and + re.charSetChild(start, itemStart, itemEnd) and + result.getEnd() = itemEnd + ) + or + i > 0 and + result.getRegExp() = re and + exists(int itemStart | itemStart = this.getChild(i - 1).getEnd() | + result.getStart() = itemStart and + re.charSetChild(start, itemStart, result.getEnd()) + ) + } + + override string getAMatchedString() { + not this.isInverted() and result = this.getAChild().getAMatchedString() + } + + override string getAPrimaryQlClass() { result = "RegExpCharacterClass" } + + override predicate isNullable() { none() } + } + + /** + * A character range in a character class in a regular expression. + * + * Example: + * + * ``` + * a-z + * ``` + */ + class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange { + int lower_end; + int upper_start; + + RegExpCharacterRange() { + this = TRegExpCharacterRange(re, start, end) and + re.charRange(_, start, lower_end, upper_start, end) + } + + /** Holds if this range goes from `lo` to `hi`, in effect is `lo-hi`. */ + predicate isRange(string lo, string hi) { + lo = re.getText().substring(start, lower_end) and + hi = re.getText().substring(upper_start, end) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + result.getEnd() = lower_end + or + i = 1 and + result.getRegExp() = re and + result.getStart() = upper_start and + result.getEnd() = end + } + + override string getAPrimaryQlClass() { result = "RegExpCharacterRange" } + + override predicate isNullable() { none() } + } + + /** + * A normal character in a regular expression, that is, a character + * without special meaning. This includes escaped characters. + * + * Examples: + * ``` + * t + * \t + * ``` + */ + class RegExpNormalChar extends RegExpTerm, TRegExpNormalChar { + RegExpNormalChar() { this = TRegExpNormalChar(re, start, end) } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string representation of the char matched by this term. */ + string getValue() { result = re.getText().substring(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpNormalChar" } + } + + /** + * A constant regular expression term, that is, a regular expression + * term matching a single string. Currently, this will always be a single character. + * + * Example: + * + * ``` + * a + * ``` + */ + class RegExpConstant extends RegExpTerm { + string value; + + RegExpConstant() { + this = TRegExpNormalChar(re, start, end) and + not this instanceof RegExpCharacterClassEscape and + // exclude chars in qualifiers + // TODO: push this into regex library + not exists(int qstart, int qend | re.qualifiedPart(_, qstart, qend, _, _) | + qstart <= start and end <= qend + ) and + value = this.(RegExpNormalChar).getValue() + or + this = TRegExpSpecialChar(re, start, end) and + re.inCharSet(start) and + value = this.(RegExpSpecialChar).getChar() + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string matched by this constant term. */ + string getValue() { result = value } + + override RegExpTerm getChild(int i) { none() } + + override string getConstantValue() { result = this.getValue() } + + override string getAPrimaryQlClass() { result = "RegExpConstant" } + + override predicate isNullable() { none() } + } + + /** + * A grouped regular expression. + * + * Examples: + * + * ``` + * (ECMA|Java) + * (?:ECMA|Java) + * (?['"]) + * ``` + */ + class RegExpGroup extends RegExpTerm, TRegExpGroup { + RegExpGroup() { this = TRegExpGroup(re, start, end) } + + /** + * Gets the index of this capture group within the enclosing regular + * expression literal. + * + * For example, in the regular expression `/((a?).)(?:b)/`, the + * group `((a?).)` has index 1, the group `(a?)` nested inside it + * has index 2, and the group `(?:b)` has no index, since it is + * not a capture group. + */ + int getNumber() { result = re.getGroupNumber(start, end) } + + /** Holds if this is a capture group. */ + predicate isCapture() { exists(this.getNumber()) } + + /** Holds if this is a named capture group. */ + predicate isNamed() { exists(this.getName()) } + + /** Gets the name of this capture group, if any. */ + string getName() { result = re.getGroupName(start, end) } + + override RegExpTerm getChild(int i) { + result.getRegExp() = re and + i = 0 and + re.groupContents(start, end, result.getStart(), result.getEnd()) + } + + override string getConstantValue() { result = this.getAChild().getConstantValue() } + + override string getAMatchedString() { result = this.getAChild().getAMatchedString() } + + override string getAPrimaryQlClass() { result = "RegExpGroup" } + + override predicate isNullable() { this.getAChild().isNullable() } + } + + /** + * A special character in a regular expression. + * + * Examples: + * ``` + * ^ + * $ + * . + * ``` + */ + class RegExpSpecialChar extends RegExpTerm, TRegExpSpecialChar { + string char; + + RegExpSpecialChar() { + this = TRegExpSpecialChar(re, start, end) and + re.specialCharacter(start, end, char) + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the char for this term. */ + string getChar() { result = char } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpSpecialChar" } + } + + /** + * A dot regular expression. + * + * Example: + * + * ``` + * . + * ``` + */ + class RegExpDot extends RegExpSpecialChar { + RegExpDot() { this.getChar() = "." } + + override string getAPrimaryQlClass() { result = "RegExpDot" } + + override predicate isNullable() { none() } + } + + /** + * A term that matches a specific position between characters in the string. + * + * Example: + * + * ``` + * \A + * ``` + */ + class RegExpAnchor extends RegExpSpecialChar { + RegExpAnchor() { this.getChar() = ["^", "$", "\\A", "\\Z", "\\z"] } + + override string getAPrimaryQlClass() { result = "RegExpAnchor" } + } + + /** + * A dollar assertion `$` or `\Z` matching the end of a line. + * + * Example: + * + * ``` + * $ + * ``` + */ + class RegExpDollar extends RegExpAnchor { + RegExpDollar() { this.getChar() = ["$", "\\Z", "\\z"] } + + override string getAPrimaryQlClass() { result = "RegExpDollar" } + + override predicate isNullable() { any() } + } + + /** + * A caret assertion `^` or `\A` matching the beginning of a line. + * + * Example: + * + * ``` + * ^ + * ``` + */ + class RegExpCaret extends RegExpAnchor { + RegExpCaret() { this.getChar() = ["^", "\\A"] } + + override string getAPrimaryQlClass() { result = "RegExpCaret" } + + override predicate isNullable() { any() } + } + + /** + * A zero-width match, that is, either an empty group or an assertion. + * + * Examples: + * ``` + * () + * (?=\w) + * ``` + */ + class RegExpZeroWidthMatch extends RegExpGroup { + RegExpZeroWidthMatch() { re.zeroWidthMatch(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpZeroWidthMatch" } + + override predicate isNullable() { any() } + } + + /** + * A zero-width lookahead or lookbehind assertion. + * + * Examples: + * + * ``` + * (?=\w) + * (?!\n) + * (?<=\.) + * (?` + * in a regular expression. + * + * Examples: + * + * ``` + * \1 + * (?P=quote) + * ``` + */ + class RegExpBackRef extends RegExpTerm, TRegExpBackRef { + RegExpBackRef() { this = TRegExpBackRef(re, start, end) } + + /** + * Gets the number of the capture group this back reference refers to, if any. + */ + int getNumber() { result = re.getBackRefNumber(start, end) } + + /** + * Gets the name of the capture group this back reference refers to, if any. + */ + string getName() { result = re.getBackRefName(start, end) } + + /** Gets the capture group this back reference refers to. */ + RegExpGroup getGroup() { + result.getLiteral() = this.getLiteral() and + ( + result.getNumber() = this.getNumber() or + result.getName() = this.getName() + ) + } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpBackRef" } + + override predicate isNullable() { this.getGroup().isNullable() } + } + + /** + * A named character property. For example, the POSIX bracket expression + * `[[:digit:]]`. + */ + class RegExpNamedCharacterProperty extends RegExpTerm, TRegExpNamedCharacterProperty { + RegExpNamedCharacterProperty() { this = TRegExpNamedCharacterProperty(re, start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpNamedCharacterProperty" } + + /** + * Gets the property name. For example, in `\p{Space}`, the result is + * `"Space"`. + */ + string getName() { result = re.getCharacterPropertyName(start, end) } + + /** + * Holds if the property is inverted. For example, it holds for `\p{^Digit}`, + * which matches non-digits. + */ + predicate isInverted() { re.namedCharacterPropertyIsInverted(start, end) } + } + + class Top = RegExpParent; + + /** + * Holds if `term` is an escape class representing e.g. `\d`. + * `clazz` is which character class it represents, e.g. "d" for `\d`. + */ + predicate isEscapeClass(RegExpTerm term, string clazz) { + exists(RegExpCharacterClassEscape escape | term = escape | escape.getValue() = clazz) + or + // TODO: expand to cover more properties + exists(RegExpNamedCharacterProperty escape | term = escape | + escape.getName().toLowerCase() = "digit" and + if escape.isInverted() then clazz = "D" else clazz = "d" + or + escape.getName().toLowerCase() = "space" and + if escape.isInverted() then clazz = "S" else clazz = "s" + or + escape.getName().toLowerCase() = "word" and + if escape.isInverted() then clazz = "W" else clazz = "w" + ) + } + + /** + * Holds if the regular expression should not be considered. + */ + predicate isExcluded(RegExpParent parent) { + parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes + } + + /** + * Holds if `term` is a possessive quantifier. + * Not currently implemented, but is used by the shared library. + */ + predicate isPossessive(RegExpQuantifier term) { none() } + + /** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + * Not yet implemented for Ruby. + */ + predicate matchesAnyPrefix(RegExpTerm term) { any() } + + /** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + * Not yet implemented for Ruby. + */ + predicate matchesAnySuffix(RegExpTerm term) { any() } + + /** + * Holds if `root` has the `i` flag for case-insensitive matching. + */ + predicate isIgnoreCase(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isIgnoreCase() + } + + /** + * Holds if `root` has the `s` flag for multi-line matching. + */ + predicate isDotAll(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isDotAll() + } } diff --git a/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll b/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll index 95bfbeeeb5d..370baaf3a5d 100644 --- a/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll @@ -2,155 +2,7 @@ * Provides predicates for reasoning about bad tag filter vulnerabilities. */ -import regexp.RegexpMatching - -/** - * Holds if the regexp `root` should be tested against `str`. - * Implements the `isRegexpMatchingCandidateSig` signature from `RegexpMatching`. - * `ignorePrefix` toggles whether the regular expression should be treated as accepting any prefix if it's unanchored. - * `testWithGroups` toggles whether it's tested which groups are filled by a given input string. - */ -private predicate isBadTagFilterCandidate( - RootTerm root, string str, boolean ignorePrefix, boolean testWithGroups -) { - // the regexp must mention "<" and ">" explicitly. - forall(string angleBracket | angleBracket = ["<", ">"] | - any(RegExpConstant term | term.getValue().matches("%" + angleBracket + "%")).getRootTerm() = - root - ) and - ignorePrefix = true and - ( - str = ["", "", "", "", "", - "", "", "", "", - "", "", - "", "", "", - "", "", "", - "", "") and - regexp.matches("") and - not regexp.matches("") and - ( - not regexp.matches("") and - msg = "This regular expression matches , but not " - or - not regexp.matches("") and - msg = "This regular expression matches , but not " - ) - or - regexp.matches("") and - regexp.matches("") and - not regexp.matches("") and - not regexp.matches("") and - msg = "This regular expression does not match script tags where the attribute uses single-quotes." - or - regexp.matches("") and - regexp.matches("") and - not regexp.matches("") and - not regexp.matches("") and - msg = "This regular expression does not match script tags where the attribute uses double-quotes." - or - regexp.matches("") and - regexp.matches("") and - not regexp.matches("") and - not regexp.matches("") and - not regexp.matches("") and - msg = "This regular expression does not match script tags where tabs are used between attributes." - or - regexp.matches("") and - not RegExpFlags::isIgnoreCase(regexp) and - not regexp.matches("") and - not regexp.matches("") and - ( - not regexp.matches("") and - msg = "This regular expression does not match upper case ") and - regexp.matches("") and - msg = "This regular expression does not match mixed case ") and - not regexp.matches("") and - not regexp.matches("") and - ( - not regexp.matches("") and - msg = "This regular expression does not match script end tags like ." - or - not regexp.matches("") and - msg = "This regular expression does not match script end tags like ." - or - not regexp.matches("