mirror of
https://github.com/github/codeql.git
synced 2025-12-22 19:56:32 +01:00
Merge branch 'main' into jcogs33/update-javascript-sink-kinds
This commit is contained in:
5
.github/workflows/check-change-note.yml
vendored
5
.github/workflows/check-change-note.yml
vendored
@@ -11,7 +11,6 @@ on:
|
|||||||
- "*/ql/lib/**/*.yml"
|
- "*/ql/lib/**/*.yml"
|
||||||
- "!**/experimental/**"
|
- "!**/experimental/**"
|
||||||
- "!ql/**"
|
- "!ql/**"
|
||||||
- "!swift/**"
|
|
||||||
- ".github/workflows/check-change-note.yml"
|
- ".github/workflows/check-change-note.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -27,9 +26,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
|
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
|
||||||
grep true -c
|
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' or 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text.
|
- 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
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
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$"))' |
|
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$"))' |
|
||||||
grep true -c
|
grep true -c
|
||||||
|
|||||||
2
.github/workflows/ql-for-ql-build.yml
vendored
2
.github/workflows/ql-for-ql-build.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
ql/extractor-pack/
|
ql/extractor-pack/
|
||||||
ql/target/release/buramu
|
ql/target/release/buramu
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v3
|
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
|
||||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
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('ruby/extractor/**/*.rs') }}
|
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') }}
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/swift.yml
vendored
2
.github/workflows/swift.yml
vendored
@@ -16,6 +16,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- rc/*
|
- rc/*
|
||||||
|
- codeql-cli-*
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- "swift/**"
|
- "swift/**"
|
||||||
@@ -30,6 +31,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- rc/*
|
- rc/*
|
||||||
|
- codeql-cli-*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
# 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,4 +17,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Check synchronized files
|
- name: Check synchronized files
|
||||||
run: python config/sync-files.py
|
run: python config/sync-files.py
|
||||||
|
- name: Check dbscheme fragments
|
||||||
|
run: python config/sync-dbscheme-fragments.py
|
||||||
|
|
||||||
|
|||||||
16
.vscode/tasks.json
vendored
16
.vscode/tasks.json
vendored
@@ -22,6 +22,22 @@
|
|||||||
"command": "${config:python.pythonPath}",
|
"command": "${config:python.pythonPath}",
|
||||||
},
|
},
|
||||||
"problemMatcher": []
|
"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": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -40,3 +40,6 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
|||||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||||
/.github/workflows/ruby-* @github/codeql-ruby
|
/.github/workflows/ruby-* @github/codeql-ruby
|
||||||
/.github/workflows/swift.yml @github/codeql-swift
|
/.github/workflows/swift.yml @github/codeql-swift
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
||||||
|
|||||||
33
config/dbscheme-fragments.json
Normal file
33
config/dbscheme-fragments.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"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 -*/"
|
||||||
|
]
|
||||||
|
}
|
||||||
86
config/sync-dbscheme-fragments.py
Executable file
86
config/sync-dbscheme-fragments.py
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/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()
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
||||||
|
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||||
|
|
||||||
|
### Major Analysis Improvements
|
||||||
|
|
||||||
|
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||||
|
|
||||||
|
### 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
|
## 0.7.1
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: feature
|
|
||||||
---
|
|
||||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* 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,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: majorAnalysis
|
|
||||||
---
|
|
||||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: feature
|
|
||||||
---
|
|
||||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
|
||||||
15
cpp/ql/lib/change-notes/released/0.7.2.md
Normal file
15
cpp/ql/lib/change-notes/released/0.7.2.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
||||||
|
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||||
|
|
||||||
|
### Major Analysis Improvements
|
||||||
|
|
||||||
|
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||||
|
|
||||||
|
### 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,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.7.1
|
lastReleaseVersion: 0.7.2
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.7.2-dev
|
version: 0.7.3-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
|||||||
* Gets the name of the macro. For example, `MAX` in
|
* Gets the name of the macro. For example, `MAX` in
|
||||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||||
*/
|
*/
|
||||||
string getName() { result = this.getHead().splitAt("(", 0) }
|
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
|
||||||
|
|
||||||
/** Holds if the macro has name `name`. */
|
/** Holds if the macro has name `name`. */
|
||||||
predicate hasName(string name) { this.getName() = name }
|
predicate hasName(string name) { this.getName() = name }
|
||||||
|
|||||||
@@ -230,8 +230,12 @@ class GlobalNamespace extends Namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The C++ `std::` namespace.
|
* The C++ `std::` namespace and its inline namespaces.
|
||||||
*/
|
*/
|
||||||
class StdNamespace extends Namespace {
|
class StdNamespace extends Namespace {
|
||||||
StdNamespace() { this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace }
|
StdNamespace() {
|
||||||
|
this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace
|
||||||
|
or
|
||||||
|
this.isInline() and this.getParentNamespace() instanceof StdNamespace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1699,7 +1699,28 @@ class AutoType extends TemplateParameter {
|
|||||||
|
|
||||||
private predicate suppressUnusedThis(Type t) { any() }
|
private predicate suppressUnusedThis(Type t) { any() }
|
||||||
|
|
||||||
/** A source code location referring to a type */
|
/**
|
||||||
|
* 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`.
|
||||||
|
*/
|
||||||
class TypeMention extends Locatable, @type_mention {
|
class TypeMention extends Locatable, @type_mention {
|
||||||
override string toString() { result = "type mention" }
|
override string toString() { result = "type mention" }
|
||||||
|
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ class IndirectOperand extends Node {
|
|||||||
this.(RawIndirectOperand).getOperand() = operand and
|
this.(RawIndirectOperand).getOperand() = operand and
|
||||||
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
|
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
|
||||||
or
|
or
|
||||||
this.(OperandNode).getOperand() =
|
nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex),
|
||||||
Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex)
|
indirectionIndex - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the underlying operand. */
|
/** Gets the underlying operand. */
|
||||||
@@ -250,8 +250,8 @@ class IndirectInstruction extends Node {
|
|||||||
this.(RawIndirectInstruction).getInstruction() = instr and
|
this.(RawIndirectInstruction).getInstruction() = instr and
|
||||||
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
|
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
|
||||||
or
|
or
|
||||||
this.(InstructionNode).getInstruction() =
|
nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex),
|
||||||
Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex)
|
indirectionIndex - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the underlying instruction. */
|
/** Gets the underlying instruction. */
|
||||||
|
|||||||
@@ -1640,8 +1640,15 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
|
|||||||
localFlow(instructionNode(e1), instructionNode(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
|
cached
|
||||||
private module ExprFlowCached {
|
module ExprFlowCached {
|
||||||
/**
|
/**
|
||||||
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
|
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
|
||||||
* `e` is the result of loading from the `PointerArithmeticInstruction`.
|
* `e` is the result of loading from the `PointerArithmeticInstruction`.
|
||||||
@@ -1692,7 +1699,8 @@ private module ExprFlowCached {
|
|||||||
* `x[i]` steps to the expression `x[i - 1]` without traversing the
|
* `x[i]` steps to the expression `x[i - 1]` without traversing the
|
||||||
* entire chain.
|
* entire chain.
|
||||||
*/
|
*/
|
||||||
private Expr asExpr(Node n) {
|
cached
|
||||||
|
Expr asExprInternal(Node n) {
|
||||||
isIndirectBaseOfArrayAccess(n, result)
|
isIndirectBaseOfArrayAccess(n, result)
|
||||||
or
|
or
|
||||||
not isIndirectBaseOfArrayAccess(n, _) and
|
not isIndirectBaseOfArrayAccess(n, _) and
|
||||||
@@ -1704,7 +1712,7 @@ private module ExprFlowCached {
|
|||||||
* dataflow step.
|
* dataflow step.
|
||||||
*/
|
*/
|
||||||
private predicate localStepFromNonExpr(Node n1, Node n2) {
|
private predicate localStepFromNonExpr(Node n1, Node n2) {
|
||||||
not exists(asExpr(n1)) and
|
not exists(asExprInternal(n1)) and
|
||||||
localFlowStep(n1, n2)
|
localFlowStep(n1, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1715,7 +1723,7 @@ private module ExprFlowCached {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
|
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
|
||||||
localStepFromNonExpr*(n1, n2) and
|
localStepFromNonExpr*(n1, n2) and
|
||||||
e2 = asExpr(n2)
|
e2 = asExprInternal(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1726,7 +1734,7 @@ private module ExprFlowCached {
|
|||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
localFlowStep(n1, mid) and
|
localFlowStep(n1, mid) and
|
||||||
localStepsToExpr(mid, n2, e2) and
|
localStepsToExpr(mid, n2, e2) and
|
||||||
e1 = asExpr(n1)
|
e1 = asExprInternal(n1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DataFlow::Node getNodeForExpr(Expr node) {
|
private DataFlow::Node getNodeForExpr(Expr node) {
|
||||||
result = DataFlow::exprNode(node)
|
node = DataFlow::ExprFlowCached::asExprInternal(result)
|
||||||
or
|
or
|
||||||
// Some of the sources in `isUserInput` are intended to match the value of
|
// Some of the sources in `isUserInput` are intended to match the value of
|
||||||
// an expression, while others (those modeled below) are intended to match
|
// an expression, while others (those modeled below) are intended to match
|
||||||
@@ -221,7 +221,7 @@ private module Cached {
|
|||||||
predicate nodeIsBarrierIn(DataFlow::Node node) {
|
predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||||
// don't use dataflow into taint sources, as this leads to duplicate results.
|
// don't use dataflow into taint sources, as this leads to duplicate results.
|
||||||
exists(Expr source | isUserInput(source, _) |
|
exists(Expr source | isUserInput(source, _) |
|
||||||
node = DataFlow::exprNode(source)
|
source = DataFlow::ExprFlowCached::asExprInternal(node)
|
||||||
or
|
or
|
||||||
// This case goes together with the similar (but not identical) rule in
|
// This case goes together with the similar (but not identical) rule in
|
||||||
// `getNodeForSource`.
|
// `getNodeForSource`.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* 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,119 +1,44 @@
|
|||||||
private import cpp
|
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.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.DataFlowUtil
|
||||||
|
private import SsaInternals as Ssa
|
||||||
private import PrintIRUtilities
|
private import PrintIRUtilities
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the local dataflow from other nodes in the same function to this node.
|
* Gets the local dataflow from other nodes in the same function to this node.
|
||||||
*/
|
*/
|
||||||
private string getFromFlow(DataFlow::Node useNode, int order1, int order2) {
|
private string getFromFlow(Node node2, int order1, int order2) {
|
||||||
exists(DataFlow::Node defNode, string prefix |
|
exists(Node node1 |
|
||||||
(
|
simpleLocalFlowStep(node1, node2) and
|
||||||
simpleLocalFlowStep(defNode, useNode) and prefix = ""
|
result = nodeId(node1, order1, order2)
|
||||||
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.
|
* Gets the local dataflow from this node to other nodes in the same function.
|
||||||
*/
|
*/
|
||||||
private string getToFlow(DataFlow::Node defNode, int order1, int order2) {
|
private string getToFlow(Node node1, int order1, int order2) {
|
||||||
exists(DataFlow::Node useNode, string prefix |
|
exists(Node node2 |
|
||||||
(
|
simpleLocalFlowStep(node1, node2) and
|
||||||
simpleLocalFlowStep(defNode, useNode) and prefix = ""
|
result = nodeId(node2, order1, order2)
|
||||||
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`.
|
* Gets the properties of the dataflow node `node`.
|
||||||
*/
|
*/
|
||||||
private string getNodeProperty(DataFlow::Node node, string key) {
|
private string getNodeProperty(Node node, string key) {
|
||||||
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
|
// 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`.
|
// out of this node is printed as `@->dest`.
|
||||||
key = "flow" and
|
key = "flow" and
|
||||||
result =
|
result =
|
||||||
strictconcat(string flow, boolean to, int order1, int order2 |
|
strictconcat(string flow, boolean to, int order1, int order2 |
|
||||||
flow = getFromFlow(node, order1, order2) + "->@" and to = false
|
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
|
||||||
or
|
or
|
||||||
flow = "@->" + getToFlow(node, order1, order2) and to = true
|
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
||||||
|
|
|
|
||||||
flow, ", " order by to, order1, order2, flow
|
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
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,16 +46,21 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
|||||||
*/
|
*/
|
||||||
class LocalFlowPropertyProvider extends IRPropertyProvider {
|
class LocalFlowPropertyProvider extends IRPropertyProvider {
|
||||||
override string getOperandProperty(Operand operand, string key) {
|
override string getOperandProperty(Operand operand, string key) {
|
||||||
exists(DataFlow::Node node |
|
exists(Node node |
|
||||||
operand = node.asOperand() and
|
operand = [node.asOperand(), node.(RawIndirectOperand).getOperand()] and
|
||||||
result = getNodeProperty(node, key)
|
result = getNodeProperty(node, key)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getInstructionProperty(Instruction instruction, string key) {
|
override string getInstructionProperty(Instruction instruction, string key) {
|
||||||
exists(DataFlow::Node node |
|
exists(Node node |
|
||||||
instruction = node.asInstruction() and
|
instruction = [node.asInstruction(), node.(RawIndirectInstruction).getInstruction()]
|
||||||
|
|
|
||||||
result = getNodeProperty(node, key)
|
result = getNodeProperty(node, key)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
|
||||||
|
|
||||||
|
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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,37 +3,59 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import cpp
|
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.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 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)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a short ID for an IR dataflow node.
|
* 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 `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
|
* - 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`).
|
* instruction and a dot (e.g. `m128.left`).
|
||||||
* - For `Variable`s, this is the qualified name of the variable.
|
|
||||||
*/
|
*/
|
||||||
string nodeId(DataFlow::Node node, int order1, int order2) {
|
string nodeId(Node node, int order1, int order2) {
|
||||||
exists(Instruction instruction | instruction = node.asInstruction() |
|
exists(Instruction instruction, string stars | instruction = getInstruction(node, stars) |
|
||||||
result = instruction.getResultId() and
|
result = stars + instruction.getResultId() and
|
||||||
order1 = instruction.getBlock().getDisplayIndex() and
|
order1 = instruction.getBlock().getDisplayIndex() and
|
||||||
order2 = instruction.getDisplayIndexInBlock()
|
order2 = instruction.getDisplayIndexInBlock()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Operand operand, Instruction instruction |
|
exists(Operand operand, Instruction instruction, string stars |
|
||||||
operand = node.asOperand() and
|
operand = getOperand(node, stars) and
|
||||||
instruction = operand.getUse()
|
instruction = operand.getUse()
|
||||||
|
|
|
|
||||||
result = instruction.getResultId() + "." + operand.getDumpId() and
|
result = stars + instruction.getResultId() + "." + operand.getDumpId() and
|
||||||
order1 = instruction.getBlock().getDisplayIndex() and
|
order1 = instruction.getBlock().getDisplayIndex() and
|
||||||
order2 = instruction.getDisplayIndexInBlock()
|
order2 = instruction.getDisplayIndexInBlock()
|
||||||
)
|
)
|
||||||
or
|
|
||||||
result = "var(" + node.asVariable().getQualifiedName() + ")" and
|
|
||||||
order1 = 1000000 and
|
|
||||||
order2 = 0
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,29 @@
|
|||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
/**
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
* Provides a library for global (inter-procedural) data flow analysis of two
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
* values "simultaneously". This can be used, for example, if you want to track
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
|
* 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
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides classes for performing global (inter-procedural) data flow analyses
|
||||||
|
* on a product dataflow graph.
|
||||||
|
*/
|
||||||
module ProductFlow {
|
module ProductFlow {
|
||||||
|
/** An input configuration for product data-flow. */
|
||||||
signature module ConfigSig {
|
signature module ConfigSig {
|
||||||
/**
|
/**
|
||||||
* Holds if `(source1, source2)` is a relevant data flow source.
|
* Holds if `(source1, source2)` is a relevant data flow source.
|
||||||
@@ -70,6 +89,9 @@ module ProductFlow {
|
|||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output of a global data flow computation.
|
||||||
|
*/
|
||||||
module Global<ConfigSig Config> {
|
module Global<ConfigSig Config> {
|
||||||
private module StateConfig implements StateConfigSig {
|
private module StateConfig implements StateConfigSig {
|
||||||
class FlowState1 = Unit;
|
class FlowState1 = Unit;
|
||||||
@@ -138,6 +160,7 @@ module ProductFlow {
|
|||||||
import GlobalWithState<StateConfig>
|
import GlobalWithState<StateConfig>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An input configuration for data flow using flow state. */
|
||||||
signature module StateConfigSig {
|
signature module StateConfigSig {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
class FlowState1;
|
class FlowState1;
|
||||||
@@ -247,6 +270,9 @@ module ProductFlow {
|
|||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output of a global data flow computation.
|
||||||
|
*/
|
||||||
module GlobalWithState<StateConfigSig Config> {
|
module GlobalWithState<StateConfigSig Config> {
|
||||||
class PathNode1 = Flow1::PathNode;
|
class PathNode1 = Flow1::PathNode;
|
||||||
|
|
||||||
@@ -260,6 +286,7 @@ module ProductFlow {
|
|||||||
|
|
||||||
class FlowState2 = Config::FlowState2;
|
class FlowState2 = Config::FlowState2;
|
||||||
|
|
||||||
|
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
|
||||||
predicate flowPath(
|
predicate flowPath(
|
||||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||||
) {
|
) {
|
||||||
@@ -290,9 +317,9 @@ module ProductFlow {
|
|||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
||||||
}
|
}
|
||||||
|
|
||||||
module Flow1 = DataFlow::GlobalWithState<Config1>;
|
private module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||||
|
|
||||||
module Config2 implements DataFlow::StateConfigSig {
|
private module Config2 implements DataFlow::StateConfigSig {
|
||||||
class FlowState = FlowState2;
|
class FlowState = FlowState2;
|
||||||
|
|
||||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||||
@@ -322,27 +349,90 @@ module ProductFlow {
|
|||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
||||||
}
|
}
|
||||||
|
|
||||||
module Flow2 = DataFlow::GlobalWithState<Config2>;
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate reachableInterprocEntry(
|
private predicate fwdIsSuccessorExit(
|
||||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
|
Flow1::PathNode mid1, Flow2::PathNode mid2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||||
) {
|
) {
|
||||||
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
isSinkPair(mid1, mid2) and
|
||||||
node1 = source1 and
|
succ1 = mid1 and
|
||||||
node2 = source2
|
succ2 = mid2
|
||||||
or
|
or
|
||||||
exists(
|
interprocEdgePair(mid1, mid2, succ1, succ2)
|
||||||
Flow1::PathNode midEntry1, Flow2::PathNode midEntry2, Flow1::PathNode midExit1,
|
}
|
||||||
Flow2::PathNode midExit2
|
|
||||||
|
|
private predicate fwdIsSuccessor1(
|
||||||
reachableInterprocEntry(source1, source2, midEntry1, midEntry2) and
|
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
|
||||||
interprocEdgePair(midExit1, midExit2, node1, node2) and
|
Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||||
localPathStep1*(midEntry1, midExit1) and
|
) {
|
||||||
localPathStep2*(midEntry2, midExit2)
|
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)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
|
||||||
Flow1::PathGraph::edges(pred, succ) and
|
Flow1::PathGraph::edges(pred, succ) and
|
||||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||||
@@ -474,11 +564,14 @@ module ProductFlow {
|
|||||||
private predicate reachable(
|
private predicate reachable(
|
||||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||||
) {
|
) {
|
||||||
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
isSourcePair(source1, source2) and
|
||||||
reachableInterprocEntry(source1, source2, mid1, mid2) and
|
isSinkPair(sink1, sink2) and
|
||||||
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
exists(TNodePair n1, TNodePair n2 |
|
||||||
localPathStep1*(mid1, sink1) and
|
n1 = TMkNodePair(source1, source2) and
|
||||||
localPathStep2*(mid2, sink2)
|
n2 = TMkNodePair(sink1, sink2)
|
||||||
|
|
|
||||||
|
pathSuccPlus(n1, n2) or
|
||||||
|
n1 = n2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -657,24 +657,16 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
|||||||
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
|
* 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`.
|
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
|
||||||
*/
|
*/
|
||||||
private predicate adjustForPointerArith(
|
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
|
||||||
DefOrUse defOrUse, Node nodeFrom, UseOrPhi use, boolean uncertain
|
exists(DefOrUse defOrUse, Node adjusted |
|
||||||
) {
|
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||||
nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and
|
nodeToDefOrUse(adjusted, defOrUse, _) and
|
||||||
exists(Node adjusted |
|
|
||||||
indirectConversionFlowStep*(adjusted, nodeFrom) and
|
|
||||||
nodeToDefOrUse(adjusted, defOrUse, uncertain) and
|
|
||||||
adjacentDefRead(defOrUse, use)
|
adjacentDefRead(defOrUse, use)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
|
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
|
||||||
// `nodeFrom = any(PostUpdateNode pun).getPreUpdateNode()` is implied by adjustedForPointerArith.
|
|
||||||
exists(UseOrPhi use |
|
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
|
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
|
||||||
adjacentDefRead(defOrUse, use) and
|
adjacentDefRead(defOrUse, use) and
|
||||||
useToNode(use, nodeTo) and
|
useToNode(use, nodeTo) and
|
||||||
@@ -719,14 +711,19 @@ 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) {
|
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
|
||||||
exists(Node preUpdate, Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
|
exists(UseOrPhi use, Node preUpdate |
|
||||||
|
adjustForPointerArith(pun, use) and
|
||||||
|
useToNode(use, nodeTo) and
|
||||||
preUpdate = pun.getPreUpdateNode() and
|
preUpdate = pun.getPreUpdateNode() and
|
||||||
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain)
|
not exists(DataFlowCall call |
|
||||||
|
|
isArgumentOfCallable(call, preUpdate) and isArgumentOfCallable(call, nodeTo)
|
||||||
if uncertain = true
|
)
|
||||||
then preUpdate = [nFrom, getAPriorDefinition(defOrUse)]
|
|
||||||
else preUpdate = nFrom
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,4 +77,16 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
|||||||
* Gets the value of the property named `key` for the specified operand.
|
* Gets the value of the property named `key` for the specified operand.
|
||||||
*/
|
*/
|
||||||
string getOperandProperty(Operand operand, string key) { none() }
|
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() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
|||||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(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) {
|
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||||
}
|
}
|
||||||
@@ -84,7 +92,9 @@ private string getOperandPropertyString(Operand operand) {
|
|||||||
private newtype TPrintableIRNode =
|
private newtype TPrintableIRNode =
|
||||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
TPrintableInstruction(Instruction instr) {
|
||||||
|
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node to be emitted in the IR graph.
|
* A node to be emitted in the IR graph.
|
||||||
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
|||||||
private string getOperandsString() {
|
private string getOperandsString() {
|
||||||
result =
|
result =
|
||||||
concat(Operand operand |
|
concat(Operand operand |
|
||||||
operand = instr.getAnOperand()
|
operand = instr.getAnOperand() and
|
||||||
|
shouldPrintOperand(operand)
|
||||||
|
|
|
|
||||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||||
order by
|
order by
|
||||||
|
|||||||
@@ -77,4 +77,16 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
|||||||
* Gets the value of the property named `key` for the specified operand.
|
* Gets the value of the property named `key` for the specified operand.
|
||||||
*/
|
*/
|
||||||
string getOperandProperty(Operand operand, string key) { none() }
|
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() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
|||||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(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) {
|
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||||
}
|
}
|
||||||
@@ -84,7 +92,9 @@ private string getOperandPropertyString(Operand operand) {
|
|||||||
private newtype TPrintableIRNode =
|
private newtype TPrintableIRNode =
|
||||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
TPrintableInstruction(Instruction instr) {
|
||||||
|
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node to be emitted in the IR graph.
|
* A node to be emitted in the IR graph.
|
||||||
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
|||||||
private string getOperandsString() {
|
private string getOperandsString() {
|
||||||
result =
|
result =
|
||||||
concat(Operand operand |
|
concat(Operand operand |
|
||||||
operand = instr.getAnOperand()
|
operand = instr.getAnOperand() and
|
||||||
|
shouldPrintOperand(operand)
|
||||||
|
|
|
|
||||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||||
order by
|
order by
|
||||||
|
|||||||
@@ -77,4 +77,16 @@ class IRPropertyProvider extends TIRPropertyProvider {
|
|||||||
* Gets the value of the property named `key` for the specified operand.
|
* Gets the value of the property named `key` for the specified operand.
|
||||||
*/
|
*/
|
||||||
string getOperandProperty(Operand operand, string key) { none() }
|
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() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
|
|||||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(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) {
|
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||||
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
|
||||||
}
|
}
|
||||||
@@ -84,7 +92,9 @@ private string getOperandPropertyString(Operand operand) {
|
|||||||
private newtype TPrintableIRNode =
|
private newtype TPrintableIRNode =
|
||||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||||
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
|
TPrintableInstruction(Instruction instr) {
|
||||||
|
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node to be emitted in the IR graph.
|
* A node to be emitted in the IR graph.
|
||||||
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
|||||||
private string getOperandsString() {
|
private string getOperandsString() {
|
||||||
result =
|
result =
|
||||||
concat(Operand operand |
|
concat(Operand operand |
|
||||||
operand = instr.getAnOperand()
|
operand = instr.getAnOperand() and
|
||||||
|
shouldPrintOperand(operand)
|
||||||
|
|
|
|
||||||
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
|
||||||
order by
|
order by
|
||||||
|
|||||||
@@ -729,7 +729,7 @@ module RangeStage<
|
|||||||
) {
|
) {
|
||||||
exists(SemExpr e, D::Delta d1, D::Delta d2 |
|
exists(SemExpr e, D::Delta d1, D::Delta d2 |
|
||||||
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
||||||
boundedUpper(e, b, d1) and
|
boundedUpper(e, b, d2) and
|
||||||
boundedLower(e, b, d2) and
|
boundedLower(e, b, d2) and
|
||||||
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
|
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 0.6.2
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 0.6.1
|
## 0.6.1
|
||||||
|
|
||||||
### New Queries
|
### New Queries
|
||||||
|
|||||||
@@ -4,16 +4,17 @@
|
|||||||
* may result in a buffer overflow.
|
* may result in a buffer overflow.
|
||||||
* @kind path-problem
|
* @kind path-problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
|
* @security-severity 9.3
|
||||||
|
* @precision medium
|
||||||
* @id cpp/overrun-write
|
* @id cpp/overrun-write
|
||||||
* @tags reliability
|
* @tags reliability
|
||||||
* security
|
* security
|
||||||
* experimental
|
|
||||||
* external/cwe/cwe-119
|
* external/cwe/cwe-119
|
||||||
* external/cwe/cwe-131
|
* external/cwe/cwe-131
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.models.interfaces.Allocation
|
import semmle.code.cpp.models.interfaces.Allocation
|
||||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||||
@@ -122,13 +123,9 @@ module ValidState {
|
|||||||
predicate isAdditionalFlowStep(
|
predicate isAdditionalFlowStep(
|
||||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||||
) {
|
) {
|
||||||
exists(AddInstruction add, Operand op, int delta |
|
isAdditionalFlowStep2(node1, node2, _) and
|
||||||
add.hasOperands(node1.asOperand(), op) and
|
state1 = [false, true] and
|
||||||
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
|
state2 = state1.booleanNot()
|
||||||
node2.asInstruction() = add and
|
|
||||||
state1 = [false, true] and
|
|
||||||
state2 = state1.booleanNot()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any() }
|
predicate includeHiddenNodes() { any() }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: newQuery
|
||||||
|
---
|
||||||
|
* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers.
|
||||||
3
cpp/ql/src/change-notes/released/0.6.2.md
Normal file
3
cpp/ql/src/change-notes/released/0.6.2.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## 0.6.2
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.6.1
|
lastReleaseVersion: 0.6.2
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
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.SemanticExprSpecific
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
|
||||||
|
|||||||
@@ -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.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
import PointerArithmeticToDerefFlow::PathGraph
|
import FieldAddressToDerefFlow::PathGraph
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||||
@@ -42,21 +42,6 @@ bindingset[b]
|
|||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
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]
|
bindingset[delta]
|
||||||
predicate isInvalidPointerDerefSinkImpl(
|
predicate isInvalidPointerDerefSinkImpl(
|
||||||
int delta, Instruction i, AddressOperand addr, string operation
|
int delta, Instruction i, AddressOperand addr, string operation
|
||||||
@@ -93,38 +78,96 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isConstantSizeOverflowSource(Field f, PointerAddInstruction pai, int delta) {
|
pragma[nomagic]
|
||||||
exists(int size, int bound, DataFlow::Node source, DataFlow::InstructionNode sink |
|
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) {
|
||||||
FieldAddressToPointerArithmeticFlow::flow(source, sink) and
|
arr.getBaseType().getSize() = baseTypeSize and
|
||||||
isFieldAddressSource(f, source) and
|
arr.getArraySize() = arraySize
|
||||||
pai.getLeft() = sink.asInstruction() and
|
}
|
||||||
f.getUnspecifiedType().(ArrayType).getArraySize() = size and
|
|
||||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
|
predicate pointerArithOverflow0(
|
||||||
delta = bound - size and
|
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
|
||||||
delta >= 0 and
|
) {
|
||||||
size != 0 and
|
not f.getNamespace() instanceof StdNamespace and
|
||||||
size != 1
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) {
|
predicate isSource(DataFlow::Node source) {
|
||||||
isConstantSizeOverflowSource(_, source.asInstruction(), _)
|
pointerArithOverflow0(source.asInstruction(), _, _, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[inline]
|
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||||
|
|
||||||
|
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
|
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
|
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
|
from
|
||||||
Field f, PointerArithmeticToDerefFlow::PathNode source,
|
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
|
||||||
PointerArithmeticToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||||
where
|
where
|
||||||
PointerArithmeticToDerefFlow::flowPath(source, sink) and
|
FieldAddressToDerefFlow::flowPath(source, sink) and
|
||||||
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
||||||
isConstantSizeOverflowSource(f, source.getNode().asInstruction(), delta)
|
source.getState() = FieldAddressToDerefConfig::TArray(f) and
|
||||||
select source, source, sink,
|
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
|
||||||
|
pointerArithOverflow(pai, f, _, _, delta)
|
||||||
|
select pai, source, sink,
|
||||||
"This pointer arithmetic may have an off-by-" + (delta + 1) +
|
"This pointer arithmetic may have an off-by-" + (delta + 1) +
|
||||||
" error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation
|
" error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
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.SemanticExprSpecific
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
@@ -48,44 +48,23 @@ bindingset[b]
|
|||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
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
|
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||||
* expression associated with `alloc`.
|
* expression associated with `alloc`.
|
||||||
*/
|
*/
|
||||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||||
hasSizeImpl(alloc.getSizeExpr(), n, 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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,8 +81,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* We do this by splitting the task up into two configurations:
|
* We do this by splitting the task up into two configurations:
|
||||||
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
|
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||||
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
|
* 2. `InvalidPointerToDerefConfig` 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
|
* 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`).
|
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
|
||||||
@@ -201,13 +180,13 @@ predicate isSinkImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
|
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
|
||||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` 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`.
|
* reads from an address that non-strictly upper-bounds `sink`.
|
||||||
*/
|
*/
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
|
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
|
||||||
exists(AddressOperand addr, int delta |
|
exists(AddressOperand addr |
|
||||||
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
||||||
delta >= 0 and
|
delta >= 0 and
|
||||||
i.getAnOperand() = addr
|
i.getAnOperand() = addr
|
||||||
@@ -222,13 +201,13 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration to track flow from a pointer-arithmetic operation found
|
* A configuration to track flow from a pointer-arithmetic operation found
|
||||||
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
|
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
|
||||||
*/
|
*/
|
||||||
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
|
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
|
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
|
||||||
|
|
||||||
predicate isBarrier(DataFlow::Node node) {
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
||||||
@@ -258,17 +237,17 @@ predicate invalidPointerToDerefSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
newtype TMergedPathNode =
|
newtype TMergedPathNode =
|
||||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
|
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
|
||||||
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
||||||
// The path nodes computed by `InvalidPointerToDerefConf`
|
// The path nodes computed by `InvalidPointerToDerefConfig`
|
||||||
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
||||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
|
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
|
||||||
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
|
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
|
||||||
// pointer, but we want to raise an alert at the dereference.
|
// pointer, but we want to raise an alert at the dereference.
|
||||||
TPathNodeSink(Instruction i) {
|
TPathNodeSink(Instruction i) {
|
||||||
exists(DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
InvalidPointerToDerefFlow::flowTo(n) and
|
InvalidPointerToDerefFlow::flowTo(n) and
|
||||||
isInvalidPointerDerefSink(n, i, _)
|
isInvalidPointerDerefSink(n, i, _, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,12 +321,30 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
|
|||||||
or
|
or
|
||||||
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
|
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
|
||||||
or
|
or
|
||||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
|
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
|
* Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
|
||||||
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
|
* of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
|
||||||
*/
|
*/
|
||||||
predicate joinOn1(
|
predicate joinOn1(
|
||||||
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
|
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
|
||||||
@@ -358,37 +355,37 @@ predicate joinOn1(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
|
* Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
|
||||||
* that dereferences `p1`. The string `operation` describes whether the `i` is
|
* that dereferences `p1`. The string `operation` describes whether the `i` is
|
||||||
* a `StoreInstruction` or `LoadInstruction`.
|
* a `StoreInstruction` or `LoadInstruction`.
|
||||||
*/
|
*/
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
|
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation, int delta) {
|
||||||
isInvalidPointerDerefSink(p1.getNode(), i, operation)
|
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasFlowPath(
|
predicate hasFlowPath(
|
||||||
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
||||||
PointerArithmeticInstruction pai, string operation
|
PointerArithmeticInstruction pai, string operation, int delta
|
||||||
) {
|
) {
|
||||||
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
|
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
|
||||||
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
|
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
|
||||||
joinOn1(pai, sink1, source3) and
|
joinOn1(pai, sink1, source3) and
|
||||||
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
|
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
|
||||||
joinOn2(sink3, sink.asSinkNode(), operation)
|
joinOn2(sink3, sink.asSinkNode(), operation, delta)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
MergedPathNode source, MergedPathNode sink, int k, string kstr,
|
MergedPathNode source, MergedPathNode sink, int k2, int k3, string kstr,
|
||||||
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
|
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
|
||||||
Expr offset, DataFlow::Node n
|
Expr offset, DataFlow::Node n
|
||||||
where
|
where
|
||||||
hasFlowPath(source, sink, source3, pai, operation) and
|
hasFlowPath(source, sink, source3, pai, operation, k3) and
|
||||||
invalidPointerToDerefSource(pai, source3.getNode(), k) and
|
invalidPointerToDerefSource(pai, source3.getNode(), k2) and
|
||||||
offset = pai.getRight().getUnconvertedResultExpression() and
|
offset = pai.getRight().getUnconvertedResultExpression() and
|
||||||
n = source.asPathNode1().getNode() and
|
n = source.asPathNode1().getNode() and
|
||||||
if k = 0 then kstr = "" else kstr = " + " + k
|
if (k2 + k3) = 0 then kstr = "" else kstr = " + " + (k2 + k3)
|
||||||
select sink, source, sink,
|
select sink, source, sink,
|
||||||
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
|
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
|
||||||
".", n, n.toString(), offset, offset.toString()
|
".", n, n.toString(), offset, offset.toString()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.6.2-dev
|
version: 0.6.3-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -16,18 +16,16 @@ private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
|
|||||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
|
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class IRFlowTest extends InlineExpectationsTest {
|
module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||||
IRFlowTest() { this = "IRFlowTest" }
|
string getARelevantTag() { result = "ir" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ir" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
exists(IRDataFlow::Node source, IRDataFlow::Node sink, int n |
|
||||||
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
|
tag = "ir" and
|
||||||
conf.hasFlow(source, sink) and
|
Flow::flow(source, sink) and
|
||||||
n =
|
n =
|
||||||
strictcount(int line, int column |
|
strictcount(int line, int column |
|
||||||
conf.hasFlow(any(IRDataFlow::Node otherSource |
|
Flow::flow(any(IRDataFlow::Node otherSource |
|
||||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||||
), sink)
|
), sink)
|
||||||
) and
|
) and
|
||||||
@@ -47,20 +45,16 @@ class IRFlowTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AstFlowTest extends InlineExpectationsTest {
|
module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
|
||||||
AstFlowTest() { this = "ASTFlowTest" }
|
string getARelevantTag() { result = "ast" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
exists(AstDataFlow::Node source, AstDataFlow::Node sink, int n |
|
||||||
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
|
tag = "ast" and
|
||||||
conf.hasFlow(source, sink) and
|
Flow::flow(source, sink) and
|
||||||
n =
|
n =
|
||||||
strictcount(int line, int column |
|
strictcount(int line, int column |
|
||||||
conf.hasFlow(any(AstDataFlow::Node otherSource |
|
Flow::flow(any(AstDataFlow::Node otherSource |
|
||||||
otherSource.hasLocationInfo(_, line, column, _, _)
|
otherSource.hasLocationInfo(_, line, column, _, _)
|
||||||
), sink)
|
), sink)
|
||||||
) and
|
) and
|
||||||
@@ -79,6 +73,3 @@ class AstFlowTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for AstFlowTest */
|
|
||||||
deprecated class ASTFlowTest = AstFlowTest;
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
experimental/Likely Bugs/OverrunWriteProductFlow.ql
|
|
||||||
@@ -1,37 +1,46 @@
|
|||||||
edges
|
edges
|
||||||
| test.cpp:66:32:66:32 | p | test.cpp:66:32:66:32 | p |
|
| test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array |
|
||||||
| test.cpp:66:32:66:32 | p | test.cpp:67:5:67:6 | * ... |
|
| test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array |
|
||||||
| test.cpp:66:32:66:32 | p | test.cpp:67:6:67:6 | p |
|
| 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:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
|
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | 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:77:27:77:44 | access to array | 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 |
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:35:5:35:22 | access to array | semmle.label | access to array |
|
| 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: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: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: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: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: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: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:66:32:66:32 | p | semmle.label | p |
|
||||||
| 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: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:72:5:72:15 | access to array | semmle.label | access to array |
|
||||||
| test.cpp:77:26:77:44 | & ... | semmle.label | & ... |
|
| test.cpp:77:26:77:44 | & ... | semmle.label | & ... |
|
||||||
| test.cpp:77:27:77:44 | access to array | semmle.label | access to array |
|
| 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 |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| 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: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 | 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: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 | 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: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 | 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: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 | 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: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 | 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: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 | 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: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 | 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: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 | 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 | 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: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,3 +78,45 @@ void testInterproc(BigArray *arr) {
|
|||||||
|
|
||||||
addToPointerAndAssign(arr->buf);
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -653,17 +653,428 @@ edges
|
|||||||
| test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308: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: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: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:342:8:342:17 | * ... | test.cpp:333:5:333:21 | Store: ... = ... |
|
||||||
|
| test.cpp:342:8:342:17 | * ... | test.cpp:341:5:341:21 | Store: ... = ... |
|
||||||
|
| test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs |
|
||||||
|
| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ |
|
||||||
|
| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:15:350:19 | Load: * ... |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ |
|
||||||
|
| 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: * ... |
|
||||||
|
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:333:5:333:21 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||||
|
| test.cpp:338:8:338:15 | * ... | semmle.label | * ... |
|
||||||
|
| test.cpp:341:5:341:21 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||||
|
| 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:350:15:350:19 | Load: * ... | semmle.label | Load: * ... |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ |
|
||||||
|
| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ |
|
||||||
|
| 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 |
|
||||||
|
subpaths
|
||||||
#select
|
#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: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 $@ + $@ + 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: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: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 $@ + $@ + 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: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 $@ + $@ + 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: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: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 |
|
| 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 |
|
||||||
@@ -677,3 +1088,9 @@ edges
|
|||||||
| 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: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: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: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:333:5:333:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:333:5:333:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size |
|
||||||
|
| test.cpp:341:5:341:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:341:5:341:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size |
|
||||||
|
| test.cpp:350:15:350:19 | Load: * ... | test.cpp:347:14:347:27 | new[] | test.cpp:350:15:350:19 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:347:14:347:27 | new[] | new[] | test.cpp:348:20:348:23 | size | size |
|
||||||
|
| 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 |
|
||||||
|
|||||||
@@ -304,7 +304,71 @@ void test21() {
|
|||||||
void** xs = new void*[n];
|
void** xs = new void*[n];
|
||||||
|
|
||||||
for (int i = 0; i < n; i += 2) {
|
for (int i = 0; i < n; i += 2) {
|
||||||
xs[i] = test21_get(i);
|
xs[i] = test21_get(i); // GOOD
|
||||||
xs[i+1] = test21_get(i+1);
|
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 [FALSE POSITIVE]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val < 2) {
|
||||||
|
if(*current - xs < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*--(*current) = 0; // GOOD [FALSE POSITIVE]
|
||||||
|
*--(*current) = 0; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test24(unsigned size) {
|
||||||
|
char *xs = new char[size];
|
||||||
|
char *end = xs + size;
|
||||||
|
if (xs < end) {
|
||||||
|
int val = *xs++; // GOOD [FALSE POSITIVE]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:9,8-47)
|
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)
|
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:20,49-74)
|
||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -38,12 +38,10 @@ predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
module IRDefaultTaintTrackingTest implements TestSig {
|
||||||
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
|
string getARelevantTag() { result = ["ir-path", "ir-sink"] }
|
||||||
|
|
||||||
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Element elem, TaintedWithPath::PathNode node, int n |
|
exists(Element elem, TaintedWithPath::PathNode node, int n |
|
||||||
irTaint(_, node, tag) and
|
irTaint(_, node, tag) and
|
||||||
elem = getElementFromPathNode(node) and
|
elem = getElementFromPathNode(node) and
|
||||||
@@ -67,12 +65,10 @@ class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AstTaintTrackingTest extends InlineExpectationsTest {
|
module AstTaintTrackingTest implements TestSig {
|
||||||
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
|
string getARelevantTag() { result = "ast" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Expr source, Element tainted, int n |
|
exists(Expr source, Element tainted, int n |
|
||||||
tag = "ast" and
|
tag = "ast" and
|
||||||
astTaint(source, tainted) and
|
astTaint(source, tainted) and
|
||||||
@@ -100,3 +96,5 @@ class AstTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:10,8-47)
|
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)
|
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:21,3-28)
|
||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -29,12 +29,10 @@ predicate irTaint(Expr source, Element sink) {
|
|||||||
TaintedWithPath::taintedWithPath(source, sink, _, _)
|
TaintedWithPath::taintedWithPath(source, sink, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
module IRDefaultTaintTrackingTest implements TestSig {
|
||||||
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
|
string getARelevantTag() { result = "ir" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ir" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Expr source, Element tainted, int n |
|
exists(Expr source, Element tainted, int n |
|
||||||
tag = "ir" and
|
tag = "ir" and
|
||||||
irTaint(source, tainted) and
|
irTaint(source, tainted) and
|
||||||
@@ -55,12 +53,10 @@ class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AstTaintTrackingTest extends InlineExpectationsTest {
|
module AstTaintTrackingTest implements TestSig {
|
||||||
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
|
string getARelevantTag() { result = "ast" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Expr source, Element tainted, int n |
|
exists(Expr source, Element tainted, int n |
|
||||||
tag = "ast" and
|
tag = "ast" and
|
||||||
astTaint(source, tainted) and
|
astTaint(source, tainted) and
|
||||||
@@ -80,3 +76,5 @@ class AstTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
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:8,3-47)
|
||||||
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:12,3-53)
|
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:12,3-53)
|
||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ predicate irTaint(Expr source, Element sink, string globalVar) {
|
|||||||
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
|
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
module IRGlobalDefaultTaintTrackingTest implements TestSig {
|
||||||
IRGlobalDefaultTaintTrackingTest() { this = "IRGlobalDefaultTaintTrackingTest" }
|
string getARelevantTag() { result = "ir" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ir" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Element tainted |
|
exists(Element tainted |
|
||||||
tag = "ir" and
|
tag = "ir" and
|
||||||
irTaint(_, tainted, value) and
|
irTaint(_, tainted, value) and
|
||||||
@@ -27,12 +25,10 @@ class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
module AstGlobalDefaultTaintTrackingTest implements TestSig {
|
||||||
AstGlobalDefaultTaintTrackingTest() { this = "ASTGlobalDefaultTaintTrackingTest" }
|
string getARelevantTag() { result = "ast" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Element tainted |
|
exists(Element tainted |
|
||||||
tag = "ast" and
|
tag = "ast" and
|
||||||
astTaint(_, tainted, value) and
|
astTaint(_, tainted, value) and
|
||||||
@@ -41,3 +37,5 @@ class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<IRGlobalDefaultTaintTrackingTest, AstGlobalDefaultTaintTrackingTest>>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// semmle-extractor-options: --edg --clang
|
// semmle-extractor-options: --edg --clang
|
||||||
|
|
||||||
int source();
|
int source();
|
||||||
void sink(int); void sink(const int *); void sink(int **);
|
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
||||||
|
|
||||||
struct twoIntFields {
|
struct twoIntFields {
|
||||||
int m1, m2;
|
int m1, m2;
|
||||||
@@ -19,7 +19,8 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
|
|||||||
|
|
||||||
sink(sourceArray1[0]); // no flow
|
sink(sourceArray1[0]); // no flow
|
||||||
sink(*sourceArray1); // no flow
|
sink(*sourceArray1); // no flow
|
||||||
sink(&sourceArray1); // $ ast,ir // [should probably be taint only]
|
sink(&sourceArray1); // $ ast // [should probably be taint only]
|
||||||
|
indirect_sink(&sourceArray1); // $ ast,ir
|
||||||
|
|
||||||
sink(sourceStruct1.m1); // no flow
|
sink(sourceStruct1.m1); // no flow
|
||||||
sink(sourceStruct1_ptr->m1); // no flow
|
sink(sourceStruct1_ptr->m1); // no flow
|
||||||
@@ -48,5 +49,6 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
|
|||||||
|
|
||||||
int stackArray[2] = { source(), source() };
|
int stackArray[2] = { source(), source() };
|
||||||
stackArray[0] = source();
|
stackArray[0] = source();
|
||||||
sink(stackArray); // $ ast ir ir=49:25 ir=49:35 ir=50:19
|
sink(stackArray); // $ ast,ir
|
||||||
|
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ postWithInFlow
|
|||||||
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| 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. |
|
| 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:22:9:22:20 | sourceArray1 [inner 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:23:18:23:29 | sourceArray1 [inner 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:29:22:29:23 | m1 [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. |
|
| 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. |
|
||||||
| dispatch.cpp:60:3:60:14 | globalBottom [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: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. |
|
| dispatch.cpp:78:24:78:37 | call to allocateBottom [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ module AstTest {
|
|||||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
||||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||||
|
|
||||||
class AstParameterDefTest extends InlineExpectationsTest {
|
module AstParameterDefTest implements TestSig {
|
||||||
AstParameterDefTest() { this = "AstParameterDefTest" }
|
string getARelevantTag() { result = "ast-def" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast-def" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Function f, Parameter p, RefParameterFinalValueNode n |
|
exists(Function f, Parameter p, RefParameterFinalValueNode n |
|
||||||
p.isNamed() and
|
p.isNamed() and
|
||||||
n.getParameter() = p and
|
n.getParameter() = p and
|
||||||
@@ -33,12 +31,10 @@ module IRTest {
|
|||||||
(if k = 0 then result = "" else result = "*" + stars(k - 1))
|
(if k = 0 then result = "" else result = "*" + stars(k - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRParameterDefTest extends InlineExpectationsTest {
|
module IRParameterDefTest implements TestSig {
|
||||||
IRParameterDefTest() { this = "IRParameterDefTest" }
|
string getARelevantTag() { result = "ir-def" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ir-def" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Function f, Parameter p, FinalParameterNode n |
|
exists(Function f, Parameter p, FinalParameterNode n |
|
||||||
p.isNamed() and
|
p.isNamed() and
|
||||||
n.getParameter() = p and
|
n.getParameter() = p and
|
||||||
@@ -51,3 +47,5 @@ module IRTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstTest::AstParameterDefTest, IRTest::IRParameterDefTest>>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ module AstTest {
|
|||||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
|
||||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||||
|
|
||||||
class AstMultipleOutNodesTest extends InlineExpectationsTest {
|
module AstMultipleOutNodesTest implements TestSig {
|
||||||
AstMultipleOutNodesTest() { this = "AstMultipleOutNodesTest" }
|
string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(DataFlowCall call, int n, ReturnKind kind |
|
exists(DataFlowCall call, int n, ReturnKind kind |
|
||||||
call.getLocation() = location and
|
call.getLocation() = location and
|
||||||
n = strictcount(getAnOutNode(call, kind)) and
|
n = strictcount(getAnOutNode(call, kind)) and
|
||||||
@@ -27,12 +25,10 @@ module IRTest {
|
|||||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||||
|
|
||||||
class IRMultipleOutNodesTest extends InlineExpectationsTest {
|
module IRMultipleOutNodesTest implements TestSig {
|
||||||
IRMultipleOutNodesTest() { this = "IRMultipleOutNodesTest" }
|
string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(DataFlowCall call, int n, ReturnKind kind |
|
exists(DataFlowCall call, int n, ReturnKind kind |
|
||||||
call.getLocation() = location and
|
call.getLocation() = location and
|
||||||
n = strictcount(getAnOutNode(call, kind)) and
|
n = strictcount(getAnOutNode(call, kind)) and
|
||||||
@@ -44,3 +40,5 @@ module IRTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstTest::AstMultipleOutNodesTest, IRTest::IRMultipleOutNodesTest>>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
int source();
|
int source();
|
||||||
void sink(int); void sink(const int *); void sink(int **);
|
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
||||||
|
|
||||||
void intraprocedural_with_local_flow() {
|
void intraprocedural_with_local_flow() {
|
||||||
int t2;
|
int t2;
|
||||||
@@ -626,7 +626,7 @@ void test_def_via_phi_read(bool b)
|
|||||||
use(buffer);
|
use(buffer);
|
||||||
}
|
}
|
||||||
intPointerSource(buffer);
|
intPointerSource(buffer);
|
||||||
sink(buffer); // $ ast,ir
|
indirect_sink(buffer); // $ ast,ir
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_static_local_1() {
|
void test_static_local_1() {
|
||||||
@@ -692,7 +692,7 @@ void test_static_local_9() {
|
|||||||
|
|
||||||
void increment_buf(int** buf) { // $ ast-def=buf ir-def=*buf ir-def=**buf
|
void increment_buf(int** buf) { // $ ast-def=buf ir-def=*buf ir-def=**buf
|
||||||
*buf += 10;
|
*buf += 10;
|
||||||
sink(buf); // $ SPURIOUS: ast,ir // should only be flow to the indirect argument, but there's also flow to the non-indirect argument
|
sink(buf); // $ SPURIOUS: ast
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_increment_buf(int** buf) { // $ ast-def=buf
|
void call_increment_buf(int** buf) { // $ ast-def=buf
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -16,10 +16,8 @@ module AstTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
/** Common data flow configuration to be used by tests. */
|
||||||
class AstTestAllocationConfig extends DataFlow::Configuration {
|
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
or
|
or
|
||||||
source.asParameter().getName().matches("source%")
|
source.asParameter().getName().matches("source%")
|
||||||
@@ -32,18 +30,20 @@ module AstTest {
|
|||||||
exists(source.asUninitialized())
|
exists(source.asUninitialized())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = ["sink", "indirect_sink"] and
|
||||||
sink.asExpr() = call.getAnArgument()
|
sink.asExpr() = call.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isBarrier(DataFlow::Node barrier) {
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
||||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
module IRTest {
|
module IRTest {
|
||||||
@@ -67,10 +67,8 @@ module IRTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
/** Common data flow configuration to be used by tests. */
|
||||||
class IRTestAllocationConfig extends DataFlow::Configuration {
|
module IRTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
IRTestAllocationConfig() { this = "IRTestAllocationConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
or
|
or
|
||||||
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
||||||
@@ -82,14 +80,17 @@ module IRTest {
|
|||||||
exists(source.asUninitialized())
|
exists(source.asUninitialized())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = "sink" and
|
||||||
call.getAnArgument() in [sink.asExpr(), sink.asIndirectExpr()]
|
sink.asExpr() = e
|
||||||
|
or
|
||||||
|
call.getTarget().getName() = "indirect_sink" and
|
||||||
|
sink.asIndirectExpr() = e
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isBarrier(DataFlow::Node barrier) {
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
||||||
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
||||||
)
|
)
|
||||||
@@ -99,4 +100,8 @@ module IRTest {
|
|||||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
private import semmle.code.cpp.dataflow.DataFlow
|
private import semmle.code.cpp.dataflow.DataFlow
|
||||||
private import DataFlow
|
private import DataFlow
|
||||||
|
|
||||||
class AstConf extends Configuration {
|
module AstConfig implements ConfigSig {
|
||||||
AstConf() { this = "ASTFieldFlowConf" }
|
predicate isSource(Node src) {
|
||||||
|
|
||||||
override predicate isSource(Node src) {
|
|
||||||
src.asExpr() instanceof NewExpr
|
src.asExpr() instanceof NewExpr
|
||||||
or
|
or
|
||||||
src.asExpr().(Call).getTarget().hasName("user_input")
|
src.asExpr().(Call).getTarget().hasName("user_input")
|
||||||
@@ -15,14 +13,14 @@ class AstConf extends Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(Node sink) {
|
predicate isSink(Node sink) {
|
||||||
exists(Call c |
|
exists(Call c |
|
||||||
c.getTarget().hasName("sink") and
|
c.getTarget().hasName("sink") and
|
||||||
c.getAnArgument() = sink.asExpr()
|
c.getAnArgument() = sink.asExpr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
predicate isAdditionalFlowStep(Node a, Node b) {
|
||||||
b.asPartialDefinition() =
|
b.asPartialDefinition() =
|
||||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||||
.getQualifier()
|
.getQualifier()
|
||||||
@@ -31,5 +29,4 @@ class AstConf extends Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for AstConf */
|
module AstFlow = Global<AstConfig>;
|
||||||
deprecated class ASTConf = AstConf;
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
private import DataFlow
|
private import DataFlow
|
||||||
|
|
||||||
class IRConf extends Configuration {
|
module IRConfig implements ConfigSig {
|
||||||
IRConf() { this = "IRFieldFlowConf" }
|
predicate isSource(Node src) {
|
||||||
|
|
||||||
override predicate isSource(Node src) {
|
|
||||||
src.asExpr() instanceof NewExpr
|
src.asExpr() instanceof NewExpr
|
||||||
or
|
or
|
||||||
src.asExpr().(Call).getTarget().hasName("user_input")
|
src.asExpr().(Call).getTarget().hasName("user_input")
|
||||||
@@ -15,14 +13,14 @@ class IRConf extends Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(Node sink) {
|
predicate isSink(Node sink) {
|
||||||
exists(Call c |
|
exists(Call c |
|
||||||
c.getTarget().hasName("sink") and
|
c.getTarget().hasName("sink") and
|
||||||
c.getAnArgument() = [sink.asExpr(), sink.asIndirectExpr(), sink.asConvertedExpr()]
|
c.getAnArgument() = [sink.asExpr(), sink.asIndirectExpr(), sink.asConvertedExpr()]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
predicate isAdditionalFlowStep(Node a, Node b) {
|
||||||
b.asPartialDefinition() =
|
b.asPartialDefinition() =
|
||||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||||
.getQualifier()
|
.getQualifier()
|
||||||
@@ -30,3 +28,5 @@ class IRConf extends Configuration {
|
|||||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module IRFlow = Global<IRConfig>;
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import TestUtilities.dataflow.FlowTestCommon
|
import TestUtilities.dataflow.FlowTestCommon
|
||||||
|
|
||||||
module AstTest {
|
module AstTest {
|
||||||
private import ASTConfiguration
|
import ASTConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
module IRTest {
|
module IRTest {
|
||||||
private import IRConfiguration
|
import IRConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
import IRConfiguration
|
import IRConfiguration
|
||||||
import DataFlow::PathGraph
|
import IRFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode src, DataFlow::PathNode sink, IRConf conf
|
from IRFlow::PathNode src, IRFlow::PathNode sink
|
||||||
where conf.hasFlowPath(src, sink)
|
where IRFlow::flowPath(src, sink)
|
||||||
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.dataflow.DataFlow
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
import ASTConfiguration
|
import ASTConfiguration
|
||||||
import DataFlow::PathGraph
|
import AstFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode src, DataFlow::PathNode sink, AstConf conf
|
from AstFlow::PathNode src, AstFlow::PathNode sink
|
||||||
where conf.hasFlowPath(src, sink)
|
where AstFlow::flowPath(src, sink)
|
||||||
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -3,37 +3,39 @@ import TestUtilities.dataflow.FlowTestCommon
|
|||||||
module AstTest {
|
module AstTest {
|
||||||
private import semmle.code.cpp.dataflow.TaintTracking
|
private import semmle.code.cpp.dataflow.TaintTracking
|
||||||
|
|
||||||
class AstSmartPointerTaintConfig extends TaintTracking::Configuration {
|
module AstSmartPointerTaintConfig implements DataFlow::ConfigSig {
|
||||||
AstSmartPointerTaintConfig() { this = "ASTSmartPointerTaintConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = "sink" and
|
||||||
sink.asExpr() = call.getAnArgument()
|
sink.asExpr() = call.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module AstFlow = TaintTracking::Global<AstSmartPointerTaintConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
module IRTest {
|
module IRTest {
|
||||||
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
|
||||||
class IRSmartPointerTaintConfig extends TaintTracking::Configuration {
|
module IRSmartPointerTaintConfig implements DataFlow::ConfigSig {
|
||||||
IRSmartPointerTaintConfig() { this = "IRSmartPointerTaintConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = "sink" and
|
||||||
sink.asExpr() = call.getAnArgument()
|
sink.asExpr() = call.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module IRFlow = TaintTracking::Global<IRSmartPointerTaintConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import cpp
|
|||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
import semmle.code.cpp.security.FlowSources
|
import semmle.code.cpp.security.FlowSources
|
||||||
|
|
||||||
class LocalFlowSourceTest extends InlineExpectationsTest {
|
module LocalFlowSourceTest implements TestSig {
|
||||||
LocalFlowSourceTest() { this = "LocalFlowSourceTest" }
|
string getARelevantTag() { result = "local_source" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "local_source" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
tag = "local_source" and
|
tag = "local_source" and
|
||||||
exists(LocalFlowSource node, int n |
|
exists(LocalFlowSource node, int n |
|
||||||
n =
|
n =
|
||||||
@@ -30,3 +28,5 @@ class LocalFlowSourceTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<LocalFlowSourceTest>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import cpp
|
|||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
import semmle.code.cpp.security.FlowSources
|
import semmle.code.cpp.security.FlowSources
|
||||||
|
|
||||||
class RemoteFlowSourceTest extends InlineExpectationsTest {
|
module RemoteFlowSourceTest implements TestSig {
|
||||||
RemoteFlowSourceTest() { this = "RemoteFlowSourceTest" }
|
string getARelevantTag() { result = "remote_source" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "remote_source" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
tag = "remote_source" and
|
tag = "remote_source" and
|
||||||
exists(RemoteFlowSource node, int n |
|
exists(RemoteFlowSource node, int n |
|
||||||
n =
|
n =
|
||||||
@@ -31,12 +29,10 @@ class RemoteFlowSourceTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoteFlowSinkTest extends InlineExpectationsTest {
|
module RemoteFlowSinkTest implements TestSig {
|
||||||
RemoteFlowSinkTest() { this = "RemoteFlowSinkTest" }
|
string getARelevantTag() { result = "remote_sink" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "remote_sink" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
tag = "remote_sink" and
|
tag = "remote_sink" and
|
||||||
exists(RemoteFlowSink node, int n |
|
exists(RemoteFlowSink node, int n |
|
||||||
n =
|
n =
|
||||||
@@ -57,3 +53,5 @@ class RemoteFlowSinkTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<RemoteFlowSourceTest, RemoteFlowSinkTest>>
|
||||||
|
|||||||
@@ -8090,20 +8090,20 @@
|
|||||||
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | |
|
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | |
|
||||||
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | |
|
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | |
|
||||||
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | |
|
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | |
|
||||||
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:539:8:539:9 | vs | |
|
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:532:8:532:9 | vs | |
|
||||||
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:540:2:540:2 | vs | |
|
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:533:2:533:2 | vs | |
|
||||||
| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT |
|
| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT |
|
||||||
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | |
|
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | |
|
||||||
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
|
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
|
||||||
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
|
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
|
||||||
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
|
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
|
||||||
| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT |
|
| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT |
|
||||||
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
|
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
|
||||||
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
|
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
|
||||||
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
|
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
|
||||||
| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT |
|
| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT |
|
||||||
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
|
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
|
||||||
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
|
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
|
||||||
| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT |
|
| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT |
|
||||||
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | |
|
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | |
|
||||||
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | |
|
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | |
|
||||||
@@ -8128,5 +8128,5 @@
|
|||||||
| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
||||||
| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT |
|
| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT |
|
||||||
| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT |
|
| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT |
|
||||||
| vector.cpp:539:8:539:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
|
| vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
|
||||||
| vector.cpp:539:8:539:9 | vs | vector.cpp:539:10:539:10 | call to operator[] | TAINT |
|
| vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT |
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -43,10 +43,8 @@ module AstTest {
|
|||||||
private import semmle.code.cpp.models.interfaces.Taint
|
private import semmle.code.cpp.models.interfaces.Taint
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
/** Common data flow configuration to be used by tests. */
|
||||||
class AstTestAllocationConfig extends TaintTracking::Configuration {
|
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
or
|
or
|
||||||
source.asParameter().getName().matches("source%")
|
source.asParameter().getName().matches("source%")
|
||||||
@@ -60,17 +58,19 @@ module AstTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = "sink" and
|
||||||
sink.asExpr() = call.getAnArgument()
|
sink.asExpr() = call.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node barrier) {
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module AstFlow = TaintTracking::Global<AstTestAllocationConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
module IRTest {
|
module IRTest {
|
||||||
@@ -78,10 +78,8 @@ module IRTest {
|
|||||||
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
|
||||||
/** Common data flow configuration to be used by tests. */
|
/** Common data flow configuration to be used by tests. */
|
||||||
class TestAllocationConfig extends TaintTracking::Configuration {
|
module TestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
TestAllocationConfig() { this = "TestAllocationConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
or
|
or
|
||||||
source.asIndirectExpr().(FunctionCall).getTarget().getName() = "source"
|
source.asIndirectExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
@@ -94,21 +92,25 @@ module IRTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(FunctionCall call |
|
exists(FunctionCall call |
|
||||||
call.getTarget().getName() = "sink" and
|
call.getTarget().getName() = "sink" and
|
||||||
[sink.asExpr(), sink.asIndirectExpr()] = call.getAnArgument()
|
[sink.asExpr(), sink.asIndirectExpr()] = call.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node barrier) {
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
// allow arbitrary reads at sinks
|
// allow arbitrary reads at sinks
|
||||||
this.isSink(node) and
|
isSink(node) and
|
||||||
c.(DataFlow::FieldContent).getField().getDeclaringType() = node.getType().getUnspecifiedType()
|
c.(DataFlow::FieldContent).getField().getDeclaringType() = node.getType().getUnspecifiedType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module IRFlow = TaintTracking::Global<TestAllocationConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>
|
||||||
|
|||||||
@@ -523,19 +523,12 @@ void test_vector_iterator() {
|
|||||||
sink(vs[1]);
|
sink(vs[1]);
|
||||||
sink(vs[source()]); // $ MISSING: ast,ir
|
sink(vs[source()]); // $ MISSING: ast,ir
|
||||||
|
|
||||||
it = vs.begin(); // (1)
|
it = vs.begin();
|
||||||
sink(*it);
|
sink(*it);
|
||||||
it += 1;
|
it += 1;
|
||||||
sink(*it);
|
sink(*it);
|
||||||
it += source(); // (2)
|
it += source();
|
||||||
sink(*it); // $ ast,ir // (3)
|
sink(*it); // $ ast,ir
|
||||||
// This FP happens because of the following flows:
|
sink(vs[1]); // clean
|
||||||
// 1. There's a write to the iterator at (2)
|
|
||||||
// 2. This write propagates to `it` on the next line at (3)
|
|
||||||
// 3. There's a taint step from `it` to `*it` at (3)
|
|
||||||
// 4. The `*it` is seen as a use of `vs` because of (1).
|
|
||||||
// 5. There's use-use flow from `*it` at (3) (which is a use of `vs`) to `vs` at (4)
|
|
||||||
// 6. There's a taint step from vs to vs[1]
|
|
||||||
sink(vs[1]); // $ SPURIOUS: ir // (4)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ import TestUtilities.InlineExpectationsTest
|
|||||||
module ModulusAnalysisInstantiated =
|
module ModulusAnalysisInstantiated =
|
||||||
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||||
|
|
||||||
class ModulusAnalysisTest extends InlineExpectationsTest {
|
module ModulusAnalysisTest implements TestSig {
|
||||||
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
string getARelevantTag() { result = "mod" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "mod" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(SemExpr e, IR::CallInstruction call |
|
exists(SemExpr e, IR::CallInstruction call |
|
||||||
getSemanticExpr(call.getArgument(0)) = e and
|
getSemanticExpr(call.getArgument(0)) = e and
|
||||||
call.getStaticCallTarget().hasName("mod") and
|
call.getStaticCallTarget().hasName("mod") and
|
||||||
@@ -29,6 +27,8 @@ class ModulusAnalysisTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<ModulusAnalysisTest>
|
||||||
|
|
||||||
private string getAModString(SemExpr e) {
|
private string getAModString(SemExpr e) {
|
||||||
exists(SemBound b, int delta, int mod |
|
exists(SemBound b, int delta, int mod |
|
||||||
ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and
|
ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ module Raw {
|
|||||||
result = getOperandMemoryLocation(instr.getAnOperand())
|
result = getOperandMemoryLocation(instr.getAnOperand())
|
||||||
}
|
}
|
||||||
|
|
||||||
class RawPointsToTest extends InlineExpectationsTest {
|
module RawPointsToTest implements TestSig {
|
||||||
RawPointsToTest() { this = "RawPointsToTest" }
|
string getARelevantTag() { result = "raw" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "raw" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Instruction instr, MemoryLocation memLocation |
|
exists(Instruction instr, MemoryLocation memLocation |
|
||||||
memLocation = getAMemoryAccess(instr) and
|
memLocation = getAMemoryAccess(instr) and
|
||||||
tag = "raw" and
|
tag = "raw" and
|
||||||
@@ -49,12 +47,10 @@ module UnaliasedSsa {
|
|||||||
result = getOperandMemoryLocation(instr.getAnOperand())
|
result = getOperandMemoryLocation(instr.getAnOperand())
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnaliasedSsaPointsToTest extends InlineExpectationsTest {
|
module UnaliasedSsaPointsToTest implements TestSig {
|
||||||
UnaliasedSsaPointsToTest() { this = "UnaliasedSSAPointsToTest" }
|
string getARelevantTag() { result = "ussa" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "ussa" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Instruction instr, MemoryLocation memLocation |
|
exists(Instruction instr, MemoryLocation memLocation |
|
||||||
memLocation = getAMemoryAccess(instr) and
|
memLocation = getAMemoryAccess(instr) and
|
||||||
not memLocation.getVirtualVariable() instanceof AliasedVirtualVariable and
|
not memLocation.getVirtualVariable() instanceof AliasedVirtualVariable and
|
||||||
@@ -69,3 +65,5 @@ module UnaliasedSsa {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<MergeTests<Raw::RawPointsToTest, UnaliasedSsa::UnaliasedSsaPointsToTest>>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ import cpp
|
|||||||
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
|
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class RangeAnalysisTest extends InlineExpectationsTest {
|
module RangeAnalysisTest implements TestSig {
|
||||||
RangeAnalysisTest() { this = "RangeAnalysisTest" }
|
string getARelevantTag() { result = "overflow" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "overflow" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(Expr e |
|
exists(Expr e |
|
||||||
tag = "overflow" and
|
tag = "overflow" and
|
||||||
element = e.toString() and
|
element = e.toString() and
|
||||||
@@ -21,3 +19,5 @@ class RangeAnalysisTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<RangeAnalysisTest>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
|||||||
import semmle.code.cpp.ir.IR as IR
|
import semmle.code.cpp.ir.IR as IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class RangeAnalysisTest extends InlineExpectationsTest {
|
module RangeAnalysisTest implements TestSig {
|
||||||
RangeAnalysisTest() { this = "RangeAnalysisTest" }
|
string getARelevantTag() { result = "range" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "range" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(SemExpr e, IR::CallInstruction call |
|
exists(SemExpr e, IR::CallInstruction call |
|
||||||
getSemanticExpr(call.getArgument(0)) = e and
|
getSemanticExpr(call.getArgument(0)) = e and
|
||||||
call.getStaticCallTarget().hasName("range") and
|
call.getStaticCallTarget().hasName("range") and
|
||||||
@@ -22,6 +20,8 @@ class RangeAnalysisTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<RangeAnalysisTest>
|
||||||
|
|
||||||
private string getDirectionString(boolean d) {
|
private string getDirectionString(boolean d) {
|
||||||
result = "<=" and d = true
|
result = "<=" and d = true
|
||||||
or
|
or
|
||||||
@@ -40,14 +40,7 @@ bindingset[delta]
|
|||||||
private string getBoundString(SemBound b, float delta) {
|
private string getBoundString(SemBound b, float delta) {
|
||||||
b instanceof SemZeroBound and result = delta.toString()
|
b instanceof SemZeroBound and result = delta.toString()
|
||||||
or
|
or
|
||||||
result =
|
result = strictconcat(b.(SemSsaBound).getAVariable().toString(), " | ") + getOffsetString(delta)
|
||||||
strictconcat(b.(SemSsaBound)
|
|
||||||
.getAVariable()
|
|
||||||
.(SemanticExprConfig::SsaVariable)
|
|
||||||
.asInstruction()
|
|
||||||
.getAst()
|
|
||||||
.toString(), ":"
|
|
||||||
) + getOffsetString(delta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getARangeString(SemExpr e) {
|
private string getARangeString(SemExpr e) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ int test1(struct List* p) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
count = count+1;
|
count = count+1;
|
||||||
range(count); // $ range===count:p+1
|
range(count); // $ range="==Phi: p | Store: count+1"
|
||||||
}
|
}
|
||||||
range(count);
|
range(count);
|
||||||
return count;
|
return count;
|
||||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
count = (count+1) % 10;
|
count = (count+1) % 10;
|
||||||
range(count); // $ range=<=9 range=>=-9 range=<=count:p+1
|
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1"
|
||||||
}
|
}
|
||||||
range(count); // $ range=>=-9 range=<=9
|
range(count); // $ range=>=-9 range=<=9
|
||||||
return count;
|
return count;
|
||||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
|||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
range(count++); // $ range=>=-9 range=<=9
|
range(count++); // $ range=>=-9 range=<=9
|
||||||
count = count % 10;
|
count = count % 10;
|
||||||
range(count); // $ range=<=9 range=>=-9 range="<=... +++0" range=<=count:p+1
|
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1"
|
||||||
}
|
}
|
||||||
range(count); // $ range=>=-9 range=<=9
|
range(count); // $ range=>=-9 range=<=9
|
||||||
return count;
|
return count;
|
||||||
@@ -42,11 +42,11 @@ int test4() {
|
|||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total);
|
range(total);
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
|
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
range(total); // $ MISSING: range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
range(i); // $ range===2
|
range(i); // $ range===2
|
||||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,11 +57,11 @@ int test5() {
|
|||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total); // $ MISSING: range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
range(total); // $ MISSING: range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
range(i); // $ range===2
|
range(i); // $ range===2
|
||||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ int test6() {
|
|||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total); // $ MISSING: range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
@@ -93,12 +93,12 @@ int test8(int x, int y) {
|
|||||||
if (-1000 < y && y < 10) {
|
if (-1000 < y && y < 10) {
|
||||||
range(y); // $ range=<=9 range=>=-999
|
range(y); // $ range=<=9 range=>=-999
|
||||||
if (x < y-2) {
|
if (x < y-2) {
|
||||||
range(x); // $ range=<=6 range=<=y-3
|
range(x); // $ range=<=6 range="<=InitializeParameter: y | Store: y-3"
|
||||||
range(y); // $ range=<=9 range=>=-999 range=>=x+3
|
range(y); // $ range=<=9 range=>=-999 range=">=InitializeParameter: x | Store: x+3"
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
range(x); // $ range=>=-1001 range=>=y-2
|
range(x); // $ range=>=-1001 range=">=InitializeParameter: y | Store: y-2"
|
||||||
range(y); // $ range=<=9 range=<=x+2 range=>=-999
|
range(y); // $ range=<=9 range="<=InitializeParameter: x | Store: x+2" range=>=-999
|
||||||
}
|
}
|
||||||
range(x);
|
range(x);
|
||||||
range(y);
|
range(y);
|
||||||
@@ -127,12 +127,12 @@ int test10(int x, int y) {
|
|||||||
if (y > 7) {
|
if (y > 7) {
|
||||||
range(y); // $ range=>=8
|
range(y); // $ range=>=8
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
range(x); // $ range=<=y-1
|
range(x); // $ range="<=InitializeParameter: y-1"
|
||||||
range(y); // $ range=>=8 range=>=x+1
|
range(y); // $ range=>=8 range=">=InitializeParameter: x | Store: x+1"
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
range(x); // $ range=>=8 range=>=y+0
|
range(x); // $ range=>=8 range=">=InitializeParameter: y+0"
|
||||||
range(y); // $ range=<=x+0 range=>=8
|
range(y); // $ range="<=InitializeParameter: x | Store: x+0" range=>=8
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
range(y); // $ range=<=7
|
range(y); // $ range=<=7
|
||||||
@@ -145,7 +145,7 @@ int test11(char *p) {
|
|||||||
range(*p);
|
range(*p);
|
||||||
if (c != '\0') {
|
if (c != '\0') {
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
range(p); // $ range===p+1
|
range(p); // $ range="==InitializeParameter: p+1"
|
||||||
range(*p);
|
range(*p);
|
||||||
}
|
}
|
||||||
if (c == ':') {
|
if (c == ':') {
|
||||||
@@ -155,7 +155,7 @@ int test11(char *p) {
|
|||||||
if (c != '\0') {
|
if (c != '\0') {
|
||||||
range(c);
|
range(c);
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
range(p); // $ range=<=p+2 range===c+1 range=>=p+1
|
range(p); // $ range="<=InitializeParameter: p+2" range="==Phi: c+1" range=">=InitializeParameter: p+1"
|
||||||
}
|
}
|
||||||
if (c != ',') {
|
if (c != ',') {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -193,7 +193,7 @@ int test13(char c, int i) {
|
|||||||
unsigned int y = x-1; // $ overflow=-
|
unsigned int y = x-1; // $ overflow=-
|
||||||
range(y); // $ range===-1 overflow=-
|
range(y); // $ range===-1 overflow=-
|
||||||
int z = i+1; // $ overflow=+
|
int z = i+1; // $ overflow=+
|
||||||
range(z); // $ range===i+1
|
range(z); // $ range="==InitializeParameter: i+1"
|
||||||
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
||||||
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
||||||
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
||||||
@@ -245,7 +245,7 @@ int test_unary(int a) {
|
|||||||
range(c); // $ range=<=0 range=>=-11
|
range(c); // $ range=<=0 range=>=-11
|
||||||
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
|
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
|
range(total); // $ range="<=Phi: 0+11" range=<=19 range=">=Phi: 0-11" range=>=-19
|
||||||
}
|
}
|
||||||
if (-7 <= a && a <= 11) {
|
if (-7 <= a && a <= 11) {
|
||||||
range(a); // $ range=<=11 range=>=-7
|
range(a); // $ range=<=11 range=>=-7
|
||||||
@@ -255,7 +255,7 @@ int test_unary(int a) {
|
|||||||
range(c); // $ range=<=7 range=>=-11
|
range(c); // $ range=<=7 range=>=-11
|
||||||
range(b+c); // $ range=<=18 range=>=-18
|
range(b+c); // $ range=<=18 range=>=-18
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range="<=- ...+18" range=">=- ...-18" range=<=0+29 range=<=37 range=>=0-29 range=>=-37
|
range(total); // $ range="<=Phi: - ...+18" range=">=Phi: - ...-18" range="<=Phi: 0+29" range=<=37 range=">=Phi: 0-29" range=>=-37
|
||||||
}
|
}
|
||||||
if (-7 <= a && a <= 1) {
|
if (-7 <= a && a <= 1) {
|
||||||
range(a); // $ range=<=1 range=>=-7
|
range(a); // $ range=<=1 range=>=-7
|
||||||
@@ -265,7 +265,7 @@ int test_unary(int a) {
|
|||||||
range(c); // $ range=<=7 range=>=-1
|
range(c); // $ range=<=7 range=>=-1
|
||||||
range(b+c); // $ range=<=8 range=>=-8
|
range(b+c); // $ range=<=8 range=>=-8
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range="<=- ...+8" range="<=- ...+26" range=">=- ...-8" range=">=- ...-26" range=<=0+37 range=<=45 range=>=0-37 range=>=-45
|
range(total); // $ range="<=Phi: - ...+8" range="<=Phi: - ...+26" range=">=Phi: - ...-8" range=">=Phi: - ...-26" range="<=Phi: 0+37" range=<=45 range=">=Phi: 0-37" range=>=-45
|
||||||
}
|
}
|
||||||
if (-7 <= a && a <= 0) {
|
if (-7 <= a && a <= 0) {
|
||||||
range(a); // $ range=<=0 range=>=-7
|
range(a); // $ range=<=0 range=>=-7
|
||||||
@@ -275,7 +275,7 @@ int test_unary(int a) {
|
|||||||
range(c); // $ range=<=7 range=>=0
|
range(c); // $ range=<=7 range=>=0
|
||||||
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
|
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
|
range(total); // $ range="<=Phi: - ...+7" range="<=Phi: - ...+15" range="<=Phi: - ...+33" range=">=Phi: - ...-7" range=">=Phi: - ...-15" range=">=Phi: - ...-33" range="<=Phi: 0+44" range=<=52 Unexpected result: range=">=Phi: 0-44" range=>=-52
|
||||||
}
|
}
|
||||||
if (-7 <= a && a <= -2) {
|
if (-7 <= a && a <= -2) {
|
||||||
range(a); // $ range=<=-2 range=>=-7
|
range(a); // $ range=<=-2 range=>=-7
|
||||||
@@ -285,9 +285,9 @@ int test_unary(int a) {
|
|||||||
range(c); // $ range=<=7 range=>=2
|
range(c); // $ range=<=7 range=>=2
|
||||||
range(b+c); // $ range=<=5 range=>=-5
|
range(b+c); // $ range=<=5 range=>=-5
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
|
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
|
||||||
}
|
}
|
||||||
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
|
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ int test_mult01(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 253
|
int r = a*b; // 0 .. 253
|
||||||
range(r); // $ range=<=253 range=>=0
|
range(r); // $ range=<=253 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=<=3+253 range=<=506 range=>=0 range=>=3+0
|
range(total); // $ range="<=Phi: 3+253" range=<=506 range=>=0 range=">=Phi: 3+0"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=3-143
|
range(total); // $ range=">=Phi: 3-143"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
|
|||||||
int r = a*b; // -143 .. -21
|
int r = a*b; // -143 .. -21
|
||||||
range(r); // $ range=<=-21 range=>=-143
|
range(r); // $ range=<=-21 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=3-143 range=>=3-286
|
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=3-143 range=>=3-286
|
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ int test_mult02(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 253
|
int r = a*b; // 0 .. 253
|
||||||
range(r); // $ range=<=253 range=>=0
|
range(r); // $ range=<=253 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=0 range=>=0+0 range=<=0+253 range=<=506
|
range(total); // $ range=>=0 range=">=Phi: 0+0" range="<=Phi: 0+253" range=<=506
|
||||||
}
|
}
|
||||||
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=0
|
range(a); // $ range=<=11 range=>=0
|
||||||
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=0-143
|
range(total); // $ range=">=Phi: 0-143"
|
||||||
}
|
}
|
||||||
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=11 range=>=0
|
range(a); // $ range=<=11 range=>=0
|
||||||
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=0-143 range=>=0-286
|
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||||
}
|
}
|
||||||
range(total); // $range=>=0-143 range=>=0-286
|
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +453,7 @@ int test_mult04(int a, int b) {
|
|||||||
int r = a*b; // -391 .. 0
|
int r = a*b; // -391 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-391
|
range(r); // $ range=<=0 range=>=-391
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
|
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=0 range=>=-17
|
range(a); // $ range=<=0 range=>=-17
|
||||||
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221"
|
range(total); // $ range="<=Phi: - ...+221"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=0 range=>=-17
|
range(a); // $ range=<=0 range=>=-17
|
||||||
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||||
}
|
}
|
||||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,7 +501,7 @@ int test_mult05(int a, int b) {
|
|||||||
int r = a*b; // -391 .. 0
|
int r = a*b; // -391 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-391
|
range(r); // $ range=<=0 range=>=-391
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
|
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=-2 range=>=-17
|
range(a); // $ range=<=-2 range=>=-17
|
||||||
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221"
|
range(total); // $ range="<=Phi: - ...+221"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=-2 range=>=-17
|
range(a); // $ range=<=-2 range=>=-17
|
||||||
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
|
|||||||
int r = a*b; // 14 .. 221
|
int r = a*b; // 14 .. 221
|
||||||
range(r); // $ range=<=221 range=>=14
|
range(r); // $ range=<=221 range=>=14
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||||
}
|
}
|
||||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ int test16(int x) {
|
|||||||
while (i < 3) {
|
while (i < 3) {
|
||||||
range(i); // $ range=<=2 range=>=0
|
range(i); // $ range=<=2 range=>=0
|
||||||
i++;
|
i++;
|
||||||
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
|
range(i); // $ range=<=3 range=>=1 range="==Phi: i | Store: ... = ...+1"
|
||||||
}
|
}
|
||||||
range(d);
|
range(d);
|
||||||
d = i;
|
d = i;
|
||||||
@@ -640,14 +640,14 @@ unsigned int test_comma01(unsigned int x) {
|
|||||||
unsigned int y1;
|
unsigned int y1;
|
||||||
unsigned int y2;
|
unsigned int y2;
|
||||||
y1 = (++y, y);
|
y1 = (++y, y);
|
||||||
range(y1); // $ range=<=101 range="==... ? ... : ...+1"
|
range(y1); // $ range=<=101 range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+1"
|
||||||
y2 = (y++,
|
y2 = (y++,
|
||||||
range(y), // $ range=<=102 range="==++ ...:... = ...+1" range="==... ? ... : ...+2"
|
range(y), // $ range=<=102 range="==Store: ++ ... | Store: ... = ...+1" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+2"
|
||||||
y += 3,
|
y += 3,
|
||||||
range(y), // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
|
range(y), // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
|
||||||
y);
|
y);
|
||||||
range(y2); // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
|
range(y2); // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" Unexpected result: range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
|
||||||
range(y1 + y2); // $ range=<=206 range="<=... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
|
range(y1 + y2); // $ range=<=206 range="<=Phi: ... ? ... : ... | Store: ... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
|
||||||
return y1 + y2;
|
return y1 + y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +672,7 @@ void test17() {
|
|||||||
range(i); // $ range===50
|
range(i); // $ range===50
|
||||||
|
|
||||||
i = 20 + (j -= 10);
|
i = 20 + (j -= 10);
|
||||||
range(i); // $ range="==... += ...:... = ...+10" range===60
|
range(i); // $ range="==Store: ... += ... | Store: ... = ...+10" range===60
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests for unsigned multiplication.
|
// Tests for unsigned multiplication.
|
||||||
@@ -693,7 +693,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
|||||||
int r = a*b; // 0 .. 253
|
int r = a*b; // 0 .. 253
|
||||||
range(r);// $ range=>=0 range=<=253
|
range(r);// $ range=>=0 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
|
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range=<=506 range="<=Phi: (unsigned int)...+253"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
@@ -701,9 +701,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
|||||||
int r = a*b; // 39 .. 253
|
int r = a*b; // 39 .. 253
|
||||||
range(r); // $ range=>=39 range=<=253
|
range(r); // $ range=>=39 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
|
range(total); // $ range=>=39 range=<=759 range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+39"
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,16 +722,16 @@ int test_unsigned_mult02(unsigned b) {
|
|||||||
int r = 11*b; // 0 .. 253
|
int r = 11*b; // 0 .. 253
|
||||||
range(r); // $ range=>=0 range=<=253
|
range(r); // $ range=>=0 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
|
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range="<=Phi: (unsigned int)...+253" range=<=506
|
||||||
}
|
}
|
||||||
if (13 <= b && b <= 23) {
|
if (13 <= b && b <= 23) {
|
||||||
range(b); // $ range=<=23 range=>=13
|
range(b); // $ range=<=23 range=>=13
|
||||||
int r = 11*b; // 143 .. 253
|
int r = 11*b; // 143 .. 253
|
||||||
range(r); // $ range=>=143 range=<=253
|
range(r); // $ range=>=143 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
|
range(total); // $ range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+143" range=>=143 range=<=759
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,7 +851,7 @@ int notequal_type_endpoint(unsigned n) {
|
|||||||
n--; // 1 ..
|
n--; // 1 ..
|
||||||
}
|
}
|
||||||
|
|
||||||
range(n); // $ range=<=n+0 // 0 .. 0
|
range(n); // $ range="<=InitializeParameter: n+0" // 0 .. 0
|
||||||
}
|
}
|
||||||
|
|
||||||
void notequal_refinement(short n) {
|
void notequal_refinement(short n) {
|
||||||
@@ -946,7 +946,7 @@ void widen_recursive_expr() {
|
|||||||
for (s = 0; s < 10; s++) {
|
for (s = 0; s < 10; s++) {
|
||||||
range(s); // $ range=<=9 range=>=0
|
range(s); // $ range=<=9 range=>=0
|
||||||
int result = s + s;
|
int result = s + s;
|
||||||
range(result); // $ range=<=18 range=<=s+9 range=>=0 range=>=s+0
|
range(result); // $ range=<=18 Unexpected result: range="<=Phi: s+9" range=>=0 Unexpected result: range=">=Phi: s+0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
|
|||||||
|
|
||||||
void test_mod_ternary(int s, bool b) {
|
void test_mod_ternary(int s, bool b) {
|
||||||
int s2 = s % (b ? 5 : 500);
|
int s2 = s % (b ? 5 : 500);
|
||||||
range(s2); // $ range=>=-499 range=<=499 range="<=... ? ... : ...-1"
|
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
int sum = x + y; // $ overflow=+-
|
int sum = x + y; // $ overflow=+-
|
||||||
} else {
|
} else {
|
||||||
if (y > 300) {
|
if (y > 300) {
|
||||||
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
|
range(x); // $ range=>=302 range=<=400 range="<=InitializeParameter: y+1" MISSING: range===y+1
|
||||||
range(y); // $ range=>=301 range=<=399 range===x-1
|
range(y); // $ range=>=301 range=<=399 range="==InitializeParameter: x | Store: x-1"
|
||||||
int sum = x + y;
|
int sum = x + y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
|
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
|
||||||
range(x); // $ range===349 range===y+1 range===z-1
|
range(x); // $ range===349 range="==InitializeParameter: y+1" range="==InitializeParameter: z-1"
|
||||||
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
|
range(y); // $ range===348 range=">=InitializeParameter: x | Store: x-1" range="==InitializeParameter: z-2" MISSING: range===x-1
|
||||||
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
|
range(z); // $ range===350 range="<=InitializeParameter: y+2" MISSING: range===x+1 range===y+2
|
||||||
return x + y + z;
|
return x + y + z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,17 @@
|
|||||||
while (f3_get(n)) n+=2;
|
while (f3_get(n)) n+=2;
|
||||||
|
|
||||||
for (int i = 0; i < n; i += 2) {
|
for (int i = 0; i < n; i += 2) {
|
||||||
range(i); // $ range=>=0 SPURIOUS: range="<=call to f3_get-1" range="<=call to f3_get-2"
|
range(i); // $ range=>=0 SPURIOUS: range="<=Phi: call to f3_get-1" range="<=Phi: call to f3_get-2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int f4(int x) {
|
||||||
|
for (int i = 0; i <= 100; i++) {
|
||||||
|
range(i); // $ range=<=100 range=>=0
|
||||||
|
if(i == 100) {
|
||||||
|
range(i); // $ range===100
|
||||||
|
} else {
|
||||||
|
range(i); // $ range=<=99 range=>=0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -11,12 +11,10 @@ import TestUtilities.InlineExpectationsTest
|
|||||||
module SignAnalysisInstantiated =
|
module SignAnalysisInstantiated =
|
||||||
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||||
|
|
||||||
class SignAnalysisTest extends InlineExpectationsTest {
|
module SignAnalysisTest implements TestSig {
|
||||||
SignAnalysisTest() { this = "SignAnalysisTest" }
|
string getARelevantTag() { result = "sign" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "sign" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(SemExpr e, IR::CallInstruction call |
|
exists(SemExpr e, IR::CallInstruction call |
|
||||||
getSemanticExpr(call.getArgument(0)) = e and
|
getSemanticExpr(call.getArgument(0)) = e and
|
||||||
call.getStaticCallTarget().hasName("sign") and
|
call.getStaticCallTarget().hasName("sign") and
|
||||||
@@ -28,6 +26,8 @@ class SignAnalysisTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<SignAnalysisTest>
|
||||||
|
|
||||||
private string getASignString(SemExpr e) {
|
private string getASignString(SemExpr e) {
|
||||||
result = strictconcat(SignAnalysisInstantiated::semExprSign(e).toString(), "")
|
result = strictconcat(SignAnalysisInstantiated::semExprSign(e).toString(), "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
testFailures
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ private import cpp
|
|||||||
private import semmle.code.cpp.ir.implementation.raw.IR
|
private import semmle.code.cpp.ir.implementation.raw.IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class IRTypesTest extends InlineExpectationsTest {
|
module IRTypesTest implements TestSig {
|
||||||
IRTypesTest() { this = "IRTypesTest" }
|
string getARelevantTag() { result = "irtype" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "irtype" }
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
||||||
exists(IRUserVariable irVar |
|
exists(IRUserVariable irVar |
|
||||||
location = irVar.getLocation() and
|
location = irVar.getLocation() and
|
||||||
element = irVar.toString() and
|
element = irVar.toString() and
|
||||||
@@ -16,3 +14,5 @@ class IRTypesTest extends InlineExpectationsTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import MakeTest<IRTypesTest>
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ edges
|
|||||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
|
||||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
|
||||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
@@ -61,7 +59,6 @@ nodes
|
|||||||
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
||||||
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||||
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||||
| test_free.cpp:241:10:241:10 | b | semmle.label | b |
|
|
||||||
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||||
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||||
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
||||||
@@ -92,8 +89,6 @@ subpaths
|
|||||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
|
||||||
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
|
||||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
|
|||||||
@@ -1,29 +1,16 @@
|
|||||||
edges
|
edges
|
||||||
| tests.cpp:26:15:26:23 | badSource indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
|
| tests.cpp:26:15:26:23 | badSource indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
|
||||||
| tests.cpp:26:32:26:35 | data indirection | tests.cpp:26:15:26:23 | badSource indirection |
|
|
||||||
| tests.cpp:26:32:26:35 | data indirection | tests.cpp:38:25:38:36 | strncat output argument |
|
|
||||||
| tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:38:39:38:49 | environment indirection |
|
| tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:38:39:38:49 | environment indirection |
|
||||||
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | badSource indirection |
|
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | badSource indirection |
|
||||||
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | badSource indirection |
|
|
||||||
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:51:22:51:25 | badSource output argument |
|
|
||||||
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
|
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
|
||||||
| tests.cpp:51:12:51:20 | call to badSource indirection | tests.cpp:53:16:53:19 | data indirection |
|
| tests.cpp:51:12:51:20 | call to badSource indirection | tests.cpp:53:16:53:19 | data indirection |
|
||||||
| tests.cpp:51:22:51:25 | badSource output argument | tests.cpp:51:22:51:25 | data indirection |
|
|
||||||
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:26:32:26:35 | data indirection |
|
|
||||||
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
|
|
||||||
nodes
|
nodes
|
||||||
| tests.cpp:26:15:26:23 | badSource indirection | semmle.label | badSource indirection |
|
| tests.cpp:26:15:26:23 | badSource indirection | semmle.label | badSource indirection |
|
||||||
| tests.cpp:26:15:26:23 | badSource indirection | semmle.label | badSource indirection |
|
|
||||||
| tests.cpp:26:32:26:35 | data indirection | semmle.label | data indirection |
|
|
||||||
| tests.cpp:33:34:33:39 | call to getenv indirection | semmle.label | call to getenv indirection |
|
| tests.cpp:33:34:33:39 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||||
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
|
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
|
||||||
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
|
|
||||||
| tests.cpp:38:39:38:49 | environment indirection | semmle.label | environment indirection |
|
| tests.cpp:38:39:38:49 | environment indirection | semmle.label | environment indirection |
|
||||||
| tests.cpp:51:12:51:20 | call to badSource indirection | semmle.label | call to badSource indirection |
|
| tests.cpp:51:12:51:20 | call to badSource indirection | semmle.label | call to badSource indirection |
|
||||||
| tests.cpp:51:22:51:25 | badSource output argument | semmle.label | badSource output argument |
|
|
||||||
| tests.cpp:51:22:51:25 | data indirection | semmle.label | data indirection |
|
|
||||||
| tests.cpp:53:16:53:19 | data indirection | semmle.label | data indirection |
|
| tests.cpp:53:16:53:19 | data indirection | semmle.label | data indirection |
|
||||||
subpaths
|
subpaths
|
||||||
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:26:32:26:35 | data indirection | tests.cpp:26:15:26:23 | badSource indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
|
|
||||||
#select
|
#select
|
||||||
| tests.cpp:53:16:53:19 | data | tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:53:16:53:19 | data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | tests.cpp:33:34:33:39 | call to getenv indirection | user input (an environment variable) | tests.cpp:38:25:38:36 | strncat output argument | strncat output argument |
|
| tests.cpp:53:16:53:19 | data | tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:53:16:53:19 | data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | tests.cpp:33:34:33:39 | call to getenv indirection | user input (an environment variable) | tests.cpp:38:25:38:36 | strncat output argument | strncat output argument |
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user