mirror of
https://github.com/github/codeql.git
synced 2026-05-18 05:07:06 +02:00
Compare commits
3 Commits
sashabu/wi
...
post-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c47e996f48 | ||
|
|
da8a002f22 | ||
|
|
994c6f5f44 |
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -11,7 +11,7 @@ Go:
|
||||
- change-notes/**/*go.*
|
||||
|
||||
Java:
|
||||
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/ql/test/kotlin/**/*' ]
|
||||
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/kotlin-explorer/**/*', '!java/ql/test/kotlin/**/*' ]
|
||||
- change-notes/**/*java.*
|
||||
|
||||
JS:
|
||||
@@ -20,6 +20,7 @@ JS:
|
||||
|
||||
Kotlin:
|
||||
- java/kotlin-extractor/**/*
|
||||
- java/kotlin-explorer/**/*
|
||||
- java/ql/test/kotlin/**/*
|
||||
|
||||
Python:
|
||||
|
||||
5
.github/workflows/check-change-note.yml
vendored
5
.github/workflows/check-change-note.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
- "*/ql/lib/**/*.yml"
|
||||
- "!**/experimental/**"
|
||||
- "!ql/**"
|
||||
- "!swift/**"
|
||||
- ".github/workflows/check-change-note.yml"
|
||||
|
||||
jobs:
|
||||
@@ -26,9 +27,9 @@ jobs:
|
||||
run: |
|
||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
|
||||
grep true -c
|
||||
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md', 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text, or released/x.y.z.md for released change-notes
|
||||
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md' or 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text.
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$") or test("/change-notes/released/[0-9]*[.][0-9]*[.][0-9]*[.]md$"))' |
|
||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$"))' |
|
||||
grep true -c
|
||||
|
||||
@@ -10,7 +10,6 @@ on:
|
||||
- "*/ql/src/**/*.qll"
|
||||
- "*/ql/lib/**/*.ql"
|
||||
- "*/ql/lib/**/*.qll"
|
||||
- "*/ql/lib/ext/**/*.yml"
|
||||
- "misc/scripts/library-coverage/*.py"
|
||||
# input data files
|
||||
- "*/documentation/library-coverage/cwe-sink.csv"
|
||||
|
||||
2
.github/workflows/ql-for-ql-build.yml
vendored
2
.github/workflows/ql-for-ql-build.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
path: |
|
||||
ql/extractor-pack/
|
||||
ql/target/release/buramu
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||
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'
|
||||
uses: actions/cache@v3
|
||||
|
||||
2
.github/workflows/ruby-build.yml
vendored
2
.github/workflows/ruby-build.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
ruby/extractor/target/release/codeql-extractor-ruby
|
||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||
- uses: actions/cache@v3
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
with:
|
||||
|
||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -16,7 +16,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- rc/*
|
||||
- codeql-cli-*
|
||||
push:
|
||||
paths:
|
||||
- "swift/**"
|
||||
@@ -31,7 +30,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- rc/*
|
||||
- codeql-cli-*
|
||||
|
||||
jobs:
|
||||
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
||||
|
||||
2
.github/workflows/sync-files.yml
vendored
2
.github/workflows/sync-files.yml
vendored
@@ -17,6 +17,4 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check synchronized files
|
||||
run: python config/sync-files.py
|
||||
- name: Check dbscheme fragments
|
||||
run: python config/sync-dbscheme-fragments.py
|
||||
|
||||
|
||||
18
.vscode/tasks.json
vendored
18
.vscode/tasks.json
vendored
@@ -22,22 +22,6 @@
|
||||
"command": "${config:python.pythonPath}",
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Accept .expected changes from CI",
|
||||
"type": "process",
|
||||
// Non-Windows OS will usually have Python 3 already installed at /usr/bin/python3.
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"misc/scripts/accept-expected-changes-from-ci.py"
|
||||
],
|
||||
"group": "build",
|
||||
"windows": {
|
||||
// On Windows, use whatever Python interpreter is configured for this workspace. The default is
|
||||
// just `python`, so if Python is already on the path, this will find it.
|
||||
"command": "${config:python.pythonPath}",
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||
|
||||
# ML-powered queries
|
||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||
@@ -39,6 +40,3 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||
/.github/workflows/ruby-* @github/codeql-ruby
|
||||
/.github/workflows/swift.yml @github/codeql-swift
|
||||
|
||||
# Misc
|
||||
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"files": [
|
||||
"javascript/ql/lib/semmlecode.javascript.dbscheme",
|
||||
"python/ql/lib/semmlecode.python.dbscheme",
|
||||
"ruby/ql/lib/ruby.dbscheme",
|
||||
"ql/ql/src/ql.dbscheme"
|
||||
],
|
||||
"fragments": [
|
||||
"/*- External data -*/",
|
||||
"/*- Files and folders -*/",
|
||||
"/*- Diagnostic messages -*/",
|
||||
"/*- Diagnostic messages: severity -*/",
|
||||
"/*- Source location prefix -*/",
|
||||
"/*- Lines of code -*/",
|
||||
"/*- Configuration files with key value pairs -*/",
|
||||
"/*- YAML -*/",
|
||||
"/*- XML Files -*/",
|
||||
"/*- XML: sourceline -*/",
|
||||
"/*- DEPRECATED: External defects and metrics -*/",
|
||||
"/*- DEPRECATED: Snapshot date -*/",
|
||||
"/*- DEPRECATED: Duplicate code -*/",
|
||||
"/*- DEPRECATED: Version control data -*/",
|
||||
"/*- JavaScript-specific part -*/",
|
||||
"/*- Ruby dbscheme -*/",
|
||||
"/*- Erb dbscheme -*/",
|
||||
"/*- QL dbscheme -*/",
|
||||
"/*- Dbscheme dbscheme -*/",
|
||||
"/*- Yaml dbscheme -*/",
|
||||
"/*- Blame dbscheme -*/",
|
||||
"/*- JSON dbscheme -*/",
|
||||
"/*- Python dbscheme -*/"
|
||||
]
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
|
||||
@@ -511,8 +512,7 @@
|
||||
"SensitiveDataHeuristics Python/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
|
||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
||||
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||
],
|
||||
"CFG": [
|
||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
@@ -599,4 +599,4 @@
|
||||
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
|
||||
|
||||
def make_groups(blocks):
|
||||
groups = {}
|
||||
for block in blocks:
|
||||
groups.setdefault("".join(block["lines"]), []).append(block)
|
||||
return list(groups.values())
|
||||
|
||||
|
||||
def validate_fragments(fragments):
|
||||
ok = True
|
||||
for header, blocks in fragments.items():
|
||||
groups = make_groups(blocks)
|
||||
if len(groups) > 1:
|
||||
ok = False
|
||||
print("Warning: dbscheme fragments with header '{}' are different for {}".format(header, ["{}:{}:{}".format(
|
||||
group[0]["file"], group[0]["start"], group[0]["end"]) for group in groups]))
|
||||
return ok
|
||||
|
||||
|
||||
def main():
|
||||
script_path = os.path.realpath(__file__)
|
||||
script_dir = os.path.dirname(script_path)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog=os.path.basename(script_path),
|
||||
description='Sync dbscheme fragments across files.'
|
||||
)
|
||||
parser.add_argument('files', metavar='dbscheme_file', type=pathlib.Path, nargs='*', default=[],
|
||||
help='dbscheme files to check')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(os.path.join(script_dir, "dbscheme-fragments.json"), "r") as f:
|
||||
config = json.load(f)
|
||||
|
||||
fragment_headers = set(config["fragments"])
|
||||
fragments = {}
|
||||
ok = True
|
||||
for file in args.files + config["files"]:
|
||||
with open(os.path.join(os.path.dirname(script_dir), file), "r") as dbscheme:
|
||||
header = None
|
||||
line_number = 1
|
||||
block = {"file": file, "start": line_number,
|
||||
"end": None, "lines": []}
|
||||
|
||||
def end_block():
|
||||
block["end"] = line_number - 1
|
||||
if len(block["lines"]) > 0:
|
||||
if header is None:
|
||||
if re.match(r'(?m)\A(\s|//.*$|/\*(\**[^\*])*\*+/)*\Z', "".join(block["lines"])):
|
||||
# Ignore comments at the beginning of the file
|
||||
pass
|
||||
else:
|
||||
ok = False
|
||||
print("Warning: dbscheme fragment without header: {}:{}:{}".format(
|
||||
block["file"], block["start"], block["end"]))
|
||||
else:
|
||||
fragments.setdefault(header, []).append(block)
|
||||
for line in dbscheme:
|
||||
m = re.match(r"^\/\*-.*-\*\/$", line)
|
||||
if m:
|
||||
end_block()
|
||||
header = line.strip()
|
||||
if header not in fragment_headers:
|
||||
ok = False
|
||||
print("Warning: unknown header for dbscheme fragment: '{}': {}:{}".format(
|
||||
header, file, line_number))
|
||||
block = {"file": file, "start": line_number,
|
||||
"end": None, "lines": []}
|
||||
block["lines"].append(line)
|
||||
line_number += 1
|
||||
block["lines"].append('\n')
|
||||
line_number += 1
|
||||
end_block()
|
||||
if not ok or not validate_fragments(fragments):
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
|
||||
## 0.7.1
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
|
||||
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `CodeDuplication.qll` file.
|
||||
@@ -11,5 +11,4 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
|
||||
@@ -1,29 +1,10 @@
|
||||
/**
|
||||
* Provides a library for global (inter-procedural) data flow analysis of two
|
||||
* values "simultaneously". This can be used, for example, if you want to track
|
||||
* a memory allocation as well as the size of the allocation.
|
||||
*
|
||||
* Intuitively, you can think of this as regular dataflow, but where each node
|
||||
* in the dataflow graph has been replaced by a pair of nodes `(node1, node2)`,
|
||||
* and two node pairs `(n11, n12)`, `(n21, n22)` is then connected by a dataflow
|
||||
* edge if there's a regular dataflow edge between `n11` and `n21`, and `n12`
|
||||
* and `n22`.
|
||||
*
|
||||
* Note that the above intuition does not reflect the actual implementation.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* Provides classes for performing global (inter-procedural) data flow analyses
|
||||
* on a product dataflow graph.
|
||||
*/
|
||||
module ProductFlow {
|
||||
/** An input configuration for product data-flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `(source1, source2)` is a relevant data flow source.
|
||||
@@ -89,9 +70,6 @@ module ProductFlow {
|
||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> {
|
||||
private module StateConfig implements StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
@@ -160,7 +138,6 @@ module ProductFlow {
|
||||
import GlobalWithState<StateConfig>
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState1;
|
||||
@@ -270,9 +247,6 @@ module ProductFlow {
|
||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> {
|
||||
class PathNode1 = Flow1::PathNode;
|
||||
|
||||
@@ -286,7 +260,6 @@ module ProductFlow {
|
||||
|
||||
class FlowState2 = Config::FlowState2;
|
||||
|
||||
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
|
||||
predicate flowPath(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||
) {
|
||||
@@ -317,9 +290,9 @@ module ProductFlow {
|
||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
||||
}
|
||||
|
||||
private module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||
module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||
|
||||
private module Config2 implements DataFlow::StateConfigSig {
|
||||
module Config2 implements DataFlow::StateConfigSig {
|
||||
class FlowState = FlowState2;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
@@ -349,90 +322,27 @@ module ProductFlow {
|
||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
||||
}
|
||||
|
||||
private module Flow2 = DataFlow::GlobalWithState<Config2>;
|
||||
|
||||
private predicate isSourcePair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
|
||||
}
|
||||
|
||||
private predicate isSinkPair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
Config::isSinkPair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate fwdReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
isSourcePair(node1, node2)
|
||||
or
|
||||
fwdIsSuccessor(_, _, node1, node2)
|
||||
}
|
||||
module Flow2 = DataFlow::GlobalWithState<Config2>;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdIsSuccessorExit(
|
||||
Flow1::PathNode mid1, Flow2::PathNode mid2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||
private predicate reachableInterprocEntry(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
|
||||
) {
|
||||
isSinkPair(mid1, mid2) and
|
||||
succ1 = mid1 and
|
||||
succ2 = mid2
|
||||
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||
node1 = source1 and
|
||||
node2 = source2
|
||||
or
|
||||
interprocEdgePair(mid1, mid2, succ1, succ2)
|
||||
}
|
||||
|
||||
private predicate fwdIsSuccessor1(
|
||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
|
||||
Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||
) {
|
||||
fwdReachableInterprocEntry(pred1, pred2) and
|
||||
localPathStep1*(pred1, mid1) and
|
||||
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
|
||||
}
|
||||
|
||||
private predicate fwdIsSuccessor2(
|
||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
|
||||
Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||
) {
|
||||
fwdReachableInterprocEntry(pred1, pred2) and
|
||||
localPathStep2*(pred2, mid2) and
|
||||
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate fwdIsSuccessor(
|
||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||
) {
|
||||
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
||||
fwdIsSuccessor1(pred1, pred2, mid1, mid2, succ1, succ2) and
|
||||
fwdIsSuccessor2(pred1, pred2, mid1, mid2, succ1, succ2)
|
||||
exists(
|
||||
Flow1::PathNode midEntry1, Flow2::PathNode midEntry2, Flow1::PathNode midExit1,
|
||||
Flow2::PathNode midExit2
|
||||
|
|
||||
reachableInterprocEntry(source1, source2, midEntry1, midEntry2) and
|
||||
interprocEdgePair(midExit1, midExit2, node1, node2) and
|
||||
localPathStep1*(midEntry1, midExit1) and
|
||||
localPathStep2*(midEntry2, midExit2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate revReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
fwdReachableInterprocEntry(node1, node2) and
|
||||
isSinkPair(node1, node2)
|
||||
or
|
||||
exists(Flow1::PathNode succ1, Flow2::PathNode succ2 |
|
||||
revReachableInterprocEntry(succ1, succ2) and
|
||||
fwdIsSuccessor(node1, node2, succ1, succ2)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TNodePair =
|
||||
TMkNodePair(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
revReachableInterprocEntry(node1, node2)
|
||||
}
|
||||
|
||||
private predicate pathSucc(TNodePair n1, TNodePair n2) {
|
||||
exists(Flow1::PathNode n11, Flow2::PathNode n12, Flow1::PathNode n21, Flow2::PathNode n22 |
|
||||
n1 = TMkNodePair(n11, n12) and
|
||||
n2 = TMkNodePair(n21, n22) and
|
||||
fwdIsSuccessor(n11, n12, n21, n22)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(TNodePair n1, TNodePair n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
|
||||
Flow1::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
@@ -564,14 +474,11 @@ module ProductFlow {
|
||||
private predicate reachable(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||
) {
|
||||
isSourcePair(source1, source2) and
|
||||
isSinkPair(sink1, sink2) and
|
||||
exists(TNodePair n1, TNodePair n2 |
|
||||
n1 = TMkNodePair(source1, source2) and
|
||||
n2 = TMkNodePair(sink1, sink2)
|
||||
|
|
||||
pathSuccPlus(n1, n2) or
|
||||
n1 = n2
|
||||
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
||||
reachableInterprocEntry(source1, source2, mid1, mid2) and
|
||||
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||
localPathStep1*(mid1, sink1) and
|
||||
localPathStep2*(mid2, sink2)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,20 @@ class Class extends UserType {
|
||||
/** Holds if this class, struct or union has a constructor. */
|
||||
predicate hasConstructor() { exists(this.getAConstructor()) }
|
||||
|
||||
/**
|
||||
* Holds if this class has a copy constructor that is either explicitly
|
||||
* declared (though possibly `= delete`) or is auto-generated, non-trivial
|
||||
* and called from somewhere.
|
||||
*
|
||||
* DEPRECATED: There is more than one reasonable definition of what it means
|
||||
* to have a copy constructor, and we do not want to promote one particular
|
||||
* definition by naming it with this predicate. Having a copy constructor
|
||||
* could mean that such a member is declared or defined in the source or that
|
||||
* it is callable by a particular caller. For C++11, there's also a question
|
||||
* of whether to include members that are defaulted or deleted.
|
||||
*/
|
||||
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
||||
|
||||
/**
|
||||
* Like accessOfBaseMember but returns multiple results if there are multiple
|
||||
* paths to `base` through the inheritance graph.
|
||||
|
||||
@@ -34,7 +34,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
||||
* Gets the name of the macro. For example, `MAX` in
|
||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||
*/
|
||||
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
|
||||
string getName() { result = this.getHead().splitAt("(", 0) }
|
||||
|
||||
/** Holds if the macro has name `name`. */
|
||||
predicate hasName(string name) { this.getName() = name }
|
||||
|
||||
@@ -230,12 +230,8 @@ class GlobalNamespace extends Namespace {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C++ `std::` namespace and its inline namespaces.
|
||||
* The C++ `std::` namespace.
|
||||
*/
|
||||
class StdNamespace extends Namespace {
|
||||
StdNamespace() {
|
||||
this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace
|
||||
or
|
||||
this.isInline() and this.getParentNamespace() instanceof StdNamespace
|
||||
}
|
||||
StdNamespace() { this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace }
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
predicate shouldPrintFunction(Function func) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||
|
||||
private predicate shouldPrintFunction(Function func) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
@@ -236,6 +239,9 @@ class PrintAstNode extends TPrintAstNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstNode */
|
||||
deprecated class PrintASTNode = PrintAstNode;
|
||||
|
||||
/**
|
||||
* Class that restricts the elements that we compute `qlClass` for.
|
||||
*/
|
||||
@@ -280,6 +286,9 @@ abstract class BaseAstNode extends PrintAstNode {
|
||||
deprecated Locatable getAST() { result = this.getAst() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for BaseAstNode */
|
||||
deprecated class BaseASTNode = BaseAstNode;
|
||||
|
||||
/**
|
||||
* A node representing an AST node other than a `DeclarationEntry`.
|
||||
*/
|
||||
@@ -287,6 +296,9 @@ abstract class AstNode extends BaseAstNode, TAstNode {
|
||||
AstNode() { this = TAstNode(ast) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstNode */
|
||||
deprecated class ASTNode = AstNode;
|
||||
|
||||
/**
|
||||
* A node representing an `Expr`.
|
||||
*/
|
||||
|
||||
@@ -1699,28 +1699,7 @@ class AutoType extends TemplateParameter {
|
||||
|
||||
private predicate suppressUnusedThis(Type t) { any() }
|
||||
|
||||
/**
|
||||
* A source code location referring to a user-defined type.
|
||||
*
|
||||
* Note that only _user-defined_ types have `TypeMention`s. In particular,
|
||||
* built-in types, and derived types with built-in types as their base don't
|
||||
* have any `TypeMention`s. For example, given
|
||||
* ```cpp
|
||||
* struct S { ... };
|
||||
* void f(S s1, int i1) {
|
||||
* S s2;
|
||||
* S* s3;
|
||||
* S& s4 = s2;
|
||||
* decltype(s2) s5;
|
||||
*
|
||||
* int i2;
|
||||
* int* i3;
|
||||
* int i4[10];
|
||||
* }
|
||||
* ```
|
||||
* there will be a `TypeMention` for the mention of `S` at `S s1`, `S s2`, and `S& s4 = s2`,
|
||||
* but not at `decltype(s2) s5`. Additionally, there will be no `TypeMention`s for `int`.
|
||||
*/
|
||||
/** A source code location referring to a type */
|
||||
class TypeMention extends Locatable, @type_mention {
|
||||
override string toString() { result = "type mention" }
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ library class StandardSsa extends SsaHelper {
|
||||
StandardSsa() { this = 0 }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StandardSsa */
|
||||
deprecated class StandardSSA = StandardSsa;
|
||||
|
||||
/**
|
||||
* A definition of one or more SSA variables, including phi node definitions.
|
||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||
|
||||
@@ -312,3 +312,6 @@ library class SsaHelper extends int {
|
||||
ssa_use(v, result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SsaHelper */
|
||||
deprecated class SSAHelper = SsaHelper;
|
||||
|
||||
@@ -1385,6 +1385,9 @@ private module Cached {
|
||||
conditionalSuccessor(n1, _, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgSuccessor */
|
||||
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
@@ -1395,6 +1398,9 @@ private module Cached {
|
||||
not conditionalSuccessor(n1, false, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
|
||||
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
@@ -1404,4 +1410,7 @@ private module Cached {
|
||||
conditionalSuccessor(n1, false, n2) and
|
||||
not conditionalSuccessor(n1, true, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
|
||||
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
|
||||
}
|
||||
|
||||
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
|
||||
);
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
|
||||
|
||||
bindingset[typ, contentType]
|
||||
predicate typecheckStore(Typ typ, DataFlowType contentType);
|
||||
@@ -1199,21 +1199,17 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
|
||||
}
|
||||
|
||||
private predicate fwdFlow1(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t0, ap, t)
|
||||
filter(node, state, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
@@ -1343,11 +1339,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
|
||||
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
|
||||
cons = apCons(c, t1, tail)
|
||||
or
|
||||
exists(Typ t0 |
|
||||
typeStrengthen(t0, cons, t2) and
|
||||
fwdFlowConsCand(t0, cons, c, t1, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1368,7 +1359,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
|
||||
) {
|
||||
exists(ApHeadContent apc |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
|
||||
apc = getHeadContent(ap) and
|
||||
readStepCand0(node1, apc, c, node2)
|
||||
)
|
||||
@@ -1529,14 +1520,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
revFlow0(node, state, returnCtx, returnAp, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _)
|
||||
fwdFlow(node, state, _, _, _, _, _, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap) and
|
||||
sinkNode(node, state) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1789,13 +1780,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
) {
|
||||
fwd = true and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
|
||||
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
|
||||
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
|
||||
@@ -1972,10 +1963,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
PrevStage::revFlowState(state) and
|
||||
t0 = t and
|
||||
exists(t) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state) and
|
||||
(
|
||||
@@ -2206,8 +2197,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import BooleanCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
exists(lcc)
|
||||
@@ -2227,16 +2218,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
exists(state) and
|
||||
// We can get away with not using type strengthening here, since we aren't
|
||||
// going to use the tracked types in the construction of Stage 4 access
|
||||
// paths. For Stage 4 and onwards, the tracked types must be consistent as
|
||||
// the cons candidates including types are used to construct subsequent
|
||||
// access path approximations.
|
||||
t0 = t and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2256,16 +2241,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
import MkStage<Stage2>::Stage<Stage3Param>
|
||||
}
|
||||
|
||||
bindingset[node, t0]
|
||||
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
|
||||
if castingNodeEx(node)
|
||||
then
|
||||
exists(DataFlowType nt | nt = node.getDataFlowType() |
|
||||
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
|
||||
)
|
||||
else t = t0
|
||||
}
|
||||
|
||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
private module PrevStage = Stage3;
|
||||
|
||||
@@ -2299,8 +2274,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2358,11 +2333,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
exists(state) and
|
||||
not clear(node, ap) and
|
||||
strengthenType(node, t0, t) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2390,7 +2365,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
exists(AccessPathFront apf |
|
||||
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
|
||||
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
|
||||
apf, _)
|
||||
apf)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2604,8 +2579,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import LocalCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2634,9 +2609,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
strengthenType(node, t0, t) and
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
exists(state) and
|
||||
exists(ap)
|
||||
}
|
||||
@@ -2657,7 +2632,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
Stage5::parameterMayFlowThrough(p, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
|
||||
TAccessPathApproxSome(apa), _, apa0, _)
|
||||
TAccessPathApproxSome(apa), _, apa0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2674,7 +2649,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
|
||||
exists(AccessPathApprox apa | ap.getApprox() = apa |
|
||||
Stage5::parameterMayFlowThrough(p, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
|
||||
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
|
||||
Stage5::revFlow(p, state, _)
|
||||
)
|
||||
}
|
||||
@@ -2845,7 +2820,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TAccessPathNil()
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
pathStep(_, node, state, cc, sc, t, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
@@ -3363,24 +3340,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = mid.getAp()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
exists(DataFlowType t0 |
|
||||
pathStep0(mid, node, state, cc, sc, t0, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
strengthenType(node, t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep0(
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
@@ -3998,7 +3964,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TPartialNil() and
|
||||
exists(explorationLimit())
|
||||
or
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
distSrc(node.getEnclosingCallable()) <= explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
@@ -4024,20 +3990,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
private predicate partialPathNodeMk0(
|
||||
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep1(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
|
||||
PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
not fullBarrier(node) and
|
||||
not stateBarrier(node, state) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
@@ -4045,14 +4002,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
strengthenType(node, t0, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathTypeStrengthen(
|
||||
DataFlowType t0, PartialAccessPath ap, DataFlowType t
|
||||
) {
|
||||
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), t)
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4231,8 +4183,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep0(
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
@@ -4358,11 +4309,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
|
||||
) {
|
||||
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
|
||||
or
|
||||
exists(DataFlowType t0 |
|
||||
partialPathTypeStrengthen(t0, ap2, t2) and
|
||||
apConsFwd(t1, ap1, c, t0, ap2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -205,8 +205,6 @@ predicate clearsContent(Node n, Content c) {
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
|
||||
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
|
||||
);
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
|
||||
|
||||
bindingset[typ, contentType]
|
||||
predicate typecheckStore(Typ typ, DataFlowType contentType);
|
||||
@@ -1199,21 +1199,17 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
|
||||
}
|
||||
|
||||
private predicate fwdFlow1(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t0, ap, t)
|
||||
filter(node, state, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
@@ -1343,11 +1339,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
|
||||
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
|
||||
cons = apCons(c, t1, tail)
|
||||
or
|
||||
exists(Typ t0 |
|
||||
typeStrengthen(t0, cons, t2) and
|
||||
fwdFlowConsCand(t0, cons, c, t1, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1368,7 +1359,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
|
||||
) {
|
||||
exists(ApHeadContent apc |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
|
||||
apc = getHeadContent(ap) and
|
||||
readStepCand0(node1, apc, c, node2)
|
||||
)
|
||||
@@ -1529,14 +1520,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
revFlow0(node, state, returnCtx, returnAp, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _)
|
||||
fwdFlow(node, state, _, _, _, _, _, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap) and
|
||||
sinkNode(node, state) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1789,13 +1780,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
) {
|
||||
fwd = true and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
|
||||
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
|
||||
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
|
||||
@@ -1972,10 +1963,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
PrevStage::revFlowState(state) and
|
||||
t0 = t and
|
||||
exists(t) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state) and
|
||||
(
|
||||
@@ -2206,8 +2197,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import BooleanCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
exists(lcc)
|
||||
@@ -2227,16 +2218,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
exists(state) and
|
||||
// We can get away with not using type strengthening here, since we aren't
|
||||
// going to use the tracked types in the construction of Stage 4 access
|
||||
// paths. For Stage 4 and onwards, the tracked types must be consistent as
|
||||
// the cons candidates including types are used to construct subsequent
|
||||
// access path approximations.
|
||||
t0 = t and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2256,16 +2241,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
import MkStage<Stage2>::Stage<Stage3Param>
|
||||
}
|
||||
|
||||
bindingset[node, t0]
|
||||
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
|
||||
if castingNodeEx(node)
|
||||
then
|
||||
exists(DataFlowType nt | nt = node.getDataFlowType() |
|
||||
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
|
||||
)
|
||||
else t = t0
|
||||
}
|
||||
|
||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
private module PrevStage = Stage3;
|
||||
|
||||
@@ -2299,8 +2274,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2358,11 +2333,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
exists(state) and
|
||||
not clear(node, ap) and
|
||||
strengthenType(node, t0, t) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2390,7 +2365,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
exists(AccessPathFront apf |
|
||||
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
|
||||
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
|
||||
apf, _)
|
||||
apf)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2604,8 +2579,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import LocalCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2634,9 +2609,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
strengthenType(node, t0, t) and
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
exists(state) and
|
||||
exists(ap)
|
||||
}
|
||||
@@ -2657,7 +2632,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
Stage5::parameterMayFlowThrough(p, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
|
||||
TAccessPathApproxSome(apa), _, apa0, _)
|
||||
TAccessPathApproxSome(apa), _, apa0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2674,7 +2649,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
|
||||
exists(AccessPathApprox apa | ap.getApprox() = apa |
|
||||
Stage5::parameterMayFlowThrough(p, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
|
||||
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
|
||||
Stage5::revFlow(p, state, _)
|
||||
)
|
||||
}
|
||||
@@ -2845,7 +2820,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TAccessPathNil()
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
pathStep(_, node, state, cc, sc, t, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
@@ -3363,24 +3340,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = mid.getAp()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
exists(DataFlowType t0 |
|
||||
pathStep0(mid, node, state, cc, sc, t0, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
strengthenType(node, t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep0(
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
@@ -3998,7 +3964,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TPartialNil() and
|
||||
exists(explorationLimit())
|
||||
or
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
distSrc(node.getEnclosingCallable()) <= explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
@@ -4024,20 +3990,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
private predicate partialPathNodeMk0(
|
||||
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep1(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
|
||||
PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
not fullBarrier(node) and
|
||||
not stateBarrier(node, state) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
@@ -4045,14 +4002,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
strengthenType(node, t0, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathTypeStrengthen(
|
||||
DataFlowType t0, PartialAccessPath ap, DataFlowType t
|
||||
) {
|
||||
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), t)
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4231,8 +4183,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep0(
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
@@ -4358,11 +4309,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
|
||||
) {
|
||||
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
|
||||
or
|
||||
exists(DataFlowType t0 |
|
||||
partialPathTypeStrengthen(t0, ap2, t2) and
|
||||
apConsFwd(t1, ap1, c, t0, ap2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -210,8 +210,8 @@ class IndirectOperand extends Node {
|
||||
this.(RawIndirectOperand).getOperand() = operand and
|
||||
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
|
||||
or
|
||||
nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex),
|
||||
indirectionIndex - 1)
|
||||
this.(OperandNode).getOperand() =
|
||||
Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex)
|
||||
}
|
||||
|
||||
/** Gets the underlying operand. */
|
||||
@@ -250,8 +250,8 @@ class IndirectInstruction extends Node {
|
||||
this.(RawIndirectInstruction).getInstruction() = instr and
|
||||
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
|
||||
or
|
||||
nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex),
|
||||
indirectionIndex - 1)
|
||||
this.(InstructionNode).getInstruction() =
|
||||
Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
@@ -753,8 +753,6 @@ predicate clearsContent(Node n, Content c) {
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
DataFlowType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
|
||||
@@ -1640,15 +1640,8 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
|
||||
localFlow(instructionNode(e1), instructionNode(e2))
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Ideally this module would be private, but the `asExprInternal` predicate is
|
||||
* needed in `DefaultTaintTrackingImpl`. Once `DefaultTaintTrackingImpl` is gone
|
||||
* we can make this module private.
|
||||
*/
|
||||
cached
|
||||
module ExprFlowCached {
|
||||
private module ExprFlowCached {
|
||||
/**
|
||||
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
|
||||
* `e` is the result of loading from the `PointerArithmeticInstruction`.
|
||||
@@ -1699,8 +1692,7 @@ module ExprFlowCached {
|
||||
* `x[i]` steps to the expression `x[i - 1]` without traversing the
|
||||
* entire chain.
|
||||
*/
|
||||
cached
|
||||
Expr asExprInternal(Node n) {
|
||||
private Expr asExpr(Node n) {
|
||||
isIndirectBaseOfArrayAccess(n, result)
|
||||
or
|
||||
not isIndirectBaseOfArrayAccess(n, _) and
|
||||
@@ -1712,7 +1704,7 @@ module ExprFlowCached {
|
||||
* dataflow step.
|
||||
*/
|
||||
private predicate localStepFromNonExpr(Node n1, Node n2) {
|
||||
not exists(asExprInternal(n1)) and
|
||||
not exists(asExpr(n1)) and
|
||||
localFlowStep(n1, n2)
|
||||
}
|
||||
|
||||
@@ -1723,7 +1715,7 @@ module ExprFlowCached {
|
||||
pragma[nomagic]
|
||||
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
|
||||
localStepFromNonExpr*(n1, n2) and
|
||||
e2 = asExprInternal(n2)
|
||||
e2 = asExpr(n2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1734,7 +1726,7 @@ module ExprFlowCached {
|
||||
exists(Node mid |
|
||||
localFlowStep(n1, mid) and
|
||||
localStepsToExpr(mid, n2, e2) and
|
||||
e1 = asExprInternal(n1)
|
||||
e1 = asExpr(n1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
|
||||
}
|
||||
|
||||
private DataFlow::Node getNodeForExpr(Expr node) {
|
||||
node = DataFlow::ExprFlowCached::asExprInternal(result)
|
||||
result = DataFlow::exprNode(node)
|
||||
or
|
||||
// Some of the sources in `isUserInput` are intended to match the value of
|
||||
// an expression, while others (those modeled below) are intended to match
|
||||
@@ -221,7 +221,7 @@ private module Cached {
|
||||
predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
// don't use dataflow into taint sources, as this leads to duplicate results.
|
||||
exists(Expr source | isUserInput(source, _) |
|
||||
source = DataFlow::ExprFlowCached::asExprInternal(node)
|
||||
node = DataFlow::exprNode(source)
|
||||
or
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Print the dataflow local store steps in IR dumps.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import PrintIRUtilities
|
||||
|
||||
/** A property provider for local IR dataflow store steps. */
|
||||
class FieldFlowPropertyProvider extends IRPropertyProvider {
|
||||
override string getOperandProperty(Operand operand, string key) {
|
||||
exists(PostFieldUpdateNode pfun, Content content |
|
||||
key = "store " + content.toString() and
|
||||
operand = pfun.getPreUpdateNode().(IndirectOperand).getOperand() and
|
||||
result =
|
||||
strictconcat(string element, Node node |
|
||||
storeStep(node, content, pfun) and
|
||||
element = nodeId(node, _, _)
|
||||
|
|
||||
element, ", "
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Node node2, Content content |
|
||||
key = "read " + content.toString() and
|
||||
operand = node2.(IndirectOperand).getOperand() and
|
||||
result =
|
||||
strictconcat(string element, Node node1 |
|
||||
readStep(node1, content, node2) and
|
||||
element = nodeId(node1, _, _)
|
||||
|
|
||||
element, ", "
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,119 @@
|
||||
private import cpp
|
||||
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
|
||||
// that the cached IR gets the same checksum here as it does in queries that use
|
||||
// `ValueNumbering` without `DataFlow`.
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import SsaInternals as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
/**
|
||||
* Gets the local dataflow from other nodes in the same function to this node.
|
||||
*/
|
||||
private string getFromFlow(Node node2, int order1, int order2) {
|
||||
exists(Node node1 |
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
result = nodeId(node1, order1, order2)
|
||||
private string getFromFlow(DataFlow::Node useNode, int order1, int order2) {
|
||||
exists(DataFlow::Node defNode, string prefix |
|
||||
(
|
||||
simpleLocalFlowStep(defNode, useNode) and prefix = ""
|
||||
or
|
||||
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
|
||||
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
|
||||
prefix = "+"
|
||||
) and
|
||||
if defNode.asInstruction() = useNode.asOperand().getAnyDef()
|
||||
then
|
||||
// Shorthand for flow from the def of this operand.
|
||||
result = prefix + "def" and
|
||||
order1 = -1 and
|
||||
order2 = 0
|
||||
else
|
||||
if defNode.asOperand().getUse() = useNode.asInstruction()
|
||||
then
|
||||
// Shorthand for flow from an operand of this instruction
|
||||
result = prefix + defNode.asOperand().getDumpId() and
|
||||
order1 = -1 and
|
||||
order2 = defNode.asOperand().getDumpSortOrder()
|
||||
else result = prefix + nodeId(defNode, order1, order2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local dataflow from this node to other nodes in the same function.
|
||||
*/
|
||||
private string getToFlow(Node node1, int order1, int order2) {
|
||||
exists(Node node2 |
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
result = nodeId(node2, order1, order2)
|
||||
private string getToFlow(DataFlow::Node defNode, int order1, int order2) {
|
||||
exists(DataFlow::Node useNode, string prefix |
|
||||
(
|
||||
simpleLocalFlowStep(defNode, useNode) and prefix = ""
|
||||
or
|
||||
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
|
||||
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
|
||||
prefix = "+"
|
||||
) and
|
||||
if useNode.asInstruction() = defNode.asOperand().getUse()
|
||||
then
|
||||
// Shorthand for flow to this operand's instruction.
|
||||
result = prefix + "result" and
|
||||
order1 = -1 and
|
||||
order2 = 0
|
||||
else result = prefix + nodeId(useNode, order1, order2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the properties of the dataflow node `node`.
|
||||
*/
|
||||
private string getNodeProperty(Node node, string key) {
|
||||
private string getNodeProperty(DataFlow::Node node, string key) {
|
||||
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
|
||||
// out of this node is printed as `@->dest`.
|
||||
key = "flow" and
|
||||
result =
|
||||
strictconcat(string flow, boolean to, int order1, int order2 |
|
||||
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
|
||||
flow = getFromFlow(node, order1, order2) + "->@" and to = false
|
||||
or
|
||||
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
||||
flow = "@->" + getToFlow(node, order1, order2) and to = true
|
||||
|
|
||||
flow, ", " order by to, order1, order2, flow
|
||||
)
|
||||
or
|
||||
// Is this node a dataflow sink?
|
||||
key = "sink" and
|
||||
any(DataFlow::Configuration cfg).isSink(node) and
|
||||
result = "true"
|
||||
or
|
||||
// Is this node a dataflow source?
|
||||
key = "source" and
|
||||
any(DataFlow::Configuration cfg).isSource(node) and
|
||||
result = "true"
|
||||
or
|
||||
// Is this node a dataflow barrier, and if so, what kind?
|
||||
key = "barrier" and
|
||||
result =
|
||||
strictconcat(string kind |
|
||||
any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full"
|
||||
or
|
||||
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
|
||||
or
|
||||
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
|
||||
|
|
||||
kind, ", "
|
||||
)
|
||||
// or
|
||||
// // Is there partial flow from a source to this node?
|
||||
// // This property will only be emitted if partial flow is enabled by overriding
|
||||
// // `DataFlow::Configuration::explorationLimit()`.
|
||||
// key = "pflow" and
|
||||
// result =
|
||||
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
|
||||
// int order1, int order2 |
|
||||
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
|
||||
// destNode.getNode() = node and
|
||||
// // Only print flow from a source in the same function.
|
||||
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
||||
// |
|
||||
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
|
||||
// order by
|
||||
// order1, order2, dist desc
|
||||
// )
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,21 +121,16 @@ private string getNodeProperty(Node node, string key) {
|
||||
*/
|
||||
class LocalFlowPropertyProvider extends IRPropertyProvider {
|
||||
override string getOperandProperty(Operand operand, string key) {
|
||||
exists(Node node |
|
||||
operand = [node.asOperand(), node.(RawIndirectOperand).getOperand()] and
|
||||
exists(DataFlow::Node node |
|
||||
operand = node.asOperand() and
|
||||
result = getNodeProperty(node, key)
|
||||
)
|
||||
}
|
||||
|
||||
override string getInstructionProperty(Instruction instruction, string key) {
|
||||
exists(Node node |
|
||||
instruction = [node.asInstruction(), node.(RawIndirectInstruction).getInstruction()]
|
||||
|
|
||||
exists(DataFlow::Node node |
|
||||
instruction = node.asInstruction() and
|
||||
result = getNodeProperty(node, key)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
|
||||
|
||||
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Print the dataflow local store steps in IR dumps.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
|
||||
// that the cached IR gets the same checksum here as it does in queries that use
|
||||
// `ValueNumbering` without `DataFlow`.
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import PrintIRUtilities
|
||||
|
||||
/**
|
||||
* Property provider for local IR dataflow store steps.
|
||||
*/
|
||||
class LocalFlowPropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instruction, string key) {
|
||||
exists(DataFlow::Node objectNode, Content content |
|
||||
key = "content[" + content.toString() + "]" and
|
||||
instruction = objectNode.asInstruction() and
|
||||
result =
|
||||
strictconcat(string element, DataFlow::Node fieldNode |
|
||||
storeStep(fieldNode, content, objectNode) and
|
||||
element = nodeId(fieldNode, _, _)
|
||||
|
|
||||
element, ", "
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3,59 +3,37 @@
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
|
||||
// that the cached IR gets the same checksum here as it does in queries that use
|
||||
// `ValueNumbering` without `DataFlow`.
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
|
||||
private string stars(int k) {
|
||||
k =
|
||||
[0 .. max([
|
||||
any(RawIndirectInstruction n).getIndirectionIndex(),
|
||||
any(RawIndirectOperand n).getIndirectionIndex()
|
||||
]
|
||||
)] and
|
||||
(if k = 0 then result = "" else result = "*" + stars(k - 1))
|
||||
}
|
||||
|
||||
string starsForNode(Node node) {
|
||||
result = stars(node.(IndirectInstruction).getIndirectionIndex())
|
||||
or
|
||||
result = stars(node.(IndirectOperand).getIndirectionIndex())
|
||||
or
|
||||
not node instanceof IndirectInstruction and
|
||||
not node instanceof IndirectOperand and
|
||||
result = ""
|
||||
}
|
||||
|
||||
private Instruction getInstruction(Node n, string stars) {
|
||||
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
|
||||
stars = starsForNode(n)
|
||||
}
|
||||
|
||||
private Operand getOperand(Node n, string stars) {
|
||||
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
|
||||
stars = starsForNode(n)
|
||||
}
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* Gets a short ID for an IR dataflow node.
|
||||
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
|
||||
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
|
||||
* instruction and a dot (e.g. `m128.left`).
|
||||
* - For `Variable`s, this is the qualified name of the variable.
|
||||
*/
|
||||
string nodeId(Node node, int order1, int order2) {
|
||||
exists(Instruction instruction, string stars | instruction = getInstruction(node, stars) |
|
||||
result = stars + instruction.getResultId() and
|
||||
string nodeId(DataFlow::Node node, int order1, int order2) {
|
||||
exists(Instruction instruction | instruction = node.asInstruction() |
|
||||
result = instruction.getResultId() and
|
||||
order1 = instruction.getBlock().getDisplayIndex() and
|
||||
order2 = instruction.getDisplayIndexInBlock()
|
||||
)
|
||||
or
|
||||
exists(Operand operand, Instruction instruction, string stars |
|
||||
operand = getOperand(node, stars) and
|
||||
exists(Operand operand, Instruction instruction |
|
||||
operand = node.asOperand() and
|
||||
instruction = operand.getUse()
|
||||
|
|
||||
result = stars + instruction.getResultId() + "." + operand.getDumpId() and
|
||||
result = instruction.getResultId() + "." + operand.getDumpId() and
|
||||
order1 = instruction.getBlock().getDisplayIndex() and
|
||||
order2 = instruction.getDisplayIndexInBlock()
|
||||
)
|
||||
or
|
||||
result = "var(" + node.asVariable().getQualifiedName() + ")" and
|
||||
order1 = 1000000 and
|
||||
order2 = 0
|
||||
}
|
||||
|
||||
@@ -364,25 +364,7 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
OperandBasedUse() { any() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
|
||||
// predicate's implementation.
|
||||
exists(BaseSourceVariableInstruction base | base = this.getBase() |
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirectionIndex, int indirection |
|
||||
indirectionIndex = this.getIndirectionIndex() and
|
||||
indirection = this.getIndirection() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, indirection, indirectionIndex) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
)
|
||||
operand.getUse() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
final Operand getOperand() { result = operand }
|
||||
@@ -675,16 +657,24 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
||||
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
|
||||
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
|
||||
*/
|
||||
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
|
||||
exists(DefOrUse defOrUse, Node adjusted |
|
||||
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||
nodeToDefOrUse(adjusted, defOrUse, _) and
|
||||
private predicate adjustForPointerArith(
|
||||
DefOrUse defOrUse, Node nodeFrom, UseOrPhi use, boolean uncertain
|
||||
) {
|
||||
nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and
|
||||
exists(Node adjusted |
|
||||
indirectConversionFlowStep*(adjusted, nodeFrom) and
|
||||
nodeToDefOrUse(adjusted, defOrUse, uncertain) and
|
||||
adjacentDefRead(defOrUse, use)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
|
||||
// `nodeFrom = any(PostUpdateNode pun).getPreUpdateNode()` is implied by adjustedForPointerArith.
|
||||
exists(UseOrPhi use |
|
||||
adjustForPointerArith(defOrUse, nodeFrom, use, uncertain) and
|
||||
useToNode(use, nodeTo)
|
||||
or
|
||||
not nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and
|
||||
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
|
||||
adjacentDefRead(defOrUse, use) and
|
||||
useToNode(use, nodeTo) and
|
||||
@@ -729,19 +719,14 @@ predicate ssaFlow(Node nodeFrom, Node nodeTo) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isArgumentOfCallable(DataFlowCall call, ArgumentNode arg) {
|
||||
arg.argumentOf(call, _)
|
||||
}
|
||||
|
||||
/** Holds if there is def-use or use-use flow from `pun` to `nodeTo`. */
|
||||
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
|
||||
exists(UseOrPhi use, Node preUpdate |
|
||||
adjustForPointerArith(pun, use) and
|
||||
useToNode(use, nodeTo) and
|
||||
exists(Node preUpdate, Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
|
||||
preUpdate = pun.getPreUpdateNode() and
|
||||
not exists(DataFlowCall call |
|
||||
isArgumentOfCallable(call, preUpdate) and isArgumentOfCallable(call, nodeTo)
|
||||
)
|
||||
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain)
|
||||
|
|
||||
if uncertain = true
|
||||
then preUpdate = [nFrom, getAPriorDefinition(defOrUse)]
|
||||
else preUpdate = nFrom
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -144,20 +144,6 @@ class AllocationInstruction extends CallInstruction {
|
||||
AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction }
|
||||
}
|
||||
|
||||
private predicate isIndirectionType(Type t) { t instanceof Indirection }
|
||||
|
||||
private predicate hasUnspecifiedBaseType(Indirection t, Type base) {
|
||||
base = t.getBaseType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t2` is the same type as `t1`, but after stripping away `result` number
|
||||
* of indirections.
|
||||
* Furthermore, specifies in `t2` been deeply stripped and typedefs has been resolved.
|
||||
*/
|
||||
private int getNumberOfIndirectionsImpl(Type t1, Type t2) =
|
||||
shortestDistances(isIndirectionType/1, hasUnspecifiedBaseType/2)(t1, t2, result)
|
||||
|
||||
/**
|
||||
* An abstract class for handling indirections.
|
||||
*
|
||||
@@ -176,10 +162,7 @@ abstract class Indirection extends Type {
|
||||
* For example, the number of indirections of a variable `p` of type
|
||||
* `int**` is `3` (i.e., `p`, `*p` and `**p`).
|
||||
*/
|
||||
final int getNumberOfIndirections() {
|
||||
result =
|
||||
getNumberOfIndirectionsImpl(this.getType(), any(Type end | not end instanceof Indirection))
|
||||
}
|
||||
abstract int getNumberOfIndirections();
|
||||
|
||||
/**
|
||||
* Holds if `deref` is an instruction that behaves as a `LoadInstruction`
|
||||
@@ -217,11 +200,19 @@ private class PointerOrArrayOrReferenceTypeIndirection extends Indirection insta
|
||||
PointerOrArrayOrReferenceTypeIndirection() {
|
||||
baseType = PointerOrArrayOrReferenceType.super.getBaseType()
|
||||
}
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
private class PointerWrapperTypeIndirection extends Indirection instanceof PointerWrapper {
|
||||
PointerWrapperTypeIndirection() { baseType = PointerWrapper.super.getBaseType() }
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
@@ -242,6 +233,10 @@ private module IteratorIndirections {
|
||||
baseType = super.getValueType()
|
||||
}
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
|
||||
@@ -122,46 +122,7 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
override string toString() { result = operand.toString() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
// Ideally, this would just be implemented as:
|
||||
// ```
|
||||
// operand.getUse() = block.getInstruction(index)
|
||||
// ```
|
||||
// but because the IR generated for a snippet such as
|
||||
// ```
|
||||
// int x = *p++;
|
||||
// ```
|
||||
// looks like
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(glval<int *>) = VariableAddress[p] :
|
||||
// r3(int *) = Load[p] : &:r2, m1
|
||||
// r4(int) = Constant[1] :
|
||||
// r5(int *) = PointerAdd[4] : r3, r4
|
||||
// m3(int *) = Store[p] : &:r2, r5
|
||||
// r6(int *) = CopyValue : r3
|
||||
// r7(int) = Load[?] : &:r6, ~m2
|
||||
// m2(int) = Store[x] : &:r1, r7
|
||||
// ```
|
||||
// we need to ensure that the `r3` operand of the `CopyValue` instruction isn't seen as a fresh use
|
||||
// of `p` that happens after the increment. So if the base instruction of this use comes from a
|
||||
// post-fix crement operation we set the index of the SSA use that wraps the `r3` operand at the
|
||||
// `CopyValue` instruction to be the same index as the `r3` operand at the `PointerAdd` instruction.
|
||||
// This ensures that the SSA library doesn't create flow from the `PointerAdd` to `r6`.
|
||||
exists(BaseSourceVariableInstruction base | base = this.getBase() |
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op |
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, _, _) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
)
|
||||
operand.getUse() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
|
||||
@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
||||
* Gets the value of the property named `key` for the specified operand.
|
||||
*/
|
||||
string getOperandProperty(Operand operand, string key) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the instruction `instr` should be included when printing
|
||||
* the IR instructions.
|
||||
*/
|
||||
predicate shouldPrintInstruction(Instruction instr) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the operand `operand` should be included when printing the an
|
||||
* instruction's operand list.
|
||||
*/
|
||||
predicate shouldPrintOperand(Operand operand) { any() }
|
||||
}
|
||||
|
||||
@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
|
||||
}
|
||||
|
||||
private predicate shouldPrintOperand(Operand operand) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
|
||||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
||||
private string getOperandsString() {
|
||||
result =
|
||||
concat(Operand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
shouldPrintOperand(operand)
|
||||
operand = instr.getAnOperand()
|
||||
|
|
||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||
order by
|
||||
|
||||
@@ -577,6 +577,9 @@ private Overlap getVariableMemoryLocationOverlap(
|
||||
*/
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
|
||||
@@ -422,6 +422,12 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -987,6 +993,9 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
|
||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||
|
||||
/**
|
||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||
* `DebugSsa` module, which is then imported by PrintSSA.
|
||||
@@ -996,6 +1005,9 @@ module DebugSsa {
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -73,6 +73,9 @@ module UnaliasedSsaInstructions {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UnaliasedSsaInstructions */
|
||||
deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions;
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* aliased SSA stage.
|
||||
@@ -104,3 +107,6 @@ module AliasedSsaInstructions {
|
||||
result = TAliasedSsaUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsaInstructions */
|
||||
deprecated module AliasedSSAInstructions = AliasedSsaInstructions;
|
||||
|
||||
@@ -74,12 +74,20 @@ private module Shared {
|
||||
|
||||
class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand;
|
||||
|
||||
/** DEPRECATED: Alias for TNonSsaMemoryOperand */
|
||||
deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand;
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSsaMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for nonSsaMemoryOperand */
|
||||
deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = nonSsaMemoryOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,6 +167,9 @@ module UnaliasedSsaOperands {
|
||||
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UnaliasedSsaOperands */
|
||||
deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands;
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* aliased SSA stage.
|
||||
@@ -206,3 +217,6 @@ module AliasedSsaOperands {
|
||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsaOperands */
|
||||
deprecated module AliasedSSAOperands = AliasedSsaOperands;
|
||||
|
||||
@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
||||
* Gets the value of the property named `key` for the specified operand.
|
||||
*/
|
||||
string getOperandProperty(Operand operand, string key) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the instruction `instr` should be included when printing
|
||||
* the IR instructions.
|
||||
*/
|
||||
predicate shouldPrintInstruction(Instruction instr) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the operand `operand` should be included when printing the an
|
||||
* instruction's operand list.
|
||||
*/
|
||||
predicate shouldPrintOperand(Operand operand) { any() }
|
||||
}
|
||||
|
||||
@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
|
||||
}
|
||||
|
||||
private predicate shouldPrintOperand(Operand operand) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
|
||||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
||||
private string getOperandsString() {
|
||||
result =
|
||||
concat(Operand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
shouldPrintOperand(operand)
|
||||
operand = instr.getAnOperand()
|
||||
|
|
||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||
order by
|
||||
|
||||
@@ -375,6 +375,11 @@ Locatable getInstructionAst(TStageInstruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
deprecated Locatable getInstructionAST(TStageInstruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
CppType getInstructionResultType(TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
|
||||
or
|
||||
|
||||
@@ -76,6 +76,9 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Declaration getFunction() { result = getEnclosingDeclaration(expr) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
||||
* Gets the value of the property named `key` for the specified operand.
|
||||
*/
|
||||
string getOperandProperty(Operand operand, string key) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the instruction `instr` should be included when printing
|
||||
* the IR instructions.
|
||||
*/
|
||||
predicate shouldPrintInstruction(Instruction instr) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the operand `operand` should be included when printing the an
|
||||
* instruction's operand list.
|
||||
*/
|
||||
predicate shouldPrintOperand(Operand operand) { any() }
|
||||
}
|
||||
|
||||
@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
|
||||
}
|
||||
|
||||
private predicate shouldPrintOperand(Operand operand) {
|
||||
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
|
||||
}
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||
}
|
||||
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
||||
private string getOperandsString() {
|
||||
result =
|
||||
concat(Operand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
shouldPrintOperand(operand)
|
||||
operand = instr.getAnOperand()
|
||||
|
|
||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||
order by
|
||||
|
||||
@@ -422,6 +422,12 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -987,6 +993,9 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
|
||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||
|
||||
/**
|
||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||
* `DebugSsa` module, which is then imported by PrintSSA.
|
||||
@@ -996,6 +1005,9 @@ module DebugSsa {
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -46,6 +46,9 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
|
||||
not allocationEscapes(var)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForVariable */
|
||||
deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1;
|
||||
|
||||
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
|
||||
|
||||
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
|
||||
@@ -77,6 +80,9 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { none() }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
|
||||
/**
|
||||
* Represents a set of `MemoryLocation`s that cannot overlap with
|
||||
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be
|
||||
|
||||
@@ -414,7 +414,7 @@ private module HeuristicAllocation {
|
||||
int sizeArg;
|
||||
|
||||
HeuristicAllocationFunctionByName() {
|
||||
Function.super.getName().matches(["%alloc%", "%Alloc%"]) and
|
||||
Function.super.getName().matches("%alloc%") and
|
||||
Function.super.getUnspecifiedType() instanceof PointerType and
|
||||
sizeArg = unique( | | getAnUnsignedParameter(this))
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ library class RangeSsa extends SsaHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for RangeSsa */
|
||||
deprecated class RangeSSA = RangeSsa;
|
||||
|
||||
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
|
||||
guardCondition(guard, v, branch) and
|
||||
guardSuccessor(guard, branch, b)
|
||||
|
||||
@@ -729,7 +729,7 @@ module RangeStage<
|
||||
) {
|
||||
exists(SemExpr e, D::Delta d1, D::Delta d2 |
|
||||
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
||||
boundedUpper(e, b, d2) and
|
||||
boundedUpper(e, b, d1) and
|
||||
boundedLower(e, b, d2) and
|
||||
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
|
||||
)
|
||||
|
||||
@@ -16,6 +16,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
@@ -48,3 +51,6 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -41,6 +41,9 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
||||
@@ -55,6 +58,9 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
|
||||
@@ -10,6 +10,9 @@ private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
*/
|
||||
abstract class SafeExternalApiFunction extends Function { }
|
||||
|
||||
/** DEPRECATED: Alias for SafeExternalApiFunction */
|
||||
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
|
||||
DefaultSafeExternalApiFunction() {
|
||||
|
||||
@@ -16,6 +16,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
@@ -48,3 +51,6 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -41,6 +41,9 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" }
|
||||
@@ -50,6 +53,9 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
@@ -10,6 +10,9 @@ private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
*/
|
||||
abstract class SafeExternalApiFunction extends Function { }
|
||||
|
||||
/** DEPRECATED: Alias for SafeExternalApiFunction */
|
||||
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
|
||||
DefaultSafeExternalApiFunction() {
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
/**
|
||||
* @name Overrunning write
|
||||
* @description Exceeding the size of a static array during write or access operations
|
||||
* may result in a buffer overflow.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @precision medium
|
||||
* @id cpp/overrun-write
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-131
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import StringSizeFlow::PathGraph1
|
||||
import codeql.util.Unit
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||
|
||||
/**
|
||||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
va = unique( | | getAVariableAccess(size)) and
|
||||
// Compute `delta` as the constant difference between `x` and `x + 1`.
|
||||
bounded(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSinkPairImpl(
|
||||
CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, int delta, Expr eBuf
|
||||
) {
|
||||
exists(
|
||||
int bufIndex, int sizeIndex, Instruction sizeInstr, Instruction bufInstr, ArrayFunction func
|
||||
|
|
||||
bufInstr = bufSink.asInstruction() and
|
||||
c.getArgument(bufIndex) = bufInstr and
|
||||
sizeInstr = sizeSink.asInstruction() and
|
||||
c.getStaticCallTarget() = func and
|
||||
pragma[only_bind_into](func)
|
||||
.hasArrayWithVariableSize(pragma[only_bind_into](bufIndex),
|
||||
pragma[only_bind_into](sizeIndex)) and
|
||||
bounded(c.getArgument(sizeIndex), sizeInstr, delta) and
|
||||
eBuf = bufInstr.getUnconvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
module ValidState {
|
||||
/**
|
||||
* In the `StringSizeConfig` configuration we use an integer as the flow state for the second
|
||||
* projection of the dataflow graph. The integer represents an offset that is added to the
|
||||
* size of the allocation. For example, given:
|
||||
* ```cpp
|
||||
* char* p = new char[size + 1];
|
||||
* size += 1;
|
||||
* memset(p, 0, size);
|
||||
* ```
|
||||
* the initial flow state is `1`. This represents the fact that `size + 1` is a valid bound
|
||||
* for the size of the allocation pointed to by `p`. After updating the size using `+=`, the
|
||||
* flow state changes to `0`, which represents the fact that `size + 0` is a valid bound for
|
||||
* the allocation.
|
||||
*
|
||||
* So we need to compute a set of valid integers that represent the offset applied to the
|
||||
* size. We do this in two steps:
|
||||
* 1. We first perform the dataflow traversal that the second projection of the product-flow
|
||||
* library will perform, and visit all the places where the size argument is modified.
|
||||
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
|
||||
* where the offset is modified (see `validStateImpl`).
|
||||
*
|
||||
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
|
||||
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
|
||||
* has a corresponding `PathNode`.
|
||||
*/
|
||||
private module ValidStateConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = boolean;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
hasSize(_, source, _) and
|
||||
state = false
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
isSinkPairImpl(_, _, sink, _, _) and
|
||||
state = [false, true]
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
isAdditionalFlowStep2(node1, node2, _) and
|
||||
state1 = [false, true] and
|
||||
state2 = state1.booleanNot()
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any() }
|
||||
}
|
||||
|
||||
private import DataFlow::GlobalWithState<ValidStateConfig>
|
||||
|
||||
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }
|
||||
|
||||
/**
|
||||
* Holds if `value` is a possible offset for `n`.
|
||||
*
|
||||
* To ensure termination, we limit `value` to be in the
|
||||
* range `[-2, 2]` if the node is part of a loop. Without
|
||||
* this restriction we wouldn't terminate on an example like:
|
||||
* ```cpp
|
||||
* while(unknown()) { size++; }
|
||||
* ```
|
||||
*/
|
||||
private predicate validStateImpl(PathNode n, int value) {
|
||||
// If the dataflow node depends recursively on itself we restrict the range.
|
||||
(inLoop(n) implies value = [-2 .. 2]) and
|
||||
(
|
||||
// For the dataflow source we have an allocation such as `malloc(size + k)`,
|
||||
// and the value of the flow-state is then `k`.
|
||||
hasSize(_, n.getNode(), value)
|
||||
or
|
||||
// For a dataflow sink any `value` that is strictly smaller than the delta
|
||||
// needs to be a valid flow-state. That is, for a snippet like:
|
||||
// ```
|
||||
// p = b ? new char[size] : new char[size + 1];
|
||||
// memset(p, 0, size + 2);
|
||||
// ```
|
||||
// the valid flow-states at the `memset` must include the set `{0, 1}` since the
|
||||
// flow-state at `new char[size]` is `0`, and the flow-state at `new char[size + 1]`
|
||||
// is `1`.
|
||||
//
|
||||
// So we find a valid flow-state at the sink's predecessor, and use the definition
|
||||
// of our sink predicate to compute the valid flow-states at the sink.
|
||||
exists(int delta, PathNode n0 |
|
||||
n0.getASuccessor() = n and
|
||||
validStateImpl(n0, value) and
|
||||
isSinkPairImpl(_, _, n.getNode(), delta, _) and
|
||||
delta > value
|
||||
)
|
||||
or
|
||||
// For a non-source and non-sink node there is two cases to consider.
|
||||
// 1. A node where we have to update the flow-state, or
|
||||
// 2. A node that doesn't update the flow-state.
|
||||
//
|
||||
// For case 1, we compute the new flow-state by adding the constant operand of the
|
||||
// `AddInstruction` to the flow-state of any predecessor node.
|
||||
// For case 2 we simply propagate the valid flow-states from the predecessor node to
|
||||
// the next one.
|
||||
exists(PathNode n0, DataFlow::Node node0, DataFlow::Node node, int value0 |
|
||||
n0.getASuccessor() = n and
|
||||
validStateImpl(n0, value0) and
|
||||
node = n.getNode() and
|
||||
node0 = n0.getNode()
|
||||
|
|
||||
exists(int delta |
|
||||
isAdditionalFlowStep2(node0, node, delta) and
|
||||
value0 = value + delta
|
||||
)
|
||||
or
|
||||
not isAdditionalFlowStep2(node0, node, _) and
|
||||
value = value0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate validState(DataFlow::Node n, int value) {
|
||||
validStateImpl(any(PathNode pn | pn.getNode() = n), value)
|
||||
}
|
||||
}
|
||||
|
||||
import ValidState
|
||||
|
||||
/**
|
||||
* Holds if `node2` is a dataflow node that represents an addition of two operands `op1`
|
||||
* and `op2` such that:
|
||||
* 1. `node1` is the dataflow node that represents `op1`, and
|
||||
* 2. the value of `op2` can be upper bounded by `delta.`
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2, int delta) {
|
||||
exists(AddInstruction add, Operand op |
|
||||
add.hasOperands(node1.asOperand(), op) and
|
||||
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
|
||||
node2.asInstruction() = add
|
||||
)
|
||||
}
|
||||
|
||||
module StringSizeConfig implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
// malloc(size + 1);
|
||||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node bufSink, FlowState1 state1, DataFlow::Node sizeSink, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
validState(sizeSink, state2) and
|
||||
exists(int delta |
|
||||
isSinkPairImpl(_, bufSink, sizeSink, delta, _) and
|
||||
delta > state2
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
validState(node2, state2) and
|
||||
exists(int delta |
|
||||
isAdditionalFlowStep2(node1, node2, delta) and
|
||||
state1 = state2 + delta
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module StringSizeFlow = ProductFlow::GlobalWithState<StringSizeConfig>;
|
||||
|
||||
/**
|
||||
* Gets the maximum number of elements accessed past the buffer `buffer` by the formatting
|
||||
* function call `c` when an overflow is detected starting at the `(source1, source2)` pair
|
||||
* and ending at the `(sink1, sink2)` pair.
|
||||
*
|
||||
* Implementation note: Since the number of elements accessed past the buffer is computed
|
||||
* using a `FlowState` on the second component of the `DataFlow::PathNode` pair we project
|
||||
* the columns down to the underlying `DataFlow::Node` in order to deduplicate the flow
|
||||
* state.
|
||||
*/
|
||||
int getOverflow(
|
||||
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2,
|
||||
CallInstruction c, Expr buffer
|
||||
) {
|
||||
result > 0 and
|
||||
exists(
|
||||
StringSizeFlow::PathNode1 pathSource1, StringSizeFlow::PathNode2 pathSource2,
|
||||
StringSizeFlow::PathNode1 pathSink1, StringSizeFlow::PathNode2 pathSink2
|
||||
|
|
||||
StringSizeFlow::flowPath(pathSource1, pathSource2, pathSink1, pathSink2) and
|
||||
source1 = pathSource1.getNode() and
|
||||
source2 = pathSource2.getNode() and
|
||||
sink1 = pathSink1.getNode() and
|
||||
sink2 = pathSink2.getNode() and
|
||||
isSinkPairImpl(c, sink1, sink2, result + pathSink2.getState(), buffer)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2,
|
||||
StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, CallInstruction c,
|
||||
Expr buffer, string element
|
||||
where
|
||||
StringSizeFlow::flowPath(source1, source2, sink1, sink2) and
|
||||
overflow =
|
||||
max(getOverflow(source1.getNode(), source2.getNode(), sink1.getNode(), sink2.getNode(), c,
|
||||
buffer)
|
||||
) and
|
||||
if overflow = 1 then element = " element." else element = " elements."
|
||||
select c.getUnconvertedResultExpression(), source1, sink1,
|
||||
"This write may overflow $@ by " + overflow + element, buffer, buffer.toString()
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers.
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
|
||||
|
||||
177
cpp/ql/src/experimental/Likely Bugs/OverrunWriteProductFlow.ql
Normal file
177
cpp/ql/src/experimental/Likely Bugs/OverrunWriteProductFlow.ql
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @name Overrunning write
|
||||
* @description Exceeding the size of a static array during write or access operations
|
||||
* may result in a buffer overflow.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id cpp/overrun-write
|
||||
* @tags reliability
|
||||
* security
|
||||
* experimental
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-131
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import StringSizeFlow::PathGraph1
|
||||
import codeql.util.Unit
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||
|
||||
/**
|
||||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(AllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
va = unique( | | getAVariableAccess(size)) and
|
||||
// Compute `delta` as the constant difference between `x` and `x + 1`.
|
||||
bounded(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSinkPairImpl(
|
||||
CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, int delta, Expr eBuf
|
||||
) {
|
||||
exists(
|
||||
int bufIndex, int sizeIndex, Instruction sizeInstr, Instruction bufInstr, ArrayFunction func
|
||||
|
|
||||
bufInstr = bufSink.asInstruction() and
|
||||
c.getArgument(bufIndex) = bufInstr and
|
||||
sizeInstr = sizeSink.asInstruction() and
|
||||
c.getStaticCallTarget() = func and
|
||||
pragma[only_bind_into](func)
|
||||
.hasArrayWithVariableSize(pragma[only_bind_into](bufIndex),
|
||||
pragma[only_bind_into](sizeIndex)) and
|
||||
bounded(c.getArgument(sizeIndex), sizeInstr, delta) and
|
||||
eBuf = bufInstr.getUnconvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
module StringSizeConfig implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
// malloc(size + 1);
|
||||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node bufSink, FlowState1 state1, DataFlow::Node sizeSink, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
state2 = [-32 .. 32] and // An arbitrary bound because we need to bound `state2`
|
||||
exists(int delta |
|
||||
isSinkPairImpl(_, bufSink, sizeSink, delta, _) and
|
||||
delta > state2
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
exists(AddInstruction add, Operand op, int delta, int s1, int s2 |
|
||||
s1 = [-32 .. 32] and // An arbitrary bound because we need to bound `state`
|
||||
state1 = s1 and
|
||||
state2 = s2 and
|
||||
add.hasOperands(node1.asOperand(), op) and
|
||||
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
|
||||
node2.asInstruction() = add and
|
||||
s1 = s2 + delta
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module StringSizeFlow = ProductFlow::GlobalWithState<StringSizeConfig>;
|
||||
|
||||
/**
|
||||
* Gets the maximum number of elements accessed past the buffer `buffer` by the formatting
|
||||
* function call `c` when an overflow is detected starting at the `(source1, source2)` pair
|
||||
* and ending at the `(sink1, sink2)` pair.
|
||||
*
|
||||
* Implementation note: Since the number of elements accessed past the buffer is computed
|
||||
* using a `FlowState` on the second component of the `DataFlow::PathNode` pair we project
|
||||
* the columns down to the underlying `DataFlow::Node` in order to deduplicate the flow
|
||||
* state.
|
||||
*/
|
||||
int getOverflow(
|
||||
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2,
|
||||
CallInstruction c, Expr buffer
|
||||
) {
|
||||
result > 0 and
|
||||
exists(
|
||||
StringSizeFlow::PathNode1 pathSource1, StringSizeFlow::PathNode2 pathSource2,
|
||||
StringSizeFlow::PathNode1 pathSink1, StringSizeFlow::PathNode2 pathSink2
|
||||
|
|
||||
StringSizeFlow::flowPath(pathSource1, pathSource2, pathSink1, pathSink2) and
|
||||
source1 = pathSource1.getNode() and
|
||||
source2 = pathSource2.getNode() and
|
||||
sink1 = pathSink1.getNode() and
|
||||
sink2 = pathSink2.getNode() and
|
||||
isSinkPairImpl(c, sink1, sink2, result + pathSink2.getState(), buffer)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2,
|
||||
StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, CallInstruction c,
|
||||
Expr buffer, string element
|
||||
where
|
||||
StringSizeFlow::flowPath(source1, source2, sink1, sink2) and
|
||||
overflow =
|
||||
max(getOverflow(source1.getNode(), source2.getNode(), sink1.getNode(), sink2.getNode(), c,
|
||||
buffer)
|
||||
) and
|
||||
if overflow = 1 then element = " element." else element = " elements."
|
||||
select c.getUnconvertedResultExpression(), source1, sink1,
|
||||
"This write may overflow $@ by " + overflow + element, buffer, buffer.toString()
|
||||
@@ -1,33 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Detects <code>if (a+b>c) a=c-b</code>, which incorrectly implements
|
||||
<code>a = min(a,c-b)</code> if <code>a+b</code> overflows.
|
||||
</p>
|
||||
<p>
|
||||
Also detects variants such as <code>if (b+a>c) a=c-b</code> (swapped
|
||||
terms in addition), <code>if (a+b>c) { a=c-b }</code> (assignment
|
||||
inside block), <code>c<a+b</code> (swapped operands), and
|
||||
<code>>=</code>, <code><</code>, <code><=</code> instead of
|
||||
<code>></code> (all operators).
|
||||
</p>
|
||||
<p>
|
||||
This integer overflow is the root cause of the buffer overflow in
|
||||
the SHA-3 reference implementation (CVE-2022-37454).
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Replace by <code>if (a>c-b) a=c-b</code>. This avoids the overflow
|
||||
and makes it easy to see that <code>a = min(a,c-b)</code>.
|
||||
</p>
|
||||
</recommendation>
|
||||
<references>
|
||||
<li>CVE-2022-37454: <a href="https://nvd.nist.gov/vuln/detail/CVE-2022-37454">The Keccak XKCP SHA-3 reference implementation before fdc6fef has an integer overflow and resultant buffer overflow that allows attackers to execute arbitrary code or eliminate expected cryptographic properties. This occurs in the sponge function interface.</a></li>
|
||||
<li>GitHub Advisory Database: <a href="https://github.com/advisories/GHSA-6w4m-2xhg-2658">CVE-2022-37454: Buffer overflow in sponge queue functions</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* @name Integer addition may overflow inside if statement
|
||||
* @description Writing 'if (a+b>c) a=c-b' incorrectly implements
|
||||
* 'a = min(a,c-b)' if 'a+b' overflows. This integer
|
||||
* overflow is the root cause of the buffer overflow
|
||||
* in the SHA-3 reference implementation (CVE-2022-37454).
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id cpp/if-statement-addition-overflow
|
||||
* @tags: experimental
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from
|
||||
GuardCondition guard, Expr expr, ExprStmt exprstmt, BasicBlock block, AssignExpr assignexpr,
|
||||
AddExpr addexpr, SubExpr subexpr
|
||||
where
|
||||
(guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) and
|
||||
addexpr.getUnspecifiedType() instanceof IntegralType and
|
||||
exprMightOverflowPositively(addexpr) and
|
||||
block.getANode() = exprstmt and
|
||||
exprstmt.getExpr() = assignexpr and
|
||||
assignexpr.getRValue() = subexpr and
|
||||
(
|
||||
hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and
|
||||
globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())
|
||||
or
|
||||
hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and
|
||||
globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand())
|
||||
) and
|
||||
globalValueNumber(expr) = globalValueNumber(subexpr.getLeftOperand())
|
||||
select guard,
|
||||
"\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.",
|
||||
addexpr, "addition"
|
||||
@@ -14,7 +14,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysi
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import FieldAddressToDerefFlow::PathGraph
|
||||
import PointerArithmeticToDerefFlow::PathGraph
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
@@ -42,6 +42,21 @@ bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
module FieldAddressToPointerArithmeticConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isFieldAddressSource(_, source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PointerAddInstruction pai | pai.getLeft() = sink.asInstruction())
|
||||
}
|
||||
}
|
||||
|
||||
module FieldAddressToPointerArithmeticFlow =
|
||||
DataFlow::Global<FieldAddressToPointerArithmeticConfig>;
|
||||
|
||||
predicate isFieldAddressSource(Field f, DataFlow::Node source) {
|
||||
source.asInstruction().(FieldAddressInstruction).getField() = f
|
||||
}
|
||||
|
||||
bindingset[delta]
|
||||
predicate isInvalidPointerDerefSinkImpl(
|
||||
int delta, Instruction i, AddressOperand addr, string operation
|
||||
@@ -78,96 +93,38 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) {
|
||||
arr.getBaseType().getSize() = baseTypeSize and
|
||||
arr.getArraySize() = arraySize
|
||||
}
|
||||
|
||||
predicate pointerArithOverflow0(
|
||||
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
|
||||
) {
|
||||
not f.getNamespace() instanceof StdNamespace and
|
||||
arrayTypeHasSizes(f.getUnspecifiedType(), pai.getElementSize(), size) and
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
|
||||
delta = bound - size and
|
||||
delta >= 0 and
|
||||
size != 0 and
|
||||
size != 1
|
||||
predicate isConstantSizeOverflowSource(Field f, PointerAddInstruction pai, int delta) {
|
||||
exists(int size, int bound, DataFlow::Node source, DataFlow::InstructionNode sink |
|
||||
FieldAddressToPointerArithmeticFlow::flow(source, sink) and
|
||||
isFieldAddressSource(f, source) and
|
||||
pai.getLeft() = sink.asInstruction() and
|
||||
f.getUnspecifiedType().(ArrayType).getArraySize() = size and
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
|
||||
delta = bound - size and
|
||||
delta >= 0 and
|
||||
size != 0 and
|
||||
size != 1
|
||||
)
|
||||
}
|
||||
|
||||
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
pointerArithOverflow0(source.asInstruction(), _, _, _, _)
|
||||
isConstantSizeOverflowSource(_, source.asInstruction(), _)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
|
||||
}
|
||||
|
||||
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
|
||||
|
||||
predicate pointerArithOverflow(
|
||||
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
|
||||
) {
|
||||
pointerArithOverflow0(pai, f, size, bound, delta) and
|
||||
PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _)
|
||||
}
|
||||
|
||||
module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
newtype FlowState =
|
||||
additional TArray(Field f) { pointerArithOverflow(_, f, _, _, _) } or
|
||||
additional TOverflowArithmetic(PointerArithmeticInstruction pai) {
|
||||
pointerArithOverflow(pai, _, _, _, _)
|
||||
}
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
exists(Field f |
|
||||
source.asInstruction().(FieldAddressInstruction).getField() = f and
|
||||
state = TArray(f)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(DataFlow::Node pai |
|
||||
state = TOverflowArithmetic(pai.asInstruction()) and
|
||||
PointerArithmeticToDerefFlow::flow(pai, sink)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node, _) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _) }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
exists(PointerArithmeticInstruction pai, Field f |
|
||||
state1 = TArray(f) and
|
||||
state2 = TOverflowArithmetic(pai) and
|
||||
pai.getLeft() = node1.asInstruction() and
|
||||
node2.asInstruction() = pai and
|
||||
pointerArithOverflow(pai, f, _, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module FieldAddressToDerefFlow = DataFlow::GlobalWithState<FieldAddressToDerefConfig>;
|
||||
|
||||
from
|
||||
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
|
||||
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
Field f, PointerArithmeticToDerefFlow::PathNode source,
|
||||
PointerArithmeticToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
where
|
||||
FieldAddressToDerefFlow::flowPath(source, sink) and
|
||||
PointerArithmeticToDerefFlow::flowPath(source, sink) and
|
||||
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
||||
source.getState() = FieldAddressToDerefConfig::TArray(f) and
|
||||
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
|
||||
pointerArithOverflow(pai, f, _, _, delta)
|
||||
select pai, source, sink,
|
||||
isConstantSizeOverflowSource(f, source.getNode().asInstruction(), delta)
|
||||
select source, source, sink,
|
||||
"This pointer arithmetic may have an off-by-" + (delta + 1) +
|
||||
" error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR
|
||||
@@ -48,23 +48,44 @@ bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||
/**
|
||||
* Holds if the combination of `n` and `state` represents an appropriate
|
||||
* source for the expression `e` suitable for use-use flow.
|
||||
*/
|
||||
private predicate hasSizeImpl(Expr e, DataFlow::Node n, int state) {
|
||||
// The simple case: If the size is a variable access with no qualifier we can just use the
|
||||
// dataflow node for that expression and no state.
|
||||
exists(VariableAccess va |
|
||||
va = e and
|
||||
not va instanceof FieldAccess and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = 0
|
||||
)
|
||||
or
|
||||
// If the size is a choice between two expressions we allow both to be nodes representing the size.
|
||||
exists(ConditionalExpr cond | cond = e | hasSizeImpl([cond.getThen(), cond.getElse()], n, state))
|
||||
or
|
||||
// If the size is an expression plus a constant, we pick the dataflow node of the expression and
|
||||
// remember the constant in the state.
|
||||
exists(Expr const, Expr nonconst |
|
||||
e.(AddExpr).hasOperands(const, nonconst) and
|
||||
state = const.getValue().toInt() and
|
||||
hasSizeImpl(nonconst, n, _)
|
||||
)
|
||||
or
|
||||
exists(Expr const, Expr nonconst |
|
||||
e.(SubExpr).hasOperands(const, nonconst) and
|
||||
state = -const.getValue().toInt() and
|
||||
hasSizeImpl(nonconst, n, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
va = unique( | | getAVariableAccess(size)) and
|
||||
// Compute `delta` as the constant difference between `x` and `x + 1`.
|
||||
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta
|
||||
)
|
||||
hasSizeImpl(alloc.getSizeExpr(), n, state)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,8 +102,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
* ```
|
||||
*
|
||||
* We do this by splitting the task up into two configurations:
|
||||
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
|
||||
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
|
||||
*
|
||||
* Finally, the range-analysis library will find a load from (or store to) an address that
|
||||
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
|
||||
@@ -180,33 +201,14 @@ predicate isSinkImpl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields any instruction that is control-flow reachable from `instr`.
|
||||
*/
|
||||
bindingset[instr, result]
|
||||
pragma[inline_late]
|
||||
Instruction getASuccessor(Instruction instr) {
|
||||
exists(IRBlock b, int instrIndex, int resultIndex |
|
||||
result.getBlock() = b and
|
||||
instr.getBlock() = b and
|
||||
b.getInstruction(instrIndex) = instr and
|
||||
b.getInstruction(resultIndex) = result
|
||||
|
|
||||
resultIndex >= instrIndex
|
||||
)
|
||||
or
|
||||
instr.getBlock().getASuccessor+() = result.getBlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
|
||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
|
||||
exists(AddressOperand addr, Instruction s |
|
||||
s = sink.asInstruction() and
|
||||
bounded1(addr.getDef(), s, delta) and
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr
|
||||
|
|
||||
@@ -220,13 +222,13 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a pointer-arithmetic operation found
|
||||
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
|
||||
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
|
||||
*/
|
||||
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
||||
@@ -256,18 +258,17 @@ predicate invalidPointerToDerefSource(
|
||||
}
|
||||
|
||||
newtype TMergedPathNode =
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
|
||||
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
||||
// The path nodes computed by `InvalidPointerToDerefConfig`
|
||||
// The path nodes computed by `InvalidPointerToDerefConf`
|
||||
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
|
||||
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
|
||||
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
|
||||
// pointer, but we want to raise an alert at the dereference.
|
||||
TPathNodeSink(Instruction i) {
|
||||
exists(DataFlow::Node n |
|
||||
InvalidPointerToDerefFlow::flowTo(n) and
|
||||
isInvalidPointerDerefSink(n, i, _, _) and
|
||||
i = getASuccessor(n.asInstruction())
|
||||
isInvalidPointerDerefSink(n, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -341,30 +342,12 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
|
||||
or
|
||||
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
|
||||
or
|
||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _, _)
|
||||
}
|
||||
|
||||
query predicate nodes(MergedPathNode n, string key, string val) {
|
||||
AllocToInvalidPointerFlow::PathGraph1::nodes(n.asPathNode1(), key, val)
|
||||
or
|
||||
InvalidPointerToDerefFlow::PathGraph::nodes(n.asPathNode3(), key, val)
|
||||
or
|
||||
key = "semmle.label" and val = n.asSinkNode().toString()
|
||||
}
|
||||
|
||||
query predicate subpaths(
|
||||
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
|
||||
) {
|
||||
AllocToInvalidPointerFlow::PathGraph1::subpaths(arg.asPathNode1(), par.asPathNode1(),
|
||||
ret.asPathNode1(), out.asPathNode1())
|
||||
or
|
||||
InvalidPointerToDerefFlow::PathGraph::subpaths(arg.asPathNode3(), par.asPathNode3(),
|
||||
ret.asPathNode3(), out.asPathNode3())
|
||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
|
||||
* of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
|
||||
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
|
||||
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
|
||||
*/
|
||||
predicate joinOn1(
|
||||
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
|
||||
@@ -375,38 +358,34 @@ predicate joinOn1(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
|
||||
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
|
||||
* that dereferences `p1`. The string `operation` describes whether the `i` is
|
||||
* a `StoreInstruction` or `LoadInstruction`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation, int delta) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
|
||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation)
|
||||
}
|
||||
|
||||
predicate hasFlowPath(
|
||||
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
||||
PointerArithmeticInstruction pai, string operation, int delta
|
||||
PointerArithmeticInstruction pai, string operation
|
||||
) {
|
||||
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
|
||||
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
|
||||
joinOn1(pai, sink1, source3) and
|
||||
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
|
||||
joinOn2(sink3, sink.asSinkNode(), operation, delta)
|
||||
joinOn2(sink3, sink.asSinkNode(), operation)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
MergedPathNode source, MergedPathNode sink, int k, string kstr, PointerArithmeticInstruction pai,
|
||||
string operation, Expr offset, DataFlow::Node n
|
||||
MergedPathNode source, MergedPathNode sink, int k, string kstr,
|
||||
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
|
||||
Expr offset, DataFlow::Node n
|
||||
where
|
||||
k =
|
||||
min(int k2, int k3, InvalidPointerToDerefFlow::PathNode source3 |
|
||||
hasFlowPath(source, sink, source3, pai, operation, k3) and
|
||||
invalidPointerToDerefSource(pai, source3.getNode(), k2)
|
||||
|
|
||||
k2 + k3
|
||||
) and
|
||||
hasFlowPath(source, sink, source3, pai, operation) and
|
||||
invalidPointerToDerefSource(pai, source3.getNode(), k) and
|
||||
offset = pai.getRight().getUnconvertedResultExpression() and
|
||||
n = source.asPathNode1().getNode() and
|
||||
if k = 0 then kstr = "" else kstr = " + " + k
|
||||
|
||||
373
cpp/ql/src/external/CodeDuplication.qll
vendored
Normal file
373
cpp/ql/src/external/CodeDuplication.qll
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
/** Provides classes for detecting duplicate or similar code. */
|
||||
|
||||
import cpp
|
||||
|
||||
deprecated private newtype TDuplicationOrSimilarity = MKDuplicationOrSimilarity()
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A token block used for detection of duplicate and similar code.
|
||||
*/
|
||||
deprecated class Copy extends TDuplicationOrSimilarity {
|
||||
/** Gets the index of the token in this block starting at the location `loc`, if any. */
|
||||
int tokenStartingAt(Location loc) { none() }
|
||||
|
||||
/** Gets the index of the token in this block ending at the location `loc`, if any. */
|
||||
int tokenEndingAt(Location loc) { none() }
|
||||
|
||||
/** Gets the line on which the first token in this block starts. */
|
||||
int sourceStartLine() { none() }
|
||||
|
||||
/** Gets the column on which the first token in this block starts. */
|
||||
int sourceStartColumn() { none() }
|
||||
|
||||
/** Gets the line on which the last token in this block ends. */
|
||||
int sourceEndLine() { none() }
|
||||
|
||||
/** Gets the column on which the last token in this block ends. */
|
||||
int sourceEndColumn() { none() }
|
||||
|
||||
/** Gets the number of lines containing at least (part of) one token in this block. */
|
||||
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
|
||||
|
||||
/** Gets an opaque identifier for the equivalence class of this block. */
|
||||
int getEquivalenceClass() { none() }
|
||||
|
||||
/** Gets the source file in which this block appears. */
|
||||
File sourceFile() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.sourceFile().getAbsolutePath() = filepath and
|
||||
startline = this.sourceStartLine() and
|
||||
startcolumn = this.sourceStartColumn() and
|
||||
endline = this.sourceEndLine() and
|
||||
endcolumn = this.sourceEndColumn()
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A block of duplicated code.
|
||||
*/
|
||||
deprecated class DuplicateBlock extends Copy {
|
||||
override string toString() {
|
||||
result = "Duplicate code: " + this.sourceLines() + " duplicated lines."
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A block of similar code.
|
||||
*/
|
||||
deprecated class SimilarBlock extends Copy {
|
||||
override string toString() {
|
||||
result = "Similar code: " + this.sourceLines() + " almost duplicated lines."
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
|
||||
*
|
||||
* Gets a function with a body and a location.
|
||||
*/
|
||||
deprecated FunctionDeclarationEntry sourceMethod() {
|
||||
result.isDefinition() and
|
||||
exists(result.getLocation()) and
|
||||
numlines(unresolveElement(result.getFunction()), _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
|
||||
*
|
||||
* Gets the number of member functions in `c` with a body and a location.
|
||||
*/
|
||||
deprecated int numberOfSourceMethods(Class c) {
|
||||
result =
|
||||
count(FunctionDeclarationEntry m |
|
||||
m = sourceMethod() and
|
||||
m.getFunction().getDeclaringType() = c
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
|
||||
exists(DuplicateBlock b, Location loc |
|
||||
stmt.getLocation() = loc and
|
||||
first = b.tokenStartingAt(loc) and
|
||||
last = b.tokenEndingAt(loc) and
|
||||
b.getEquivalenceClass() = equivClass
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private Stmt statementInMethod(FunctionDeclarationEntry m) {
|
||||
result.getParent+() = m.getBlock() and
|
||||
not result.getLocation() instanceof UnknownStmtLocation and
|
||||
not result instanceof BlockStmt
|
||||
}
|
||||
|
||||
deprecated private predicate duplicateStatement(
|
||||
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, Stmt s1, Stmt s2
|
||||
) {
|
||||
exists(int equivClass, int first, int last |
|
||||
s1 = statementInMethod(m1) and
|
||||
s2 = statementInMethod(m2) and
|
||||
blockCoversStatement(equivClass, first, last, s1) and
|
||||
blockCoversStatement(equivClass, first, last, s2) and
|
||||
s1 != s2 and
|
||||
m1 != m2
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicated statements is no longer available.
|
||||
*
|
||||
* Holds if `m1` is a function with `total` lines, and `m2` is a function
|
||||
* that has `duplicate` lines in common with `m1`.
|
||||
*/
|
||||
deprecated predicate duplicateStatements(
|
||||
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total
|
||||
) {
|
||||
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
|
||||
total = strictcount(statementInMethod(m1))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicated methods is no longer available.
|
||||
*
|
||||
* Holds if `m` and other are identical functions.
|
||||
*/
|
||||
deprecated predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) {
|
||||
exists(int total | duplicateStatements(m, other, total, total))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar lines is no longer available.
|
||||
*
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Holds if `line` in `f` is similar to a line somewhere else.
|
||||
*/
|
||||
deprecated predicate similarLines(File f, int line) {
|
||||
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
|
||||
}
|
||||
|
||||
deprecated private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(SimilarBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate similarLinesCoveredFiles(File f, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
similarLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
(coveredApprox * 100) / numLines > 75
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar lines is no longer available.
|
||||
*
|
||||
* Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`.
|
||||
*/
|
||||
deprecated predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
similarLinesCoveredFiles(f, otherFile) and
|
||||
exists(int notCovered |
|
||||
notCovered =
|
||||
count(int j |
|
||||
j in [1 .. numLines] and
|
||||
not similarLines(f, j)
|
||||
) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate lines is no longer available.
|
||||
*
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Holds if `line` in `f` is duplicated by a line somewhere else.
|
||||
*/
|
||||
deprecated predicate duplicateLines(File f, int line) {
|
||||
exists(DuplicateBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(DuplicateBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate lines is no longer available.
|
||||
*
|
||||
* Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`.
|
||||
*/
|
||||
deprecated predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
(coveredApprox * 100) / numLines > 75
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered =
|
||||
count(int j |
|
||||
j in [1 .. numLines] and
|
||||
not duplicateLines(f, j)
|
||||
) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar files is no longer available.
|
||||
*
|
||||
* Holds if most of `f` (`percent`%) is similar to `other`.
|
||||
*/
|
||||
deprecated predicate similarFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
similarLinesCovered(f, covered, other) and
|
||||
total = f.getMetrics().getNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 80
|
||||
) and
|
||||
not duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate files is no longer available.
|
||||
*
|
||||
* Holds if most of `f` (`percent`%) is duplicated by `other`.
|
||||
*/
|
||||
deprecated predicate duplicateFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
duplicateLinesCovered(f, covered, other) and
|
||||
total = f.getMetrics().getNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 70
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate classes is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` (`numDup` out of `total`) are
|
||||
* duplicates of member functions in `other`.
|
||||
*/
|
||||
deprecated predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
|
||||
numDup =
|
||||
strictcount(FunctionDeclarationEntry m1 |
|
||||
exists(FunctionDeclarationEntry m2 |
|
||||
duplicateMethod(m1, m2) and
|
||||
m1 = sourceMethod() and
|
||||
exists(Function f | f = m1.getFunction() and f.getDeclaringType() = c) and
|
||||
exists(Function f | f = m2.getFunction() and f.getDeclaringType() = other) and
|
||||
c != other
|
||||
)
|
||||
) and
|
||||
total = numberOfSourceMethods(c) and
|
||||
(numDup * 100) / total > 80
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate classes is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` are duplicates of member functions in
|
||||
* `other`. Provides the human-readable `message` to describe the amount of
|
||||
* duplication.
|
||||
*/
|
||||
deprecated predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
exists(int numDup, int total |
|
||||
mostlyDuplicateClassBase(c, other, numDup, total) and
|
||||
(
|
||||
total != numDup and
|
||||
exists(string s1, string s2, string s3, string name |
|
||||
s1 = " out of " and
|
||||
s2 = " methods in " and
|
||||
s3 = " are duplicated in $@." and
|
||||
name = c.getName()
|
||||
|
|
||||
message = numDup + s1 + total + s2 + name + s3
|
||||
)
|
||||
or
|
||||
total = numDup and
|
||||
exists(string s1, string s2, string name |
|
||||
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
||||
|
|
||||
message = s1 + name + s2
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on file duplication is no longer available.
|
||||
*
|
||||
* Holds if `f` and `other` are similar or duplicates.
|
||||
*/
|
||||
deprecated predicate fileLevelDuplication(File f, File other) {
|
||||
similarFiles(f, other, _) or duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on class duplication is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` are duplicates of member functions in
|
||||
* `other`.
|
||||
*/
|
||||
deprecated predicate classLevelDuplication(Class c, Class other) {
|
||||
mostlyDuplicateClass(c, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The CodeDuplication library will be removed in a future release.
|
||||
*
|
||||
* Holds if `line` in `f` should be allowed to be duplicated. This is the case
|
||||
* for `#include` directives.
|
||||
*/
|
||||
deprecated predicate whitelistedLineForDuplication(File f, int line) {
|
||||
exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line)
|
||||
}
|
||||
@@ -16,16 +16,18 @@ private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
|
||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
string getARelevantTag() { result = "ir" }
|
||||
class IRFlowTest extends InlineExpectationsTest {
|
||||
IRFlowTest() { this = "IRFlowTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(IRDataFlow::Node source, IRDataFlow::Node sink, int n |
|
||||
override string getARelevantTag() { result = "ir" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(IRDataFlow::Node source, IRDataFlow::Node sink, IRDataFlow::Configuration conf, int n |
|
||||
tag = "ir" and
|
||||
Flow::flow(source, sink) and
|
||||
conf.hasFlow(source, sink) and
|
||||
n =
|
||||
strictcount(int line, int column |
|
||||
Flow::flow(any(IRDataFlow::Node otherSource |
|
||||
conf.hasFlow(any(IRDataFlow::Node otherSource |
|
||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||
), sink)
|
||||
) and
|
||||
@@ -45,16 +47,20 @@ module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
string getARelevantTag() { result = "ast" }
|
||||
class AstFlowTest extends InlineExpectationsTest {
|
||||
AstFlowTest() { this = "ASTFlowTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(AstDataFlow::Node source, AstDataFlow::Node sink, int n |
|
||||
override string getARelevantTag() { result = "ast" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(
|
||||
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
|
||||
|
|
||||
tag = "ast" and
|
||||
Flow::flow(source, sink) and
|
||||
conf.hasFlow(source, sink) and
|
||||
n =
|
||||
strictcount(int line, int column |
|
||||
Flow::flow(any(AstDataFlow::Node otherSource |
|
||||
conf.hasFlow(any(AstDataFlow::Node otherSource |
|
||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||
), sink)
|
||||
) and
|
||||
@@ -73,3 +79,6 @@ module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstFlowTest */
|
||||
deprecated class ASTFlowTest = AstFlowTest;
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
edges
|
||||
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:24:21:24:31 | call to mk_string_t indirection [string] |
|
||||
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:34:21:34:31 | call to mk_string_t indirection [string] |
|
||||
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] |
|
||||
| test.cpp:18:5:18:30 | ... = ... | test.cpp:18:10:18:15 | str indirection [post update] [string] |
|
||||
| test.cpp:18:10:18:15 | str indirection [post update] [string] | test.cpp:16:11:16:21 | mk_string_t indirection [string] |
|
||||
| test.cpp:18:19:18:24 | call to malloc | test.cpp:18:5:18:30 | ... = ... |
|
||||
| test.cpp:24:21:24:31 | call to mk_string_t indirection [string] | test.cpp:26:13:26:15 | str indirection [string] |
|
||||
| test.cpp:26:13:26:15 | str indirection [string] | test.cpp:26:18:26:23 | string |
|
||||
| test.cpp:26:13:26:15 | str indirection [string] | test.cpp:26:18:26:23 | string indirection |
|
||||
| test.cpp:26:18:26:23 | string indirection | test.cpp:26:18:26:23 | string |
|
||||
| test.cpp:29:32:29:34 | str indirection [string] | test.cpp:30:13:30:15 | str indirection [string] |
|
||||
| test.cpp:30:13:30:15 | str indirection [string] | test.cpp:30:18:30:23 | string |
|
||||
| test.cpp:30:13:30:15 | str indirection [string] | test.cpp:30:18:30:23 | string indirection |
|
||||
| test.cpp:30:18:30:23 | string indirection | test.cpp:30:18:30:23 | string |
|
||||
| test.cpp:34:21:34:31 | call to mk_string_t indirection [string] | test.cpp:35:21:35:23 | str indirection [string] |
|
||||
| test.cpp:35:21:35:23 | str indirection [string] | test.cpp:29:32:29:34 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:41:13:41:15 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:42:13:42:15 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:44:13:44:15 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:45:13:45:15 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:48:17:48:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:52:17:52:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:56:17:56:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:60:17:60:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:64:17:64:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:68:17:68:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:72:17:72:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:76:17:76:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:80:17:80:19 | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:84:17:84:19 | str indirection [string] |
|
||||
| test.cpp:41:13:41:15 | str indirection [string] | test.cpp:41:18:41:23 | string |
|
||||
| test.cpp:41:13:41:15 | str indirection [string] | test.cpp:41:18:41:23 | string indirection |
|
||||
| test.cpp:41:18:41:23 | string indirection | test.cpp:41:18:41:23 | string |
|
||||
| test.cpp:42:13:42:15 | str indirection [string] | test.cpp:42:18:42:23 | string |
|
||||
| test.cpp:42:13:42:15 | str indirection [string] | test.cpp:42:18:42:23 | string indirection |
|
||||
| test.cpp:42:18:42:23 | string indirection | test.cpp:42:18:42:23 | string |
|
||||
| test.cpp:44:13:44:15 | str indirection [string] | test.cpp:44:18:44:23 | string |
|
||||
| test.cpp:44:13:44:15 | str indirection [string] | test.cpp:44:18:44:23 | string indirection |
|
||||
| test.cpp:44:18:44:23 | string indirection | test.cpp:44:18:44:23 | string |
|
||||
| test.cpp:45:13:45:15 | str indirection [string] | test.cpp:45:18:45:23 | string |
|
||||
| test.cpp:45:13:45:15 | str indirection [string] | test.cpp:45:18:45:23 | string indirection |
|
||||
| test.cpp:45:18:45:23 | string indirection | test.cpp:45:18:45:23 | string |
|
||||
| test.cpp:48:17:48:19 | str indirection [string] | test.cpp:48:22:48:27 | string |
|
||||
| test.cpp:48:17:48:19 | str indirection [string] | test.cpp:48:22:48:27 | string indirection |
|
||||
| test.cpp:48:22:48:27 | string indirection | test.cpp:48:22:48:27 | string |
|
||||
| test.cpp:52:17:52:19 | str indirection [string] | test.cpp:52:22:52:27 | string |
|
||||
| test.cpp:52:17:52:19 | str indirection [string] | test.cpp:52:22:52:27 | string indirection |
|
||||
| test.cpp:52:22:52:27 | string indirection | test.cpp:52:22:52:27 | string |
|
||||
| test.cpp:56:17:56:19 | str indirection [string] | test.cpp:56:22:56:27 | string |
|
||||
| test.cpp:56:17:56:19 | str indirection [string] | test.cpp:56:22:56:27 | string indirection |
|
||||
| test.cpp:56:22:56:27 | string indirection | test.cpp:56:22:56:27 | string |
|
||||
| test.cpp:60:17:60:19 | str indirection [string] | test.cpp:60:22:60:27 | string |
|
||||
| test.cpp:60:17:60:19 | str indirection [string] | test.cpp:60:22:60:27 | string indirection |
|
||||
| test.cpp:60:22:60:27 | string indirection | test.cpp:60:22:60:27 | string |
|
||||
| test.cpp:64:17:64:19 | str indirection [string] | test.cpp:64:22:64:27 | string |
|
||||
| test.cpp:64:17:64:19 | str indirection [string] | test.cpp:64:22:64:27 | string indirection |
|
||||
| test.cpp:64:22:64:27 | string indirection | test.cpp:64:22:64:27 | string |
|
||||
| test.cpp:68:17:68:19 | str indirection [string] | test.cpp:68:22:68:27 | string |
|
||||
| test.cpp:68:17:68:19 | str indirection [string] | test.cpp:68:22:68:27 | string indirection |
|
||||
| test.cpp:68:22:68:27 | string indirection | test.cpp:68:22:68:27 | string |
|
||||
| test.cpp:72:17:72:19 | str indirection [string] | test.cpp:72:22:72:27 | string |
|
||||
| test.cpp:72:17:72:19 | str indirection [string] | test.cpp:72:22:72:27 | string indirection |
|
||||
| test.cpp:72:22:72:27 | string indirection | test.cpp:72:22:72:27 | string |
|
||||
| test.cpp:76:17:76:19 | str indirection [string] | test.cpp:76:22:76:27 | string |
|
||||
| test.cpp:76:17:76:19 | str indirection [string] | test.cpp:76:22:76:27 | string indirection |
|
||||
| test.cpp:76:22:76:27 | string indirection | test.cpp:76:22:76:27 | string |
|
||||
| test.cpp:80:17:80:19 | str indirection [string] | test.cpp:80:22:80:27 | string |
|
||||
| test.cpp:80:17:80:19 | str indirection [string] | test.cpp:80:22:80:27 | string indirection |
|
||||
| test.cpp:80:22:80:27 | string indirection | test.cpp:80:22:80:27 | string |
|
||||
| test.cpp:84:17:84:19 | str indirection [string] | test.cpp:84:22:84:27 | string |
|
||||
| test.cpp:84:17:84:19 | str indirection [string] | test.cpp:84:22:84:27 | string indirection |
|
||||
| test.cpp:84:22:84:27 | string indirection | test.cpp:84:22:84:27 | string |
|
||||
| test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] |
|
||||
| test.cpp:90:5:90:34 | ... = ... | test.cpp:90:10:90:15 | str indirection [post update] [string] |
|
||||
| test.cpp:90:10:90:15 | str indirection [post update] [string] | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] |
|
||||
| test.cpp:90:19:90:24 | call to malloc | test.cpp:90:5:90:34 | ... = ... |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:98:13:98:15 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:99:13:99:15 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:101:13:101:15 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:102:13:102:15 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:105:17:105:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:109:17:109:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:113:17:113:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:117:17:117:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:121:17:121:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:125:17:125:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:129:17:129:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:133:17:133:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:137:17:137:19 | str indirection [string] |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:141:17:141:19 | str indirection [string] |
|
||||
| test.cpp:98:13:98:15 | str indirection [string] | test.cpp:98:18:98:23 | string |
|
||||
| test.cpp:98:13:98:15 | str indirection [string] | test.cpp:98:18:98:23 | string indirection |
|
||||
| test.cpp:98:18:98:23 | string indirection | test.cpp:98:18:98:23 | string |
|
||||
| test.cpp:99:13:99:15 | str indirection [string] | test.cpp:99:18:99:23 | string |
|
||||
| test.cpp:99:13:99:15 | str indirection [string] | test.cpp:99:18:99:23 | string indirection |
|
||||
| test.cpp:99:18:99:23 | string indirection | test.cpp:99:18:99:23 | string |
|
||||
| test.cpp:101:13:101:15 | str indirection [string] | test.cpp:101:18:101:23 | string |
|
||||
| test.cpp:101:13:101:15 | str indirection [string] | test.cpp:101:18:101:23 | string indirection |
|
||||
| test.cpp:101:18:101:23 | string indirection | test.cpp:101:18:101:23 | string |
|
||||
| test.cpp:102:13:102:15 | str indirection [string] | test.cpp:102:18:102:23 | string |
|
||||
| test.cpp:102:13:102:15 | str indirection [string] | test.cpp:102:18:102:23 | string indirection |
|
||||
| test.cpp:102:18:102:23 | string indirection | test.cpp:102:18:102:23 | string |
|
||||
| test.cpp:105:17:105:19 | str indirection [string] | test.cpp:105:22:105:27 | string |
|
||||
| test.cpp:105:17:105:19 | str indirection [string] | test.cpp:105:22:105:27 | string indirection |
|
||||
| test.cpp:105:22:105:27 | string indirection | test.cpp:105:22:105:27 | string |
|
||||
| test.cpp:109:17:109:19 | str indirection [string] | test.cpp:109:22:109:27 | string |
|
||||
| test.cpp:109:17:109:19 | str indirection [string] | test.cpp:109:22:109:27 | string indirection |
|
||||
| test.cpp:109:22:109:27 | string indirection | test.cpp:109:22:109:27 | string |
|
||||
| test.cpp:113:17:113:19 | str indirection [string] | test.cpp:113:22:113:27 | string |
|
||||
| test.cpp:113:17:113:19 | str indirection [string] | test.cpp:113:22:113:27 | string indirection |
|
||||
| test.cpp:113:22:113:27 | string indirection | test.cpp:113:22:113:27 | string |
|
||||
| test.cpp:117:17:117:19 | str indirection [string] | test.cpp:117:22:117:27 | string |
|
||||
| test.cpp:117:17:117:19 | str indirection [string] | test.cpp:117:22:117:27 | string indirection |
|
||||
| test.cpp:117:22:117:27 | string indirection | test.cpp:117:22:117:27 | string |
|
||||
| test.cpp:121:17:121:19 | str indirection [string] | test.cpp:121:22:121:27 | string |
|
||||
| test.cpp:121:17:121:19 | str indirection [string] | test.cpp:121:22:121:27 | string indirection |
|
||||
| test.cpp:121:22:121:27 | string indirection | test.cpp:121:22:121:27 | string |
|
||||
| test.cpp:125:17:125:19 | str indirection [string] | test.cpp:125:22:125:27 | string |
|
||||
| test.cpp:125:17:125:19 | str indirection [string] | test.cpp:125:22:125:27 | string indirection |
|
||||
| test.cpp:125:22:125:27 | string indirection | test.cpp:125:22:125:27 | string |
|
||||
| test.cpp:129:17:129:19 | str indirection [string] | test.cpp:129:22:129:27 | string |
|
||||
| test.cpp:129:17:129:19 | str indirection [string] | test.cpp:129:22:129:27 | string indirection |
|
||||
| test.cpp:129:22:129:27 | string indirection | test.cpp:129:22:129:27 | string |
|
||||
| test.cpp:133:17:133:19 | str indirection [string] | test.cpp:133:22:133:27 | string |
|
||||
| test.cpp:133:17:133:19 | str indirection [string] | test.cpp:133:22:133:27 | string indirection |
|
||||
| test.cpp:133:22:133:27 | string indirection | test.cpp:133:22:133:27 | string |
|
||||
| test.cpp:137:17:137:19 | str indirection [string] | test.cpp:137:22:137:27 | string |
|
||||
| test.cpp:137:17:137:19 | str indirection [string] | test.cpp:137:22:137:27 | string indirection |
|
||||
| test.cpp:137:22:137:27 | string indirection | test.cpp:137:22:137:27 | string |
|
||||
| test.cpp:141:17:141:19 | str indirection [string] | test.cpp:141:22:141:27 | string |
|
||||
| test.cpp:141:17:141:19 | str indirection [string] | test.cpp:141:22:141:27 | string indirection |
|
||||
| test.cpp:141:22:141:27 | string indirection | test.cpp:141:22:141:27 | string |
|
||||
| test.cpp:147:5:147:34 | ... = ... | test.cpp:147:10:147:15 | str indirection [post update] [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:150:13:150:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:151:13:151:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:152:13:152:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:154:13:154:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:155:13:155:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:156:13:156:15 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:159:17:159:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:163:17:163:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:167:17:167:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:171:17:171:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:175:17:175:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:179:17:179:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:183:17:183:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:187:17:187:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:191:17:191:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:195:17:195:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:199:17:199:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:203:17:203:19 | str indirection [string] |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:207:17:207:19 | str indirection [string] |
|
||||
| test.cpp:147:19:147:24 | call to malloc | test.cpp:147:5:147:34 | ... = ... |
|
||||
| test.cpp:150:13:150:15 | str indirection [string] | test.cpp:150:18:150:23 | string |
|
||||
| test.cpp:150:13:150:15 | str indirection [string] | test.cpp:150:18:150:23 | string indirection |
|
||||
| test.cpp:150:18:150:23 | string indirection | test.cpp:150:18:150:23 | string |
|
||||
| test.cpp:151:13:151:15 | str indirection [string] | test.cpp:151:18:151:23 | string |
|
||||
| test.cpp:151:13:151:15 | str indirection [string] | test.cpp:151:18:151:23 | string indirection |
|
||||
| test.cpp:151:18:151:23 | string indirection | test.cpp:151:18:151:23 | string |
|
||||
| test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string |
|
||||
| test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string indirection |
|
||||
| test.cpp:152:18:152:23 | string indirection | test.cpp:152:18:152:23 | string |
|
||||
| test.cpp:154:13:154:15 | str indirection [string] | test.cpp:154:18:154:23 | string |
|
||||
| test.cpp:154:13:154:15 | str indirection [string] | test.cpp:154:18:154:23 | string indirection |
|
||||
| test.cpp:154:18:154:23 | string indirection | test.cpp:154:18:154:23 | string |
|
||||
| test.cpp:155:13:155:15 | str indirection [string] | test.cpp:155:18:155:23 | string |
|
||||
| test.cpp:155:13:155:15 | str indirection [string] | test.cpp:155:18:155:23 | string indirection |
|
||||
| test.cpp:155:18:155:23 | string indirection | test.cpp:155:18:155:23 | string |
|
||||
| test.cpp:156:13:156:15 | str indirection [string] | test.cpp:156:18:156:23 | string |
|
||||
| test.cpp:156:13:156:15 | str indirection [string] | test.cpp:156:18:156:23 | string indirection |
|
||||
| test.cpp:156:18:156:23 | string indirection | test.cpp:156:18:156:23 | string |
|
||||
| test.cpp:159:17:159:19 | str indirection [string] | test.cpp:159:22:159:27 | string |
|
||||
| test.cpp:159:17:159:19 | str indirection [string] | test.cpp:159:22:159:27 | string indirection |
|
||||
| test.cpp:159:22:159:27 | string indirection | test.cpp:159:22:159:27 | string |
|
||||
| test.cpp:163:17:163:19 | str indirection [string] | test.cpp:163:22:163:27 | string |
|
||||
| test.cpp:163:17:163:19 | str indirection [string] | test.cpp:163:22:163:27 | string indirection |
|
||||
| test.cpp:163:22:163:27 | string indirection | test.cpp:163:22:163:27 | string |
|
||||
| test.cpp:167:17:167:19 | str indirection [string] | test.cpp:167:22:167:27 | string |
|
||||
| test.cpp:167:17:167:19 | str indirection [string] | test.cpp:167:22:167:27 | string indirection |
|
||||
| test.cpp:167:22:167:27 | string indirection | test.cpp:167:22:167:27 | string |
|
||||
| test.cpp:171:17:171:19 | str indirection [string] | test.cpp:171:22:171:27 | string |
|
||||
| test.cpp:171:17:171:19 | str indirection [string] | test.cpp:171:22:171:27 | string indirection |
|
||||
| test.cpp:171:22:171:27 | string indirection | test.cpp:171:22:171:27 | string |
|
||||
| test.cpp:175:17:175:19 | str indirection [string] | test.cpp:175:22:175:27 | string |
|
||||
| test.cpp:175:17:175:19 | str indirection [string] | test.cpp:175:22:175:27 | string indirection |
|
||||
| test.cpp:175:22:175:27 | string indirection | test.cpp:175:22:175:27 | string |
|
||||
| test.cpp:179:17:179:19 | str indirection [string] | test.cpp:179:22:179:27 | string |
|
||||
| test.cpp:179:17:179:19 | str indirection [string] | test.cpp:179:22:179:27 | string indirection |
|
||||
| test.cpp:179:22:179:27 | string indirection | test.cpp:179:22:179:27 | string |
|
||||
| test.cpp:183:17:183:19 | str indirection [string] | test.cpp:183:22:183:27 | string |
|
||||
| test.cpp:183:17:183:19 | str indirection [string] | test.cpp:183:22:183:27 | string indirection |
|
||||
| test.cpp:183:22:183:27 | string indirection | test.cpp:183:22:183:27 | string |
|
||||
| test.cpp:187:17:187:19 | str indirection [string] | test.cpp:187:22:187:27 | string |
|
||||
| test.cpp:187:17:187:19 | str indirection [string] | test.cpp:187:22:187:27 | string indirection |
|
||||
| test.cpp:187:22:187:27 | string indirection | test.cpp:187:22:187:27 | string |
|
||||
| test.cpp:191:17:191:19 | str indirection [string] | test.cpp:191:22:191:27 | string |
|
||||
| test.cpp:191:17:191:19 | str indirection [string] | test.cpp:191:22:191:27 | string indirection |
|
||||
| test.cpp:191:22:191:27 | string indirection | test.cpp:191:22:191:27 | string |
|
||||
| test.cpp:195:17:195:19 | str indirection [string] | test.cpp:195:22:195:27 | string |
|
||||
| test.cpp:195:17:195:19 | str indirection [string] | test.cpp:195:22:195:27 | string indirection |
|
||||
| test.cpp:195:22:195:27 | string indirection | test.cpp:195:22:195:27 | string |
|
||||
| test.cpp:199:17:199:19 | str indirection [string] | test.cpp:199:22:199:27 | string |
|
||||
| test.cpp:199:17:199:19 | str indirection [string] | test.cpp:199:22:199:27 | string indirection |
|
||||
| test.cpp:199:22:199:27 | string indirection | test.cpp:199:22:199:27 | string |
|
||||
| test.cpp:203:17:203:19 | str indirection [string] | test.cpp:203:22:203:27 | string |
|
||||
| test.cpp:203:17:203:19 | str indirection [string] | test.cpp:203:22:203:27 | string indirection |
|
||||
| test.cpp:203:22:203:27 | string indirection | test.cpp:203:22:203:27 | string |
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string |
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string indirection |
|
||||
| test.cpp:207:22:207:27 | string indirection | test.cpp:207:22:207:27 | string |
|
||||
| test.cpp:214:24:214:24 | p | test.cpp:216:10:216:10 | p |
|
||||
| test.cpp:220:43:220:48 | call to malloc | test.cpp:222:15:222:20 | buffer |
|
||||
| test.cpp:222:15:222:20 | buffer | test.cpp:214:24:214:24 | p |
|
||||
| test.cpp:228:43:228:48 | call to malloc | test.cpp:232:10:232:15 | buffer |
|
||||
| test.cpp:235:40:235:45 | buffer | test.cpp:236:5:236:26 | ... = ... |
|
||||
| test.cpp:236:5:236:26 | ... = ... | test.cpp:236:12:236:17 | p_str indirection [post update] [string] |
|
||||
| test.cpp:241:27:241:32 | call to malloc | test.cpp:242:22:242:27 | buffer |
|
||||
| test.cpp:242:16:242:19 | set_string output argument [string] | test.cpp:243:12:243:14 | str indirection [string] |
|
||||
| test.cpp:242:22:242:27 | buffer | test.cpp:235:40:235:45 | buffer |
|
||||
| test.cpp:242:22:242:27 | buffer | test.cpp:242:16:242:19 | set_string output argument [string] |
|
||||
| test.cpp:243:12:243:14 | str indirection [string] | test.cpp:243:12:243:21 | string |
|
||||
| test.cpp:243:12:243:14 | str indirection [string] | test.cpp:243:16:243:21 | string indirection |
|
||||
| test.cpp:243:16:243:21 | string indirection | test.cpp:243:12:243:21 | string |
|
||||
nodes
|
||||
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | semmle.label | mk_string_t indirection [string] |
|
||||
| test.cpp:18:5:18:30 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:18:10:18:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
|
||||
| test.cpp:18:19:18:24 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:24:21:24:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
|
||||
| test.cpp:26:13:26:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:26:18:26:23 | string | semmle.label | string |
|
||||
| test.cpp:26:18:26:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:29:32:29:34 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:30:13:30:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:30:18:30:23 | string | semmle.label | string |
|
||||
| test.cpp:30:18:30:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:34:21:34:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
|
||||
| test.cpp:35:21:35:23 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
|
||||
| test.cpp:41:13:41:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:41:18:41:23 | string | semmle.label | string |
|
||||
| test.cpp:41:18:41:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:42:13:42:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:42:18:42:23 | string | semmle.label | string |
|
||||
| test.cpp:42:18:42:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:44:13:44:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:44:18:44:23 | string | semmle.label | string |
|
||||
| test.cpp:44:18:44:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:45:13:45:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:45:18:45:23 | string | semmle.label | string |
|
||||
| test.cpp:45:18:45:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:48:17:48:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:48:22:48:27 | string | semmle.label | string |
|
||||
| test.cpp:48:22:48:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:52:17:52:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:52:22:52:27 | string | semmle.label | string |
|
||||
| test.cpp:52:22:52:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:56:17:56:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:56:22:56:27 | string | semmle.label | string |
|
||||
| test.cpp:56:22:56:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:60:17:60:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:60:22:60:27 | string | semmle.label | string |
|
||||
| test.cpp:60:22:60:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:64:17:64:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:64:22:64:27 | string | semmle.label | string |
|
||||
| test.cpp:64:22:64:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:68:17:68:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:68:22:68:27 | string | semmle.label | string |
|
||||
| test.cpp:68:22:68:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:72:17:72:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:72:22:72:27 | string | semmle.label | string |
|
||||
| test.cpp:72:22:72:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:76:17:76:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:76:22:76:27 | string | semmle.label | string |
|
||||
| test.cpp:76:22:76:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:80:17:80:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:80:22:80:27 | string | semmle.label | string |
|
||||
| test.cpp:80:22:80:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:84:17:84:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:84:22:84:27 | string | semmle.label | string |
|
||||
| test.cpp:84:22:84:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | semmle.label | mk_string_t_plus_one indirection [string] |
|
||||
| test.cpp:90:5:90:34 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:90:10:90:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
|
||||
| test.cpp:90:19:90:24 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | semmle.label | call to mk_string_t_plus_one indirection [string] |
|
||||
| test.cpp:98:13:98:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:98:18:98:23 | string | semmle.label | string |
|
||||
| test.cpp:98:18:98:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:99:13:99:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:99:18:99:23 | string | semmle.label | string |
|
||||
| test.cpp:99:18:99:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:101:13:101:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:101:18:101:23 | string | semmle.label | string |
|
||||
| test.cpp:101:18:101:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:102:13:102:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:102:18:102:23 | string | semmle.label | string |
|
||||
| test.cpp:102:18:102:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:105:17:105:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:105:22:105:27 | string | semmle.label | string |
|
||||
| test.cpp:105:22:105:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:109:17:109:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:109:22:109:27 | string | semmle.label | string |
|
||||
| test.cpp:109:22:109:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:113:17:113:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:113:22:113:27 | string | semmle.label | string |
|
||||
| test.cpp:113:22:113:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:117:17:117:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:117:22:117:27 | string | semmle.label | string |
|
||||
| test.cpp:117:22:117:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:121:17:121:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:121:22:121:27 | string | semmle.label | string |
|
||||
| test.cpp:121:22:121:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:125:17:125:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:125:22:125:27 | string | semmle.label | string |
|
||||
| test.cpp:125:22:125:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:129:17:129:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:129:22:129:27 | string | semmle.label | string |
|
||||
| test.cpp:129:22:129:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:133:17:133:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:133:22:133:27 | string | semmle.label | string |
|
||||
| test.cpp:133:22:133:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:137:17:137:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:137:22:137:27 | string | semmle.label | string |
|
||||
| test.cpp:137:22:137:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:141:17:141:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:141:22:141:27 | string | semmle.label | string |
|
||||
| test.cpp:141:22:141:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:147:5:147:34 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:147:10:147:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
|
||||
| test.cpp:147:19:147:24 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:150:13:150:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:150:18:150:23 | string | semmle.label | string |
|
||||
| test.cpp:150:18:150:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:151:13:151:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:151:18:151:23 | string | semmle.label | string |
|
||||
| test.cpp:151:18:151:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:152:13:152:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:152:18:152:23 | string | semmle.label | string |
|
||||
| test.cpp:152:18:152:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:154:13:154:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:154:18:154:23 | string | semmle.label | string |
|
||||
| test.cpp:154:18:154:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:155:13:155:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:155:18:155:23 | string | semmle.label | string |
|
||||
| test.cpp:155:18:155:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:156:13:156:15 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:156:18:156:23 | string | semmle.label | string |
|
||||
| test.cpp:156:18:156:23 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:159:17:159:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:159:22:159:27 | string | semmle.label | string |
|
||||
| test.cpp:159:22:159:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:163:17:163:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:163:22:163:27 | string | semmle.label | string |
|
||||
| test.cpp:163:22:163:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:167:17:167:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:167:22:167:27 | string | semmle.label | string |
|
||||
| test.cpp:167:22:167:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:171:17:171:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:171:22:171:27 | string | semmle.label | string |
|
||||
| test.cpp:171:22:171:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:175:17:175:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:175:22:175:27 | string | semmle.label | string |
|
||||
| test.cpp:175:22:175:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:179:17:179:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:179:22:179:27 | string | semmle.label | string |
|
||||
| test.cpp:179:22:179:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:183:17:183:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:183:22:183:27 | string | semmle.label | string |
|
||||
| test.cpp:183:22:183:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:187:17:187:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:187:22:187:27 | string | semmle.label | string |
|
||||
| test.cpp:187:22:187:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:191:17:191:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:191:22:191:27 | string | semmle.label | string |
|
||||
| test.cpp:191:22:191:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:195:17:195:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:195:22:195:27 | string | semmle.label | string |
|
||||
| test.cpp:195:22:195:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:199:17:199:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:199:22:199:27 | string | semmle.label | string |
|
||||
| test.cpp:199:22:199:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:203:17:203:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:203:22:203:27 | string | semmle.label | string |
|
||||
| test.cpp:203:22:203:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:207:22:207:27 | string | semmle.label | string |
|
||||
| test.cpp:207:22:207:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:214:24:214:24 | p | semmle.label | p |
|
||||
| test.cpp:216:10:216:10 | p | semmle.label | p |
|
||||
| test.cpp:220:43:220:48 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:222:15:222:20 | buffer | semmle.label | buffer |
|
||||
| test.cpp:228:43:228:48 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:232:10:232:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:235:40:235:45 | buffer | semmle.label | buffer |
|
||||
| test.cpp:236:5:236:26 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:236:12:236:17 | p_str indirection [post update] [string] | semmle.label | p_str indirection [post update] [string] |
|
||||
| test.cpp:241:27:241:32 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:242:16:242:19 | set_string output argument [string] | semmle.label | set_string output argument [string] |
|
||||
| test.cpp:242:22:242:27 | buffer | semmle.label | buffer |
|
||||
| test.cpp:243:12:243:14 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:243:12:243:21 | string | semmle.label | string |
|
||||
| test.cpp:243:16:243:21 | string indirection | semmle.label | string indirection |
|
||||
subpaths
|
||||
| test.cpp:242:22:242:27 | buffer | test.cpp:235:40:235:45 | buffer | test.cpp:236:12:236:17 | p_str indirection [post update] [string] | test.cpp:242:16:242:19 | set_string output argument [string] |
|
||||
#select
|
||||
| test.cpp:42:5:42:11 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:42:18:42:23 | string | This write may overflow $@ by 1 element. | test.cpp:42:18:42:23 | string | string |
|
||||
| test.cpp:72:9:72:15 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:72:22:72:27 | string | This write may overflow $@ by 1 element. | test.cpp:72:22:72:27 | string | string |
|
||||
| test.cpp:80:9:80:15 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:80:22:80:27 | string | This write may overflow $@ by 2 elements. | test.cpp:80:22:80:27 | string | string |
|
||||
| test.cpp:99:5:99:11 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:99:18:99:23 | string | This write may overflow $@ by 1 element. | test.cpp:99:18:99:23 | string | string |
|
||||
| test.cpp:129:9:129:15 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:129:22:129:27 | string | This write may overflow $@ by 1 element. | test.cpp:129:22:129:27 | string | string |
|
||||
| test.cpp:137:9:137:15 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:137:22:137:27 | string | This write may overflow $@ by 2 elements. | test.cpp:137:22:137:27 | string | string |
|
||||
| test.cpp:152:5:152:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:152:18:152:23 | string | This write may overflow $@ by 1 element. | test.cpp:152:18:152:23 | string | string |
|
||||
| test.cpp:154:5:154:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:154:18:154:23 | string | This write may overflow $@ by 1 element. | test.cpp:154:18:154:23 | string | string |
|
||||
| test.cpp:156:5:156:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:156:18:156:23 | string | This write may overflow $@ by 2 elements. | test.cpp:156:18:156:23 | string | string |
|
||||
| test.cpp:175:9:175:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:175:22:175:27 | string | This write may overflow $@ by 1 element. | test.cpp:175:22:175:27 | string | string |
|
||||
| test.cpp:187:9:187:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:187:22:187:27 | string | This write may overflow $@ by 1 element. | test.cpp:187:22:187:27 | string | string |
|
||||
| test.cpp:195:9:195:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:195:22:195:27 | string | This write may overflow $@ by 1 element. | test.cpp:195:22:195:27 | string | string |
|
||||
| test.cpp:199:9:199:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:199:22:199:27 | string | This write may overflow $@ by 2 elements. | test.cpp:199:22:199:27 | string | string |
|
||||
| test.cpp:203:9:203:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:203:22:203:27 | string | This write may overflow $@ by 2 elements. | test.cpp:203:22:203:27 | string | string |
|
||||
| test.cpp:207:9:207:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:207:22:207:27 | string | This write may overflow $@ by 3 elements. | test.cpp:207:22:207:27 | string | string |
|
||||
| test.cpp:232:3:232:8 | call to memset | test.cpp:228:43:228:48 | call to malloc | test.cpp:232:10:232:15 | buffer | This write may overflow $@ by 32 elements. | test.cpp:232:10:232:15 | buffer | buffer |
|
||||
| test.cpp:243:5:243:10 | call to memset | test.cpp:241:27:241:32 | call to malloc | test.cpp:243:12:243:21 | string | This write may overflow $@ by 1 element. | test.cpp:243:16:243:21 | string | string |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Likely Bugs/OverrunWriteProductFlow.ql
|
||||
@@ -213,7 +213,7 @@ void *memset(void *, int, unsigned);
|
||||
|
||||
void call_memset(void *p, unsigned size)
|
||||
{
|
||||
memset(p, 0, size); // GOOD
|
||||
memset(p, 0, size); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test_missing_call_context(unsigned char *unrelated_buffer, unsigned size) {
|
||||
@@ -229,7 +229,7 @@ void repeated_alerts(unsigned size, unsigned offset) {
|
||||
while(unknown()) {
|
||||
++size;
|
||||
}
|
||||
memset(buffer, 0, size); // BAD [NOT DETECTED]
|
||||
memset(buffer, 0, size); // BAD
|
||||
}
|
||||
|
||||
void set_string(string_t* p_str, char* buffer) {
|
||||
@@ -243,25 +243,3 @@ void test_flow_through_setter(unsigned size) {
|
||||
memset(str.string, 0, size + 1); // BAD
|
||||
}
|
||||
|
||||
void* my_alloc(unsigned size);
|
||||
|
||||
void foo(unsigned size) {
|
||||
int* p = (int*)my_alloc(size); // BAD
|
||||
memset(p, 0, size + 1);
|
||||
}
|
||||
|
||||
void test6(unsigned long n, char *p) {
|
||||
while (unknown()) {
|
||||
n++;
|
||||
p = (char *)malloc(n);
|
||||
memset(p, 0, n); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test7(unsigned n) {
|
||||
char* p = (char*)malloc(n);
|
||||
if(!p) {
|
||||
p = (char*)malloc(++n);
|
||||
}
|
||||
memset(p, 0, n); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
| test.cpp:18:6:18:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition |
|
||||
| test.cpp:19:6:19:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition |
|
||||
| test.cpp:20:6:20:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition |
|
||||
| test.cpp:21:6:21:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition |
|
||||
| test.cpp:22:6:22:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition |
|
||||
| test.cpp:23:6:23:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition |
|
||||
| test.cpp:24:6:24:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition |
|
||||
| test.cpp:25:6:25:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition |
|
||||
| test.cpp:27:6:27:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition |
|
||||
| test.cpp:28:6:28:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition |
|
||||
| test.cpp:29:6:29:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition |
|
||||
| test.cpp:30:6:30:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition |
|
||||
| test.cpp:31:6:31:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition |
|
||||
| test.cpp:32:6:32:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition |
|
||||
| test.cpp:33:6:33:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition |
|
||||
| test.cpp:34:6:34:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition |
|
||||
| test.cpp:36:6:36:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition |
|
||||
| test.cpp:37:6:37:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition |
|
||||
| test.cpp:38:6:38:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition |
|
||||
| test.cpp:39:6:39:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition |
|
||||
| test.cpp:40:6:40:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition |
|
||||
| test.cpp:41:6:41:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition |
|
||||
| test.cpp:42:6:42:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition |
|
||||
| test.cpp:43:6:43:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition |
|
||||
| test.cpp:45:6:45:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition |
|
||||
| test.cpp:46:6:46:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition |
|
||||
| test.cpp:47:6:47:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition |
|
||||
| test.cpp:48:6:48:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition |
|
||||
| test.cpp:49:6:49:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition |
|
||||
| test.cpp:50:6:50:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition |
|
||||
| test.cpp:51:6:51:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition |
|
||||
| test.cpp:52:6:52:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition |
|
||||
| test.cpp:54:6:54:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition |
|
||||
| test.cpp:61:6:61:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:61:6:61:8 | ... + ... | addition |
|
||||
| test.cpp:62:6:62:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:62:6:62:8 | ... + ... | addition |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
int getAnInt();
|
||||
double getADouble();
|
||||
unsigned short getAnUnsignedShort();
|
||||
|
||||
void test()
|
||||
{
|
||||
int a = getAnInt();
|
||||
int b = getAnInt();
|
||||
int c = getAnInt();
|
||||
int x = getAnInt();
|
||||
int y = getAnInt();
|
||||
double d = getADouble();
|
||||
unsigned short a1 = getAnUnsignedShort();
|
||||
unsigned short b1 = getAnUnsignedShort();
|
||||
unsigned short c1 = getAnUnsignedShort();
|
||||
|
||||
if (a+b>c) a = c-b; // BAD
|
||||
if (a+b>c) { a = c-b; } // BAD
|
||||
if (b+a>c) a = c-b; // BAD
|
||||
if (b+a>c) { a = c-b; } // BAD
|
||||
if (c>a+b) a = c-b; // BAD
|
||||
if (c>a+b) { a = c-b; } // BAD
|
||||
if (c>b+a) a = c-b; // BAD
|
||||
if (c>b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b>=c) a = c-b; // BAD
|
||||
if (a+b>=c) { a = c-b; } // BAD
|
||||
if (b+a>=c) a = c-b; // BAD
|
||||
if (b+a>=c) { a = c-b; } // BAD
|
||||
if (c>=a+b) a = c-b; // BAD
|
||||
if (c>=a+b) { a = c-b; } // BAD
|
||||
if (c>=b+a) a = c-b; // BAD
|
||||
if (c>=b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b<c) a = c-b; // BAD
|
||||
if (a+b<c) { a = c-b; } // BAD
|
||||
if (b+a<c) a = c-b; // BAD
|
||||
if (b+a<c) { a = c-b; } // BAD
|
||||
if (c<a+b) a = c-b; // BAD
|
||||
if (c<a+b) { a = c-b; } // BAD
|
||||
if (c<b+a) a = c-b; // BAD
|
||||
if (c<b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b<=c) a = c-b; // BAD
|
||||
if (a+b<=c) { a = c-b; } // BAD
|
||||
if (b+a<=c) a = c-b; // BAD
|
||||
if (b+a<=c) { a = c-b; } // BAD
|
||||
if (c<=a+b) a = c-b; // BAD
|
||||
if (c<=a+b) { a = c-b; } // BAD
|
||||
if (c<=b+a) a = c-b; // BAD
|
||||
if (c<=b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b>d) a = d-b; // BAD
|
||||
if (a+(double)b>c) a = c-b; // GOOD
|
||||
if (a+(-x)>c) a = c-(-y); // GOOD
|
||||
if (a+b>c) { b++; a = c-b; } // GOOD
|
||||
if (a+d>c) a = c-d; // GOOD
|
||||
if (a1+b1>c1) a1 = c1-b1; // GOOD
|
||||
|
||||
if (a+b<=c) { /* ... */ } else { a = c-b; } // BAD
|
||||
if (a+b<=c) { return; } a = c-b; // BAD
|
||||
}
|
||||
@@ -1,46 +1,37 @@
|
||||
edges
|
||||
| test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array |
|
||||
| test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array |
|
||||
| test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array |
|
||||
| test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array |
|
||||
| test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array |
|
||||
| test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array |
|
||||
| test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array |
|
||||
| test.cpp:66:32:66:32 | p | test.cpp:66:32:66:32 | p |
|
||||
| test.cpp:66:32:66:32 | p | test.cpp:67:5:67:6 | * ... |
|
||||
| test.cpp:66:32:66:32 | p | test.cpp:67:6:67:6 | p |
|
||||
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
|
||||
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... |
|
||||
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p |
|
||||
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf |
|
||||
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
|
||||
| test.cpp:77:27:77:44 | access to array | test.cpp:77:26:77:44 | & ... |
|
||||
nodes
|
||||
| test.cpp:35:5:35:22 | access to array | semmle.label | access to array |
|
||||
| test.cpp:35:10:35:12 | buf | semmle.label | buf |
|
||||
| test.cpp:36:5:36:24 | access to array | semmle.label | access to array |
|
||||
| test.cpp:36:10:36:12 | buf | semmle.label | buf |
|
||||
| test.cpp:43:9:43:19 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:14:43:16 | buf | semmle.label | buf |
|
||||
| test.cpp:49:5:49:22 | access to array | semmle.label | access to array |
|
||||
| test.cpp:49:10:49:12 | buf | semmle.label | buf |
|
||||
| test.cpp:50:5:50:24 | access to array | semmle.label | access to array |
|
||||
| test.cpp:50:10:50:12 | buf | semmle.label | buf |
|
||||
| test.cpp:57:9:57:19 | access to array | semmle.label | access to array |
|
||||
| test.cpp:57:14:57:16 | buf | semmle.label | buf |
|
||||
| test.cpp:61:9:61:19 | access to array | semmle.label | access to array |
|
||||
| test.cpp:61:14:61:16 | buf | semmle.label | buf |
|
||||
| test.cpp:66:32:66:32 | p | semmle.label | p |
|
||||
| test.cpp:70:33:70:33 | p | semmle.label | p |
|
||||
| test.cpp:66:32:66:32 | p | semmle.label | p |
|
||||
| test.cpp:66:32:66:32 | p | semmle.label | p |
|
||||
| test.cpp:67:5:67:6 | * ... | semmle.label | * ... |
|
||||
| test.cpp:67:6:67:6 | p | semmle.label | p |
|
||||
| test.cpp:72:5:72:15 | access to array | semmle.label | access to array |
|
||||
| test.cpp:77:26:77:44 | & ... | semmle.label | & ... |
|
||||
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
|
||||
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
|
||||
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
|
||||
| test.cpp:77:27:77:44 | access to array | semmle.label | access to array |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
|
||||
| test.cpp:36:5:36:24 | PointerAdd: access to array | test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:36:5:36:28 | Store: ... = ... | write |
|
||||
| test.cpp:43:9:43:19 | PointerAdd: access to array | test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:43:9:43:23 | Store: ... = ... | write |
|
||||
| test.cpp:49:5:49:22 | PointerAdd: access to array | test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:49:5:49:26 | Store: ... = ... | write |
|
||||
| test.cpp:50:5:50:24 | PointerAdd: access to array | test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:50:5:50:28 | Store: ... = ... | write |
|
||||
| test.cpp:57:9:57:19 | PointerAdd: access to array | test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:57:9:57:23 | Store: ... = ... | write |
|
||||
| test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
|
||||
| test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
| test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
|
||||
| test.cpp:36:5:36:24 | access to array | test.cpp:36:5:36:24 | access to array | test.cpp:36:5:36:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:36:5:36:28 | Store: ... = ... | write |
|
||||
| test.cpp:43:9:43:19 | access to array | test.cpp:43:9:43:19 | access to array | test.cpp:43:9:43:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:43:9:43:23 | Store: ... = ... | write |
|
||||
| test.cpp:49:5:49:22 | access to array | test.cpp:49:5:49:22 | access to array | test.cpp:49:5:49:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:49:5:49:26 | Store: ... = ... | write |
|
||||
| test.cpp:50:5:50:24 | access to array | test.cpp:50:5:50:24 | access to array | test.cpp:50:5:50:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:50:5:50:28 | Store: ... = ... | write |
|
||||
| test.cpp:57:9:57:19 | access to array | test.cpp:57:9:57:19 | access to array | test.cpp:57:9:57:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:57:9:57:23 | Store: ... = ... | write |
|
||||
| test.cpp:61:9:61:19 | access to array | test.cpp:61:9:61:19 | access to array | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
|
||||
| test.cpp:72:5:72:15 | access to array | test.cpp:72:5:72:15 | access to array | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:67:5:67:6 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:67:6:67:6 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
|
||||
@@ -78,45 +78,3 @@ void testInterproc(BigArray *arr) {
|
||||
|
||||
addToPointerAndAssign(arr->buf);
|
||||
}
|
||||
|
||||
#define MAX_SIZE_BYTES 4096
|
||||
|
||||
void testCharIndex(BigArray *arr) {
|
||||
char *charBuf = (char*) arr->buf;
|
||||
|
||||
charBuf[MAX_SIZE_BYTES - 1] = 0; // GOOD
|
||||
charBuf[MAX_SIZE_BYTES] = 0; // BAD [FALSE NEGATIVE]
|
||||
}
|
||||
|
||||
void testEqRefinement() {
|
||||
int arr[MAX_SIZE];
|
||||
|
||||
for(int i = 0; i <= MAX_SIZE; i++) {
|
||||
if(i != MAX_SIZE) {
|
||||
arr[i] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testEqRefinement2() {
|
||||
int arr[MAX_SIZE];
|
||||
|
||||
int n = 0;
|
||||
|
||||
for(int i = 0; i <= MAX_SIZE; i++) {
|
||||
if(n == 0) {
|
||||
if(i == MAX_SIZE) {
|
||||
break;
|
||||
}
|
||||
n = arr[i]; // GOOD
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == MAX_SIZE || n != arr[i]) {
|
||||
if (i == MAX_SIZE) {
|
||||
break;
|
||||
}
|
||||
n = arr[i]; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,453 +649,17 @@ edges
|
||||
| test.cpp:280:13:280:24 | new[] | test.cpp:281:14:281:15 | xs |
|
||||
| test.cpp:290:13:290:24 | new[] | test.cpp:291:14:291:15 | xs |
|
||||
| test.cpp:290:13:290:24 | new[] | test.cpp:292:30:292:30 | x |
|
||||
| test.cpp:304:15:304:26 | new[] | test.cpp:307:5:307:6 | xs |
|
||||
| test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:6 | xs |
|
||||
| test.cpp:308:5:308:6 | xs | test.cpp:308:5:308:11 | access to array |
|
||||
| test.cpp:308:5:308:11 | access to array | test.cpp:308:5:308:29 | Store: ... = ... |
|
||||
| test.cpp:313:14:313:27 | new[] | test.cpp:314:15:314:16 | xs |
|
||||
| test.cpp:325:14:325:27 | new[] | test.cpp:326:15:326:16 | xs |
|
||||
| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... |
|
||||
| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... |
|
||||
| test.cpp:326:15:326:16 | xs | test.cpp:338:8:338:15 | * ... |
|
||||
| test.cpp:326:15:326:16 | xs | test.cpp:341:8:341:17 | * ... |
|
||||
| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:16 | xs |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:31 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:26 | end | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:26 | end | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p |
|
||||
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
|
||||
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
|
||||
| test.cpp:371:7:371:7 | p | test.cpp:372:15:372:16 | Load: * ... |
|
||||
| test.cpp:372:16:372:16 | p | test.cpp:372:15:372:16 | Load: * ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:16 | xs |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:381:5:381:7 | end | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:384:14:384:16 | end | test.cpp:384:13:384:16 | Load: * ... |
|
||||
nodes
|
||||
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:5:15:5:15 | p | semmle.label | p |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:6:14:6:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:6:15:6:15 | q | semmle.label | q |
|
||||
| test.cpp:6:15:6:15 | q | semmle.label | q |
|
||||
| test.cpp:7:16:7:16 | q | semmle.label | q |
|
||||
| test.cpp:7:16:7:16 | q | semmle.label | q |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:8:16:8:16 | q | semmle.label | q |
|
||||
| test.cpp:8:16:8:16 | q | semmle.label | q |
|
||||
| test.cpp:8:16:8:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:9:16:9:16 | q | semmle.label | q |
|
||||
| test.cpp:9:16:9:16 | q | semmle.label | q |
|
||||
| test.cpp:10:16:10:16 | q | semmle.label | q |
|
||||
| test.cpp:10:16:10:16 | q | semmle.label | q |
|
||||
| test.cpp:11:16:11:16 | q | semmle.label | q |
|
||||
| test.cpp:11:16:11:16 | q | semmle.label | q |
|
||||
| test.cpp:12:16:12:16 | q | semmle.label | q |
|
||||
| test.cpp:16:15:16:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:17:15:17:15 | p | semmle.label | p |
|
||||
| test.cpp:17:15:17:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:20:14:20:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:20:16:20:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:28:15:28:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:29:15:29:15 | p | semmle.label | p |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:30:14:30:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:30:15:30:15 | q | semmle.label | q |
|
||||
| test.cpp:30:15:30:15 | q | semmle.label | q |
|
||||
| test.cpp:31:16:31:16 | q | semmle.label | q |
|
||||
| test.cpp:31:16:31:16 | q | semmle.label | q |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:32:16:32:16 | q | semmle.label | q |
|
||||
| test.cpp:32:16:32:16 | q | semmle.label | q |
|
||||
| test.cpp:32:16:32:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:33:16:33:16 | q | semmle.label | q |
|
||||
| test.cpp:33:16:33:16 | q | semmle.label | q |
|
||||
| test.cpp:34:16:34:16 | q | semmle.label | q |
|
||||
| test.cpp:34:16:34:16 | q | semmle.label | q |
|
||||
| test.cpp:35:16:35:16 | q | semmle.label | q |
|
||||
| test.cpp:35:16:35:16 | q | semmle.label | q |
|
||||
| test.cpp:36:16:36:16 | q | semmle.label | q |
|
||||
| test.cpp:40:15:40:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:41:15:41:15 | p | semmle.label | p |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:42:14:42:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:42:15:42:15 | q | semmle.label | q |
|
||||
| test.cpp:42:15:42:15 | q | semmle.label | q |
|
||||
| test.cpp:43:16:43:16 | q | semmle.label | q |
|
||||
| test.cpp:43:16:43:16 | q | semmle.label | q |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:44:16:44:16 | q | semmle.label | q |
|
||||
| test.cpp:44:16:44:16 | q | semmle.label | q |
|
||||
| test.cpp:44:16:44:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:45:16:45:16 | q | semmle.label | q |
|
||||
| test.cpp:45:16:45:16 | q | semmle.label | q |
|
||||
| test.cpp:46:16:46:16 | q | semmle.label | q |
|
||||
| test.cpp:46:16:46:16 | q | semmle.label | q |
|
||||
| test.cpp:47:16:47:16 | q | semmle.label | q |
|
||||
| test.cpp:47:16:47:16 | q | semmle.label | q |
|
||||
| test.cpp:48:16:48:16 | q | semmle.label | q |
|
||||
| test.cpp:51:7:51:14 | mk_array indirection | semmle.label | mk_array indirection |
|
||||
| test.cpp:51:33:51:35 | end | semmle.label | end |
|
||||
| test.cpp:52:19:52:24 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:53:5:53:23 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:53:12:53:16 | begin | semmle.label | begin |
|
||||
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:60:19:60:26 | call to mk_array | semmle.label | call to mk_array |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
||||
| test.cpp:62:32:62:34 | end | semmle.label | end |
|
||||
| test.cpp:62:39:62:39 | p | semmle.label | p |
|
||||
| test.cpp:66:32:66:34 | end | semmle.label | end |
|
||||
| test.cpp:66:39:66:39 | p | semmle.label | p |
|
||||
| test.cpp:67:9:67:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:70:31:70:33 | end | semmle.label | end |
|
||||
| test.cpp:70:38:70:38 | p | semmle.label | p |
|
||||
| test.cpp:80:9:80:16 | mk_array indirection [begin] | semmle.label | mk_array indirection [begin] |
|
||||
| test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] |
|
||||
| test.cpp:82:5:82:28 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:82:17:82:22 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:83:5:83:30 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
||||
| test.cpp:83:15:83:17 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:83:15:83:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:83:19:83:23 | begin | semmle.label | begin |
|
||||
| test.cpp:83:19:83:23 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:89:19:89:26 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
|
||||
| test.cpp:89:19:89:26 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
||||
| test.cpp:91:20:91:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:91:24:91:28 | begin | semmle.label | begin |
|
||||
| test.cpp:91:24:91:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:91:36:91:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:91:40:91:42 | end | semmle.label | end |
|
||||
| test.cpp:91:40:91:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:91:47:91:47 | p | semmle.label | p |
|
||||
| test.cpp:95:20:95:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:95:24:95:28 | begin | semmle.label | begin |
|
||||
| test.cpp:95:24:95:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:95:36:95:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:95:40:95:42 | end | semmle.label | end |
|
||||
| test.cpp:95:40:95:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:95:47:95:47 | p | semmle.label | p |
|
||||
| test.cpp:96:9:96:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:99:20:99:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:99:24:99:28 | begin | semmle.label | begin |
|
||||
| test.cpp:99:24:99:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:99:35:99:37 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:99:39:99:41 | end | semmle.label | end |
|
||||
| test.cpp:99:39:99:41 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:99:46:99:46 | p | semmle.label | p |
|
||||
| test.cpp:104:27:104:29 | arr [begin] | semmle.label | arr [begin] |
|
||||
| test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] |
|
||||
| test.cpp:105:20:105:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:105:24:105:28 | begin | semmle.label | begin |
|
||||
| test.cpp:105:24:105:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:105:36:105:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:105:40:105:42 | end | semmle.label | end |
|
||||
| test.cpp:105:40:105:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:105:47:105:47 | p | semmle.label | p |
|
||||
| test.cpp:109:20:109:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:109:24:109:28 | begin | semmle.label | begin |
|
||||
| test.cpp:109:24:109:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:109:36:109:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:109:40:109:42 | end | semmle.label | end |
|
||||
| test.cpp:109:40:109:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:109:47:109:47 | p | semmle.label | p |
|
||||
| test.cpp:110:9:110:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:113:20:113:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:113:24:113:28 | begin | semmle.label | begin |
|
||||
| test.cpp:113:24:113:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:113:35:113:37 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:113:39:113:41 | end | semmle.label | end |
|
||||
| test.cpp:113:39:113:41 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:113:46:113:46 | p | semmle.label | p |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
||||
| test.cpp:124:15:124:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:125:5:125:17 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:126:15:126:15 | p | semmle.label | p |
|
||||
| test.cpp:129:11:129:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:129:15:129:19 | begin | semmle.label | begin |
|
||||
| test.cpp:129:15:129:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:133:11:133:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:133:15:133:19 | begin | semmle.label | begin |
|
||||
| test.cpp:133:15:133:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:137:11:137:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:137:15:137:19 | begin | semmle.label | begin |
|
||||
| test.cpp:137:15:137:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:141:10:141:19 | mk_array_p indirection [begin] | semmle.label | mk_array_p indirection [begin] |
|
||||
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | semmle.label | mk_array_p indirection [end] |
|
||||
| test.cpp:143:5:143:29 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:143:18:143:23 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:144:5:144:32 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:144:10:144:12 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
||||
| test.cpp:144:16:144:18 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:144:16:144:32 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:144:21:144:25 | begin | semmle.label | begin |
|
||||
| test.cpp:144:21:144:25 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
|
||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
||||
| test.cpp:152:20:152:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:152:25:152:29 | begin | semmle.label | begin |
|
||||
| test.cpp:152:25:152:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:152:49:152:49 | p | semmle.label | p |
|
||||
| test.cpp:156:20:156:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:156:25:156:29 | begin | semmle.label | begin |
|
||||
| test.cpp:156:25:156:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:156:37:156:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:156:42:156:44 | end | semmle.label | end |
|
||||
| test.cpp:156:42:156:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:156:49:156:49 | p | semmle.label | p |
|
||||
| test.cpp:157:9:157:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:160:20:160:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:160:25:160:29 | begin | semmle.label | begin |
|
||||
| test.cpp:160:25:160:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:160:48:160:48 | p | semmle.label | p |
|
||||
| test.cpp:165:29:165:31 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:165:29:165:31 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:166:20:166:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:166:25:166:29 | begin | semmle.label | begin |
|
||||
| test.cpp:166:25:166:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:166:37:166:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:166:42:166:44 | end | semmle.label | end |
|
||||
| test.cpp:166:42:166:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:166:49:166:49 | p | semmle.label | p |
|
||||
| test.cpp:170:20:170:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:170:25:170:29 | begin | semmle.label | begin |
|
||||
| test.cpp:170:25:170:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:170:37:170:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:170:42:170:44 | end | semmle.label | end |
|
||||
| test.cpp:170:42:170:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:170:49:170:49 | p | semmle.label | p |
|
||||
| test.cpp:171:9:171:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:174:20:174:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:174:25:174:29 | begin | semmle.label | begin |
|
||||
| test.cpp:174:25:174:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:174:36:174:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:174:41:174:43 | end | semmle.label | end |
|
||||
| test.cpp:174:41:174:43 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:174:48:174:48 | p | semmle.label | p |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
||||
| test.cpp:188:15:188:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:189:15:189:15 | p | semmle.label | p |
|
||||
| test.cpp:194:23:194:28 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:195:17:195:17 | p | semmle.label | p |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:197:8:197:8 | p | semmle.label | p |
|
||||
| test.cpp:197:20:197:22 | end | semmle.label | end |
|
||||
| test.cpp:201:5:201:5 | p | semmle.label | p |
|
||||
| test.cpp:201:5:201:12 | access to array | semmle.label | access to array |
|
||||
| test.cpp:201:5:201:19 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:205:23:205:28 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:206:17:206:17 | p | semmle.label | p |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:208:15:208:15 | p | semmle.label | p |
|
||||
| test.cpp:209:12:209:14 | end | semmle.label | end |
|
||||
| test.cpp:213:5:213:6 | * ... | semmle.label | * ... |
|
||||
| test.cpp:213:5:213:13 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:213:6:213:6 | q | semmle.label | q |
|
||||
| test.cpp:213:6:213:6 | q | semmle.label | q |
|
||||
| test.cpp:221:17:221:22 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:222:5:222:5 | p | semmle.label | p |
|
||||
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
|
||||
| test.cpp:232:3:232:9 | newname | semmle.label | newname |
|
||||
| test.cpp:232:3:232:16 | access to array | semmle.label | access to array |
|
||||
| test.cpp:232:3:232:20 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
|
||||
| test.cpp:239:5:239:11 | newname | semmle.label | newname |
|
||||
| test.cpp:239:5:239:18 | access to array | semmle.label | access to array |
|
||||
| test.cpp:239:5:239:22 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:248:24:248:30 | call to realloc | semmle.label | call to realloc |
|
||||
| test.cpp:249:9:249:9 | p | semmle.label | p |
|
||||
| test.cpp:250:22:250:22 | p | semmle.label | p |
|
||||
| test.cpp:254:9:254:9 | p | semmle.label | p |
|
||||
| test.cpp:254:9:254:12 | access to array | semmle.label | access to array |
|
||||
| test.cpp:254:9:254:16 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:261:14:261:15 | xs | semmle.label | xs |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:262:26:262:28 | end | semmle.label | end |
|
||||
| test.cpp:262:26:262:28 | end | semmle.label | end |
|
||||
| test.cpp:262:31:262:31 | x | semmle.label | x |
|
||||
| test.cpp:264:13:264:14 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:264:14:264:14 | x | semmle.label | x |
|
||||
| test.cpp:264:14:264:14 | x | semmle.label | x |
|
||||
| test.cpp:270:13:270:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:271:14:271:15 | xs | semmle.label | xs |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:272:26:272:28 | end | semmle.label | end |
|
||||
| test.cpp:272:26:272:28 | end | semmle.label | end |
|
||||
| test.cpp:272:31:272:31 | x | semmle.label | x |
|
||||
| test.cpp:272:31:272:31 | x | semmle.label | x |
|
||||
| test.cpp:274:5:274:6 | * ... | semmle.label | * ... |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:274:6:274:6 | x | semmle.label | x |
|
||||
| test.cpp:274:6:274:6 | x | semmle.label | x |
|
||||
| test.cpp:280:13:280:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:281:14:281:15 | xs | semmle.label | xs |
|
||||
| test.cpp:290:13:290:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:291:14:291:15 | xs | semmle.label | xs |
|
||||
| test.cpp:292:30:292:30 | x | semmle.label | x |
|
||||
| test.cpp:304:15:304:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:307:5:307:6 | xs | semmle.label | xs |
|
||||
| test.cpp:308:5:308:6 | xs | semmle.label | xs |
|
||||
| test.cpp:308:5:308:11 | access to array | semmle.label | access to array |
|
||||
| test.cpp:308:5:308:29 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:313:14:313:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:314:15:314:16 | xs | semmle.label | xs |
|
||||
| test.cpp:325:14:325:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:326:15:326:16 | xs | semmle.label | xs |
|
||||
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:338:8:338:15 | * ... | semmle.label | * ... |
|
||||
| test.cpp:341:8:341:17 | * ... | semmle.label | * ... |
|
||||
| test.cpp:342:8:342:17 | * ... | semmle.label | * ... |
|
||||
| test.cpp:347:14:347:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:348:15:348:16 | xs | semmle.label | xs |
|
||||
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:356:15:356:16 | xs | semmle.label | xs |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:26 | end | semmle.label | end |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:358:14:358:26 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:359:14:359:32 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:359:16:359:31 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:363:14:363:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:365:15:365:15 | p | semmle.label | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:371:7:371:7 | p | semmle.label | p |
|
||||
| test.cpp:372:15:372:16 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:372:16:372:16 | p | semmle.label | p |
|
||||
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:378:15:378:16 | xs | semmle.label | xs |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:381:5:381:7 | end | semmle.label | end |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:384:13:384:16 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:384:14:384:16 | end | semmle.label | end |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:20:14:20:21 | Load: * ... | test.cpp:16:15:16:20 | call to malloc | test.cpp:20:14:20:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:16:15:16:20 | call to malloc | call to malloc | test.cpp:17:19:17:22 | size | size |
|
||||
| test.cpp:30:14:30:15 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:30:14:30:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:42:14:42:15 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:67:9:67:14 | Store: ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
||||
| test.cpp:96:9:96:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
||||
| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
||||
@@ -1108,8 +672,3 @@ subpaths
|
||||
| test.cpp:254:9:254:16 | Store: ... = ... | test.cpp:248:24:248:30 | call to realloc | test.cpp:254:9:254:16 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:248:24:248:30 | call to realloc | call to realloc | test.cpp:254:11:254:11 | i | i |
|
||||
| test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||
| test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... |
|
||||
| test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||
| test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||
| test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size |
|
||||
| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size |
|
||||
|
||||
@@ -293,93 +293,4 @@ void test20(unsigned len)
|
||||
{
|
||||
*x = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void* test21_get(int n);
|
||||
|
||||
void test21() {
|
||||
int n = 0;
|
||||
while (test21_get(n)) n+=2;
|
||||
|
||||
void** xs = new void*[n];
|
||||
|
||||
for (int i = 0; i < n; i += 2) {
|
||||
xs[i] = test21_get(i); // GOOD
|
||||
xs[i+1] = test21_get(i+1); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test22(unsigned size, int val) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size; // GOOD
|
||||
char **current = &end;
|
||||
do {
|
||||
if (*current - xs < 1) // GOOD
|
||||
return;
|
||||
*--(*current) = 0; // GOOD
|
||||
val >>= 8;
|
||||
} while (val > 0);
|
||||
}
|
||||
|
||||
void test23(unsigned size, int val) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char **current = &end;
|
||||
|
||||
if (val < 1) {
|
||||
if(*current - xs < 1)
|
||||
return;
|
||||
|
||||
*--(*current) = 0; // GOOD
|
||||
return;
|
||||
}
|
||||
|
||||
if (val < 2) {
|
||||
if(*current - xs < 2)
|
||||
return;
|
||||
|
||||
*--(*current) = 0; // GOOD
|
||||
*--(*current) = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test24(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
if (xs < end) {
|
||||
int val = *xs++; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test25(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end_plus_one = end + 1;
|
||||
int val1 = *end_plus_one; // BAD
|
||||
int val2 = *(end_plus_one + 1); // BAD
|
||||
}
|
||||
|
||||
void test26(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *p = xs;
|
||||
char *end = p + size;
|
||||
|
||||
if (p + 4 <= end) {
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (p < end) {
|
||||
int val = *p; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test27(unsigned size, bool b) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
|
||||
if (b) {
|
||||
end++;
|
||||
}
|
||||
|
||||
int val = *end; // BAD
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,2 @@
|
||||
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:9,8-47)
|
||||
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:20,49-74)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -38,10 +38,12 @@ predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag
|
||||
)
|
||||
}
|
||||
|
||||
module IRDefaultTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = ["ir-path", "ir-sink"] }
|
||||
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
||||
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Element elem, TaintedWithPath::PathNode node, int n |
|
||||
irTaint(_, node, tag) and
|
||||
elem = getElementFromPathNode(node) and
|
||||
@@ -65,10 +67,12 @@ module IRDefaultTaintTrackingTest implements TestSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AstTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "ast" }
|
||||
class AstTaintTrackingTest extends InlineExpectationsTest {
|
||||
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ast" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Expr source, Element tainted, int n |
|
||||
tag = "ast" and
|
||||
astTaint(source, tainted) and
|
||||
@@ -96,5 +100,3 @@ module AstTaintTrackingTest implements TestSig {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:10,8-47)
|
||||
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:21,3-28)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -29,10 +29,12 @@ predicate irTaint(Expr source, Element sink) {
|
||||
TaintedWithPath::taintedWithPath(source, sink, _, _)
|
||||
}
|
||||
|
||||
module IRDefaultTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "ir" }
|
||||
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
||||
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ir" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Expr source, Element tainted, int n |
|
||||
tag = "ir" and
|
||||
irTaint(source, tainted) and
|
||||
@@ -53,10 +55,12 @@ module IRDefaultTaintTrackingTest implements TestSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AstTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "ast" }
|
||||
class AstTaintTrackingTest extends InlineExpectationsTest {
|
||||
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ast" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Expr source, Element tainted, int n |
|
||||
tag = "ast" and
|
||||
astTaint(source, tainted) and
|
||||
@@ -76,5 +80,3 @@ module AstTaintTrackingTest implements TestSig {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:8,3-47)
|
||||
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:12,3-53)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -12,10 +12,12 @@ predicate irTaint(Expr source, Element sink, string globalVar) {
|
||||
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
|
||||
}
|
||||
|
||||
module IRGlobalDefaultTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "ir" }
|
||||
class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
||||
IRGlobalDefaultTaintTrackingTest() { this = "IRGlobalDefaultTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ir" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Element tainted |
|
||||
tag = "ir" and
|
||||
irTaint(_, tainted, value) and
|
||||
@@ -25,10 +27,12 @@ module IRGlobalDefaultTaintTrackingTest implements TestSig {
|
||||
}
|
||||
}
|
||||
|
||||
module AstGlobalDefaultTaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "ast" }
|
||||
class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
||||
AstGlobalDefaultTaintTrackingTest() { this = "ASTGlobalDefaultTaintTrackingTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ast" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Element tainted |
|
||||
tag = "ast" and
|
||||
astTaint(_, tainted, value) and
|
||||
@@ -37,5 +41,3 @@ module AstGlobalDefaultTaintTrackingTest implements TestSig {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<IRGlobalDefaultTaintTrackingTest, AstGlobalDefaultTaintTrackingTest>>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// semmle-extractor-options: --edg --clang
|
||||
|
||||
int source();
|
||||
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
||||
void sink(int); void sink(const int *); void sink(int **);
|
||||
|
||||
struct twoIntFields {
|
||||
int m1, m2;
|
||||
@@ -19,8 +19,7 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
|
||||
|
||||
sink(sourceArray1[0]); // no flow
|
||||
sink(*sourceArray1); // no flow
|
||||
sink(&sourceArray1); // $ ast // [should probably be taint only]
|
||||
indirect_sink(&sourceArray1); // $ ast,ir
|
||||
sink(&sourceArray1); // $ ast,ir // [should probably be taint only]
|
||||
|
||||
sink(sourceStruct1.m1); // no flow
|
||||
sink(sourceStruct1_ptr->m1); // no flow
|
||||
@@ -49,6 +48,5 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
|
||||
|
||||
int stackArray[2] = { source(), source() };
|
||||
stackArray[0] = source();
|
||||
sink(stackArray); // $ ast,ir
|
||||
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
|
||||
sink(stackArray); // $ ast ir ir=49:25 ir=49:35 ir=50:19
|
||||
}
|
||||
|
||||
@@ -28,10 +28,9 @@ postWithInFlow
|
||||
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:22:9:22:20 | sourceArray1 [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:23:18:23:29 | sourceArray1 [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:29:22:29:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:51:3:51:12 | stackArray [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:51:3:51:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:50:3:50:12 | stackArray [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clang.cpp:50:3:50:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| dispatch.cpp:61:3:61:14 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| dispatch.cpp:78:24:78:37 | call to allocateBottom [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
@@ -126,8 +125,6 @@ postWithInFlow
|
||||
| test.cpp:681:3:681:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:689:3:689:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:694:4:694:6 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:704:23:704:25 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
uniqueParameterNodeAtPosition
|
||||
uniqueParameterNodePosition
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -5,10 +5,12 @@ module AstTest {
|
||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||
|
||||
module AstParameterDefTest implements TestSig {
|
||||
string getARelevantTag() { result = "ast-def" }
|
||||
class AstParameterDefTest extends InlineExpectationsTest {
|
||||
AstParameterDefTest() { this = "AstParameterDefTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ast-def" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Function f, Parameter p, RefParameterFinalValueNode n |
|
||||
p.isNamed() and
|
||||
n.getParameter() = p and
|
||||
@@ -31,10 +33,12 @@ module IRTest {
|
||||
(if k = 0 then result = "" else result = "*" + stars(k - 1))
|
||||
}
|
||||
|
||||
module IRParameterDefTest implements TestSig {
|
||||
string getARelevantTag() { result = "ir-def" }
|
||||
class IRParameterDefTest extends InlineExpectationsTest {
|
||||
IRParameterDefTest() { this = "IRParameterDefTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ir-def" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Function f, Parameter p, FinalParameterNode n |
|
||||
p.isNamed() and
|
||||
n.getParameter() = p and
|
||||
@@ -47,5 +51,3 @@ module IRTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<AstTest::AstParameterDefTest, IRTest::IRParameterDefTest>>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -5,10 +5,12 @@ module AstTest {
|
||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||
|
||||
module AstMultipleOutNodesTest implements TestSig {
|
||||
string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
|
||||
class AstMultipleOutNodesTest extends InlineExpectationsTest {
|
||||
AstMultipleOutNodesTest() { this = "AstMultipleOutNodesTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlowCall call, int n, ReturnKind kind |
|
||||
call.getLocation() = location and
|
||||
n = strictcount(getAnOutNode(call, kind)) and
|
||||
@@ -25,10 +27,12 @@ module IRTest {
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
|
||||
module IRMultipleOutNodesTest implements TestSig {
|
||||
string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
|
||||
class IRMultipleOutNodesTest extends InlineExpectationsTest {
|
||||
IRMultipleOutNodesTest() { this = "IRMultipleOutNodesTest" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
override string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlowCall call, int n, ReturnKind kind |
|
||||
call.getLocation() = location and
|
||||
n = strictcount(getAnOutNode(call, kind)) and
|
||||
@@ -40,5 +44,3 @@ module IRTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<AstTest::AstMultipleOutNodesTest, IRTest::IRMultipleOutNodesTest>>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
int source();
|
||||
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
||||
void sink(int); void sink(const int *); void sink(int **);
|
||||
|
||||
void intraprocedural_with_local_flow() {
|
||||
int t2;
|
||||
@@ -626,7 +626,7 @@ void test_def_via_phi_read(bool b)
|
||||
use(buffer);
|
||||
}
|
||||
intPointerSource(buffer);
|
||||
indirect_sink(buffer); // $ ast,ir
|
||||
sink(buffer); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_static_local_1() {
|
||||
@@ -690,16 +690,3 @@ void test_static_local_9() {
|
||||
s = 0;
|
||||
}
|
||||
|
||||
void increment_buf(int** buf) { // $ ast-def=buf ir-def=*buf ir-def=**buf
|
||||
*buf += 10;
|
||||
sink(buf); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
void call_increment_buf(int** buf) { // $ ast-def=buf
|
||||
increment_buf(buf);
|
||||
}
|
||||
|
||||
void test_conflation_regression(int* source) { // $ ast-def=source
|
||||
int* buf = source;
|
||||
call_increment_buf(&buf);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -16,8 +16,10 @@ module AstTest {
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
class AstTestAllocationConfig extends DataFlow::Configuration {
|
||||
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||
or
|
||||
source.asParameter().getName().matches("source%")
|
||||
@@ -30,20 +32,18 @@ module AstTest {
|
||||
exists(source.asUninitialized())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(FunctionCall call |
|
||||
call.getTarget().getName() = ["sink", "indirect_sink"] and
|
||||
call.getTarget().getName() = "sink" and
|
||||
sink.asExpr() = call.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) {
|
||||
override predicate isBarrier(DataFlow::Node barrier) {
|
||||
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
|
||||
}
|
||||
|
||||
module IRTest {
|
||||
@@ -67,8 +67,10 @@ module IRTest {
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
module IRTestAllocationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
class IRTestAllocationConfig extends DataFlow::Configuration {
|
||||
IRTestAllocationConfig() { this = "IRTestAllocationConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||
or
|
||||
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
||||
@@ -80,17 +82,14 @@ module IRTest {
|
||||
exists(source.asUninitialized())
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(FunctionCall call |
|
||||
call.getTarget().getName() = "sink" and
|
||||
sink.asExpr() = e
|
||||
or
|
||||
call.getTarget().getName() = "indirect_sink" and
|
||||
sink.asIndirectExpr() = e
|
||||
call.getAnArgument() in [sink.asExpr(), sink.asIndirectExpr()]
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) {
|
||||
override predicate isBarrier(DataFlow::Node barrier) {
|
||||
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
||||
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
||||
)
|
||||
@@ -100,8 +99,4 @@ module IRTest {
|
||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user