mirror of
https://github.com/github/codeql.git
synced 2026-05-16 12:17:07 +02:00
Compare commits
1 Commits
codeql-cli
...
igfoo/expe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6260f95d5a |
111
.github/actions/cache-query-compilation/action.yml
vendored
111
.github/actions/cache-query-compilation/action.yml
vendored
@@ -9,7 +9,7 @@ inputs:
|
||||
outputs:
|
||||
cache-dir:
|
||||
description: "The directory where the cache was stored"
|
||||
value: ${{ steps.output-compilation-dir.outputs.compdir }}
|
||||
value: ${{ steps.fill-compilation-dir.outputs.compdir }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -27,9 +27,7 @@ runs:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: |
|
||||
**/.cache
|
||||
~/.codeql/compile-cache
|
||||
path: '**/.cache'
|
||||
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }}
|
||||
restore-keys: |
|
||||
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
|
||||
@@ -39,111 +37,18 @@ runs:
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
**/.cache
|
||||
~/.codeql/compile-cache
|
||||
path: '**/.cache'
|
||||
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
||||
restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation.
|
||||
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
||||
codeql-compile-${{ inputs.key }}-main-
|
||||
- name: Output-compilationdir
|
||||
id: output-compilation-dir
|
||||
- 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.
|
||||
node $GITHUB_WORKSPACE/.github/actions/cache-query-compilation/move-caches.js ${COMBINED_CACHE_DIR}
|
||||
|
||||
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||
- name: Fill compilation cache directory
|
||||
id: fill-compilation-dir
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||
with:
|
||||
script: |
|
||||
// # 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/*
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
// the first argv is the cache folder to create.
|
||||
const COMBINED_CACHE_DIR = process.env.COMBINED_CACHE_DIR;
|
||||
|
||||
function* walkCaches(dir) {
|
||||
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
if (file.isDirectory()) {
|
||||
const filePath = path.join(dir, file.name);
|
||||
yield* walkCaches(filePath);
|
||||
if (file.name === ".cache") {
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDir(src, dest) {
|
||||
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
||||
const srcPath = path.join(src, file.name);
|
||||
const destPath = path.join(dest, file.name);
|
||||
if (file.isDirectory()) {
|
||||
if (!fs.existsSync(destPath)) {
|
||||
fs.mkdirSync(destPath);
|
||||
}
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const cacheDirs = [...walkCaches(".")];
|
||||
|
||||
for (const dir of cacheDirs) {
|
||||
console.log(`Found .cache dir at ${dir}`);
|
||||
}
|
||||
|
||||
const globalCacheDir = path.join(os.homedir(), ".codeql", "compile-cache");
|
||||
if (fs.existsSync(globalCacheDir)) {
|
||||
console.log("Found global home dir: " + globalCacheDir);
|
||||
cacheDirs.push(globalCacheDir);
|
||||
}
|
||||
|
||||
if (cacheDirs.length === 0) {
|
||||
console.log("No cache dirs found");
|
||||
return;
|
||||
}
|
||||
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
||||
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) =>
|
||||
(async function () {
|
||||
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
||||
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
||||
})()
|
||||
)
|
||||
);
|
||||
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
||||
);
|
||||
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
||||
);
|
||||
}
|
||||
main();
|
||||
|
||||
75
.github/actions/cache-query-compilation/move-caches.js
vendored
Normal file
75
.github/actions/cache-query-compilation/move-caches.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// # 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/*
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// the first argv is the cache folder to create.
|
||||
const COMBINED_CACHE_DIR = process.argv[2];
|
||||
|
||||
function* walkCaches(dir) {
|
||||
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
if (file.isDirectory()) {
|
||||
const filePath = path.join(dir, file.name);
|
||||
yield* walkCaches(filePath);
|
||||
if (file.name === ".cache") {
|
||||
yield filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDir(src, dest) {
|
||||
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
||||
const srcPath = path.join(src, file.name);
|
||||
const destPath = path.join(dest, file.name);
|
||||
if (file.isDirectory()) {
|
||||
if (!fs.existsSync(destPath)) {
|
||||
fs.mkdirSync(destPath);
|
||||
}
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const cacheDirs = [...walkCaches(".")];
|
||||
|
||||
for (const dir of cacheDirs) {
|
||||
console.log(`Found .cache dir at ${dir}`);
|
||||
}
|
||||
|
||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
||||
|
||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) =>
|
||||
(async function () {
|
||||
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
||||
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
||||
})()
|
||||
)
|
||||
);
|
||||
|
||||
// # copy the contents of the .cache folders into the combined cache folder.
|
||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
||||
);
|
||||
|
||||
// # clean up the .cache folders
|
||||
// rm -rf **/.cache/*
|
||||
await Promise.all(
|
||||
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
||||
);
|
||||
}
|
||||
main();
|
||||
3
.github/workflows/check-qldoc.yml
vendored
3
.github/workflows/check-qldoc.yml
vendored
@@ -26,8 +26,9 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
# TODO: remove the swift exception from the regex when we fix generated QLdoc
|
||||
# TODO: remove the shared exception from the regex when coverage of qlpacks without dbschemes is supported
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(shared))[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(swift|shared))[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||
|
||||
6
.github/workflows/compile-queries.yml
vendored
6
.github/workflows/compile-queries.yml
vendored
@@ -24,14 +24,14 @@ jobs:
|
||||
with:
|
||||
key: all-queries
|
||||
- name: check formatting
|
||||
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
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 -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
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: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
8
.github/workflows/go-tests-other-os.yml
vendored
8
.github/workflows/go-tests-other-os.yml
vendored
@@ -12,10 +12,10 @@ jobs:
|
||||
name: Test MacOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Set up Go 1.20
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
@@ -47,10 +47,10 @@ jobs:
|
||||
name: Test Windows
|
||||
runs-on: windows-latest-xl
|
||||
steps:
|
||||
- name: Set up Go 1.20
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
4
.github/workflows/go-tests.yml
vendored
4
.github/workflows/go-tests.yml
vendored
@@ -20,10 +20,10 @@ jobs:
|
||||
name: Test Linux (Ubuntu)
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- name: Set up Go 1.20
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
15
.github/workflows/ql-for-ql-build.yml
vendored
15
.github/workflows/ql-for-ql-build.yml
vendored
@@ -5,6 +5,13 @@ on:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- "**.qll"
|
||||
- "**.ql"
|
||||
- "**.dbscheme"
|
||||
- "**/qlpack.yml"
|
||||
- ".github/workflows/ql-for-ql-build.yml"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -15,8 +22,6 @@ jobs:
|
||||
steps:
|
||||
### Build the queries ###
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@v2
|
||||
@@ -29,9 +34,7 @@ jobs:
|
||||
id: cache-extractor
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
ql/extractor-pack/
|
||||
ql/target/release/buramu
|
||||
path: ql/extractor-pack/
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||
- name: Cache cargo
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
@@ -54,7 +57,6 @@ jobs:
|
||||
key: run-ql-for-ql
|
||||
- name: Make database and analyze
|
||||
run: |
|
||||
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
||||
${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
|
||||
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
@@ -63,7 +65,6 @@ jobs:
|
||||
LGTM_INDEX_FILTERS: |
|
||||
exclude:ql/ql/test
|
||||
exclude:*/ql/lib/upgrades/
|
||||
exclude:java/ql/integration-tests
|
||||
- name: Upload sarif to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
@@ -20,7 +19,6 @@ on:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "misc/codegen/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/**
|
||||
|
||||
@@ -53,5 +53,5 @@ repos:
|
||||
name: Run Swift code generation unit tests
|
||||
files: ^swift/codegen/.*\.py$
|
||||
language: system
|
||||
entry: bazel test //misc/codegen/test
|
||||
entry: bazel test //swift/codegen/test
|
||||
pass_filenames: false
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
/csharp/ @github/codeql-csharp
|
||||
/go/ @github/codeql-go
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-dynamic
|
||||
/python/ @github/codeql-dynamic
|
||||
/ruby/ @github/codeql-dynamic
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||
|
||||
|
||||
@@ -131,14 +131,6 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
public bool IsMacOs { get; set; }
|
||||
|
||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||
|
||||
public bool IsArm { get; set; }
|
||||
|
||||
bool IBuildActions.IsArm() => IsArm;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.4
|
||||
lastReleaseVersion: 0.5.2
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -707,8 +707,8 @@ private module Cached {
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableCallable(call)
|
||||
or
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.5.4
|
||||
version: 0.5.3-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -707,8 +707,8 @@ private module Cached {
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableCallable(call)
|
||||
or
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -707,8 +707,8 @@ private module Cached {
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableCallable(call)
|
||||
or
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.5.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.4
|
||||
lastReleaseVersion: 0.5.2
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
...
|
||||
a = getc(f);
|
||||
if (a < 123) ret = 123/a; // BAD
|
||||
...
|
||||
if (a != 0) ret = 123/a; // GOOD
|
||||
...
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p> Possible cases of division by zero when using the return value from functions.</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<example>
|
||||
<p>The following example shows the use of a function with an error when using the return value and without an error.</p>
|
||||
<sample src="DivideByZeroUsingReturnValue.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT33-C.+Ensure+that+division+and+remainder+operations+do+not+result+in+divide-by-zero+errors">INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors - SEI CERT C Coding Standard - Confluence</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,274 +0,0 @@
|
||||
/**
|
||||
* @name Divide by zero using return value
|
||||
* @description Possible cases of division by zero when using the return value from functions.
|
||||
* @kind problem
|
||||
* @id cpp/divide-by-zero-using-return-value
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-369
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
/** Holds if function `fn` can return a value equal to value `val` */
|
||||
predicate mayBeReturnValue(Function fn, float val) {
|
||||
exists(Expr tmpExp, ReturnStmt rs |
|
||||
tmpExp.getValue().toFloat() = val and
|
||||
rs.getEnclosingFunction() = fn and
|
||||
(
|
||||
globalValueNumber(rs.getExpr()) = globalValueNumber(tmpExp)
|
||||
or
|
||||
exists(AssignExpr ae |
|
||||
ae.getLValue().(VariableAccess).getTarget() =
|
||||
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget() and
|
||||
globalValueNumber(ae.getRValue()) = globalValueNumber(tmpExp)
|
||||
)
|
||||
or
|
||||
exists(Initializer it |
|
||||
globalValueNumber(it.getExpr()) = globalValueNumber(tmpExp) and
|
||||
it.getDeclaration().(Variable).getAnAccess().getTarget() =
|
||||
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if function `fn` can return a value equal zero */
|
||||
predicate mayBeReturnZero(Function fn) {
|
||||
mayBeReturnValue(fn, 0)
|
||||
or
|
||||
fn.hasName([
|
||||
"iswalpha", "iswlower", "iswprint", "iswspace", "iswblank", "iswupper", "iswcntrl",
|
||||
"iswctype", "iswalnum", "iswgraph", "iswxdigit", "iswdigit", "iswpunct", "isblank", "isupper",
|
||||
"isgraph", "isalnum", "ispunct", "islower", "isspace", "isprint", "isxdigit", "iscntrl",
|
||||
"isdigit", "isalpha", "timespec_get", "feof", "atomic_is_lock_free",
|
||||
"atomic_compare_exchange", "thrd_equal", "isfinite", "islessequal", "isnan", "isgreater",
|
||||
"signbit", "isinf", "islessgreater", "isnormal", "isless", "isgreaterequal", "isunordered",
|
||||
"ferror"
|
||||
])
|
||||
or
|
||||
fn.hasName([
|
||||
"thrd_sleep", "feenv", "feholdexcept", "feclearexcept", "feexceptflag", "feupdateenv",
|
||||
"remove", "fflush", "setvbuf", "fgetpos", "fsetpos", "fclose", "rename", "fseek", "raise"
|
||||
])
|
||||
or
|
||||
fn.hasName(["tss_get", "gets"])
|
||||
or
|
||||
fn.hasName(["getc", "atoi"])
|
||||
}
|
||||
|
||||
/** Gets the Guard which compares the expression `bound` */
|
||||
pragma[inline]
|
||||
GuardCondition checkByValue(Expr bound, Expr val) {
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(bound, val, _, _, _) or
|
||||
gc.ensuresEq(val, bound, _, _, _) or
|
||||
gc.ensuresLt(bound, val, _, _, _) or
|
||||
gc.ensuresLt(val, bound, _, _, _) or
|
||||
gc = globalValueNumber(bound).getAnExpr()
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if there are no comparisons between the value returned by possible function calls `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
|
||||
pragma[inline]
|
||||
predicate compareFunctionWithValue(Expr guardExp, Function compArg, Expr valArg) {
|
||||
not exists(Expr exp |
|
||||
exp.getAChild*() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
|
||||
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
|
||||
)
|
||||
or
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresEq(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
|
||||
guardExp.getBasicBlock(), false)
|
||||
or
|
||||
gc.ensuresLt(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), false)
|
||||
)
|
||||
or
|
||||
exists(Expr exp |
|
||||
exp.getValue().toFloat() > valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), exp, 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
exp.getValue().toFloat() < valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(exp, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
)
|
||||
)
|
||||
or
|
||||
valArg.getValue().toFloat() = 0 and
|
||||
exists(NotExpr ne, IfStmt ifne |
|
||||
ne.getOperand() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
|
||||
ifne.getCondition() = ne and
|
||||
ifne.getThen().getAChild*() = guardExp
|
||||
)
|
||||
}
|
||||
|
||||
/** Wraping predicate for call `compareFunctionWithValue`. */
|
||||
pragma[inline]
|
||||
predicate checkConditions1(Expr div, Function fn, float changeInt) {
|
||||
exists(Expr val |
|
||||
val.getEnclosingFunction() = fn and
|
||||
val.getValue().toFloat() = changeInt and
|
||||
compareFunctionWithValue(div, fn, val)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if there are no comparisons between the value `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
|
||||
pragma[inline]
|
||||
predicate compareExprWithValue(Expr guardExp, Expr compArg, Expr valArg) {
|
||||
not exists(Expr exp |
|
||||
exp.getAChild*() = globalValueNumber(compArg).getAnExpr() and
|
||||
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
|
||||
)
|
||||
or
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresEq(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(),
|
||||
false)
|
||||
or
|
||||
gc.ensuresLt(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(),
|
||||
false)
|
||||
)
|
||||
or
|
||||
exists(Expr exp |
|
||||
exp.getValue().toFloat() > valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), exp, 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
exp.getValue().toFloat() < valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(exp, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
|
||||
)
|
||||
)
|
||||
or
|
||||
valArg.getValue().toFloat() = 0 and
|
||||
exists(NotExpr ne, IfStmt ifne |
|
||||
ne.getOperand() = globalValueNumber(compArg).getAnExpr() and
|
||||
ifne.getCondition() = ne and
|
||||
ifne.getThen().getAChild*() = guardExp
|
||||
)
|
||||
}
|
||||
|
||||
/** Wraping predicate for call `compareExprWithValue`. */
|
||||
pragma[inline]
|
||||
predicate checkConditions2(Expr div, Expr divVal, float changeInt2) {
|
||||
exists(Expr val |
|
||||
(
|
||||
val.getEnclosingFunction() =
|
||||
div.getEnclosingFunction().getACallToThisFunction().getEnclosingFunction() or
|
||||
val.getEnclosingFunction() = div.getEnclosingFunction()
|
||||
) and
|
||||
val.getValue().toFloat() = changeInt2 and
|
||||
compareExprWithValue(div, divVal, val)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the value of the difference or summand from the expression `src`. */
|
||||
float getValueOperand(Expr src, Expr e1, Expr e2) {
|
||||
src.(SubExpr).hasOperands(e1, e2) and
|
||||
result = e2.getValue().toFloat()
|
||||
or
|
||||
src.(AddExpr).hasOperands(e1, e2) and
|
||||
result = -e2.getValue().toFloat()
|
||||
}
|
||||
|
||||
/** Function the return of the expression `e1` and the multiplication operands, or the left operand of division if `e1` contains a multiplication or division, respectively. */
|
||||
Expr getMulDivOperand(Expr e1) {
|
||||
result = e1 or
|
||||
result = e1.(MulExpr).getAnOperand() or
|
||||
result = e1.(DivExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
/** The class that defines possible variants of the division expression or the search for the remainder. */
|
||||
class MyDiv extends Expr {
|
||||
MyDiv() {
|
||||
this instanceof DivExpr or
|
||||
this instanceof RemExpr or
|
||||
this instanceof AssignDivExpr or
|
||||
this instanceof AssignRemExpr
|
||||
}
|
||||
|
||||
Expr getRV() {
|
||||
result = this.(AssignArithmeticOperation).getRValue() or
|
||||
result = this.(BinaryArithmeticOperation).getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
from Expr exp, string msg, Function fn, GVN findVal, float changeInt, MyDiv div
|
||||
where
|
||||
findVal = globalValueNumber(fn.getACallToThisFunction()) and
|
||||
(
|
||||
// Look for divide-by-zero operations possible due to the return value of the function `fn`.
|
||||
checkConditions1(div, fn, changeInt) and
|
||||
(
|
||||
// Function return value can be zero.
|
||||
mayBeReturnZero(fn) and
|
||||
getMulDivOperand(globalValueNumber(div.getRV()).getAnExpr()) = findVal.getAnExpr() and
|
||||
changeInt = 0
|
||||
or
|
||||
// Denominator can be sum or difference.
|
||||
changeInt = getValueOperand(div.getRV(), findVal.getAnExpr(), _) and
|
||||
mayBeReturnValue(fn, changeInt)
|
||||
) and
|
||||
exp = div and
|
||||
msg =
|
||||
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
|
||||
changeInt.toString() + "."
|
||||
or
|
||||
// Search for situations where division by zero is possible inside the `divFn` function if the passed argument can be equal to a certain value.
|
||||
exists(int posArg, Expr divVal, FunctionCall divFc, float changeInt2 |
|
||||
// Division is associated with the function argument.
|
||||
exists(Function divFn |
|
||||
divFn.getParameter(posArg).getAnAccess() = divVal and
|
||||
divVal.getEnclosingStmt() = div.getEnclosingStmt() and
|
||||
divFc = divFn.getACallToThisFunction()
|
||||
) and
|
||||
(
|
||||
divVal = div.getRV() and
|
||||
divFc.getArgument(posArg) != findVal.getAnExpr() and
|
||||
(
|
||||
// Function return value can be zero.
|
||||
mayBeReturnZero(fn) and
|
||||
getMulDivOperand(globalValueNumber(divFc.getArgument(posArg)).getAnExpr()) =
|
||||
findVal.getAnExpr() and
|
||||
changeInt = 0 and
|
||||
changeInt2 = 0
|
||||
or
|
||||
// Denominator can be sum or difference.
|
||||
changeInt = getValueOperand(divFc.getArgument(posArg), findVal.getAnExpr(), _) and
|
||||
mayBeReturnValue(fn, changeInt) and
|
||||
changeInt2 = 0
|
||||
)
|
||||
or
|
||||
// Look for a situation where the difference or subtraction is considered as an argument, and it can be used in the same way.
|
||||
changeInt = getValueOperand(div.getRV(), divVal, _) and
|
||||
changeInt2 = changeInt and
|
||||
mayBeReturnValue(fn, changeInt) and
|
||||
divFc.getArgument(posArg) = findVal.getAnExpr()
|
||||
) and
|
||||
checkConditions2(div, divVal, changeInt2) and
|
||||
checkConditions1(divFc, fn, changeInt) and
|
||||
exp = divFc and
|
||||
msg =
|
||||
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
|
||||
changeInt.toString() + "."
|
||||
)
|
||||
)
|
||||
select exp, msg
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.5.4
|
||||
version: 0.5.3-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
| test.cpp:47:24:47:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:48:15:48:34 | ... / ... | Can lead to division by 0, since the function getSize2 can return a value 0. |
|
||||
| test.cpp:53:10:53:17 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:65:15:65:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:68:15:68:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:71:9:71:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:74:9:74:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:77:21:77:28 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:79:25:79:32 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:81:24:81:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:128:10:128:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:135:10:135:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:141:10:141:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:153:12:153:19 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:172:3:172:12 | ... /= ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:173:3:173:12 | ... %= ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:187:10:187:17 | ... / ... | Can lead to division by 0, since the function getSizeFloat can return a value 0. |
|
||||
| test.cpp:199:12:199:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value -1. |
|
||||
| test.cpp:202:12:202:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
|
||||
| test.cpp:205:10:205:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
|
||||
| test.cpp:210:10:210:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:258:3:258:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:259:3:259:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 2. |
|
||||
| test.cpp:260:3:260:13 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:263:5:263:15 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:273:5:273:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:275:5:275:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value -1. |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-369/DivideByZeroUsingReturnValue.ql
|
||||
@@ -1,278 +0,0 @@
|
||||
typedef struct {}
|
||||
FILE;
|
||||
int getc(FILE * stream);
|
||||
|
||||
int getSize(int type) {
|
||||
int st;
|
||||
switch (type) {
|
||||
case 1:
|
||||
st = 1;
|
||||
break;
|
||||
case 2:
|
||||
st = 2;
|
||||
break;
|
||||
case 3:
|
||||
st = 3;
|
||||
break;
|
||||
case 4:
|
||||
st = -1;
|
||||
break;
|
||||
default:
|
||||
st = 0;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
int getSize2(int type) {
|
||||
int st = 0;
|
||||
switch (type) {
|
||||
case 1:
|
||||
st = 1;
|
||||
break;
|
||||
case 2:
|
||||
st = 2;
|
||||
break;
|
||||
case 3:
|
||||
st = 3;
|
||||
break;
|
||||
case 4:
|
||||
st = -1;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
int badTestf1(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (met == 1) return 123 / is; // BAD
|
||||
else return 123 / getSize2(type); // BAD
|
||||
}
|
||||
int badTestf2(int type) {
|
||||
int is;
|
||||
is = getSize(type);
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
|
||||
int badTestf3(int type, int met) {
|
||||
int is;
|
||||
is = getSize(type);
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is >= 0) return 123 / is; // BAD [NOT DETECTED]
|
||||
case 2:
|
||||
if (0 == is) return 123 / is; // BAD [NOT DETECTED]
|
||||
case 3:
|
||||
if (!is & 123 / is) // BAD
|
||||
return 123;
|
||||
case 4:
|
||||
if (!is | 123 / is) // BAD
|
||||
return 123;
|
||||
case 5:
|
||||
if (123 / is || !is) // BAD
|
||||
return 123;
|
||||
case 6:
|
||||
if (123 / is && !is) // BAD
|
||||
return 123;
|
||||
case 7:
|
||||
if (!is) return 123 / is; // BAD
|
||||
case 8:
|
||||
if (is > -1) return 123 / is; // BAD
|
||||
case 9:
|
||||
if (is < 2) return 123 / is; // BAD
|
||||
}
|
||||
if (is != 0) return -1;
|
||||
if (is == 0) type += 1;
|
||||
return 123 / is; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
int goodTestf3(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) return -1;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0) return 123 / is; // GOOD
|
||||
case 2:
|
||||
if (!is && 123 / is) // GOOD
|
||||
return 123;
|
||||
case 3:
|
||||
if (!is || 123 / is) // GOOD
|
||||
return 123;
|
||||
case 8:
|
||||
if (is < -1) return 123 / is; // GOOD
|
||||
case 9:
|
||||
if (is > 2) return 123 / is; // GOOD
|
||||
}
|
||||
return 123 / is;
|
||||
}
|
||||
|
||||
int goodTestf3a(int type, int met) {
|
||||
int is = getSize(type);
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0)
|
||||
return 123 / is; // GOOD
|
||||
case 2:
|
||||
if (!is && 123 / is) // GOOD
|
||||
return 123;
|
||||
case 3:
|
||||
if (!is || 123 / is) // GOOD
|
||||
return 123;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int badTestf4(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = type * is;
|
||||
return 123 / d; // BAD
|
||||
}
|
||||
|
||||
int badTestf5(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = is / type;
|
||||
return 123 / d; // BAD
|
||||
}
|
||||
int badTestf6(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = is / type;
|
||||
return type * 123 / d; // BAD
|
||||
}
|
||||
|
||||
int badTestf7(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) goto quit;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0)
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
quit:
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
|
||||
int goodTestf7(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) goto quit2;
|
||||
if (is == 0.) return -1;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0.)
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
return 123 / is; // GOOD
|
||||
quit2:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int badTestf8(int type) {
|
||||
int is = getSize(type);
|
||||
type /= is; // BAD
|
||||
type %= is; // BAD
|
||||
return type;
|
||||
}
|
||||
|
||||
float getSizeFloat(float type) {
|
||||
float st;
|
||||
if (type)
|
||||
st = 1.0;
|
||||
else
|
||||
st = 0.0;
|
||||
return st;
|
||||
}
|
||||
float badTestf9(float type) {
|
||||
float is = getSizeFloat(type);
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
float goodTestf9(float type) {
|
||||
float is = getSizeFloat(type);
|
||||
if (is == 0.0) return -1;
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
|
||||
int badTestf10(int type) {
|
||||
int out = type;
|
||||
int is = getSize(type);
|
||||
if (is > -2) {
|
||||
out /= 123 / (is + 1); // BAD
|
||||
}
|
||||
if (is > 0) {
|
||||
return 123 / (is - 1); // BAD
|
||||
}
|
||||
if (is <= 0) return 0;
|
||||
return 123 / (is - 1); // BAD
|
||||
return 0;
|
||||
}
|
||||
int badTestf11(int type) {
|
||||
int is = getSize(type);
|
||||
return 123 / (is - 3); // BAD
|
||||
}
|
||||
|
||||
int goodTestf11(int type) {
|
||||
int is = getSize(type);
|
||||
if (is > 1) {
|
||||
return 123 / (is - 1); // GOOD
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int badTestf12(FILE * f) {
|
||||
int a;
|
||||
int ret = -1;
|
||||
a = getc(f);
|
||||
if (a == 0) ret = 123 / a; // BAD [NOT DETECTED]
|
||||
return ret;
|
||||
}
|
||||
|
||||
int goodTestf12(FILE * f) {
|
||||
int a;
|
||||
int ret = -1;
|
||||
a = getc(f);
|
||||
if (a != 0) ret = 123 / a; // GOOD
|
||||
return ret;
|
||||
}
|
||||
|
||||
int badMyDiv(int type, int is) {
|
||||
type /= is;
|
||||
type %= is;
|
||||
return type;
|
||||
}
|
||||
|
||||
int goodMyDiv(int type, int is) {
|
||||
if (is == 0) return -1;
|
||||
type /= is;
|
||||
type %= is;
|
||||
return type;
|
||||
}
|
||||
int badMySubDiv(int type, int is) {
|
||||
type /= (is - 3);
|
||||
type %= (is + 1);
|
||||
return type;
|
||||
}
|
||||
|
||||
void badTestf13(int type) {
|
||||
int is = getSize(type);
|
||||
badMyDiv(type, is); // BAD
|
||||
badMyDiv(type, is - 2); // BAD
|
||||
badMySubDiv(type, is); // BAD
|
||||
goodMyDiv(type, is); // GOOD
|
||||
if (is < 5)
|
||||
badMySubDiv(type, is); // BAD
|
||||
if (is < 0)
|
||||
badMySubDiv(type, is); // BAD [NOT DETECTED]
|
||||
if (is > 5)
|
||||
badMySubDiv(type, is); // GOOD
|
||||
if (is == 0)
|
||||
badMyDiv(type, is); // BAD
|
||||
if (is > 0)
|
||||
badMyDiv(type, is); // GOOD
|
||||
if (is < 5)
|
||||
badMyDiv(type, is - 3); // BAD
|
||||
if (is < 0)
|
||||
badMyDiv(type, is + 1); // BAD
|
||||
if (is > 5)
|
||||
badMyDiv(type, is - 3); // GOOD
|
||||
}
|
||||
@@ -145,14 +145,6 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
public bool IsMacOs { get; set; }
|
||||
|
||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||
|
||||
public bool IsArm { get; set; }
|
||||
|
||||
bool IBuildActions.IsArm() => IsArm;
|
||||
|
||||
public string PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Xml;
|
||||
using System.Net.Http;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
@@ -99,18 +98,6 @@ namespace Semmle.Autobuild.Shared
|
||||
/// </summary>
|
||||
bool IsWindows();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we are running on macOS.
|
||||
/// </summary>
|
||||
/// <returns>True if we are running on macOS.</returns>
|
||||
bool IsMacOs();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we are running on arm.
|
||||
/// </summary>
|
||||
/// <returns>True if we are running on arm.</returns>
|
||||
bool IsArm();
|
||||
|
||||
/// <summary>
|
||||
/// Combine path segments, Path.Combine().
|
||||
/// </summary>
|
||||
@@ -216,12 +203,6 @@ namespace Semmle.Autobuild.Shared
|
||||
|
||||
bool IBuildActions.IsWindows() => Win32.IsWindows();
|
||||
|
||||
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
bool IBuildActions.IsArm() =>
|
||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ||
|
||||
RuntimeInformation.ProcessArchitecture == Architecture.Arm;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
||||
|
||||
@@ -1,36 +1,18 @@
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
internal static class MsBuildCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Appends a call to msbuild.
|
||||
/// </summary>
|
||||
/// <param name="cmdBuilder"></param>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder)
|
||||
{
|
||||
var isArmMac = builder.Actions.IsMacOs() && builder.Actions.IsArm();
|
||||
|
||||
// mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to
|
||||
// msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild`
|
||||
// perhaps we should do this on all platforms?
|
||||
return isArmMac ?
|
||||
cmdBuilder.RunCommand("dotnet").Argument("msbuild") :
|
||||
cmdBuilder.RunCommand("msbuild");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A build rule using msbuild.
|
||||
/// </summary>
|
||||
public class MsBuildRule : IBuildRule<AutobuildOptionsShared>
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the msbuild command.
|
||||
/// </summary>
|
||||
private const string msBuild = "msbuild";
|
||||
|
||||
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
|
||||
{
|
||||
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
||||
@@ -75,7 +57,7 @@ namespace Semmle.Autobuild.Shared
|
||||
Script;
|
||||
var nugetRestore = GetNugetRestoreScript();
|
||||
var msbuildRestoreCommand = new CommandBuilder(builder.Actions).
|
||||
MsBuildCommand(builder).
|
||||
RunCommand(msBuild).
|
||||
Argument("/t:restore").
|
||||
QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
@@ -113,7 +95,7 @@ namespace Semmle.Autobuild.Shared
|
||||
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
||||
}
|
||||
|
||||
command.MsBuildCommand(builder);
|
||||
command.RunCommand(msBuild);
|
||||
command.QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
var target = builder.Options.MsBuildTarget ?? "rebuild";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
description: Remove a relation for scoped annotations.
|
||||
compatibility: backwards
|
||||
scoped_annotation.rel: delete
|
||||
@@ -106,6 +106,36 @@ namespace Semmle.BuildAnalyser
|
||||
return result;
|
||||
}
|
||||
|
||||
// Attempt to load the reference from the GAC.
|
||||
try
|
||||
{
|
||||
var loadedAssembly = System.Reflection.Assembly.ReflectionOnlyLoad(id);
|
||||
|
||||
if (loadedAssembly is not null)
|
||||
{
|
||||
// The assembly was somewhere we haven't indexed before.
|
||||
// Add this assembly to our index so that subsequent lookups are faster.
|
||||
|
||||
result = AssemblyInfo.MakeFromAssembly(loadedAssembly);
|
||||
assemblyInfoById[id] = result;
|
||||
assemblyInfoByFileName[loadedAssembly.Location] = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// A suitable assembly could not be found
|
||||
}
|
||||
catch (FileLoadException)
|
||||
{
|
||||
// The assembly cannot be loaded for some reason
|
||||
// e.g. The name is malformed.
|
||||
}
|
||||
catch (PlatformNotSupportedException)
|
||||
{
|
||||
// .NET Core does not have a GAC.
|
||||
}
|
||||
|
||||
// Fallback position - locate the assembly by its lower-case name only.
|
||||
var asmName = assemblyName.ToLowerInvariant();
|
||||
|
||||
|
||||
@@ -59,19 +59,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected void PopulateScopedKind(TextWriter trapFile, ScopedKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ScopedKind.ScopedRef:
|
||||
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedRef);
|
||||
break;
|
||||
case ScopedKind.ScopedValue:
|
||||
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void ExtractCompilerGenerated(TextWriter trapFile)
|
||||
{
|
||||
if (Symbol.IsImplicitlyDeclared)
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
private Conversion(Context cx, IMethodSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
protected override MethodKind ExplicitlyImplementsKind => MethodKind.Conversion;
|
||||
|
||||
public static new Conversion Create(Context cx, IMethodSymbol symbol) =>
|
||||
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||
|
||||
var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition);
|
||||
var kind = Symbol.IsConst ? VariableKind.Const : VariableKind.None;
|
||||
trapFile.fields(this, kind, Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
||||
trapFile.fields(this, (Symbol.IsConst ? 2 : 1), Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
||||
|
||||
PopulateModifiers(trapFile);
|
||||
|
||||
|
||||
@@ -23,23 +23,17 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
public void PopulateManual(Expression parent, bool isVar)
|
||||
{
|
||||
var trapFile = Context.TrapWriter.Writer;
|
||||
var @var = isVar ? 1 : 0;
|
||||
var (kind, type) = Symbol is ILocalSymbol l
|
||||
? (l.IsRef ? 3 : l.IsConst ? 2 : 1, l.GetAnnotatedType())
|
||||
: (1, parent.Type);
|
||||
trapFile.localvars(this, kind, Symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent);
|
||||
|
||||
if (Symbol is ILocalSymbol local)
|
||||
{
|
||||
var kind = local.IsRef ? Kinds.VariableKind.Ref : local.IsConst ? Kinds.VariableKind.Const : Kinds.VariableKind.None;
|
||||
var type = local.GetAnnotatedType();
|
||||
trapFile.localvars(this, kind, Symbol.Name, @var, Type.Create(Context, type).TypeRef, parent);
|
||||
|
||||
PopulateNullability(trapFile, local.GetAnnotatedType());
|
||||
PopulateScopedKind(trapFile, local.ScopedKind);
|
||||
if (local.IsRef)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.localvars(this, Kinds.VariableKind.None, Symbol.Name, @var, Type.Create(Context, parent.Type).TypeRef, parent);
|
||||
}
|
||||
|
||||
trapFile.localvar_location(this, Location);
|
||||
|
||||
|
||||
@@ -83,12 +83,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual MethodKind ExplicitlyImplementsKind => MethodKind.Ordinary;
|
||||
|
||||
public void Overrides(TextWriter trapFile)
|
||||
{
|
||||
foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations
|
||||
.Where(sym => sym.MethodKind == ExplicitlyImplementsKind)
|
||||
.Where(sym => sym.MethodKind == MethodKind.Ordinary)
|
||||
.Select(impl => Type.Create(Context, impl.ContainingType)))
|
||||
{
|
||||
trapFile.explicitly_implements(this, explicitInterface.TypeRef);
|
||||
|
||||
@@ -65,15 +65,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.has_modifiers(target, Modifier.Create(cx, modifier));
|
||||
}
|
||||
|
||||
private static void ExtractFieldModifiers(Context cx, TextWriter trapFile, IEntity key, IFieldSymbol symbol)
|
||||
{
|
||||
if (symbol.IsReadOnly)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
||||
|
||||
if (symbol.IsRequired)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||
}
|
||||
|
||||
private static void ExtractNamedTypeModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
||||
{
|
||||
if (symbol.Kind != SymbolKind.NamedType)
|
||||
@@ -85,9 +76,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (nt.IsRecord)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Record);
|
||||
|
||||
if (nt.IsFileLocal)
|
||||
HasModifier(cx, trapFile, key, Modifiers.File);
|
||||
|
||||
if (nt.TypeKind == TypeKind.Struct)
|
||||
{
|
||||
if (nt.IsReadOnly)
|
||||
@@ -100,11 +88,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
||||
{
|
||||
// A file scoped type has declared accessibility `internal` which we shouldn't extract.
|
||||
// The file modifier is extracted as a source level modifier.
|
||||
if (symbol.Kind != SymbolKind.NamedType || !((INamedTypeSymbol)symbol).IsFileLocal)
|
||||
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
|
||||
|
||||
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
|
||||
if (symbol.Kind == SymbolKind.ErrorType)
|
||||
trapFile.has_modifiers(key, Modifier.Create(cx, Accessibility.Public));
|
||||
|
||||
@@ -122,11 +106,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (symbol.IsVirtual)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Virtual);
|
||||
|
||||
if (symbol is IFieldSymbol field)
|
||||
ExtractFieldModifiers(cx, trapFile, key, field);
|
||||
|
||||
if (symbol.Kind == SymbolKind.Property && ((IPropertySymbol)symbol).IsRequired)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||
if (symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsReadOnly)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
||||
|
||||
if (symbol.IsOverride)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Override);
|
||||
|
||||
@@ -4,7 +4,6 @@ internal static class Modifiers
|
||||
public const string Async = "async";
|
||||
public const string Const = "const";
|
||||
public const string Extern = "extern";
|
||||
public const string File = "file";
|
||||
public const string Internal = "internal";
|
||||
public const string New = "new";
|
||||
public const string Override = "override";
|
||||
@@ -14,7 +13,6 @@ internal static class Modifiers
|
||||
public const string Public = "public";
|
||||
public const string Readonly = "readonly";
|
||||
public const string Record = "record";
|
||||
public const string Required = "required";
|
||||
public const string Ref = "ref";
|
||||
public const string Sealed = "sealed";
|
||||
public const string Static = "static";
|
||||
|
||||
@@ -100,7 +100,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateAttributes();
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||
PopulateScopedKind(trapFile, Symbol.ScopedKind);
|
||||
|
||||
if (Symbol.Name != Original.Symbol.Name)
|
||||
Context.ModelError(Symbol, "Inconsistent parameter declaration");
|
||||
|
||||
@@ -11,8 +11,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
protected UserOperator(Context cx, IMethodSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
protected override MethodKind ExplicitlyImplementsKind => MethodKind.UserDefinedOperator;
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMethod(trapFile);
|
||||
@@ -39,7 +37,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
ContainingType.PopulateGenerics();
|
||||
Overrides(trapFile);
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Semmle.Extraction.Kinds;
|
||||
|
||||
public enum ScopedAnnotation
|
||||
{
|
||||
None = 0,
|
||||
ScopedRef = 1,
|
||||
ScopedValue = 2
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Semmle.Extraction.Kinds;
|
||||
|
||||
public enum VariableKind
|
||||
{
|
||||
None = 1,
|
||||
Const = 2,
|
||||
Ref = 3
|
||||
}
|
||||
@@ -77,8 +77,12 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <summary>
|
||||
/// Gets the source-level modifiers belonging to this symbol, if any.
|
||||
/// </summary>
|
||||
public static IEnumerable<string> GetSourceLevelModifiers(this ISymbol symbol) =>
|
||||
symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax>(md => md.Modifiers).Select(m => m.Text);
|
||||
public static IEnumerable<string> GetSourceLevelModifiers(this ISymbol symbol)
|
||||
{
|
||||
var methodModifiers = symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax>(md => md.Modifiers);
|
||||
var typeModifiers = symbol.GetModifiers<Microsoft.CodeAnalysis.CSharp.Syntax.TypeDeclarationSyntax>(cd => cd.Modifiers);
|
||||
return methodModifiers.Concat(typeModifiers).Select(m => m.Text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds if the ID generated for `dependant` will contain a reference to
|
||||
@@ -282,60 +286,54 @@ namespace Semmle.Extraction.CSharp
|
||||
public static IEnumerable<IFieldSymbol?> GetTupleElementsMaybeNull(this INamedTypeSymbol type) =>
|
||||
type.TupleElements;
|
||||
|
||||
private static void BuildQualifierAndName(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
if (named.ContainingType is not null)
|
||||
{
|
||||
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace is not null)
|
||||
{
|
||||
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
|
||||
BuildAssembly(named.ContainingAssembly, trapFile);
|
||||
named.ContainingNamespace.BuildNamespace(cx, trapFile);
|
||||
}
|
||||
|
||||
var name = named.IsFileLocal ? named.MetadataName : named.Name;
|
||||
trapFile.Write(name);
|
||||
}
|
||||
|
||||
private static void BuildTupleId(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
if (f is null)
|
||||
{
|
||||
trapFile.Write($"null({i})");
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
}
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
}
|
||||
|
||||
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
|
||||
{
|
||||
if (!constructUnderlyingTupleType && named.IsTupleType)
|
||||
{
|
||||
BuildTupleId(named, cx, trapFile, symbolBeingDefined);
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
if (f is null)
|
||||
{
|
||||
trapFile.Write($"null({i})");
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
}
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
return;
|
||||
}
|
||||
|
||||
void AddContaining()
|
||||
{
|
||||
if (named.ContainingType is not null)
|
||||
{
|
||||
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace is not null)
|
||||
{
|
||||
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
|
||||
BuildAssembly(named.ContainingAssembly, trapFile);
|
||||
named.ContainingNamespace.BuildNamespace(cx, trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (named.TypeParameters.IsEmpty)
|
||||
{
|
||||
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
|
||||
AddContaining();
|
||||
trapFile.Write(named.Name);
|
||||
}
|
||||
else if (named.IsReallyUnbound())
|
||||
{
|
||||
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
|
||||
AddContaining();
|
||||
trapFile.Write(named.Name);
|
||||
trapFile.Write("`");
|
||||
trapFile.Write(named.TypeParameters.Length);
|
||||
}
|
||||
|
||||
@@ -191,8 +191,8 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void field_location(this TextWriter trapFile, Field field, Location location) =>
|
||||
trapFile.WriteTuple("field_location", field, location);
|
||||
|
||||
internal static void fields(this TextWriter trapFile, Field field, VariableKind kind, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
||||
trapFile.WriteTuple("fields", field, (int)kind, name, declaringType, fieldType, unboundKey);
|
||||
internal static void fields(this TextWriter trapFile, Field field, int @const, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
||||
trapFile.WriteTuple("fields", field, @const, name, declaringType, fieldType, unboundKey);
|
||||
|
||||
internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind) =>
|
||||
trapFile.WriteTuple("general_type_parameter_constraints", constraints, hasKind);
|
||||
@@ -227,8 +227,8 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void localvar_location(this TextWriter trapFile, LocalVariable var, Location location) =>
|
||||
trapFile.WriteTuple("localvar_location", var, location);
|
||||
|
||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
|
||||
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
|
||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, int @const, string name, int @var, Type type, Expression expr) =>
|
||||
trapFile.WriteTuple("localvars", key, @const, name, @var, type, expr);
|
||||
|
||||
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
|
||||
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
|
||||
@@ -462,8 +462,5 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, ExtractorMode mode) =>
|
||||
trapFile.WriteTuple("file_extraction_mode", file, mode);
|
||||
|
||||
internal static void scoped_annotation(this TextWriter trapFile, IEntity element, ScopedAnnotation @scoped) =>
|
||||
trapFile.WriteTuple("scoped_annotation", element, (int)@scoped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 1.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.4.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.4
|
||||
lastReleaseVersion: 1.4.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.4.4
|
||||
version: 1.4.3-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
## 1.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.4.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.4.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.4
|
||||
lastReleaseVersion: 1.4.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.4.4
|
||||
version: 1.4.3-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello world!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net4.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
from create_database_utils import *
|
||||
|
||||
# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET`
|
||||
run_codeql_database_create([], test_db="default-db", db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
|
||||
@@ -1,20 +1,3 @@
|
||||
## 0.5.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `cs/static-field-written-by-instance` is updated to handle properties.
|
||||
* C# 11: Support for explicit interface member implementation of operators.
|
||||
* The extraction of member modifiers has been generalized, which could lead to the extraction of more modifiers.
|
||||
* C# 11: Added extractor and library support for `file` scoped types.
|
||||
* C# 11: Added extractor support for `required` fields and properties.
|
||||
* C# 11: Added library support for `checked` operators.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.5.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
@@ -1,10 +0,0 @@
|
||||
## 0.5.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `cs/static-field-written-by-instance` is updated to handle properties.
|
||||
* C# 11: Support for explicit interface member implementation of operators.
|
||||
* The extraction of member modifiers has been generalized, which could lead to the extraction of more modifiers.
|
||||
* C# 11: Added extractor and library support for `file` scoped types.
|
||||
* C# 11: Added extractor support for `required` fields and properties.
|
||||
* C# 11: Added library support for `checked` operators.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.4
|
||||
lastReleaseVersion: 0.5.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.5.4
|
||||
version: 0.5.3-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
@@ -8,7 +8,6 @@ upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
dataExtensions:
|
||||
- ext/*.model.yml
|
||||
- ext/generated/*.model.yml
|
||||
|
||||
@@ -434,13 +434,9 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
|
||||
* Either a unary operator (`UnaryOperator`), a binary operator
|
||||
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
|
||||
*/
|
||||
class Operator extends Callable, Member, Attributable, Overridable, @operator {
|
||||
/**
|
||||
* DEPRECATED: use `getFunctionName()` instead.
|
||||
*
|
||||
* Gets the assembly name of this operator.
|
||||
*/
|
||||
deprecated string getAssemblyName() { result = this.getFunctionName() }
|
||||
class Operator extends Callable, Member, Attributable, @operator {
|
||||
/** Gets the assembly name of this operator. */
|
||||
string getAssemblyName() { operators(this, result, _, _, _, _) }
|
||||
|
||||
override string getName() { operators(this, _, result, _, _, _) }
|
||||
|
||||
@@ -449,7 +445,7 @@ class Operator extends Callable, Member, Attributable, Overridable, @operator {
|
||||
/**
|
||||
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
||||
*/
|
||||
string getFunctionName() { operators(this, result, _, _, _, _) }
|
||||
string getFunctionName() { none() }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
|
||||
|
||||
@@ -485,11 +481,10 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
|
||||
* A user-defined unary operator - an operator taking one operand.
|
||||
*
|
||||
* Either a plus operator (`PlusOperator`), minus operator (`MinusOperator`),
|
||||
* checked minus operator (`CheckedMinusOperator`), not operator (`NotOperator`),
|
||||
* complement operator (`ComplementOperator`), true operator (`TrueOperator`),
|
||||
* false operator (`FalseOperator`), increment operator (`IncrementOperator`),
|
||||
* checked increment operator (`CheckedIncrementOperator`), decrement operator
|
||||
* (`DecrementOperator`) or checked decrement operator (`CheckedDecrementOperator`).
|
||||
* not operator (`NotOperator`), complement operator (`ComplementOperator`),
|
||||
* true operator (`TrueOperator`), false operator (`FalseOperator`),
|
||||
* increment operator (`IncrementOperator`), or decrement operator
|
||||
* (`DecrementOperator`).
|
||||
*/
|
||||
class UnaryOperator extends Operator {
|
||||
UnaryOperator() {
|
||||
@@ -510,6 +505,8 @@ class UnaryOperator extends Operator {
|
||||
class PlusOperator extends UnaryOperator {
|
||||
PlusOperator() { this.getName() = "+" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnaryPlus" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PlusOperator" }
|
||||
}
|
||||
|
||||
@@ -525,24 +522,11 @@ class PlusOperator extends UnaryOperator {
|
||||
class MinusOperator extends UnaryOperator {
|
||||
MinusOperator() { this.getName() = "-" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnaryNegation" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MinusOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked minus operator (`-`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked -(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedMinusOperator extends UnaryOperator {
|
||||
CheckedMinusOperator() { this.getName() = "checked -" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedMinusOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined not operator (`!`), for example
|
||||
*
|
||||
@@ -555,6 +539,8 @@ class CheckedMinusOperator extends UnaryOperator {
|
||||
class NotOperator extends UnaryOperator {
|
||||
NotOperator() { this.getName() = "!" }
|
||||
|
||||
override string getFunctionName() { result = "op_LogicalNot" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NotOperator" }
|
||||
}
|
||||
|
||||
@@ -570,6 +556,8 @@ class NotOperator extends UnaryOperator {
|
||||
class ComplementOperator extends UnaryOperator {
|
||||
ComplementOperator() { this.getName() = "~" }
|
||||
|
||||
override string getFunctionName() { result = "op_OnesComplement" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ComplementOperator" }
|
||||
}
|
||||
|
||||
@@ -585,24 +573,11 @@ class ComplementOperator extends UnaryOperator {
|
||||
class IncrementOperator extends UnaryOperator {
|
||||
IncrementOperator() { this.getName() = "++" }
|
||||
|
||||
override string getFunctionName() { result = "op_Increment" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IncrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked increment operator (`++`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked ++(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedIncrementOperator extends UnaryOperator {
|
||||
CheckedIncrementOperator() { this.getName() = "checked ++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedIncrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined decrement operator (`--`), for example
|
||||
*
|
||||
@@ -615,24 +590,11 @@ class CheckedIncrementOperator extends UnaryOperator {
|
||||
class DecrementOperator extends UnaryOperator {
|
||||
DecrementOperator() { this.getName() = "--" }
|
||||
|
||||
override string getFunctionName() { result = "op_Decrement" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DecrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked decrement operator (`--`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked --(Widget w) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedDecrementOperator extends UnaryOperator {
|
||||
CheckedDecrementOperator() { this.getName() = "checked --" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedDecrementOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined false operator (`false`), for example
|
||||
*
|
||||
@@ -645,6 +607,8 @@ class CheckedDecrementOperator extends UnaryOperator {
|
||||
class FalseOperator extends UnaryOperator {
|
||||
FalseOperator() { this.getName() = "false" }
|
||||
|
||||
override string getFunctionName() { result = "op_False" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FalseOperator" }
|
||||
}
|
||||
|
||||
@@ -660,18 +624,17 @@ class FalseOperator extends UnaryOperator {
|
||||
class TrueOperator extends UnaryOperator {
|
||||
TrueOperator() { this.getName() = "true" }
|
||||
|
||||
override string getFunctionName() { result = "op_True" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TrueOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined binary operator.
|
||||
*
|
||||
* Either an addition operator (`AddOperator`), a checked addition operator
|
||||
* (`CheckedAddOperator`) a subtraction operator (`SubOperator`), a checked
|
||||
* substraction operator (`CheckedSubOperator`), a multiplication operator
|
||||
* (`MulOperator`), a checked multiplication operator (`CheckedMulOperator`),
|
||||
* a division operator (`DivOperator`), a checked division operator
|
||||
* (`CheckedDivOperator`), a remainder operator (`RemOperator`), an and
|
||||
* Either an addition operator (`AddOperator`), a subtraction operator
|
||||
* (`SubOperator`), a multiplication operator (`MulOperator`), a division
|
||||
* operator (`DivOperator`), a remainder operator (`RemOperator`), an and
|
||||
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
|
||||
* operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
|
||||
* a right shift operator (`RightShiftOperator`), an unsigned right shift
|
||||
@@ -696,24 +659,11 @@ class BinaryOperator extends Operator {
|
||||
class AddOperator extends BinaryOperator {
|
||||
AddOperator() { this.getName() = "+" }
|
||||
|
||||
override string getFunctionName() { result = "op_Addition" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AddOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked addition operator (`+`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked +(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedAddOperator extends BinaryOperator {
|
||||
CheckedAddOperator() { this.getName() = "checked +" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedAddOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined subtraction operator (`-`), for example
|
||||
*
|
||||
@@ -726,24 +676,11 @@ class CheckedAddOperator extends BinaryOperator {
|
||||
class SubOperator extends BinaryOperator {
|
||||
SubOperator() { this.getName() = "-" }
|
||||
|
||||
override string getFunctionName() { result = "op_Subtraction" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SubOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked subtraction operator (`-`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked -(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedSubOperator extends BinaryOperator {
|
||||
CheckedSubOperator() { this.getName() = "checked -" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedSubOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined multiplication operator (`*`), for example
|
||||
*
|
||||
@@ -756,24 +693,11 @@ class CheckedSubOperator extends BinaryOperator {
|
||||
class MulOperator extends BinaryOperator {
|
||||
MulOperator() { this.getName() = "*" }
|
||||
|
||||
override string getFunctionName() { result = "op_Multiply" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MulOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked multiplication operator (`*`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked *(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedMulOperator extends BinaryOperator {
|
||||
CheckedMulOperator() { this.getName() = "checked *" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedMulOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined division operator (`/`), for example
|
||||
*
|
||||
@@ -786,24 +710,11 @@ class CheckedMulOperator extends BinaryOperator {
|
||||
class DivOperator extends BinaryOperator {
|
||||
DivOperator() { this.getName() = "/" }
|
||||
|
||||
override string getFunctionName() { result = "op_Division" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DivOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked division operator (`/`), for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static Widget operator checked /(Widget lhs, Widget rhs) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedDivOperator extends BinaryOperator {
|
||||
CheckedDivOperator() { this.getName() = "checked /" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedDivOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined remainder operator (`%`), for example
|
||||
*
|
||||
@@ -816,6 +727,8 @@ class CheckedDivOperator extends BinaryOperator {
|
||||
class RemOperator extends BinaryOperator {
|
||||
RemOperator() { this.getName() = "%" }
|
||||
|
||||
override string getFunctionName() { result = "op_Modulus" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RemOperator" }
|
||||
}
|
||||
|
||||
@@ -831,6 +744,8 @@ class RemOperator extends BinaryOperator {
|
||||
class AndOperator extends BinaryOperator {
|
||||
AndOperator() { this.getName() = "&" }
|
||||
|
||||
override string getFunctionName() { result = "op_BitwiseAnd" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AndOperator" }
|
||||
}
|
||||
|
||||
@@ -846,6 +761,8 @@ class AndOperator extends BinaryOperator {
|
||||
class OrOperator extends BinaryOperator {
|
||||
OrOperator() { this.getName() = "|" }
|
||||
|
||||
override string getFunctionName() { result = "op_BitwiseOr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OrOperator" }
|
||||
}
|
||||
|
||||
@@ -861,6 +778,8 @@ class OrOperator extends BinaryOperator {
|
||||
class XorOperator extends BinaryOperator {
|
||||
XorOperator() { this.getName() = "^" }
|
||||
|
||||
override string getFunctionName() { result = "op_ExclusiveOr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "XorOperator" }
|
||||
}
|
||||
|
||||
@@ -876,6 +795,8 @@ class XorOperator extends BinaryOperator {
|
||||
class LeftShiftOperator extends BinaryOperator {
|
||||
LeftShiftOperator() { this.getName() = "<<" }
|
||||
|
||||
override string getFunctionName() { result = "op_LeftShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -894,6 +815,8 @@ deprecated class LShiftOperator = LeftShiftOperator;
|
||||
class RightShiftOperator extends BinaryOperator {
|
||||
RightShiftOperator() { this.getName() = ">>" }
|
||||
|
||||
override string getFunctionName() { result = "op_RightShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RightShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -912,6 +835,8 @@ deprecated class RShiftOperator = RightShiftOperator;
|
||||
class UnsignedRightShiftOperator extends BinaryOperator {
|
||||
UnsignedRightShiftOperator() { this.getName() = ">>>" }
|
||||
|
||||
override string getFunctionName() { result = "op_UnsignedRightShift" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" }
|
||||
}
|
||||
|
||||
@@ -927,6 +852,8 @@ class UnsignedRightShiftOperator extends BinaryOperator {
|
||||
class EQOperator extends BinaryOperator {
|
||||
EQOperator() { this.getName() = "==" }
|
||||
|
||||
override string getFunctionName() { result = "op_Equality" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "EQOperator" }
|
||||
}
|
||||
|
||||
@@ -942,6 +869,8 @@ class EQOperator extends BinaryOperator {
|
||||
class NEOperator extends BinaryOperator {
|
||||
NEOperator() { this.getName() = "!=" }
|
||||
|
||||
override string getFunctionName() { result = "op_Inequality" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NEOperator" }
|
||||
}
|
||||
|
||||
@@ -957,6 +886,8 @@ class NEOperator extends BinaryOperator {
|
||||
class LTOperator extends BinaryOperator {
|
||||
LTOperator() { this.getName() = "<" }
|
||||
|
||||
override string getFunctionName() { result = "op_LessThan" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LTOperator" }
|
||||
}
|
||||
|
||||
@@ -972,6 +903,8 @@ class LTOperator extends BinaryOperator {
|
||||
class GTOperator extends BinaryOperator {
|
||||
GTOperator() { this.getName() = ">" }
|
||||
|
||||
override string getFunctionName() { result = "op_GreaterThan" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GTOperator" }
|
||||
}
|
||||
|
||||
@@ -987,6 +920,8 @@ class GTOperator extends BinaryOperator {
|
||||
class LEOperator extends BinaryOperator {
|
||||
LEOperator() { this.getName() = "<=" }
|
||||
|
||||
override string getFunctionName() { result = "op_LessThanOrEqual" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LEOperator" }
|
||||
}
|
||||
|
||||
@@ -1002,6 +937,8 @@ class LEOperator extends BinaryOperator {
|
||||
class GEOperator extends BinaryOperator {
|
||||
GEOperator() { this.getName() = ">=" }
|
||||
|
||||
override string getFunctionName() { result = "op_GreaterThanOrEqual" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GEOperator" }
|
||||
}
|
||||
|
||||
@@ -1017,8 +954,7 @@ class GEOperator extends BinaryOperator {
|
||||
class ConversionOperator extends Operator {
|
||||
ConversionOperator() {
|
||||
this.getName() = "implicit conversion" or
|
||||
this.getName() = "explicit conversion" or
|
||||
this.getName() = "checked explicit conversion"
|
||||
this.getName() = "explicit conversion"
|
||||
}
|
||||
|
||||
/** Gets the source type of the conversion. */
|
||||
@@ -1040,6 +976,8 @@ class ConversionOperator extends Operator {
|
||||
class ImplicitConversionOperator extends ConversionOperator {
|
||||
ImplicitConversionOperator() { this.getName() = "implicit conversion" }
|
||||
|
||||
override string getFunctionName() { result = "op_Implicit" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" }
|
||||
}
|
||||
|
||||
@@ -1055,24 +993,11 @@ class ImplicitConversionOperator extends ConversionOperator {
|
||||
class ExplicitConversionOperator extends ConversionOperator {
|
||||
ExplicitConversionOperator() { this.getName() = "explicit conversion" }
|
||||
|
||||
override string getFunctionName() { result = "op_Explicit" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined checked explicit conversion operator, for example
|
||||
*
|
||||
* ```csharp
|
||||
* public static explicit operator checked int(BigInteger i) {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class CheckedExplicitConversionOperator extends ConversionOperator {
|
||||
CheckedExplicitConversionOperator() { this.getName() = "checked explicit conversion" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CheckedExplicitConversionOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local function, defined within the scope of another callable.
|
||||
* For example, `Fac` on lines 2--4 in
|
||||
|
||||
@@ -3,34 +3,184 @@
|
||||
*/
|
||||
|
||||
private import Comments
|
||||
private import codeql.util.FileSystem
|
||||
|
||||
private module Input implements InputSig {
|
||||
abstract class ContainerBase extends @container {
|
||||
abstract string getAbsolutePath();
|
||||
/** A file or folder. */
|
||||
class Container extends @container {
|
||||
/**
|
||||
* Gets the absolute, canonical path of this container, using forward slashes
|
||||
* as path separator.
|
||||
*
|
||||
* The path starts with a _root prefix_ followed by zero or more _path
|
||||
* segments_ separated by forward slashes.
|
||||
*
|
||||
* The root prefix is of one of the following forms:
|
||||
*
|
||||
* 1. A single forward slash `/` (Unix-style)
|
||||
* 2. An upper-case drive letter followed by a colon and a forward slash,
|
||||
* such as `C:/` (Windows-style)
|
||||
* 3. Two forward slashes, a computer name, and then another forward slash,
|
||||
* such as `//FileServer/` (UNC-style)
|
||||
*
|
||||
* Path segments are never empty (that is, absolute paths never contain two
|
||||
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
|
||||
* segments never contain forward slashes, and no path segment is of the
|
||||
* form `.` (one dot) or `..` (two dots).
|
||||
*
|
||||
* Note that an absolute path never ends with a forward slash, except if it is
|
||||
* a bare root prefix, that is, the path has no path segments. A container
|
||||
* whose absolute path has no segments is always a `Folder`, not a `File`.
|
||||
*/
|
||||
string getAbsolutePath() { none() }
|
||||
|
||||
ContainerBase getParentContainer() { containerparent(result, this) }
|
||||
/**
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
string getURL() { none() }
|
||||
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
/**
|
||||
* Gets the relative path of this file or folder from the root folder of the
|
||||
* analyzed source location. The relative path of the root folder itself is
|
||||
* the empty string.
|
||||
*
|
||||
* This has no result if the container is outside the source root, that is,
|
||||
* if the root folder is not a reflexive, transitive parent of this container.
|
||||
*/
|
||||
string getRelativePath() {
|
||||
exists(string absPath, string pref |
|
||||
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
||||
|
|
||||
absPath = pref and result = ""
|
||||
or
|
||||
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
|
||||
not result.matches("/%")
|
||||
)
|
||||
}
|
||||
|
||||
class FolderBase extends ContainerBase, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
/**
|
||||
* Gets the base name of this container including extension, that is, the last
|
||||
* segment of its absolute path, or the empty string if it has no segments.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding base names
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Base name</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"tst.cs"</td></tr>
|
||||
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
|
||||
* <tr><td>"/"</td><td>""</td></tr>
|
||||
* <tr><td>"C:/"</td><td>""</td></tr>
|
||||
* <tr><td>"D:/"</td><td>""</td></tr>
|
||||
* <tr><td>"//FileServer/"</td><td>""</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getBaseName() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
|
||||
}
|
||||
|
||||
class FileBase extends ContainerBase, @file {
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
/**
|
||||
* Gets the extension of this container, that is, the suffix of its base name
|
||||
* after the last dot character, if any.
|
||||
*
|
||||
* In particular,
|
||||
*
|
||||
* - if the name does not include a dot, there is no extension, so this
|
||||
* predicate has no result;
|
||||
* - if the name ends in a dot, the extension is the empty string;
|
||||
* - if the name contains multiple dots, the extension follows the last dot.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding extensions
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Extension</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"cs"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getExtension() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
|
||||
}
|
||||
|
||||
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
|
||||
/**
|
||||
* Gets the stem of this container, that is, the prefix of its base name up to
|
||||
* (but not including) the last dot character if there is one, or the entire
|
||||
* base name if there is not.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding stems
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Stem</th></tr>
|
||||
* <tr><td>"/tmp/tst.cs"</td><td>"tst"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getStem() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
|
||||
}
|
||||
|
||||
/** Gets the parent container of this file or folder, if any. */
|
||||
Container getParentContainer() { containerparent(result, this) }
|
||||
|
||||
/** Gets a file or sub-folder in this container. */
|
||||
Container getAChildContainer() { this = result.getParentContainer() }
|
||||
|
||||
/** Gets a file in this container. */
|
||||
File getAFile() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the file in this container that has the given `baseName`, if any. */
|
||||
File getFile(string baseName) {
|
||||
result = this.getAFile() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets a sub-folder in this container. */
|
||||
Folder getAFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
|
||||
Folder getFolder(string baseName) {
|
||||
result = this.getAFolder() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets the file or sub-folder in this container that has the given `name`, if any. */
|
||||
Container getChildContainer(string name) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getBaseName() = name
|
||||
}
|
||||
|
||||
/** Gets the file in this container that has the given `stem` and `extension`, if any. */
|
||||
File getFile(string stem, string extension) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getStem() = stem and
|
||||
result.getExtension() = extension
|
||||
}
|
||||
|
||||
/** Gets a sub-folder contained in this container. */
|
||||
Folder getASubFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of the path of this container.
|
||||
*
|
||||
* This is the absolute path of the container.
|
||||
*/
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
private module Impl = Make<Input>;
|
||||
|
||||
class Container = Impl::Container;
|
||||
|
||||
/** A folder. */
|
||||
class Folder extends Container, Impl::Folder { }
|
||||
class Folder extends Container, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
|
||||
override string getURL() { result = "folder://" + this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
bindingset[flag]
|
||||
private predicate fileHasExtractionFlag(File f, int flag) {
|
||||
@@ -41,7 +191,9 @@ private predicate fileHasExtractionFlag(File f, int flag) {
|
||||
}
|
||||
|
||||
/** A file. */
|
||||
class File extends Container, Impl::File {
|
||||
class File extends Container, @file {
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
|
||||
/** Gets the number of lines in this file. */
|
||||
int getNumberOfLines() { numlines(this, result, _, _) }
|
||||
|
||||
|
||||
@@ -90,12 +90,6 @@ class Modifiable extends Declaration, @modifiable {
|
||||
/** Holds if this declaration is `const`. */
|
||||
predicate isConst() { this.hasModifier("const") }
|
||||
|
||||
/** Holds if this declaration has the modifier `required`. */
|
||||
predicate isRequired() { this.hasModifier("required") }
|
||||
|
||||
/** Holds if this declaration is `file` local. */
|
||||
predicate isFile() { this.hasModifier("file") }
|
||||
|
||||
/** Holds if this declaration is `unsafe`. */
|
||||
predicate isUnsafe() {
|
||||
this.hasModifier("unsafe") or
|
||||
@@ -184,10 +178,6 @@ class Member extends DotNet::Member, Modifiable, @member {
|
||||
override predicate isAbstract() { Modifiable.super.isAbstract() }
|
||||
|
||||
override predicate isStatic() { Modifiable.super.isStatic() }
|
||||
|
||||
override predicate isRequired() { Modifiable.super.isRequired() }
|
||||
|
||||
override predicate isFile() { Modifiable.super.isFile() }
|
||||
}
|
||||
|
||||
private class TOverridable = @virtualizable or @callable_accessor;
|
||||
|
||||
@@ -71,11 +71,6 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
|
||||
*/
|
||||
predicate isRef() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this local variable or parameter is `scoped`.
|
||||
*/
|
||||
predicate isScoped() { scoped_annotation(this, _) }
|
||||
|
||||
override predicate hasQualifiedName(string qualifier, string name) { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -137,8 +137,6 @@ private class RecordConstructorFlow extends SummarizedCallable {
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(string provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -707,8 +707,8 @@ private module Cached {
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableCallable(call)
|
||||
or
|
||||
|
||||
@@ -667,75 +667,20 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
fwdFlowIn(_, _, _, node, config) and
|
||||
cc = true
|
||||
exists(NodeEx arg |
|
||||
fwdFlow(arg, _, config) and
|
||||
viableParamArgEx(_, node, arg) and
|
||||
cc = true and
|
||||
not fullBarrier(node, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||
) {
|
||||
// call context cannot help reduce virtual dispatch
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
not fullBarrier(p, config) and
|
||||
(
|
||||
fwdFlowOut(call, node, false, config) and
|
||||
cc = false
|
||||
or
|
||||
cc = true and
|
||||
not reducedViableImplInCallContext(call, _, _)
|
||||
)
|
||||
or
|
||||
// call context may help reduce virtual dispatch
|
||||
exists(DataFlowCallable target |
|
||||
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||
cc = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
fwdFlowIn(call, _, cc, _, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||
) {
|
||||
fwdFlow(arg, true, config) and
|
||||
viableParamArgEx(call, p, arg) and
|
||||
reducedViableImplInCallContext(call, _, _) and
|
||||
target = p.getEnclosingCallable() and
|
||||
not fullBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference,
|
||||
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall ctx |
|
||||
fwdFlowIsEntered(ctx, _, config) and
|
||||
result = viableImplInCallContextExt(call, ctx)
|
||||
fwdFlowOutFromArg(call, node, config) and
|
||||
fwdFlowIsEntered(call, cc, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -781,8 +726,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||
exists(ReturnPosition pos |
|
||||
fwdFlowReturnPosition(pos, cc, config) and
|
||||
@@ -796,6 +740,17 @@ private module Stage1 implements StageSig {
|
||||
fwdFlowOut(call, out, true, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgNodeEx arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArgEx(call, _, arg)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||
exists(NodeEx node1 |
|
||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||
@@ -862,8 +817,13 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
revFlowIn(_, node, false, config) and
|
||||
toReturn = false
|
||||
exists(DataFlowCall call |
|
||||
revFlowIn(call, node, false, config) and
|
||||
toReturn = false
|
||||
or
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(ReturnPosition pos |
|
||||
@@ -871,12 +831,6 @@ private module Stage1 implements StageSig {
|
||||
node.(RetNodeEx).getReturnPosition() = pos and
|
||||
toReturn = true
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(DataFlowCall call |
|
||||
revFlowInToReturn(call, node, config) and
|
||||
revFlowIsReturned(call, toReturn, config)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,11 +886,11 @@ private module Stage1 implements StageSig {
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
fwdFlowIn(call, arg, _, p, config)
|
||||
viableParamArgEx(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
// inline to reduce the number of iterations
|
||||
pragma[inline]
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
|
||||
@@ -248,9 +248,7 @@ module Public {
|
||||
/**
|
||||
* Holds if all the summaries that apply to `this` are auto generated and not manually created.
|
||||
*/
|
||||
final predicate isAutoGenerated() {
|
||||
this.hasProvenance(["generated", "ai-generated"]) and not this.isManual()
|
||||
}
|
||||
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual summary that applies to `this`.
|
||||
@@ -270,7 +268,7 @@ module Public {
|
||||
/**
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { neutralElement(this, ["generated", "ai-generated"]) }
|
||||
predicate isAutoGenerated() { neutralElement(this, "generated") }
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual neutral that applies to `this`.
|
||||
@@ -1204,11 +1202,11 @@ module Private {
|
||||
}
|
||||
|
||||
private string renderProvenance(SummarizedCallable c) {
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,8 +86,6 @@ module EntityFramework {
|
||||
abstract class EFSummarizedCallable extends SummarizedCallable {
|
||||
bindingset[this]
|
||||
EFSummarizedCallable() { any() }
|
||||
|
||||
override predicate hasProvenance(string provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
private class DbSetAddOrUpdateRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
|
||||
@@ -80,12 +80,6 @@ class Member extends Declaration, @dotnet_member {
|
||||
/** Holds if this member is `static`. */
|
||||
predicate isStatic() { none() }
|
||||
|
||||
/** Holds if this member is declared `required`. */
|
||||
predicate isRequired() { none() }
|
||||
|
||||
/** Holds if this member is declared `file` local. */
|
||||
predicate isFile() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this member has name `name` and is defined in type `type`
|
||||
* with namespace `namespace`.
|
||||
|
||||
@@ -878,13 +878,6 @@ param_location(
|
||||
int id: @parameter ref,
|
||||
int loc: @location ref);
|
||||
|
||||
@has_scoped_annotation = @local_scope_variable
|
||||
|
||||
scoped_annotation(
|
||||
int id: @has_scoped_annotation ref,
|
||||
int kind: int ref // scoped ref = 1, scoped value = 2
|
||||
);
|
||||
|
||||
/** STATEMENTS **/
|
||||
|
||||
@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
|
||||
|
||||
@@ -26228,59 +26228,6 @@
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>scoped_annotation</name>
|
||||
<cardinality>43498</cardinality>
|
||||
<columnsizes>
|
||||
<e>
|
||||
<k>id</k>
|
||||
<v>43498</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>kind</k>
|
||||
<v>18</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>kind</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>43498</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>kind</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>11</a>
|
||||
<b>12</b>
|
||||
<v>9</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4599</a>
|
||||
<b>4600</b>
|
||||
<v>9</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>statements</name>
|
||||
<cardinality>2458000</cardinality>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user