Compare commits

..

3 Commits

Author SHA1 Message Date
github-actions[bot]
c47e996f48 Post-release preparation for codeql-cli-2.13.2 2023-05-15 17:28:52 +00:00
Ian Lynagh
da8a002f22 Merge pull request #13162 from github/release-prep/2.13.2
Release preparation for version 2.13.2
2023-05-15 13:28:56 +01:00
github-actions[bot]
994c6f5f44 Release preparation for version 2.13.2 2023-05-15 10:59:27 +00:00
1588 changed files with 38301 additions and 73826 deletions

3
.github/labeler.yml vendored
View File

@@ -11,7 +11,7 @@ Go:
- change-notes/**/*go.*
Java:
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/ql/test/kotlin/**/*' ]
- any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/kotlin-explorer/**/*', '!java/ql/test/kotlin/**/*' ]
- change-notes/**/*java.*
JS:
@@ -20,6 +20,7 @@ JS:
Kotlin:
- java/kotlin-extractor/**/*
- java/kotlin-explorer/**/*
- java/ql/test/kotlin/**/*
Python:

View File

@@ -11,6 +11,7 @@ on:
- "*/ql/lib/**/*.yml"
- "!**/experimental/**"
- "!ql/**"
- "!swift/**"
- ".github/workflows/check-change-note.yml"
jobs:
@@ -26,9 +27,9 @@ jobs:
run: |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
grep true -c
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md', 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text, or released/x.y.z.md for released change-notes
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md' or 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$") or test("/change-notes/released/[0-9]*[.][0-9]*[.][0-9]*[.]md$"))' |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$"))' |
grep true -c

View File

@@ -10,7 +10,6 @@ on:
- "*/ql/src/**/*.qll"
- "*/ql/lib/**/*.ql"
- "*/ql/lib/**/*.qll"
- "*/ql/lib/ext/**/*.yml"
- "misc/scripts/library-coverage/*.py"
# input data files
- "*/documentation/library-coverage/cwe-sink.csv"

View File

@@ -32,7 +32,7 @@ jobs:
path: |
ql/extractor-pack/
ql/target/release/buramu
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ql/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo
if: steps.cache-extractor.outputs.cache-hit != 'true'
uses: actions/cache@v3

View File

@@ -61,7 +61,7 @@ jobs:
ruby/extractor/target/release/codeql-extractor-ruby
ruby/extractor/target/release/codeql-extractor-ruby.exe
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
- uses: actions/cache@v3
if: steps.cache-extractor.outputs.cache-hit != 'true'
with:

View File

@@ -16,7 +16,6 @@ on:
branches:
- main
- rc/*
- codeql-cli-*
push:
paths:
- "swift/**"
@@ -31,7 +30,6 @@ on:
branches:
- main
- rc/*
- codeql-cli-*
jobs:
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks

View File

@@ -17,6 +17,4 @@ jobs:
- uses: actions/checkout@v3
- name: Check synchronized files
run: python config/sync-files.py
- name: Check dbscheme fragments
run: python config/sync-dbscheme-fragments.py

18
.vscode/tasks.json vendored
View File

@@ -22,22 +22,6 @@
"command": "${config:python.pythonPath}",
},
"problemMatcher": []
},
{
"label": "Accept .expected changes from CI",
"type": "process",
// Non-Windows OS will usually have Python 3 already installed at /usr/bin/python3.
"command": "python3",
"args": [
"misc/scripts/accept-expected-changes-from-ci.py"
],
"group": "build",
"windows": {
// On Windows, use whatever Python interpreter is configured for this workspace. The default is
// just `python`, so if Python is already on the path, this will find it.
"command": "${config:python.pythonPath}",
},
"problemMatcher": []
}
]
}
}

View File

@@ -8,6 +8,7 @@
/swift/ @github/codeql-swift
/misc/codegen/ @github/codeql-swift
/java/kotlin-extractor/ @github/codeql-kotlin
/java/kotlin-explorer/ @github/codeql-kotlin
# ML-powered queries
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
@@ -39,6 +40,3 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
/.github/workflows/ruby-* @github/codeql-ruby
/.github/workflows/swift.yml @github/codeql-swift
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL

View File

@@ -1,33 +0,0 @@
{
"files": [
"javascript/ql/lib/semmlecode.javascript.dbscheme",
"python/ql/lib/semmlecode.python.dbscheme",
"ruby/ql/lib/ruby.dbscheme",
"ql/ql/src/ql.dbscheme"
],
"fragments": [
"/*- External data -*/",
"/*- Files and folders -*/",
"/*- Diagnostic messages -*/",
"/*- Diagnostic messages: severity -*/",
"/*- Source location prefix -*/",
"/*- Lines of code -*/",
"/*- Configuration files with key value pairs -*/",
"/*- YAML -*/",
"/*- XML Files -*/",
"/*- XML: sourceline -*/",
"/*- DEPRECATED: External defects and metrics -*/",
"/*- DEPRECATED: Snapshot date -*/",
"/*- DEPRECATED: Duplicate code -*/",
"/*- DEPRECATED: Version control data -*/",
"/*- JavaScript-specific part -*/",
"/*- Ruby dbscheme -*/",
"/*- Erb dbscheme -*/",
"/*- QL dbscheme -*/",
"/*- Dbscheme dbscheme -*/",
"/*- Yaml dbscheme -*/",
"/*- Blame dbscheme -*/",
"/*- JSON dbscheme -*/",
"/*- Python dbscheme -*/"
]
}

View File

@@ -47,6 +47,7 @@
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
@@ -511,8 +512,7 @@
"SensitiveDataHeuristics Python/JS": [
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
@@ -599,4 +599,4 @@
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
]
}
}

View File

@@ -1,86 +0,0 @@
#!/usr/bin/env python3
import argparse
import json
import os
import pathlib
import re
def make_groups(blocks):
groups = {}
for block in blocks:
groups.setdefault("".join(block["lines"]), []).append(block)
return list(groups.values())
def validate_fragments(fragments):
ok = True
for header, blocks in fragments.items():
groups = make_groups(blocks)
if len(groups) > 1:
ok = False
print("Warning: dbscheme fragments with header '{}' are different for {}".format(header, ["{}:{}:{}".format(
group[0]["file"], group[0]["start"], group[0]["end"]) for group in groups]))
return ok
def main():
script_path = os.path.realpath(__file__)
script_dir = os.path.dirname(script_path)
parser = argparse.ArgumentParser(
prog=os.path.basename(script_path),
description='Sync dbscheme fragments across files.'
)
parser.add_argument('files', metavar='dbscheme_file', type=pathlib.Path, nargs='*', default=[],
help='dbscheme files to check')
args = parser.parse_args()
with open(os.path.join(script_dir, "dbscheme-fragments.json"), "r") as f:
config = json.load(f)
fragment_headers = set(config["fragments"])
fragments = {}
ok = True
for file in args.files + config["files"]:
with open(os.path.join(os.path.dirname(script_dir), file), "r") as dbscheme:
header = None
line_number = 1
block = {"file": file, "start": line_number,
"end": None, "lines": []}
def end_block():
block["end"] = line_number - 1
if len(block["lines"]) > 0:
if header is None:
if re.match(r'(?m)\A(\s|//.*$|/\*(\**[^\*])*\*+/)*\Z', "".join(block["lines"])):
# Ignore comments at the beginning of the file
pass
else:
ok = False
print("Warning: dbscheme fragment without header: {}:{}:{}".format(
block["file"], block["start"], block["end"]))
else:
fragments.setdefault(header, []).append(block)
for line in dbscheme:
m = re.match(r"^\/\*-.*-\*\/$", line)
if m:
end_block()
header = line.strip()
if header not in fragment_headers:
ok = False
print("Warning: unknown header for dbscheme fragment: '{}': {}:{}".format(
header, file, line_number))
block = {"file": file, "start": line_number,
"end": None, "lines": []}
block["lines"].append(line)
line_number += 1
block["lines"].append('\n')
line_number += 1
end_block()
if not ok or not validate_fragments(fragments):
exit(1)
if __name__ == "__main__":
main()

View File

@@ -11,7 +11,6 @@
### Minor Analysis Improvements
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
## 0.7.1

View File

@@ -1,6 +0,0 @@
---
category: minorAnalysis
---
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `CodeDuplication.qll` file.

View File

@@ -11,5 +11,4 @@
### Minor Analysis Improvements
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.

View File

@@ -1,29 +1,10 @@
/**
* Provides a library for global (inter-procedural) data flow analysis of two
* values "simultaneously". This can be used, for example, if you want to track
* a memory allocation as well as the size of the allocation.
*
* Intuitively, you can think of this as regular dataflow, but where each node
* in the dataflow graph has been replaced by a pair of nodes `(node1, node2)`,
* and two node pairs `(n11, n12)`, `(n21, n22)` is then connected by a dataflow
* edge if there's a regular dataflow edge between `n11` and `n21`, and `n12`
* and `n22`.
*
* Note that the above intuition does not reflect the actual implementation.
*/
import semmle.code.cpp.dataflow.new.DataFlow
private import DataFlowPrivate
private import DataFlowUtil
private import DataFlowImplCommon
import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
private import codeql.util.Unit
/**
* Provides classes for performing global (inter-procedural) data flow analyses
* on a product dataflow graph.
*/
module ProductFlow {
/** An input configuration for product data-flow. */
signature module ConfigSig {
/**
* Holds if `(source1, source2)` is a relevant data flow source.
@@ -89,9 +70,6 @@ module ProductFlow {
default predicate isBarrierIn2(DataFlow::Node node) { none() }
}
/**
* The output of a global data flow computation.
*/
module Global<ConfigSig Config> {
private module StateConfig implements StateConfigSig {
class FlowState1 = Unit;
@@ -160,7 +138,6 @@ module ProductFlow {
import GlobalWithState<StateConfig>
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState1;
@@ -270,9 +247,6 @@ module ProductFlow {
default predicate isBarrierIn2(DataFlow::Node node) { none() }
}
/**
* The output of a global data flow computation.
*/
module GlobalWithState<StateConfigSig Config> {
class PathNode1 = Flow1::PathNode;
@@ -286,7 +260,6 @@ module ProductFlow {
class FlowState2 = Config::FlowState2;
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
predicate flowPath(
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
) {
@@ -317,9 +290,9 @@ module ProductFlow {
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
}
private module Flow1 = DataFlow::GlobalWithState<Config1>;
module Flow1 = DataFlow::GlobalWithState<Config1>;
private module Config2 implements DataFlow::StateConfigSig {
module Config2 implements DataFlow::StateConfigSig {
class FlowState = FlowState2;
predicate isSource(DataFlow::Node source, FlowState state) {
@@ -349,90 +322,27 @@ module ProductFlow {
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
}
private module Flow2 = DataFlow::GlobalWithState<Config2>;
private predicate isSourcePair(Flow1::PathNode node1, Flow2::PathNode node2) {
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
}
private predicate isSinkPair(Flow1::PathNode node1, Flow2::PathNode node2) {
Config::isSinkPair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
}
pragma[assume_small_delta]
pragma[nomagic]
private predicate fwdReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
isSourcePair(node1, node2)
or
fwdIsSuccessor(_, _, node1, node2)
}
module Flow2 = DataFlow::GlobalWithState<Config2>;
pragma[nomagic]
private predicate fwdIsSuccessorExit(
Flow1::PathNode mid1, Flow2::PathNode mid2, Flow1::PathNode succ1, Flow2::PathNode succ2
private predicate reachableInterprocEntry(
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
) {
isSinkPair(mid1, mid2) and
succ1 = mid1 and
succ2 = mid2
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
node1 = source1 and
node2 = source2
or
interprocEdgePair(mid1, mid2, succ1, succ2)
}
private predicate fwdIsSuccessor1(
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
Flow1::PathNode succ1, Flow2::PathNode succ2
) {
fwdReachableInterprocEntry(pred1, pred2) and
localPathStep1*(pred1, mid1) and
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
}
private predicate fwdIsSuccessor2(
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode mid1, Flow2::PathNode mid2,
Flow1::PathNode succ1, Flow2::PathNode succ2
) {
fwdReachableInterprocEntry(pred1, pred2) and
localPathStep2*(pred2, mid2) and
fwdIsSuccessorExit(pragma[only_bind_into](mid1), pragma[only_bind_into](mid2), succ1, succ2)
}
pragma[assume_small_delta]
private predicate fwdIsSuccessor(
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
) {
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
fwdIsSuccessor1(pred1, pred2, mid1, mid2, succ1, succ2) and
fwdIsSuccessor2(pred1, pred2, mid1, mid2, succ1, succ2)
exists(
Flow1::PathNode midEntry1, Flow2::PathNode midEntry2, Flow1::PathNode midExit1,
Flow2::PathNode midExit2
|
reachableInterprocEntry(source1, source2, midEntry1, midEntry2) and
interprocEdgePair(midExit1, midExit2, node1, node2) and
localPathStep1*(midEntry1, midExit1) and
localPathStep2*(midEntry2, midExit2)
)
}
pragma[assume_small_delta]
pragma[nomagic]
private predicate revReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
fwdReachableInterprocEntry(node1, node2) and
isSinkPair(node1, node2)
or
exists(Flow1::PathNode succ1, Flow2::PathNode succ2 |
revReachableInterprocEntry(succ1, succ2) and
fwdIsSuccessor(node1, node2, succ1, succ2)
)
}
private newtype TNodePair =
TMkNodePair(Flow1::PathNode node1, Flow2::PathNode node2) {
revReachableInterprocEntry(node1, node2)
}
private predicate pathSucc(TNodePair n1, TNodePair n2) {
exists(Flow1::PathNode n11, Flow2::PathNode n12, Flow1::PathNode n21, Flow2::PathNode n22 |
n1 = TMkNodePair(n11, n12) and
n2 = TMkNodePair(n21, n22) and
fwdIsSuccessor(n11, n12, n21, n22)
)
}
private predicate pathSuccPlus(TNodePair n1, TNodePair n2) = fastTC(pathSucc/2)(n1, n2)
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
Flow1::PathGraph::edges(pred, succ) and
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
@@ -564,14 +474,11 @@ module ProductFlow {
private predicate reachable(
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
) {
isSourcePair(source1, source2) and
isSinkPair(sink1, sink2) and
exists(TNodePair n1, TNodePair n2 |
n1 = TMkNodePair(source1, source2) and
n2 = TMkNodePair(sink1, sink2)
|
pathSuccPlus(n1, n2) or
n1 = n2
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
reachableInterprocEntry(source1, source2, mid1, mid2) and
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
localPathStep1*(mid1, sink1) and
localPathStep2*(mid2, sink2)
)
}
}

View File

@@ -176,6 +176,20 @@ class Class extends UserType {
/** Holds if this class, struct or union has a constructor. */
predicate hasConstructor() { exists(this.getAConstructor()) }
/**
* Holds if this class has a copy constructor that is either explicitly
* declared (though possibly `= delete`) or is auto-generated, non-trivial
* and called from somewhere.
*
* DEPRECATED: There is more than one reasonable definition of what it means
* to have a copy constructor, and we do not want to promote one particular
* definition by naming it with this predicate. Having a copy constructor
* could mean that such a member is declared or defined in the source or that
* it is callable by a particular caller. For C++11, there's also a question
* of whether to include members that are defaulted or deleted.
*/
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
/**
* Like accessOfBaseMember but returns multiple results if there are multiple
* paths to `base` through the inheritance graph.

View File

@@ -34,7 +34,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
* Gets the name of the macro. For example, `MAX` in
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
*/
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
string getName() { result = this.getHead().splitAt("(", 0) }
/** Holds if the macro has name `name`. */
predicate hasName(string name) { this.getName() = name }

View File

@@ -230,12 +230,8 @@ class GlobalNamespace extends Namespace {
}
/**
* The C++ `std::` namespace and its inline namespaces.
* The C++ `std::` namespace.
*/
class StdNamespace extends Namespace {
StdNamespace() {
this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace
or
this.isInline() and this.getParentNamespace() instanceof StdNamespace
}
StdNamespace() { this.hasName("std") and this.getParentNamespace() instanceof GlobalNamespace }
}

View File

@@ -27,6 +27,9 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
predicate shouldPrintFunction(Function func) { any() }
}
/** DEPRECATED: Alias for PrintAstConfiguration */
deprecated class PrintASTConfiguration = PrintAstConfiguration;
private predicate shouldPrintFunction(Function func) {
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
}
@@ -236,6 +239,9 @@ class PrintAstNode extends TPrintAstNode {
}
}
/** DEPRECATED: Alias for PrintAstNode */
deprecated class PrintASTNode = PrintAstNode;
/**
* Class that restricts the elements that we compute `qlClass` for.
*/
@@ -280,6 +286,9 @@ abstract class BaseAstNode extends PrintAstNode {
deprecated Locatable getAST() { result = this.getAst() }
}
/** DEPRECATED: Alias for BaseAstNode */
deprecated class BaseASTNode = BaseAstNode;
/**
* A node representing an AST node other than a `DeclarationEntry`.
*/
@@ -287,6 +296,9 @@ abstract class AstNode extends BaseAstNode, TAstNode {
AstNode() { this = TAstNode(ast) }
}
/** DEPRECATED: Alias for AstNode */
deprecated class ASTNode = AstNode;
/**
* A node representing an `Expr`.
*/

View File

@@ -1699,28 +1699,7 @@ class AutoType extends TemplateParameter {
private predicate suppressUnusedThis(Type t) { any() }
/**
* A source code location referring to a user-defined type.
*
* Note that only _user-defined_ types have `TypeMention`s. In particular,
* built-in types, and derived types with built-in types as their base don't
* have any `TypeMention`s. For example, given
* ```cpp
* struct S { ... };
* void f(S s1, int i1) {
* S s2;
* S* s3;
* S& s4 = s2;
* decltype(s2) s5;
*
* int i2;
* int* i3;
* int i4[10];
* }
* ```
* there will be a `TypeMention` for the mention of `S` at `S s1`, `S s2`, and `S& s4 = s2`,
* but not at `decltype(s2) s5`. Additionally, there will be no `TypeMention`s for `int`.
*/
/** A source code location referring to a type */
class TypeMention extends Locatable, @type_mention {
override string toString() { result = "type mention" }

View File

@@ -14,6 +14,9 @@ library class StandardSsa extends SsaHelper {
StandardSsa() { this = 0 }
}
/** DEPRECATED: Alias for StandardSsa */
deprecated class StandardSSA = StandardSsa;
/**
* A definition of one or more SSA variables, including phi node definitions.
* An _SSA variable_, as defined in the literature, is effectively the pair of

View File

@@ -312,3 +312,6 @@ library class SsaHelper extends int {
ssa_use(v, result, _, _)
}
}
/** DEPRECATED: Alias for SsaHelper */
deprecated class SSAHelper = SsaHelper;

View File

@@ -1385,6 +1385,9 @@ private module Cached {
conditionalSuccessor(n1, _, n2)
}
/** DEPRECATED: Alias for qlCfgSuccessor */
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
/**
* Holds if `n2` is a control-flow node such that the control-flow
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
@@ -1395,6 +1398,9 @@ private module Cached {
not conditionalSuccessor(n1, false, n2)
}
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
/**
* Holds if `n2` is a control-flow node such that the control-flow
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
@@ -1404,4 +1410,7 @@ private module Cached {
conditionalSuccessor(n1, false, n2) and
not conditionalSuccessor(n1, true, n2)
}
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
}

View File

@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
);
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType);
@@ -1199,21 +1199,17 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa
) {
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
}
private predicate fwdFlow1(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
PrevStage::revFlow(node, state, apa) and
filter(node, state, t0, ap, t)
filter(node, state, t, ap)
}
pragma[nomagic]
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap
) {
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
}
pragma[assume_small_delta]
@@ -1343,11 +1339,6 @@ module Impl<FullStateConfigSig Config> {
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
cons = apCons(c, t1, tail)
or
exists(Typ t0 |
typeStrengthen(t0, cons, t2) and
fwdFlowConsCand(t0, cons, c, t1, tail)
)
}
pragma[nomagic]
@@ -1368,7 +1359,7 @@ module Impl<FullStateConfigSig Config> {
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
) {
exists(ApHeadContent apc |
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
apc = getHeadContent(ap) and
readStepCand0(node1, apc, c, node2)
)
@@ -1529,14 +1520,14 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
revFlow0(node, state, returnCtx, returnAp, ap) and
fwdFlow(node, state, _, _, _, _, _, ap, _)
fwdFlow(node, state, _, _, _, _, _, ap)
}
pragma[nomagic]
private predicate revFlow0(
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
fwdFlow(node, state, _, _, _, _, _, ap, _) and
fwdFlow(node, state, _, _, _, _, _, ap) and
sinkNode(node, state) and
(
if hasSinkCallCtx()
@@ -1789,13 +1780,13 @@ module Impl<FullStateConfigSig Config> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
) {
fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
@@ -1972,10 +1963,10 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
PrevStage::revFlowState(state) and
t0 = t and
exists(t) and
exists(ap) and
not stateBarrier(node, state) and
(
@@ -2206,8 +2197,8 @@ module Impl<FullStateConfigSig Config> {
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
exists(lcc)
@@ -2227,16 +2218,10 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
exists(state) and
// We can get away with not using type strengthening here, since we aren't
// going to use the tracked types in the construction of Stage 4 access
// paths. For Stage 4 and onwards, the tracked types must be consistent as
// the cons candidates including types are used to construct subsequent
// access path approximations.
t0 = t and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
(
notExpectsContent(node)
or
@@ -2256,16 +2241,6 @@ module Impl<FullStateConfigSig Config> {
import MkStage<Stage2>::Stage<Stage3Param>
}
bindingset[node, t0]
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
if castingNodeEx(node)
then
exists(DataFlowType nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
@@ -2299,8 +2274,8 @@ module Impl<FullStateConfigSig Config> {
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2358,11 +2333,11 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
exists(state) and
not clear(node, ap) and
strengthenType(node, t0, t) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
(
notExpectsContent(node)
or
@@ -2390,7 +2365,7 @@ module Impl<FullStateConfigSig Config> {
exists(AccessPathFront apf |
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
apf, _)
apf)
)
}
@@ -2604,8 +2579,8 @@ module Impl<FullStateConfigSig Config> {
import LocalCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2634,9 +2609,9 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
strengthenType(node, t0, t) and
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
exists(state) and
exists(ap)
}
@@ -2657,7 +2632,7 @@ module Impl<FullStateConfigSig Config> {
Stage5::parameterMayFlowThrough(p, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
TAccessPathApproxSome(apa), _, apa0, _)
TAccessPathApproxSome(apa), _, apa0)
)
}
@@ -2674,7 +2649,7 @@ module Impl<FullStateConfigSig Config> {
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
exists(AccessPathApprox apa | ap.getApprox() = apa |
Stage5::parameterMayFlowThrough(p, apa) and
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
Stage5::revFlow(p, state, _)
)
}
@@ -2845,7 +2820,9 @@ module Impl<FullStateConfigSig Config> {
ap = TAccessPathNil()
or
// ... or a step from an existing PathNode to another node.
pathStep(_, node, state, cc, sc, t, ap)
pathStep(_, node, state, cc, sc, t, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
} or
TPathNodeSink(NodeEx node, FlowState state) {
exists(PathNodeMid sink |
@@ -3363,24 +3340,13 @@ module Impl<FullStateConfigSig Config> {
ap = mid.getAp()
}
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
exists(DataFlowType t0 |
pathStep0(mid, node, state, cc, sc, t0, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
strengthenType(node, t0, t)
)
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep0(
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
@@ -3998,7 +3964,7 @@ module Impl<FullStateConfigSig Config> {
ap = TPartialNil() and
exists(explorationLimit())
or
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
distSrc(node.getEnclosingCallable()) <= explorationLimit()
} or
TPartialPathNodeRev(
@@ -4024,20 +3990,11 @@ module Impl<FullStateConfigSig Config> {
}
pragma[nomagic]
private predicate partialPathStep(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
private predicate partialPathNodeMk0(
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
}
pragma[nomagic]
private predicate partialPathStep1(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
PartialAccessPath ap
) {
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
not fullBarrier(node) and
not stateBarrier(node, state) and
not clearsContentEx(node, ap.getHead()) and
@@ -4045,14 +4002,9 @@ module Impl<FullStateConfigSig Config> {
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
strengthenType(node, t0, t)
}
pragma[nomagic]
private predicate partialPathTypeStrengthen(
DataFlowType t0, PartialAccessPath ap, DataFlowType t
) {
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), t)
else any()
}
/**
@@ -4231,8 +4183,7 @@ module Impl<FullStateConfigSig Config> {
}
}
pragma[nomagic]
private predicate partialPathStep0(
private predicate partialPathStep(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
@@ -4358,11 +4309,6 @@ module Impl<FullStateConfigSig Config> {
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
) {
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
or
exists(DataFlowType t0 |
partialPathTypeStrengthen(t0, ap2, t2) and
apConsFwd(t1, ap1, c, t0, ap2)
)
}
pragma[nomagic]

View File

@@ -205,8 +205,6 @@ predicate clearsContent(Node n, Content c) {
*/
predicate expectsContent(Node n, ContentSet c) { none() }
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
/** Gets the type of `n` used for type pruning. */
Type getNodeType(Node n) {
suppressUnusedNode(n) and

View File

@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
);
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType);
@@ -1199,21 +1199,17 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa
) {
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
}
private predicate fwdFlow1(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
PrevStage::revFlow(node, state, apa) and
filter(node, state, t0, ap, t)
filter(node, state, t, ap)
}
pragma[nomagic]
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap
) {
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
}
pragma[assume_small_delta]
@@ -1343,11 +1339,6 @@ module Impl<FullStateConfigSig Config> {
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
cons = apCons(c, t1, tail)
or
exists(Typ t0 |
typeStrengthen(t0, cons, t2) and
fwdFlowConsCand(t0, cons, c, t1, tail)
)
}
pragma[nomagic]
@@ -1368,7 +1359,7 @@ module Impl<FullStateConfigSig Config> {
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
) {
exists(ApHeadContent apc |
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
apc = getHeadContent(ap) and
readStepCand0(node1, apc, c, node2)
)
@@ -1529,14 +1520,14 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
revFlow0(node, state, returnCtx, returnAp, ap) and
fwdFlow(node, state, _, _, _, _, _, ap, _)
fwdFlow(node, state, _, _, _, _, _, ap)
}
pragma[nomagic]
private predicate revFlow0(
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
fwdFlow(node, state, _, _, _, _, _, ap, _) and
fwdFlow(node, state, _, _, _, _, _, ap) and
sinkNode(node, state) and
(
if hasSinkCallCtx()
@@ -1789,13 +1780,13 @@ module Impl<FullStateConfigSig Config> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
) {
fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
@@ -1972,10 +1963,10 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
PrevStage::revFlowState(state) and
t0 = t and
exists(t) and
exists(ap) and
not stateBarrier(node, state) and
(
@@ -2206,8 +2197,8 @@ module Impl<FullStateConfigSig Config> {
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
exists(lcc)
@@ -2227,16 +2218,10 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
exists(state) and
// We can get away with not using type strengthening here, since we aren't
// going to use the tracked types in the construction of Stage 4 access
// paths. For Stage 4 and onwards, the tracked types must be consistent as
// the cons candidates including types are used to construct subsequent
// access path approximations.
t0 = t and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
(
notExpectsContent(node)
or
@@ -2256,16 +2241,6 @@ module Impl<FullStateConfigSig Config> {
import MkStage<Stage2>::Stage<Stage3Param>
}
bindingset[node, t0]
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
if castingNodeEx(node)
then
exists(DataFlowType nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
@@ -2299,8 +2274,8 @@ module Impl<FullStateConfigSig Config> {
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2358,11 +2333,11 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
exists(state) and
not clear(node, ap) and
strengthenType(node, t0, t) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
(
notExpectsContent(node)
or
@@ -2390,7 +2365,7 @@ module Impl<FullStateConfigSig Config> {
exists(AccessPathFront apf |
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
apf, _)
apf)
)
}
@@ -2604,8 +2579,8 @@ module Impl<FullStateConfigSig Config> {
import LocalCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2634,9 +2609,9 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
strengthenType(node, t0, t) and
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
exists(state) and
exists(ap)
}
@@ -2657,7 +2632,7 @@ module Impl<FullStateConfigSig Config> {
Stage5::parameterMayFlowThrough(p, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
TAccessPathApproxSome(apa), _, apa0, _)
TAccessPathApproxSome(apa), _, apa0)
)
}
@@ -2674,7 +2649,7 @@ module Impl<FullStateConfigSig Config> {
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
exists(AccessPathApprox apa | ap.getApprox() = apa |
Stage5::parameterMayFlowThrough(p, apa) and
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
Stage5::revFlow(p, state, _)
)
}
@@ -2845,7 +2820,9 @@ module Impl<FullStateConfigSig Config> {
ap = TAccessPathNil()
or
// ... or a step from an existing PathNode to another node.
pathStep(_, node, state, cc, sc, t, ap)
pathStep(_, node, state, cc, sc, t, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
} or
TPathNodeSink(NodeEx node, FlowState state) {
exists(PathNodeMid sink |
@@ -3363,24 +3340,13 @@ module Impl<FullStateConfigSig Config> {
ap = mid.getAp()
}
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
exists(DataFlowType t0 |
pathStep0(mid, node, state, cc, sc, t0, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
strengthenType(node, t0, t)
)
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep0(
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
@@ -3998,7 +3964,7 @@ module Impl<FullStateConfigSig Config> {
ap = TPartialNil() and
exists(explorationLimit())
or
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
distSrc(node.getEnclosingCallable()) <= explorationLimit()
} or
TPartialPathNodeRev(
@@ -4024,20 +3990,11 @@ module Impl<FullStateConfigSig Config> {
}
pragma[nomagic]
private predicate partialPathStep(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
private predicate partialPathNodeMk0(
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
}
pragma[nomagic]
private predicate partialPathStep1(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
PartialAccessPath ap
) {
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
not fullBarrier(node) and
not stateBarrier(node, state) and
not clearsContentEx(node, ap.getHead()) and
@@ -4045,14 +4002,9 @@ module Impl<FullStateConfigSig Config> {
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
strengthenType(node, t0, t)
}
pragma[nomagic]
private predicate partialPathTypeStrengthen(
DataFlowType t0, PartialAccessPath ap, DataFlowType t
) {
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), t)
else any()
}
/**
@@ -4231,8 +4183,7 @@ module Impl<FullStateConfigSig Config> {
}
}
pragma[nomagic]
private predicate partialPathStep0(
private predicate partialPathStep(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
@@ -4358,11 +4309,6 @@ module Impl<FullStateConfigSig Config> {
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
) {
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
or
exists(DataFlowType t0 |
partialPathTypeStrengthen(t0, ap2, t2) and
apConsFwd(t1, ap1, c, t0, ap2)
)
}
pragma[nomagic]

View File

@@ -210,8 +210,8 @@ class IndirectOperand extends Node {
this.(RawIndirectOperand).getOperand() = operand and
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
or
nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex),
indirectionIndex - 1)
this.(OperandNode).getOperand() =
Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex)
}
/** Gets the underlying operand. */
@@ -250,8 +250,8 @@ class IndirectInstruction extends Node {
this.(RawIndirectInstruction).getInstruction() = instr and
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
or
nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex),
indirectionIndex - 1)
this.(InstructionNode).getInstruction() =
Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex)
}
/** Gets the underlying instruction. */
@@ -753,8 +753,6 @@ predicate clearsContent(Node n, Content c) {
*/
predicate expectsContent(Node n, ContentSet c) { none() }
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(Node n) {
suppressUnusedNode(n) and

View File

@@ -1640,15 +1640,8 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
localFlow(instructionNode(e1), instructionNode(e2))
}
/**
* INTERNAL: Do not use.
*
* Ideally this module would be private, but the `asExprInternal` predicate is
* needed in `DefaultTaintTrackingImpl`. Once `DefaultTaintTrackingImpl` is gone
* we can make this module private.
*/
cached
module ExprFlowCached {
private module ExprFlowCached {
/**
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
* `e` is the result of loading from the `PointerArithmeticInstruction`.
@@ -1699,8 +1692,7 @@ module ExprFlowCached {
* `x[i]` steps to the expression `x[i - 1]` without traversing the
* entire chain.
*/
cached
Expr asExprInternal(Node n) {
private Expr asExpr(Node n) {
isIndirectBaseOfArrayAccess(n, result)
or
not isIndirectBaseOfArrayAccess(n, _) and
@@ -1712,7 +1704,7 @@ module ExprFlowCached {
* dataflow step.
*/
private predicate localStepFromNonExpr(Node n1, Node n2) {
not exists(asExprInternal(n1)) and
not exists(asExpr(n1)) and
localFlowStep(n1, n2)
}
@@ -1723,7 +1715,7 @@ module ExprFlowCached {
pragma[nomagic]
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
localStepFromNonExpr*(n1, n2) and
e2 = asExprInternal(n2)
e2 = asExpr(n2)
}
/**
@@ -1734,7 +1726,7 @@ module ExprFlowCached {
exists(Node mid |
localFlowStep(n1, mid) and
localStepsToExpr(mid, n2, e2) and
e1 = asExprInternal(n1)
e1 = asExpr(n1)
)
}

View File

@@ -60,7 +60,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
}
private DataFlow::Node getNodeForExpr(Expr node) {
node = DataFlow::ExprFlowCached::asExprInternal(result)
result = DataFlow::exprNode(node)
or
// Some of the sources in `isUserInput` are intended to match the value of
// an expression, while others (those modeled below) are intended to match
@@ -221,7 +221,7 @@ private module Cached {
predicate nodeIsBarrierIn(DataFlow::Node node) {
// don't use dataflow into taint sources, as this leads to duplicate results.
exists(Expr source | isUserInput(source, _) |
source = DataFlow::ExprFlowCached::asExprInternal(node)
node = DataFlow::exprNode(source)
or
// This case goes together with the similar (but not identical) rule in
// `getNodeForSource`.

View File

@@ -1,38 +0,0 @@
/**
* Print the dataflow local store steps in IR dumps.
*/
private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import PrintIRUtilities
/** A property provider for local IR dataflow store steps. */
class FieldFlowPropertyProvider extends IRPropertyProvider {
override string getOperandProperty(Operand operand, string key) {
exists(PostFieldUpdateNode pfun, Content content |
key = "store " + content.toString() and
operand = pfun.getPreUpdateNode().(IndirectOperand).getOperand() and
result =
strictconcat(string element, Node node |
storeStep(node, content, pfun) and
element = nodeId(node, _, _)
|
element, ", "
)
)
or
exists(Node node2, Content content |
key = "read " + content.toString() and
operand = node2.(IndirectOperand).getOperand() and
result =
strictconcat(string element, Node node1 |
readStep(node1, content, node2) and
element = nodeId(node1, _, _)
|
element, ", "
)
)
}
}

View File

@@ -1,44 +1,119 @@
private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import SsaInternals as Ssa
private import PrintIRUtilities
/**
* Gets the local dataflow from other nodes in the same function to this node.
*/
private string getFromFlow(Node node2, int order1, int order2) {
exists(Node node1 |
simpleLocalFlowStep(node1, node2) and
result = nodeId(node1, order1, order2)
private string getFromFlow(DataFlow::Node useNode, int order1, int order2) {
exists(DataFlow::Node defNode, string prefix |
(
simpleLocalFlowStep(defNode, useNode) and prefix = ""
or
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
prefix = "+"
) and
if defNode.asInstruction() = useNode.asOperand().getAnyDef()
then
// Shorthand for flow from the def of this operand.
result = prefix + "def" and
order1 = -1 and
order2 = 0
else
if defNode.asOperand().getUse() = useNode.asInstruction()
then
// Shorthand for flow from an operand of this instruction
result = prefix + defNode.asOperand().getDumpId() and
order1 = -1 and
order2 = defNode.asOperand().getDumpSortOrder()
else result = prefix + nodeId(defNode, order1, order2)
)
}
/**
* Gets the local dataflow from this node to other nodes in the same function.
*/
private string getToFlow(Node node1, int order1, int order2) {
exists(Node node2 |
simpleLocalFlowStep(node1, node2) and
result = nodeId(node2, order1, order2)
private string getToFlow(DataFlow::Node defNode, int order1, int order2) {
exists(DataFlow::Node useNode, string prefix |
(
simpleLocalFlowStep(defNode, useNode) and prefix = ""
or
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
prefix = "+"
) and
if useNode.asInstruction() = defNode.asOperand().getUse()
then
// Shorthand for flow to this operand's instruction.
result = prefix + "result" and
order1 = -1 and
order2 = 0
else result = prefix + nodeId(useNode, order1, order2)
)
}
/**
* Gets the properties of the dataflow node `node`.
*/
private string getNodeProperty(Node node, string key) {
private string getNodeProperty(DataFlow::Node node, string key) {
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
// out of this node is printed as `@->dest`.
key = "flow" and
result =
strictconcat(string flow, boolean to, int order1, int order2 |
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
flow = getFromFlow(node, order1, order2) + "->@" and to = false
or
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
flow = "@->" + getToFlow(node, order1, order2) and to = true
|
flow, ", " order by to, order1, order2, flow
)
or
// Is this node a dataflow sink?
key = "sink" and
any(DataFlow::Configuration cfg).isSink(node) and
result = "true"
or
// Is this node a dataflow source?
key = "source" and
any(DataFlow::Configuration cfg).isSource(node) and
result = "true"
or
// Is this node a dataflow barrier, and if so, what kind?
key = "barrier" and
result =
strictconcat(string kind |
any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full"
or
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
or
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
|
kind, ", "
)
// or
// // Is there partial flow from a source to this node?
// // This property will only be emitted if partial flow is enabled by overriding
// // `DataFlow::Configuration::explorationLimit()`.
// key = "pflow" and
// result =
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
// int order1, int order2 |
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
// destNode.getNode() = node and
// // Only print flow from a source in the same function.
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
// |
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
// order by
// order1, order2, dist desc
// )
}
/**
@@ -46,21 +121,16 @@ private string getNodeProperty(Node node, string key) {
*/
class LocalFlowPropertyProvider extends IRPropertyProvider {
override string getOperandProperty(Operand operand, string key) {
exists(Node node |
operand = [node.asOperand(), node.(RawIndirectOperand).getOperand()] and
exists(DataFlow::Node node |
operand = node.asOperand() and
result = getNodeProperty(node, key)
)
}
override string getInstructionProperty(Instruction instruction, string key) {
exists(Node node |
instruction = [node.asInstruction(), node.(RawIndirectInstruction).getInstruction()]
|
exists(DataFlow::Node node |
instruction = node.asInstruction() and
result = getNodeProperty(node, key)
)
}
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

@@ -0,0 +1,33 @@
/**
* Print the dataflow local store steps in IR dumps.
*/
private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import PrintIRUtilities
/**
* Property provider for local IR dataflow store steps.
*/
class LocalFlowPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instruction, string key) {
exists(DataFlow::Node objectNode, Content content |
key = "content[" + content.toString() + "]" and
instruction = objectNode.asInstruction() and
result =
strictconcat(string element, DataFlow::Node fieldNode |
storeStep(fieldNode, content, objectNode) and
element = nodeId(fieldNode, _, _)
|
element, ", "
)
)
}
}

View File

@@ -3,59 +3,37 @@
*/
private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private string stars(int k) {
k =
[0 .. max([
any(RawIndirectInstruction n).getIndirectionIndex(),
any(RawIndirectOperand n).getIndirectionIndex()
]
)] and
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
string starsForNode(Node node) {
result = stars(node.(IndirectInstruction).getIndirectionIndex())
or
result = stars(node.(IndirectOperand).getIndirectionIndex())
or
not node instanceof IndirectInstruction and
not node instanceof IndirectOperand and
result = ""
}
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
stars = starsForNode(n)
}
private Operand getOperand(Node n, string stars) {
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
stars = starsForNode(n)
}
private import semmle.code.cpp.ir.dataflow.DataFlow
/**
* Gets a short ID for an IR dataflow node.
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
* instruction and a dot (e.g. `m128.left`).
* - For `Variable`s, this is the qualified name of the variable.
*/
string nodeId(Node node, int order1, int order2) {
exists(Instruction instruction, string stars | instruction = getInstruction(node, stars) |
result = stars + instruction.getResultId() and
string nodeId(DataFlow::Node node, int order1, int order2) {
exists(Instruction instruction | instruction = node.asInstruction() |
result = instruction.getResultId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
exists(Operand operand, Instruction instruction, string stars |
operand = getOperand(node, stars) and
exists(Operand operand, Instruction instruction |
operand = node.asOperand() and
instruction = operand.getUse()
|
result = stars + instruction.getResultId() + "." + operand.getDumpId() and
result = instruction.getResultId() + "." + operand.getDumpId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
result = "var(" + node.asVariable().getQualifiedName() + ")" and
order1 = 1000000 and
order2 = 0
}

View File

@@ -364,25 +364,7 @@ abstract private class OperandBasedUse extends UseImpl {
OperandBasedUse() { any() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
// predicate's implementation.
exists(BaseSourceVariableInstruction base | base = this.getBase() |
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
then
exists(Operand op, int indirectionIndex, int indirection |
indirectionIndex = this.getIndirectionIndex() and
indirection = this.getIndirection() and
op =
min(Operand cand, int i |
isUse(_, cand, base, indirection, indirectionIndex) and
block.getInstruction(i) = cand.getUse()
|
cand order by i
) and
block.getInstruction(index) = op.getUse()
)
else operand.getUse() = block.getInstruction(index)
)
operand.getUse() = block.getInstruction(index)
}
final Operand getOperand() { result = operand }
@@ -675,16 +657,24 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
*/
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
exists(DefOrUse defOrUse, Node adjusted |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
nodeToDefOrUse(adjusted, defOrUse, _) and
private predicate adjustForPointerArith(
DefOrUse defOrUse, Node nodeFrom, UseOrPhi use, boolean uncertain
) {
nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and
exists(Node adjusted |
indirectConversionFlowStep*(adjusted, nodeFrom) and
nodeToDefOrUse(adjusted, defOrUse, uncertain) and
adjacentDefRead(defOrUse, use)
)
}
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
// `nodeFrom = any(PostUpdateNode pun).getPreUpdateNode()` is implied by adjustedForPointerArith.
exists(UseOrPhi use |
adjustForPointerArith(defOrUse, nodeFrom, use, uncertain) and
useToNode(use, nodeTo)
or
not nodeFrom = any(PostUpdateNode pun).getPreUpdateNode() and
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
adjacentDefRead(defOrUse, use) and
useToNode(use, nodeTo) and
@@ -729,19 +719,14 @@ predicate ssaFlow(Node nodeFrom, Node nodeTo) {
)
}
private predicate isArgumentOfCallable(DataFlowCall call, ArgumentNode arg) {
arg.argumentOf(call, _)
}
/** Holds if there is def-use or use-use flow from `pun` to `nodeTo`. */
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
exists(UseOrPhi use, Node preUpdate |
adjustForPointerArith(pun, use) and
useToNode(use, nodeTo) and
exists(Node preUpdate, Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
preUpdate = pun.getPreUpdateNode() and
not exists(DataFlowCall call |
isArgumentOfCallable(call, preUpdate) and isArgumentOfCallable(call, nodeTo)
)
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain)
|
if uncertain = true
then preUpdate = [nFrom, getAPriorDefinition(defOrUse)]
else preUpdate = nFrom
)
}

View File

@@ -144,20 +144,6 @@ class AllocationInstruction extends CallInstruction {
AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction }
}
private predicate isIndirectionType(Type t) { t instanceof Indirection }
private predicate hasUnspecifiedBaseType(Indirection t, Type base) {
base = t.getBaseType().getUnspecifiedType()
}
/**
* Holds if `t2` is the same type as `t1`, but after stripping away `result` number
* of indirections.
* Furthermore, specifies in `t2` been deeply stripped and typedefs has been resolved.
*/
private int getNumberOfIndirectionsImpl(Type t1, Type t2) =
shortestDistances(isIndirectionType/1, hasUnspecifiedBaseType/2)(t1, t2, result)
/**
* An abstract class for handling indirections.
*
@@ -176,10 +162,7 @@ abstract class Indirection extends Type {
* For example, the number of indirections of a variable `p` of type
* `int**` is `3` (i.e., `p`, `*p` and `**p`).
*/
final int getNumberOfIndirections() {
result =
getNumberOfIndirectionsImpl(this.getType(), any(Type end | not end instanceof Indirection))
}
abstract int getNumberOfIndirections();
/**
* Holds if `deref` is an instruction that behaves as a `LoadInstruction`
@@ -217,11 +200,19 @@ private class PointerOrArrayOrReferenceTypeIndirection extends Indirection insta
PointerOrArrayOrReferenceTypeIndirection() {
baseType = PointerOrArrayOrReferenceType.super.getBaseType()
}
override int getNumberOfIndirections() {
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
}
}
private class PointerWrapperTypeIndirection extends Indirection instanceof PointerWrapper {
PointerWrapperTypeIndirection() { baseType = PointerWrapper.super.getBaseType() }
override int getNumberOfIndirections() {
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
}
override predicate isAdditionalDereference(Instruction deref, Operand address) {
exists(CallInstruction call |
operandForFullyConvertedCall(getAUse(deref), call) and
@@ -242,6 +233,10 @@ private module IteratorIndirections {
baseType = super.getValueType()
}
override int getNumberOfIndirections() {
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
}
override predicate isAdditionalDereference(Instruction deref, Operand address) {
exists(CallInstruction call |
operandForFullyConvertedCall(getAUse(deref), call) and

View File

@@ -122,46 +122,7 @@ abstract private class OperandBasedUse extends UseImpl {
override string toString() { result = operand.toString() }
final override predicate hasIndexInBlock(IRBlock block, int index) {
// Ideally, this would just be implemented as:
// ```
// operand.getUse() = block.getInstruction(index)
// ```
// but because the IR generated for a snippet such as
// ```
// int x = *p++;
// ```
// looks like
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(glval<int *>) = VariableAddress[p] :
// r3(int *) = Load[p] : &:r2, m1
// r4(int) = Constant[1] :
// r5(int *) = PointerAdd[4] : r3, r4
// m3(int *) = Store[p] : &:r2, r5
// r6(int *) = CopyValue : r3
// r7(int) = Load[?] : &:r6, ~m2
// m2(int) = Store[x] : &:r1, r7
// ```
// we need to ensure that the `r3` operand of the `CopyValue` instruction isn't seen as a fresh use
// of `p` that happens after the increment. So if the base instruction of this use comes from a
// post-fix crement operation we set the index of the SSA use that wraps the `r3` operand at the
// `CopyValue` instruction to be the same index as the `r3` operand at the `PointerAdd` instruction.
// This ensures that the SSA library doesn't create flow from the `PointerAdd` to `r6`.
exists(BaseSourceVariableInstruction base | base = this.getBase() |
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
then
exists(Operand op |
op =
min(Operand cand, int i |
isUse(_, cand, base, _, _) and
block.getInstruction(i) = cand.getUse()
|
cand order by i
) and
block.getInstruction(index) = op.getUse()
)
else operand.getUse() = block.getInstruction(index)
)
operand.getUse() = block.getInstruction(index)
}
final override Cpp::Location getLocation() { result = operand.getLocation() }

View File

@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
* Gets the value of the property named `key` for the specified operand.
*/
string getOperandProperty(Operand operand, string key) { none() }
/**
* Holds if the instruction `instr` should be included when printing
* the IR instructions.
*/
predicate shouldPrintInstruction(Instruction instr) { any() }
/**
* Holds if the operand `operand` should be included when printing the an
* instruction's operand list.
*/
predicate shouldPrintOperand(Operand operand) { any() }
}

View File

@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
*/
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets the location of the source code for this instruction.
*/
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
/** DEPRECATED: Alias for getAstVariable */
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
}
/**

View File

@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
}
private predicate shouldPrintOperand(Operand operand) {
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
}
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
/**
* A node to be emitted in the IR graph.
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
operand = instr.getAnOperand()
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

View File

@@ -577,6 +577,9 @@ private Overlap getVariableMemoryLocationOverlap(
*/
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
/** DEPRECATED: Alias for canReuseSsaForOldResult */
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }

View File

@@ -422,6 +422,12 @@ private module Cached {
)
}
/** DEPRECATED: Alias for getInstructionAst */
cached
deprecated Language::AST getInstructionAST(Instruction instr) {
result = getInstructionAst(instr)
}
cached
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
@@ -987,6 +993,9 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
// We don't support reusing SSA for any location that could create a `Chi` instruction.
}
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
/**
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
* `DebugSsa` module, which is then imported by PrintSSA.
@@ -996,6 +1005,9 @@ module DebugSsa {
import DefUse
}
/** DEPRECATED: Alias for DebugSsa */
deprecated module DebugSSA = DebugSsa;
import CachedForDebugging
cached

View File

@@ -73,6 +73,9 @@ module UnaliasedSsaInstructions {
}
}
/** DEPRECATED: Alias for UnaliasedSsaInstructions */
deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions;
/**
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
* aliased SSA stage.
@@ -104,3 +107,6 @@ module AliasedSsaInstructions {
result = TAliasedSsaUnreachedInstruction(irFunc)
}
}
/** DEPRECATED: Alias for AliasedSsaInstructions */
deprecated module AliasedSSAInstructions = AliasedSsaInstructions;

View File

@@ -74,12 +74,20 @@ private module Shared {
class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand;
/** DEPRECATED: Alias for TNonSsaMemoryOperand */
deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand;
/**
* Returns the non-Phi memory operand with the specified parameters.
*/
TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
result = Internal::TNonSsaMemoryOperand(useInstr, tag)
}
/** DEPRECATED: Alias for nonSsaMemoryOperand */
deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
result = nonSsaMemoryOperand(useInstr, tag)
}
}
/**
@@ -159,6 +167,9 @@ module UnaliasedSsaOperands {
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
}
/** DEPRECATED: Alias for UnaliasedSsaOperands */
deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands;
/**
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
* aliased SSA stage.
@@ -206,3 +217,6 @@ module AliasedSsaOperands {
result = Internal::TAliasedChiOperand(useInstr, tag)
}
}
/** DEPRECATED: Alias for AliasedSsaOperands */
deprecated module AliasedSSAOperands = AliasedSsaOperands;

View File

@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
* Gets the value of the property named `key` for the specified operand.
*/
string getOperandProperty(Operand operand, string key) { none() }
/**
* Holds if the instruction `instr` should be included when printing
* the IR instructions.
*/
predicate shouldPrintInstruction(Instruction instr) { any() }
/**
* Holds if the operand `operand` should be included when printing the an
* instruction's operand list.
*/
predicate shouldPrintOperand(Operand operand) { any() }
}

View File

@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
*/
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets the location of the source code for this instruction.
*/
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
/** DEPRECATED: Alias for getAstVariable */
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
}
/**

View File

@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
}
private predicate shouldPrintOperand(Operand operand) {
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
}
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
/**
* A node to be emitted in the IR graph.
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
operand = instr.getAnOperand()
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

View File

@@ -375,6 +375,11 @@ Locatable getInstructionAst(TStageInstruction instr) {
)
}
/** DEPRECATED: Alias for getInstructionAst */
deprecated Locatable getInstructionAST(TStageInstruction instr) {
result = getInstructionAst(instr)
}
CppType getInstructionResultType(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
or

View File

@@ -76,6 +76,9 @@ abstract class TranslatedExpr extends TranslatedElement {
final override Locatable getAst() { result = expr }
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Declaration getFunction() { result = getEnclosingDeclaration(expr) }
/**

View File

@@ -77,16 +77,4 @@ class IRPropertyProvider extends TIRPropertyProvider {
* Gets the value of the property named `key` for the specified operand.
*/
string getOperandProperty(Operand operand, string key) { none() }
/**
* Holds if the instruction `instr` should be included when printing
* the IR instructions.
*/
predicate shouldPrintInstruction(Instruction instr) { any() }
/**
* Holds if the operand `operand` should be included when printing the an
* instruction's operand list.
*/
predicate shouldPrintOperand(Operand operand) { any() }
}

View File

@@ -210,6 +210,9 @@ class Instruction extends Construction::TStageInstruction {
*/
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
/** DEPRECATED: Alias for getAst */
deprecated Language::AST getAST() { result = this.getAst() }
/**
* Gets the location of the source code for this instruction.
*/
@@ -460,6 +463,9 @@ class VariableInstruction extends Instruction {
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
/** DEPRECATED: Alias for getAstVariable */
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
}
/**

View File

@@ -42,14 +42,6 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
}
private predicate shouldPrintOperand(Operand operand) {
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
}
@@ -92,9 +84,7 @@ private string getOperandPropertyString(Operand operand) {
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
/**
* A node to be emitted in the IR graph.
@@ -262,8 +252,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
operand = instr.getAnOperand()
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

View File

@@ -422,6 +422,12 @@ private module Cached {
)
}
/** DEPRECATED: Alias for getInstructionAst */
cached
deprecated Language::AST getInstructionAST(Instruction instr) {
result = getInstructionAst(instr)
}
cached
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
@@ -987,6 +993,9 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
// We don't support reusing SSA for any location that could create a `Chi` instruction.
}
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
/**
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
* `DebugSsa` module, which is then imported by PrintSSA.
@@ -996,6 +1005,9 @@ module DebugSsa {
import DefUse
}
/** DEPRECATED: Alias for DebugSsa */
deprecated module DebugSSA = DebugSsa;
import CachedForDebugging
cached

View File

@@ -46,6 +46,9 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
not allocationEscapes(var)
}
/** DEPRECATED: Alias for canReuseSsaForVariable */
deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1;
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
@@ -77,6 +80,9 @@ class MemoryLocation extends TMemoryLocation {
predicate canReuseSsaForOldResult(Instruction instr) { none() }
/** DEPRECATED: Alias for canReuseSsaForOldResult */
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
/**
* Represents a set of `MemoryLocation`s that cannot overlap with
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be

View File

@@ -414,7 +414,7 @@ private module HeuristicAllocation {
int sizeArg;
HeuristicAllocationFunctionByName() {
Function.super.getName().matches(["%alloc%", "%Alloc%"]) and
Function.super.getName().matches("%alloc%") and
Function.super.getUnspecifiedType() instanceof PointerType and
sizeArg = unique( | | getAnUnsignedParameter(this))
}

View File

@@ -40,6 +40,9 @@ library class RangeSsa extends SsaHelper {
}
}
/** DEPRECATED: Alias for RangeSsa */
deprecated class RangeSSA = RangeSsa;
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
guardCondition(guard, v, branch) and
guardSuccessor(guard, branch, b)

View File

@@ -729,7 +729,7 @@ module RangeStage<
) {
exists(SemExpr e, D::Delta d1, D::Delta d2 |
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
boundedUpper(e, b, d2) and
boundedUpper(e, b, d1) and
boundedLower(e, b, d2) and
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
)

View File

@@ -16,6 +16,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
}
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi =
/** An untrusted API method `m` where untrusted data is passed at `index`. */
@@ -48,3 +51,6 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
)
}
}
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;

View File

@@ -41,6 +41,9 @@ class ExternalApiDataNode extends DataFlow::Node {
string getFunctionDescription() { result = this.getExternalFunction().toString() }
}
/** DEPRECATED: Alias for ExternalApiDataNode */
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
@@ -55,6 +58,9 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {

View File

@@ -10,6 +10,9 @@ private import semmle.code.cpp.models.interfaces.SideEffect
*/
abstract class SafeExternalApiFunction extends Function { }
/** DEPRECATED: Alias for SafeExternalApiFunction */
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
/** The default set of "safe" external APIs. */
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
DefaultSafeExternalApiFunction() {

View File

@@ -16,6 +16,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
}
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi =
/** An untrusted API method `m` where untrusted data is passed at `index`. */
@@ -48,3 +51,6 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
)
}
}
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;

View File

@@ -41,6 +41,9 @@ class ExternalApiDataNode extends DataFlow::Node {
string getFunctionDescription() { result = this.getExternalFunction().toString() }
}
/** DEPRECATED: Alias for ExternalApiDataNode */
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" }
@@ -50,6 +53,9 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

View File

@@ -10,6 +10,9 @@ private import semmle.code.cpp.models.interfaces.SideEffect
*/
abstract class SafeExternalApiFunction extends Function { }
/** DEPRECATED: Alias for SafeExternalApiFunction */
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
/** The default set of "safe" external APIs. */
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
DefaultSafeExternalApiFunction() {

View File

@@ -1,317 +0,0 @@
/**
* @name Overrunning write
* @description Exceeding the size of a static array during write or access operations
* may result in a buffer overflow.
* @kind path-problem
* @problem.severity error
* @security-severity 9.3
* @precision medium
* @id cpp/overrun-write
* @tags reliability
* security
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import StringSizeFlow::PathGraph1
import codeql.util.Unit
pragma[nomagic]
Instruction getABoundIn(SemBound b, IRFunction func) {
getSemanticExpr(result) = b.getExpr(0) and
result.getEnclosingIRFunction() = func
}
/**
* Holds if `i <= b + delta`.
*/
bindingset[i]
pragma[inline_late]
predicate bounded(Instruction i, Instruction b, int delta) {
exists(SemBound bound, IRFunction func |
semBounded(getSemanticExpr(i), bound, delta, true, _) and
b = getABoundIn(bound, func) and
i.getEnclosingIRFunction() = func
)
}
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
/**
* Holds if `(n, state)` pair represents the source of flow for the size
* expression associated with `alloc`.
*/
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
exists(VariableAccess va, Expr size, int delta |
size = alloc.getSizeExpr() and
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
va = unique( | | getAVariableAccess(size)) and
// Compute `delta` as the constant difference between `x` and `x + 1`.
bounded(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
n.asConvertedExpr() = va.getFullyConverted() and
state = delta
)
}
predicate isSinkPairImpl(
CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, int delta, Expr eBuf
) {
exists(
int bufIndex, int sizeIndex, Instruction sizeInstr, Instruction bufInstr, ArrayFunction func
|
bufInstr = bufSink.asInstruction() and
c.getArgument(bufIndex) = bufInstr and
sizeInstr = sizeSink.asInstruction() and
c.getStaticCallTarget() = func and
pragma[only_bind_into](func)
.hasArrayWithVariableSize(pragma[only_bind_into](bufIndex),
pragma[only_bind_into](sizeIndex)) and
bounded(c.getArgument(sizeIndex), sizeInstr, delta) and
eBuf = bufInstr.getUnconvertedResultExpression()
)
}
module ValidState {
/**
* In the `StringSizeConfig` configuration we use an integer as the flow state for the second
* projection of the dataflow graph. The integer represents an offset that is added to the
* size of the allocation. For example, given:
* ```cpp
* char* p = new char[size + 1];
* size += 1;
* memset(p, 0, size);
* ```
* the initial flow state is `1`. This represents the fact that `size + 1` is a valid bound
* for the size of the allocation pointed to by `p`. After updating the size using `+=`, the
* flow state changes to `0`, which represents the fact that `size + 0` is a valid bound for
* the allocation.
*
* So we need to compute a set of valid integers that represent the offset applied to the
* size. We do this in two steps:
* 1. We first perform the dataflow traversal that the second projection of the product-flow
* library will perform, and visit all the places where the size argument is modified.
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
* where the offset is modified (see `validStateImpl`).
*
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
* has a corresponding `PathNode`.
*/
private module ValidStateConfig implements DataFlow::StateConfigSig {
class FlowState = boolean;
predicate isSource(DataFlow::Node source, FlowState state) {
hasSize(_, source, _) and
state = false
}
predicate isSink(DataFlow::Node sink, FlowState state) {
isSinkPairImpl(_, _, sink, _, _) and
state = [false, true]
}
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
isAdditionalFlowStep2(node1, node2, _) and
state1 = [false, true] and
state2 = state1.booleanNot()
}
predicate includeHiddenNodes() { any() }
}
private import DataFlow::GlobalWithState<ValidStateConfig>
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }
/**
* Holds if `value` is a possible offset for `n`.
*
* To ensure termination, we limit `value` to be in the
* range `[-2, 2]` if the node is part of a loop. Without
* this restriction we wouldn't terminate on an example like:
* ```cpp
* while(unknown()) { size++; }
* ```
*/
private predicate validStateImpl(PathNode n, int value) {
// If the dataflow node depends recursively on itself we restrict the range.
(inLoop(n) implies value = [-2 .. 2]) and
(
// For the dataflow source we have an allocation such as `malloc(size + k)`,
// and the value of the flow-state is then `k`.
hasSize(_, n.getNode(), value)
or
// For a dataflow sink any `value` that is strictly smaller than the delta
// needs to be a valid flow-state. That is, for a snippet like:
// ```
// p = b ? new char[size] : new char[size + 1];
// memset(p, 0, size + 2);
// ```
// the valid flow-states at the `memset` must include the set `{0, 1}` since the
// flow-state at `new char[size]` is `0`, and the flow-state at `new char[size + 1]`
// is `1`.
//
// So we find a valid flow-state at the sink's predecessor, and use the definition
// of our sink predicate to compute the valid flow-states at the sink.
exists(int delta, PathNode n0 |
n0.getASuccessor() = n and
validStateImpl(n0, value) and
isSinkPairImpl(_, _, n.getNode(), delta, _) and
delta > value
)
or
// For a non-source and non-sink node there is two cases to consider.
// 1. A node where we have to update the flow-state, or
// 2. A node that doesn't update the flow-state.
//
// For case 1, we compute the new flow-state by adding the constant operand of the
// `AddInstruction` to the flow-state of any predecessor node.
// For case 2 we simply propagate the valid flow-states from the predecessor node to
// the next one.
exists(PathNode n0, DataFlow::Node node0, DataFlow::Node node, int value0 |
n0.getASuccessor() = n and
validStateImpl(n0, value0) and
node = n.getNode() and
node0 = n0.getNode()
|
exists(int delta |
isAdditionalFlowStep2(node0, node, delta) and
value0 = value + delta
)
or
not isAdditionalFlowStep2(node0, node, _) and
value = value0
)
)
}
predicate validState(DataFlow::Node n, int value) {
validStateImpl(any(PathNode pn | pn.getNode() = n), value)
}
}
import ValidState
/**
* Holds if `node2` is a dataflow node that represents an addition of two operands `op1`
* and `op2` such that:
* 1. `node1` is the dataflow node that represents `op1`, and
* 2. the value of `op2` can be upper bounded by `delta.`
*/
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2, int delta) {
exists(AddInstruction add, Operand op |
add.hasOperands(node1.asOperand(), op) and
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
node2.asInstruction() = add
)
}
module StringSizeConfig implements ProductFlow::StateConfigSig {
class FlowState1 = Unit;
class FlowState2 = int;
predicate isSourcePair(
DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2
) {
// In the case of an allocation like
// ```cpp
// malloc(size + 1);
// ```
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
// to the size of the allocation. This state is then checked in `isSinkPair`.
exists(state1) and
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
}
predicate isSinkPair(
DataFlow::Node bufSink, FlowState1 state1, DataFlow::Node sizeSink, FlowState2 state2
) {
exists(state1) and
validState(sizeSink, state2) and
exists(int delta |
isSinkPairImpl(_, bufSink, sizeSink, delta, _) and
delta > state2
)
}
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
predicate isBarrierOut2(DataFlow::Node node) {
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
}
predicate isAdditionalFlowStep1(
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
) {
none()
}
predicate isAdditionalFlowStep2(
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
) {
validState(node2, state2) and
exists(int delta |
isAdditionalFlowStep2(node1, node2, delta) and
state1 = state2 + delta
)
}
}
module StringSizeFlow = ProductFlow::GlobalWithState<StringSizeConfig>;
/**
* Gets the maximum number of elements accessed past the buffer `buffer` by the formatting
* function call `c` when an overflow is detected starting at the `(source1, source2)` pair
* and ending at the `(sink1, sink2)` pair.
*
* Implementation note: Since the number of elements accessed past the buffer is computed
* using a `FlowState` on the second component of the `DataFlow::PathNode` pair we project
* the columns down to the underlying `DataFlow::Node` in order to deduplicate the flow
* state.
*/
int getOverflow(
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2,
CallInstruction c, Expr buffer
) {
result > 0 and
exists(
StringSizeFlow::PathNode1 pathSource1, StringSizeFlow::PathNode2 pathSource2,
StringSizeFlow::PathNode1 pathSink1, StringSizeFlow::PathNode2 pathSink2
|
StringSizeFlow::flowPath(pathSource1, pathSource2, pathSink1, pathSink2) and
source1 = pathSource1.getNode() and
source2 = pathSource2.getNode() and
sink1 = pathSink1.getNode() and
sink2 = pathSink2.getNode() and
isSinkPairImpl(c, sink1, sink2, result + pathSink2.getState(), buffer)
)
}
from
StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2,
StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, CallInstruction c,
Expr buffer, string element
where
StringSizeFlow::flowPath(source1, source2, sink1, sink2) and
overflow =
max(getOverflow(source1.getNode(), source2.getNode(), sink1.getNode(), sink2.getNode(), c,
buffer)
) and
if overflow = 1 then element = " element." else element = " elements."
select c.getUnconvertedResultExpression(), source1, sink1,
"This write may overflow $@ by " + overflow + element, buffer, buffer.toString()

View File

@@ -1,4 +0,0 @@
---
category: newQuery
---
* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers.

View File

@@ -10,7 +10,7 @@
*/
import cpp
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound

View File

@@ -0,0 +1,177 @@
/**
* @name Overrunning write
* @description Exceeding the size of a static array during write or access operations
* may result in a buffer overflow.
* @kind path-problem
* @problem.severity error
* @id cpp/overrun-write
* @tags reliability
* security
* experimental
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import StringSizeFlow::PathGraph1
import codeql.util.Unit
pragma[nomagic]
Instruction getABoundIn(SemBound b, IRFunction func) {
getSemanticExpr(result) = b.getExpr(0) and
result.getEnclosingIRFunction() = func
}
/**
* Holds if `i <= b + delta`.
*/
bindingset[i]
pragma[inline_late]
predicate bounded(Instruction i, Instruction b, int delta) {
exists(SemBound bound, IRFunction func |
semBounded(getSemanticExpr(i), bound, delta, true, _) and
b = getABoundIn(bound, func) and
i.getEnclosingIRFunction() = func
)
}
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
/**
* Holds if `(n, state)` pair represents the source of flow for the size
* expression associated with `alloc`.
*/
predicate hasSize(AllocationExpr alloc, DataFlow::Node n, int state) {
exists(VariableAccess va, Expr size, int delta |
size = alloc.getSizeExpr() and
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
va = unique( | | getAVariableAccess(size)) and
// Compute `delta` as the constant difference between `x` and `x + 1`.
bounded(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
n.asConvertedExpr() = va.getFullyConverted() and
state = delta
)
}
predicate isSinkPairImpl(
CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, int delta, Expr eBuf
) {
exists(
int bufIndex, int sizeIndex, Instruction sizeInstr, Instruction bufInstr, ArrayFunction func
|
bufInstr = bufSink.asInstruction() and
c.getArgument(bufIndex) = bufInstr and
sizeInstr = sizeSink.asInstruction() and
c.getStaticCallTarget() = func and
pragma[only_bind_into](func)
.hasArrayWithVariableSize(pragma[only_bind_into](bufIndex),
pragma[only_bind_into](sizeIndex)) and
bounded(c.getArgument(sizeIndex), sizeInstr, delta) and
eBuf = bufInstr.getUnconvertedResultExpression()
)
}
module StringSizeConfig implements ProductFlow::StateConfigSig {
class FlowState1 = Unit;
class FlowState2 = int;
predicate isSourcePair(
DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2
) {
// In the case of an allocation like
// ```cpp
// malloc(size + 1);
// ```
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
// to the size of the allocation. This state is then checked in `isSinkPair`.
exists(state1) and
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
}
predicate isSinkPair(
DataFlow::Node bufSink, FlowState1 state1, DataFlow::Node sizeSink, FlowState2 state2
) {
exists(state1) and
state2 = [-32 .. 32] and // An arbitrary bound because we need to bound `state2`
exists(int delta |
isSinkPairImpl(_, bufSink, sizeSink, delta, _) and
delta > state2
)
}
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
predicate isAdditionalFlowStep1(
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
) {
none()
}
predicate isAdditionalFlowStep2(
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
) {
exists(AddInstruction add, Operand op, int delta, int s1, int s2 |
s1 = [-32 .. 32] and // An arbitrary bound because we need to bound `state`
state1 = s1 and
state2 = s2 and
add.hasOperands(node1.asOperand(), op) and
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
node2.asInstruction() = add and
s1 = s2 + delta
)
}
}
module StringSizeFlow = ProductFlow::GlobalWithState<StringSizeConfig>;
/**
* Gets the maximum number of elements accessed past the buffer `buffer` by the formatting
* function call `c` when an overflow is detected starting at the `(source1, source2)` pair
* and ending at the `(sink1, sink2)` pair.
*
* Implementation note: Since the number of elements accessed past the buffer is computed
* using a `FlowState` on the second component of the `DataFlow::PathNode` pair we project
* the columns down to the underlying `DataFlow::Node` in order to deduplicate the flow
* state.
*/
int getOverflow(
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2,
CallInstruction c, Expr buffer
) {
result > 0 and
exists(
StringSizeFlow::PathNode1 pathSource1, StringSizeFlow::PathNode2 pathSource2,
StringSizeFlow::PathNode1 pathSink1, StringSizeFlow::PathNode2 pathSink2
|
StringSizeFlow::flowPath(pathSource1, pathSource2, pathSink1, pathSink2) and
source1 = pathSource1.getNode() and
source2 = pathSource2.getNode() and
sink1 = pathSink1.getNode() and
sink2 = pathSink2.getNode() and
isSinkPairImpl(c, sink1, sink2, result + pathSink2.getState(), buffer)
)
}
from
StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2,
StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, CallInstruction c,
Expr buffer, string element
where
StringSizeFlow::flowPath(source1, source2, sink1, sink2) and
overflow =
max(getOverflow(source1.getNode(), source2.getNode(), sink1.getNode(), sink2.getNode(), c,
buffer)
) and
if overflow = 1 then element = " element." else element = " elements."
select c.getUnconvertedResultExpression(), source1, sink1,
"This write may overflow $@ by " + overflow + element, buffer, buffer.toString()

View File

@@ -1,33 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Detects <code>if (a+b>c) a=c-b</code>, which incorrectly implements
<code>a = min(a,c-b)</code> if <code>a+b</code> overflows.
</p>
<p>
Also detects variants such as <code>if (b+a>c) a=c-b</code> (swapped
terms in addition), <code>if (a+b>c) { a=c-b }</code> (assignment
inside block), <code>c&lt;a+b</code> (swapped operands), and
<code>&gt;=</code>, <code>&lt;</code>, <code>&lt;=</code> instead of
<code>&gt;</code> (all operators).
</p>
<p>
This integer overflow is the root cause of the buffer overflow in
the SHA-3 reference implementation (CVE-2022-37454).
</p>
</overview>
<recommendation>
<p>
Replace by <code>if (a>c-b) a=c-b</code>. This avoids the overflow
and makes it easy to see that <code>a = min(a,c-b)</code>.
</p>
</recommendation>
<references>
<li>CVE-2022-37454: <a href="https://nvd.nist.gov/vuln/detail/CVE-2022-37454">The Keccak XKCP SHA-3 reference implementation before fdc6fef has an integer overflow and resultant buffer overflow that allows attackers to execute arbitrary code or eliminate expected cryptographic properties. This occurs in the sponge function interface.</a></li>
<li>GitHub Advisory Database: <a href="https://github.com/advisories/GHSA-6w4m-2xhg-2658">CVE-2022-37454: Buffer overflow in sponge queue functions</a></li>
</references>
</qhelp>

View File

@@ -1,42 +0,0 @@
/**
* @name Integer addition may overflow inside if statement
* @description Writing 'if (a+b>c) a=c-b' incorrectly implements
* 'a = min(a,c-b)' if 'a+b' overflows. This integer
* overflow is the root cause of the buffer overflow
* in the SHA-3 reference implementation (CVE-2022-37454).
* @kind problem
* @problem.severity warning
* @id cpp/if-statement-addition-overflow
* @tags: experimental
* correctness
* security
* external/cwe/cwe-190
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.valuenumbering.HashCons
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.controlflow.Guards
from
GuardCondition guard, Expr expr, ExprStmt exprstmt, BasicBlock block, AssignExpr assignexpr,
AddExpr addexpr, SubExpr subexpr
where
(guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) and
addexpr.getUnspecifiedType() instanceof IntegralType and
exprMightOverflowPositively(addexpr) and
block.getANode() = exprstmt and
exprstmt.getExpr() = assignexpr and
assignexpr.getRValue() = subexpr and
(
hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and
globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())
or
hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and
globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand())
) and
globalValueNumber(expr) = globalValueNumber(subexpr.getLeftOperand())
select guard,
"\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.",
addexpr, "addition"

View File

@@ -14,7 +14,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysi
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.DataFlow
import FieldAddressToDerefFlow::PathGraph
import PointerArithmeticToDerefFlow::PathGraph
pragma[nomagic]
Instruction getABoundIn(SemBound b, IRFunction func) {
@@ -42,6 +42,21 @@ bindingset[b]
pragma[inline_late]
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
module FieldAddressToPointerArithmeticConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isFieldAddressSource(_, source) }
predicate isSink(DataFlow::Node sink) {
exists(PointerAddInstruction pai | pai.getLeft() = sink.asInstruction())
}
}
module FieldAddressToPointerArithmeticFlow =
DataFlow::Global<FieldAddressToPointerArithmeticConfig>;
predicate isFieldAddressSource(Field f, DataFlow::Node source) {
source.asInstruction().(FieldAddressInstruction).getField() = f
}
bindingset[delta]
predicate isInvalidPointerDerefSinkImpl(
int delta, Instruction i, AddressOperand addr, string operation
@@ -78,96 +93,38 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
)
}
pragma[nomagic]
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) {
arr.getBaseType().getSize() = baseTypeSize and
arr.getArraySize() = arraySize
}
predicate pointerArithOverflow0(
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
) {
not f.getNamespace() instanceof StdNamespace and
arrayTypeHasSizes(f.getUnspecifiedType(), pai.getElementSize(), size) and
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
delta = bound - size and
delta >= 0 and
size != 0 and
size != 1
predicate isConstantSizeOverflowSource(Field f, PointerAddInstruction pai, int delta) {
exists(int size, int bound, DataFlow::Node source, DataFlow::InstructionNode sink |
FieldAddressToPointerArithmeticFlow::flow(source, sink) and
isFieldAddressSource(f, source) and
pai.getLeft() = sink.asInstruction() and
f.getUnspecifiedType().(ArrayType).getArraySize() = size and
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
delta = bound - size and
delta >= 0 and
size != 0 and
size != 1
)
}
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
pointerArithOverflow0(source.asInstruction(), _, _, _, _)
isConstantSizeOverflowSource(_, source.asInstruction(), _)
}
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
pragma[inline]
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
}
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
predicate pointerArithOverflow(
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
) {
pointerArithOverflow0(pai, f, size, bound, delta) and
PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _)
}
module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
newtype FlowState =
additional TArray(Field f) { pointerArithOverflow(_, f, _, _, _) } or
additional TOverflowArithmetic(PointerArithmeticInstruction pai) {
pointerArithOverflow(pai, _, _, _, _)
}
predicate isSource(DataFlow::Node source, FlowState state) {
exists(Field f |
source.asInstruction().(FieldAddressInstruction).getField() = f and
state = TArray(f)
)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(DataFlow::Node pai |
state = TOverflowArithmetic(pai.asInstruction()) and
PointerArithmeticToDerefFlow::flow(pai, sink)
)
}
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
predicate isBarrierIn(DataFlow::Node node) { isSource(node, _) }
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _) }
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
exists(PointerArithmeticInstruction pai, Field f |
state1 = TArray(f) and
state2 = TOverflowArithmetic(pai) and
pai.getLeft() = node1.asInstruction() and
node2.asInstruction() = pai and
pointerArithOverflow(pai, f, _, _, _)
)
}
}
module FieldAddressToDerefFlow = DataFlow::GlobalWithState<FieldAddressToDerefConfig>;
from
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
Field f, PointerArithmeticToDerefFlow::PathNode source,
PointerArithmeticToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
where
FieldAddressToDerefFlow::flowPath(source, sink) and
PointerArithmeticToDerefFlow::flowPath(source, sink) and
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
source.getState() = FieldAddressToDerefConfig::TArray(f) and
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
pointerArithOverflow(pai, f, _, _, delta)
select pai, source, sink,
isConstantSizeOverflowSource(f, source.getNode().asInstruction(), delta)
select source, source, sink,
"This pointer arithmetic may have an off-by-" + (delta + 1) +
" error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation

View File

@@ -16,7 +16,7 @@
*/
import cpp
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
@@ -48,23 +48,44 @@ bindingset[b]
pragma[inline_late]
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
/**
* Holds if the combination of `n` and `state` represents an appropriate
* source for the expression `e` suitable for use-use flow.
*/
private predicate hasSizeImpl(Expr e, DataFlow::Node n, int state) {
// The simple case: If the size is a variable access with no qualifier we can just use the
// dataflow node for that expression and no state.
exists(VariableAccess va |
va = e and
not va instanceof FieldAccess and
n.asConvertedExpr() = va.getFullyConverted() and
state = 0
)
or
// If the size is a choice between two expressions we allow both to be nodes representing the size.
exists(ConditionalExpr cond | cond = e | hasSizeImpl([cond.getThen(), cond.getElse()], n, state))
or
// If the size is an expression plus a constant, we pick the dataflow node of the expression and
// remember the constant in the state.
exists(Expr const, Expr nonconst |
e.(AddExpr).hasOperands(const, nonconst) and
state = const.getValue().toInt() and
hasSizeImpl(nonconst, n, _)
)
or
exists(Expr const, Expr nonconst |
e.(SubExpr).hasOperands(const, nonconst) and
state = -const.getValue().toInt() and
hasSizeImpl(nonconst, n, _)
)
}
/**
* Holds if `(n, state)` pair represents the source of flow for the size
* expression associated with `alloc`.
*/
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
exists(VariableAccess va, Expr size, int delta |
size = alloc.getSizeExpr() and
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
va = unique( | | getAVariableAccess(size)) and
// Compute `delta` as the constant difference between `x` and `x + 1`.
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
n.asConvertedExpr() = va.getFullyConverted() and
state = delta
)
hasSizeImpl(alloc.getSizeExpr(), n, state)
}
/**
@@ -81,8 +102,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
* ```
*
* We do this by splitting the task up into two configurations:
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
*
* Finally, the range-analysis library will find a load from (or store to) an address that
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
@@ -180,33 +201,14 @@ predicate isSinkImpl(
}
/**
* Yields any instruction that is control-flow reachable from `instr`.
*/
bindingset[instr, result]
pragma[inline_late]
Instruction getASuccessor(Instruction instr) {
exists(IRBlock b, int instrIndex, int resultIndex |
result.getBlock() = b and
instr.getBlock() = b and
b.getInstruction(instrIndex) = instr and
b.getInstruction(resultIndex) = result
|
resultIndex >= instrIndex
)
or
instr.getBlock().getASuccessor+() = result.getBlock()
}
/**
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
* reads from an address that non-strictly upper-bounds `sink`.
*/
pragma[inline]
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
exists(AddressOperand addr, Instruction s |
s = sink.asInstruction() and
bounded1(addr.getDef(), s, delta) and
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
exists(AddressOperand addr, int delta |
bounded1(addr.getDef(), sink.asInstruction(), delta) and
delta >= 0 and
i.getAnOperand() = addr
|
@@ -220,13 +222,13 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
/**
* A configuration to track flow from a pointer-arithmetic operation found
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
*/
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
pragma[inline]
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
predicate isBarrier(DataFlow::Node node) {
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
@@ -256,18 +258,17 @@ predicate invalidPointerToDerefSource(
}
newtype TMergedPathNode =
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
// The path nodes computed by `InvalidPointerToDerefConfig`
// The path nodes computed by `InvalidPointerToDerefConf`
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
// pointer, but we want to raise an alert at the dereference.
TPathNodeSink(Instruction i) {
exists(DataFlow::Node n |
InvalidPointerToDerefFlow::flowTo(n) and
isInvalidPointerDerefSink(n, i, _, _) and
i = getASuccessor(n.asInstruction())
isInvalidPointerDerefSink(n, i, _)
)
}
@@ -341,30 +342,12 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
or
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
or
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _, _)
}
query predicate nodes(MergedPathNode n, string key, string val) {
AllocToInvalidPointerFlow::PathGraph1::nodes(n.asPathNode1(), key, val)
or
InvalidPointerToDerefFlow::PathGraph::nodes(n.asPathNode3(), key, val)
or
key = "semmle.label" and val = n.asSinkNode().toString()
}
query predicate subpaths(
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
) {
AllocToInvalidPointerFlow::PathGraph1::subpaths(arg.asPathNode1(), par.asPathNode1(),
ret.asPathNode1(), out.asPathNode1())
or
InvalidPointerToDerefFlow::PathGraph::subpaths(arg.asPathNode3(), par.asPathNode3(),
ret.asPathNode3(), out.asPathNode3())
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
}
/**
* Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
* of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
*/
predicate joinOn1(
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
@@ -375,38 +358,34 @@ predicate joinOn1(
}
/**
* Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
* that dereferences `p1`. The string `operation` describes whether the `i` is
* a `StoreInstruction` or `LoadInstruction`.
*/
pragma[inline]
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation, int delta) {
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
isInvalidPointerDerefSink(p1.getNode(), i, operation)
}
predicate hasFlowPath(
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
PointerArithmeticInstruction pai, string operation, int delta
PointerArithmeticInstruction pai, string operation
) {
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
joinOn1(pai, sink1, source3) and
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
joinOn2(sink3, sink.asSinkNode(), operation, delta)
joinOn2(sink3, sink.asSinkNode(), operation)
)
}
from
MergedPathNode source, MergedPathNode sink, int k, string kstr, PointerArithmeticInstruction pai,
string operation, Expr offset, DataFlow::Node n
MergedPathNode source, MergedPathNode sink, int k, string kstr,
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
Expr offset, DataFlow::Node n
where
k =
min(int k2, int k3, InvalidPointerToDerefFlow::PathNode source3 |
hasFlowPath(source, sink, source3, pai, operation, k3) and
invalidPointerToDerefSource(pai, source3.getNode(), k2)
|
k2 + k3
) and
hasFlowPath(source, sink, source3, pai, operation) and
invalidPointerToDerefSource(pai, source3.getNode(), k) and
offset = pai.getRight().getUnconvertedResultExpression() and
n = source.asPathNode1().getNode() and
if k = 0 then kstr = "" else kstr = " + " + k

373
cpp/ql/src/external/CodeDuplication.qll vendored Normal file
View File

@@ -0,0 +1,373 @@
/** Provides classes for detecting duplicate or similar code. */
import cpp
deprecated private newtype TDuplicationOrSimilarity = MKDuplicationOrSimilarity()
/**
* DEPRECATED: This class is no longer used.
*
* A token block used for detection of duplicate and similar code.
*/
deprecated class Copy extends TDuplicationOrSimilarity {
/** Gets the index of the token in this block starting at the location `loc`, if any. */
int tokenStartingAt(Location loc) { none() }
/** Gets the index of the token in this block ending at the location `loc`, if any. */
int tokenEndingAt(Location loc) { none() }
/** Gets the line on which the first token in this block starts. */
int sourceStartLine() { none() }
/** Gets the column on which the first token in this block starts. */
int sourceStartColumn() { none() }
/** Gets the line on which the last token in this block ends. */
int sourceEndLine() { none() }
/** Gets the column on which the last token in this block ends. */
int sourceEndColumn() { none() }
/** Gets the number of lines containing at least (part of) one token in this block. */
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
/** Gets an opaque identifier for the equivalence class of this block. */
int getEquivalenceClass() { none() }
/** Gets the source file in which this block appears. */
File sourceFile() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.sourceFile().getAbsolutePath() = filepath and
startline = this.sourceStartLine() and
startcolumn = this.sourceStartColumn() and
endline = this.sourceEndLine() and
endcolumn = this.sourceEndColumn()
}
/** Gets a textual representation of this element. */
string toString() { none() }
}
/**
* DEPRECATED: This class is no longer used.
*
* A block of duplicated code.
*/
deprecated class DuplicateBlock extends Copy {
override string toString() {
result = "Duplicate code: " + this.sourceLines() + " duplicated lines."
}
}
/**
* DEPRECATED: This class is no longer used.
*
* A block of similar code.
*/
deprecated class SimilarBlock extends Copy {
override string toString() {
result = "Similar code: " + this.sourceLines() + " almost duplicated lines."
}
}
/**
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
*
* Gets a function with a body and a location.
*/
deprecated FunctionDeclarationEntry sourceMethod() {
result.isDefinition() and
exists(result.getLocation()) and
numlines(unresolveElement(result.getFunction()), _, _, _)
}
/**
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
*
* Gets the number of member functions in `c` with a body and a location.
*/
deprecated int numberOfSourceMethods(Class c) {
result =
count(FunctionDeclarationEntry m |
m = sourceMethod() and
m.getFunction().getDeclaringType() = c
)
}
deprecated private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
exists(DuplicateBlock b, Location loc |
stmt.getLocation() = loc and
first = b.tokenStartingAt(loc) and
last = b.tokenEndingAt(loc) and
b.getEquivalenceClass() = equivClass
)
}
deprecated private Stmt statementInMethod(FunctionDeclarationEntry m) {
result.getParent+() = m.getBlock() and
not result.getLocation() instanceof UnknownStmtLocation and
not result instanceof BlockStmt
}
deprecated private predicate duplicateStatement(
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, Stmt s1, Stmt s2
) {
exists(int equivClass, int first, int last |
s1 = statementInMethod(m1) and
s2 = statementInMethod(m2) and
blockCoversStatement(equivClass, first, last, s1) and
blockCoversStatement(equivClass, first, last, s2) and
s1 != s2 and
m1 != m2
)
}
/**
* DEPRECATED: Information on duplicated statements is no longer available.
*
* Holds if `m1` is a function with `total` lines, and `m2` is a function
* that has `duplicate` lines in common with `m1`.
*/
deprecated predicate duplicateStatements(
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total
) {
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
total = strictcount(statementInMethod(m1))
}
/**
* DEPRECATED: Information on duplicated methods is no longer available.
*
* Holds if `m` and other are identical functions.
*/
deprecated predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) {
exists(int total | duplicateStatements(m, other, total, total))
}
/**
* DEPRECATED: Information on similar lines is no longer available.
*
* INTERNAL: do not use.
*
* Holds if `line` in `f` is similar to a line somewhere else.
*/
deprecated predicate similarLines(File f, int line) {
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
deprecated private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines =
strictsum(SimilarBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
deprecated private predicate similarLinesCoveredFiles(File f, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
exists(int coveredApprox |
coveredApprox =
strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
(coveredApprox * 100) / numLines > 75
)
)
}
/**
* DEPRECATED: Information on similar lines is no longer available.
*
* Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`.
*/
deprecated predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
similarLinesCoveredFiles(f, otherFile) and
exists(int notCovered |
notCovered =
count(int j |
j in [1 .. numLines] and
not similarLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
/**
* DEPRECATED: Information on duplicate lines is no longer available.
*
* INTERNAL: do not use.
*
* Holds if `line` in `f` is duplicated by a line somewhere else.
*/
deprecated predicate duplicateLines(File f, int line) {
exists(DuplicateBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
)
}
deprecated private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines =
strictsum(DuplicateBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
/**
* DEPRECATED: Information on duplicate lines is no longer available.
*
* Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`.
*/
deprecated predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
exists(int coveredApprox |
coveredApprox =
strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
(coveredApprox * 100) / numLines > 75
) and
exists(int notCovered |
notCovered =
count(int j |
j in [1 .. numLines] and
not duplicateLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
/**
* DEPRECATED: Information on similar files is no longer available.
*
* Holds if most of `f` (`percent`%) is similar to `other`.
*/
deprecated predicate similarFiles(File f, File other, int percent) {
exists(int covered, int total |
similarLinesCovered(f, covered, other) and
total = f.getMetrics().getNumberOfLines() and
covered * 100 / total = percent and
percent > 80
) and
not duplicateFiles(f, other, _)
}
/**
* DEPRECATED: Information on duplicate files is no longer available.
*
* Holds if most of `f` (`percent`%) is duplicated by `other`.
*/
deprecated predicate duplicateFiles(File f, File other, int percent) {
exists(int covered, int total |
duplicateLinesCovered(f, covered, other) and
total = f.getMetrics().getNumberOfLines() and
covered * 100 / total = percent and
percent > 70
)
}
/**
* DEPRECATED: Information on duplicate classes is no longer available.
*
* Holds if most member functions of `c` (`numDup` out of `total`) are
* duplicates of member functions in `other`.
*/
deprecated predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup =
strictcount(FunctionDeclarationEntry m1 |
exists(FunctionDeclarationEntry m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
exists(Function f | f = m1.getFunction() and f.getDeclaringType() = c) and
exists(Function f | f = m2.getFunction() and f.getDeclaringType() = other) and
c != other
)
) and
total = numberOfSourceMethods(c) and
(numDup * 100) / total > 80
}
/**
* DEPRECATED: Information on duplicate classes is no longer available.
*
* Holds if most member functions of `c` are duplicates of member functions in
* `other`. Provides the human-readable `message` to describe the amount of
* duplication.
*/
deprecated predicate mostlyDuplicateClass(Class c, Class other, string message) {
exists(int numDup, int total |
mostlyDuplicateClassBase(c, other, numDup, total) and
(
total != numDup and
exists(string s1, string s2, string s3, string name |
s1 = " out of " and
s2 = " methods in " and
s3 = " are duplicated in $@." and
name = c.getName()
|
message = numDup + s1 + total + s2 + name + s3
)
or
total = numDup and
exists(string s1, string s2, string name |
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
message = s1 + name + s2
)
)
)
}
/**
* DEPRECATED: Information on file duplication is no longer available.
*
* Holds if `f` and `other` are similar or duplicates.
*/
deprecated predicate fileLevelDuplication(File f, File other) {
similarFiles(f, other, _) or duplicateFiles(f, other, _)
}
/**
* DEPRECATED: Information on class duplication is no longer available.
*
* Holds if most member functions of `c` are duplicates of member functions in
* `other`.
*/
deprecated predicate classLevelDuplication(Class c, Class other) {
mostlyDuplicateClass(c, other, _)
}
/**
* DEPRECATED: The CodeDuplication library will be removed in a future release.
*
* Holds if `line` in `f` should be allowed to be duplicated. This is the case
* for `#include` directives.
*/
deprecated predicate whitelistedLineForDuplication(File f, int line) {
exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line)
}

View File

@@ -16,16 +16,18 @@ private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
import TestUtilities.InlineExpectationsTest
module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
string getARelevantTag() { result = "ir" }
class IRFlowTest extends InlineExpectationsTest {
IRFlowTest() { this = "IRFlowTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRDataFlow::Node source, IRDataFlow::Node sink, int n |
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRDataFlow::Node source, IRDataFlow::Node sink, IRDataFlow::Configuration conf, int n |
tag = "ir" and
Flow::flow(source, sink) and
conf.hasFlow(source, sink) and
n =
strictcount(int line, int column |
Flow::flow(any(IRDataFlow::Node otherSource |
conf.hasFlow(any(IRDataFlow::Node otherSource |
otherSource.hasLocationInfo(_, line, column, _, _)
), sink)
) and
@@ -45,16 +47,20 @@ module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
}
}
module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
string getARelevantTag() { result = "ast" }
class AstFlowTest extends InlineExpectationsTest {
AstFlowTest() { this = "ASTFlowTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstDataFlow::Node source, AstDataFlow::Node sink, int n |
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
|
tag = "ast" and
Flow::flow(source, sink) and
conf.hasFlow(source, sink) and
n =
strictcount(int line, int column |
Flow::flow(any(AstDataFlow::Node otherSource |
conf.hasFlow(any(AstDataFlow::Node otherSource |
otherSource.hasLocationInfo(_, line, column, _, _)
), sink)
) and
@@ -73,3 +79,6 @@ module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
)
}
}
/** DEPRECATED: Alias for AstFlowTest */
deprecated class ASTFlowTest = AstFlowTest;

View File

@@ -0,0 +1,424 @@
edges
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:24:21:24:31 | call to mk_string_t indirection [string] |
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:34:21:34:31 | call to mk_string_t indirection [string] |
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] |
| test.cpp:18:5:18:30 | ... = ... | test.cpp:18:10:18:15 | str indirection [post update] [string] |
| test.cpp:18:10:18:15 | str indirection [post update] [string] | test.cpp:16:11:16:21 | mk_string_t indirection [string] |
| test.cpp:18:19:18:24 | call to malloc | test.cpp:18:5:18:30 | ... = ... |
| test.cpp:24:21:24:31 | call to mk_string_t indirection [string] | test.cpp:26:13:26:15 | str indirection [string] |
| test.cpp:26:13:26:15 | str indirection [string] | test.cpp:26:18:26:23 | string |
| test.cpp:26:13:26:15 | str indirection [string] | test.cpp:26:18:26:23 | string indirection |
| test.cpp:26:18:26:23 | string indirection | test.cpp:26:18:26:23 | string |
| test.cpp:29:32:29:34 | str indirection [string] | test.cpp:30:13:30:15 | str indirection [string] |
| test.cpp:30:13:30:15 | str indirection [string] | test.cpp:30:18:30:23 | string |
| test.cpp:30:13:30:15 | str indirection [string] | test.cpp:30:18:30:23 | string indirection |
| test.cpp:30:18:30:23 | string indirection | test.cpp:30:18:30:23 | string |
| test.cpp:34:21:34:31 | call to mk_string_t indirection [string] | test.cpp:35:21:35:23 | str indirection [string] |
| test.cpp:35:21:35:23 | str indirection [string] | test.cpp:29:32:29:34 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:41:13:41:15 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:42:13:42:15 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:44:13:44:15 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:45:13:45:15 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:48:17:48:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:52:17:52:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:56:17:56:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:60:17:60:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:64:17:64:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:68:17:68:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:72:17:72:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:76:17:76:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:80:17:80:19 | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:84:17:84:19 | str indirection [string] |
| test.cpp:41:13:41:15 | str indirection [string] | test.cpp:41:18:41:23 | string |
| test.cpp:41:13:41:15 | str indirection [string] | test.cpp:41:18:41:23 | string indirection |
| test.cpp:41:18:41:23 | string indirection | test.cpp:41:18:41:23 | string |
| test.cpp:42:13:42:15 | str indirection [string] | test.cpp:42:18:42:23 | string |
| test.cpp:42:13:42:15 | str indirection [string] | test.cpp:42:18:42:23 | string indirection |
| test.cpp:42:18:42:23 | string indirection | test.cpp:42:18:42:23 | string |
| test.cpp:44:13:44:15 | str indirection [string] | test.cpp:44:18:44:23 | string |
| test.cpp:44:13:44:15 | str indirection [string] | test.cpp:44:18:44:23 | string indirection |
| test.cpp:44:18:44:23 | string indirection | test.cpp:44:18:44:23 | string |
| test.cpp:45:13:45:15 | str indirection [string] | test.cpp:45:18:45:23 | string |
| test.cpp:45:13:45:15 | str indirection [string] | test.cpp:45:18:45:23 | string indirection |
| test.cpp:45:18:45:23 | string indirection | test.cpp:45:18:45:23 | string |
| test.cpp:48:17:48:19 | str indirection [string] | test.cpp:48:22:48:27 | string |
| test.cpp:48:17:48:19 | str indirection [string] | test.cpp:48:22:48:27 | string indirection |
| test.cpp:48:22:48:27 | string indirection | test.cpp:48:22:48:27 | string |
| test.cpp:52:17:52:19 | str indirection [string] | test.cpp:52:22:52:27 | string |
| test.cpp:52:17:52:19 | str indirection [string] | test.cpp:52:22:52:27 | string indirection |
| test.cpp:52:22:52:27 | string indirection | test.cpp:52:22:52:27 | string |
| test.cpp:56:17:56:19 | str indirection [string] | test.cpp:56:22:56:27 | string |
| test.cpp:56:17:56:19 | str indirection [string] | test.cpp:56:22:56:27 | string indirection |
| test.cpp:56:22:56:27 | string indirection | test.cpp:56:22:56:27 | string |
| test.cpp:60:17:60:19 | str indirection [string] | test.cpp:60:22:60:27 | string |
| test.cpp:60:17:60:19 | str indirection [string] | test.cpp:60:22:60:27 | string indirection |
| test.cpp:60:22:60:27 | string indirection | test.cpp:60:22:60:27 | string |
| test.cpp:64:17:64:19 | str indirection [string] | test.cpp:64:22:64:27 | string |
| test.cpp:64:17:64:19 | str indirection [string] | test.cpp:64:22:64:27 | string indirection |
| test.cpp:64:22:64:27 | string indirection | test.cpp:64:22:64:27 | string |
| test.cpp:68:17:68:19 | str indirection [string] | test.cpp:68:22:68:27 | string |
| test.cpp:68:17:68:19 | str indirection [string] | test.cpp:68:22:68:27 | string indirection |
| test.cpp:68:22:68:27 | string indirection | test.cpp:68:22:68:27 | string |
| test.cpp:72:17:72:19 | str indirection [string] | test.cpp:72:22:72:27 | string |
| test.cpp:72:17:72:19 | str indirection [string] | test.cpp:72:22:72:27 | string indirection |
| test.cpp:72:22:72:27 | string indirection | test.cpp:72:22:72:27 | string |
| test.cpp:76:17:76:19 | str indirection [string] | test.cpp:76:22:76:27 | string |
| test.cpp:76:17:76:19 | str indirection [string] | test.cpp:76:22:76:27 | string indirection |
| test.cpp:76:22:76:27 | string indirection | test.cpp:76:22:76:27 | string |
| test.cpp:80:17:80:19 | str indirection [string] | test.cpp:80:22:80:27 | string |
| test.cpp:80:17:80:19 | str indirection [string] | test.cpp:80:22:80:27 | string indirection |
| test.cpp:80:22:80:27 | string indirection | test.cpp:80:22:80:27 | string |
| test.cpp:84:17:84:19 | str indirection [string] | test.cpp:84:22:84:27 | string |
| test.cpp:84:17:84:19 | str indirection [string] | test.cpp:84:22:84:27 | string indirection |
| test.cpp:84:22:84:27 | string indirection | test.cpp:84:22:84:27 | string |
| test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] |
| test.cpp:90:5:90:34 | ... = ... | test.cpp:90:10:90:15 | str indirection [post update] [string] |
| test.cpp:90:10:90:15 | str indirection [post update] [string] | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] |
| test.cpp:90:19:90:24 | call to malloc | test.cpp:90:5:90:34 | ... = ... |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:98:13:98:15 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:99:13:99:15 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:101:13:101:15 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:102:13:102:15 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:105:17:105:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:109:17:109:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:113:17:113:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:117:17:117:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:121:17:121:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:125:17:125:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:129:17:129:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:133:17:133:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:137:17:137:19 | str indirection [string] |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:141:17:141:19 | str indirection [string] |
| test.cpp:98:13:98:15 | str indirection [string] | test.cpp:98:18:98:23 | string |
| test.cpp:98:13:98:15 | str indirection [string] | test.cpp:98:18:98:23 | string indirection |
| test.cpp:98:18:98:23 | string indirection | test.cpp:98:18:98:23 | string |
| test.cpp:99:13:99:15 | str indirection [string] | test.cpp:99:18:99:23 | string |
| test.cpp:99:13:99:15 | str indirection [string] | test.cpp:99:18:99:23 | string indirection |
| test.cpp:99:18:99:23 | string indirection | test.cpp:99:18:99:23 | string |
| test.cpp:101:13:101:15 | str indirection [string] | test.cpp:101:18:101:23 | string |
| test.cpp:101:13:101:15 | str indirection [string] | test.cpp:101:18:101:23 | string indirection |
| test.cpp:101:18:101:23 | string indirection | test.cpp:101:18:101:23 | string |
| test.cpp:102:13:102:15 | str indirection [string] | test.cpp:102:18:102:23 | string |
| test.cpp:102:13:102:15 | str indirection [string] | test.cpp:102:18:102:23 | string indirection |
| test.cpp:102:18:102:23 | string indirection | test.cpp:102:18:102:23 | string |
| test.cpp:105:17:105:19 | str indirection [string] | test.cpp:105:22:105:27 | string |
| test.cpp:105:17:105:19 | str indirection [string] | test.cpp:105:22:105:27 | string indirection |
| test.cpp:105:22:105:27 | string indirection | test.cpp:105:22:105:27 | string |
| test.cpp:109:17:109:19 | str indirection [string] | test.cpp:109:22:109:27 | string |
| test.cpp:109:17:109:19 | str indirection [string] | test.cpp:109:22:109:27 | string indirection |
| test.cpp:109:22:109:27 | string indirection | test.cpp:109:22:109:27 | string |
| test.cpp:113:17:113:19 | str indirection [string] | test.cpp:113:22:113:27 | string |
| test.cpp:113:17:113:19 | str indirection [string] | test.cpp:113:22:113:27 | string indirection |
| test.cpp:113:22:113:27 | string indirection | test.cpp:113:22:113:27 | string |
| test.cpp:117:17:117:19 | str indirection [string] | test.cpp:117:22:117:27 | string |
| test.cpp:117:17:117:19 | str indirection [string] | test.cpp:117:22:117:27 | string indirection |
| test.cpp:117:22:117:27 | string indirection | test.cpp:117:22:117:27 | string |
| test.cpp:121:17:121:19 | str indirection [string] | test.cpp:121:22:121:27 | string |
| test.cpp:121:17:121:19 | str indirection [string] | test.cpp:121:22:121:27 | string indirection |
| test.cpp:121:22:121:27 | string indirection | test.cpp:121:22:121:27 | string |
| test.cpp:125:17:125:19 | str indirection [string] | test.cpp:125:22:125:27 | string |
| test.cpp:125:17:125:19 | str indirection [string] | test.cpp:125:22:125:27 | string indirection |
| test.cpp:125:22:125:27 | string indirection | test.cpp:125:22:125:27 | string |
| test.cpp:129:17:129:19 | str indirection [string] | test.cpp:129:22:129:27 | string |
| test.cpp:129:17:129:19 | str indirection [string] | test.cpp:129:22:129:27 | string indirection |
| test.cpp:129:22:129:27 | string indirection | test.cpp:129:22:129:27 | string |
| test.cpp:133:17:133:19 | str indirection [string] | test.cpp:133:22:133:27 | string |
| test.cpp:133:17:133:19 | str indirection [string] | test.cpp:133:22:133:27 | string indirection |
| test.cpp:133:22:133:27 | string indirection | test.cpp:133:22:133:27 | string |
| test.cpp:137:17:137:19 | str indirection [string] | test.cpp:137:22:137:27 | string |
| test.cpp:137:17:137:19 | str indirection [string] | test.cpp:137:22:137:27 | string indirection |
| test.cpp:137:22:137:27 | string indirection | test.cpp:137:22:137:27 | string |
| test.cpp:141:17:141:19 | str indirection [string] | test.cpp:141:22:141:27 | string |
| test.cpp:141:17:141:19 | str indirection [string] | test.cpp:141:22:141:27 | string indirection |
| test.cpp:141:22:141:27 | string indirection | test.cpp:141:22:141:27 | string |
| test.cpp:147:5:147:34 | ... = ... | test.cpp:147:10:147:15 | str indirection [post update] [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:150:13:150:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:151:13:151:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:152:13:152:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:154:13:154:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:155:13:155:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:156:13:156:15 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:159:17:159:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:163:17:163:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:167:17:167:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:171:17:171:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:175:17:175:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:179:17:179:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:183:17:183:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:187:17:187:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:191:17:191:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:195:17:195:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:199:17:199:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:203:17:203:19 | str indirection [string] |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:207:17:207:19 | str indirection [string] |
| test.cpp:147:19:147:24 | call to malloc | test.cpp:147:5:147:34 | ... = ... |
| test.cpp:150:13:150:15 | str indirection [string] | test.cpp:150:18:150:23 | string |
| test.cpp:150:13:150:15 | str indirection [string] | test.cpp:150:18:150:23 | string indirection |
| test.cpp:150:18:150:23 | string indirection | test.cpp:150:18:150:23 | string |
| test.cpp:151:13:151:15 | str indirection [string] | test.cpp:151:18:151:23 | string |
| test.cpp:151:13:151:15 | str indirection [string] | test.cpp:151:18:151:23 | string indirection |
| test.cpp:151:18:151:23 | string indirection | test.cpp:151:18:151:23 | string |
| test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string |
| test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string indirection |
| test.cpp:152:18:152:23 | string indirection | test.cpp:152:18:152:23 | string |
| test.cpp:154:13:154:15 | str indirection [string] | test.cpp:154:18:154:23 | string |
| test.cpp:154:13:154:15 | str indirection [string] | test.cpp:154:18:154:23 | string indirection |
| test.cpp:154:18:154:23 | string indirection | test.cpp:154:18:154:23 | string |
| test.cpp:155:13:155:15 | str indirection [string] | test.cpp:155:18:155:23 | string |
| test.cpp:155:13:155:15 | str indirection [string] | test.cpp:155:18:155:23 | string indirection |
| test.cpp:155:18:155:23 | string indirection | test.cpp:155:18:155:23 | string |
| test.cpp:156:13:156:15 | str indirection [string] | test.cpp:156:18:156:23 | string |
| test.cpp:156:13:156:15 | str indirection [string] | test.cpp:156:18:156:23 | string indirection |
| test.cpp:156:18:156:23 | string indirection | test.cpp:156:18:156:23 | string |
| test.cpp:159:17:159:19 | str indirection [string] | test.cpp:159:22:159:27 | string |
| test.cpp:159:17:159:19 | str indirection [string] | test.cpp:159:22:159:27 | string indirection |
| test.cpp:159:22:159:27 | string indirection | test.cpp:159:22:159:27 | string |
| test.cpp:163:17:163:19 | str indirection [string] | test.cpp:163:22:163:27 | string |
| test.cpp:163:17:163:19 | str indirection [string] | test.cpp:163:22:163:27 | string indirection |
| test.cpp:163:22:163:27 | string indirection | test.cpp:163:22:163:27 | string |
| test.cpp:167:17:167:19 | str indirection [string] | test.cpp:167:22:167:27 | string |
| test.cpp:167:17:167:19 | str indirection [string] | test.cpp:167:22:167:27 | string indirection |
| test.cpp:167:22:167:27 | string indirection | test.cpp:167:22:167:27 | string |
| test.cpp:171:17:171:19 | str indirection [string] | test.cpp:171:22:171:27 | string |
| test.cpp:171:17:171:19 | str indirection [string] | test.cpp:171:22:171:27 | string indirection |
| test.cpp:171:22:171:27 | string indirection | test.cpp:171:22:171:27 | string |
| test.cpp:175:17:175:19 | str indirection [string] | test.cpp:175:22:175:27 | string |
| test.cpp:175:17:175:19 | str indirection [string] | test.cpp:175:22:175:27 | string indirection |
| test.cpp:175:22:175:27 | string indirection | test.cpp:175:22:175:27 | string |
| test.cpp:179:17:179:19 | str indirection [string] | test.cpp:179:22:179:27 | string |
| test.cpp:179:17:179:19 | str indirection [string] | test.cpp:179:22:179:27 | string indirection |
| test.cpp:179:22:179:27 | string indirection | test.cpp:179:22:179:27 | string |
| test.cpp:183:17:183:19 | str indirection [string] | test.cpp:183:22:183:27 | string |
| test.cpp:183:17:183:19 | str indirection [string] | test.cpp:183:22:183:27 | string indirection |
| test.cpp:183:22:183:27 | string indirection | test.cpp:183:22:183:27 | string |
| test.cpp:187:17:187:19 | str indirection [string] | test.cpp:187:22:187:27 | string |
| test.cpp:187:17:187:19 | str indirection [string] | test.cpp:187:22:187:27 | string indirection |
| test.cpp:187:22:187:27 | string indirection | test.cpp:187:22:187:27 | string |
| test.cpp:191:17:191:19 | str indirection [string] | test.cpp:191:22:191:27 | string |
| test.cpp:191:17:191:19 | str indirection [string] | test.cpp:191:22:191:27 | string indirection |
| test.cpp:191:22:191:27 | string indirection | test.cpp:191:22:191:27 | string |
| test.cpp:195:17:195:19 | str indirection [string] | test.cpp:195:22:195:27 | string |
| test.cpp:195:17:195:19 | str indirection [string] | test.cpp:195:22:195:27 | string indirection |
| test.cpp:195:22:195:27 | string indirection | test.cpp:195:22:195:27 | string |
| test.cpp:199:17:199:19 | str indirection [string] | test.cpp:199:22:199:27 | string |
| test.cpp:199:17:199:19 | str indirection [string] | test.cpp:199:22:199:27 | string indirection |
| test.cpp:199:22:199:27 | string indirection | test.cpp:199:22:199:27 | string |
| test.cpp:203:17:203:19 | str indirection [string] | test.cpp:203:22:203:27 | string |
| test.cpp:203:17:203:19 | str indirection [string] | test.cpp:203:22:203:27 | string indirection |
| test.cpp:203:22:203:27 | string indirection | test.cpp:203:22:203:27 | string |
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string |
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string indirection |
| test.cpp:207:22:207:27 | string indirection | test.cpp:207:22:207:27 | string |
| test.cpp:214:24:214:24 | p | test.cpp:216:10:216:10 | p |
| test.cpp:220:43:220:48 | call to malloc | test.cpp:222:15:222:20 | buffer |
| test.cpp:222:15:222:20 | buffer | test.cpp:214:24:214:24 | p |
| test.cpp:228:43:228:48 | call to malloc | test.cpp:232:10:232:15 | buffer |
| test.cpp:235:40:235:45 | buffer | test.cpp:236:5:236:26 | ... = ... |
| test.cpp:236:5:236:26 | ... = ... | test.cpp:236:12:236:17 | p_str indirection [post update] [string] |
| test.cpp:241:27:241:32 | call to malloc | test.cpp:242:22:242:27 | buffer |
| test.cpp:242:16:242:19 | set_string output argument [string] | test.cpp:243:12:243:14 | str indirection [string] |
| test.cpp:242:22:242:27 | buffer | test.cpp:235:40:235:45 | buffer |
| test.cpp:242:22:242:27 | buffer | test.cpp:242:16:242:19 | set_string output argument [string] |
| test.cpp:243:12:243:14 | str indirection [string] | test.cpp:243:12:243:21 | string |
| test.cpp:243:12:243:14 | str indirection [string] | test.cpp:243:16:243:21 | string indirection |
| test.cpp:243:16:243:21 | string indirection | test.cpp:243:12:243:21 | string |
nodes
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | semmle.label | mk_string_t indirection [string] |
| test.cpp:18:5:18:30 | ... = ... | semmle.label | ... = ... |
| test.cpp:18:10:18:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
| test.cpp:18:19:18:24 | call to malloc | semmle.label | call to malloc |
| test.cpp:24:21:24:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
| test.cpp:26:13:26:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:26:18:26:23 | string | semmle.label | string |
| test.cpp:26:18:26:23 | string indirection | semmle.label | string indirection |
| test.cpp:29:32:29:34 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:30:13:30:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:30:18:30:23 | string | semmle.label | string |
| test.cpp:30:18:30:23 | string indirection | semmle.label | string indirection |
| test.cpp:34:21:34:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
| test.cpp:35:21:35:23 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] |
| test.cpp:41:13:41:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:41:18:41:23 | string | semmle.label | string |
| test.cpp:41:18:41:23 | string indirection | semmle.label | string indirection |
| test.cpp:42:13:42:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:42:18:42:23 | string | semmle.label | string |
| test.cpp:42:18:42:23 | string indirection | semmle.label | string indirection |
| test.cpp:44:13:44:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:44:18:44:23 | string | semmle.label | string |
| test.cpp:44:18:44:23 | string indirection | semmle.label | string indirection |
| test.cpp:45:13:45:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:45:18:45:23 | string | semmle.label | string |
| test.cpp:45:18:45:23 | string indirection | semmle.label | string indirection |
| test.cpp:48:17:48:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:48:22:48:27 | string | semmle.label | string |
| test.cpp:48:22:48:27 | string indirection | semmle.label | string indirection |
| test.cpp:52:17:52:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:52:22:52:27 | string | semmle.label | string |
| test.cpp:52:22:52:27 | string indirection | semmle.label | string indirection |
| test.cpp:56:17:56:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:56:22:56:27 | string | semmle.label | string |
| test.cpp:56:22:56:27 | string indirection | semmle.label | string indirection |
| test.cpp:60:17:60:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:60:22:60:27 | string | semmle.label | string |
| test.cpp:60:22:60:27 | string indirection | semmle.label | string indirection |
| test.cpp:64:17:64:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:64:22:64:27 | string | semmle.label | string |
| test.cpp:64:22:64:27 | string indirection | semmle.label | string indirection |
| test.cpp:68:17:68:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:68:22:68:27 | string | semmle.label | string |
| test.cpp:68:22:68:27 | string indirection | semmle.label | string indirection |
| test.cpp:72:17:72:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:72:22:72:27 | string | semmle.label | string |
| test.cpp:72:22:72:27 | string indirection | semmle.label | string indirection |
| test.cpp:76:17:76:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:76:22:76:27 | string | semmle.label | string |
| test.cpp:76:22:76:27 | string indirection | semmle.label | string indirection |
| test.cpp:80:17:80:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:80:22:80:27 | string | semmle.label | string |
| test.cpp:80:22:80:27 | string indirection | semmle.label | string indirection |
| test.cpp:84:17:84:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:84:22:84:27 | string | semmle.label | string |
| test.cpp:84:22:84:27 | string indirection | semmle.label | string indirection |
| test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | semmle.label | mk_string_t_plus_one indirection [string] |
| test.cpp:90:5:90:34 | ... = ... | semmle.label | ... = ... |
| test.cpp:90:10:90:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
| test.cpp:90:19:90:24 | call to malloc | semmle.label | call to malloc |
| test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | semmle.label | call to mk_string_t_plus_one indirection [string] |
| test.cpp:98:13:98:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:98:18:98:23 | string | semmle.label | string |
| test.cpp:98:18:98:23 | string indirection | semmle.label | string indirection |
| test.cpp:99:13:99:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:99:18:99:23 | string | semmle.label | string |
| test.cpp:99:18:99:23 | string indirection | semmle.label | string indirection |
| test.cpp:101:13:101:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:101:18:101:23 | string | semmle.label | string |
| test.cpp:101:18:101:23 | string indirection | semmle.label | string indirection |
| test.cpp:102:13:102:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:102:18:102:23 | string | semmle.label | string |
| test.cpp:102:18:102:23 | string indirection | semmle.label | string indirection |
| test.cpp:105:17:105:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:105:22:105:27 | string | semmle.label | string |
| test.cpp:105:22:105:27 | string indirection | semmle.label | string indirection |
| test.cpp:109:17:109:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:109:22:109:27 | string | semmle.label | string |
| test.cpp:109:22:109:27 | string indirection | semmle.label | string indirection |
| test.cpp:113:17:113:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:113:22:113:27 | string | semmle.label | string |
| test.cpp:113:22:113:27 | string indirection | semmle.label | string indirection |
| test.cpp:117:17:117:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:117:22:117:27 | string | semmle.label | string |
| test.cpp:117:22:117:27 | string indirection | semmle.label | string indirection |
| test.cpp:121:17:121:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:121:22:121:27 | string | semmle.label | string |
| test.cpp:121:22:121:27 | string indirection | semmle.label | string indirection |
| test.cpp:125:17:125:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:125:22:125:27 | string | semmle.label | string |
| test.cpp:125:22:125:27 | string indirection | semmle.label | string indirection |
| test.cpp:129:17:129:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:129:22:129:27 | string | semmle.label | string |
| test.cpp:129:22:129:27 | string indirection | semmle.label | string indirection |
| test.cpp:133:17:133:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:133:22:133:27 | string | semmle.label | string |
| test.cpp:133:22:133:27 | string indirection | semmle.label | string indirection |
| test.cpp:137:17:137:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:137:22:137:27 | string | semmle.label | string |
| test.cpp:137:22:137:27 | string indirection | semmle.label | string indirection |
| test.cpp:141:17:141:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:141:22:141:27 | string | semmle.label | string |
| test.cpp:141:22:141:27 | string indirection | semmle.label | string indirection |
| test.cpp:147:5:147:34 | ... = ... | semmle.label | ... = ... |
| test.cpp:147:10:147:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] |
| test.cpp:147:19:147:24 | call to malloc | semmle.label | call to malloc |
| test.cpp:150:13:150:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:150:18:150:23 | string | semmle.label | string |
| test.cpp:150:18:150:23 | string indirection | semmle.label | string indirection |
| test.cpp:151:13:151:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:151:18:151:23 | string | semmle.label | string |
| test.cpp:151:18:151:23 | string indirection | semmle.label | string indirection |
| test.cpp:152:13:152:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:152:18:152:23 | string | semmle.label | string |
| test.cpp:152:18:152:23 | string indirection | semmle.label | string indirection |
| test.cpp:154:13:154:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:154:18:154:23 | string | semmle.label | string |
| test.cpp:154:18:154:23 | string indirection | semmle.label | string indirection |
| test.cpp:155:13:155:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:155:18:155:23 | string | semmle.label | string |
| test.cpp:155:18:155:23 | string indirection | semmle.label | string indirection |
| test.cpp:156:13:156:15 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:156:18:156:23 | string | semmle.label | string |
| test.cpp:156:18:156:23 | string indirection | semmle.label | string indirection |
| test.cpp:159:17:159:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:159:22:159:27 | string | semmle.label | string |
| test.cpp:159:22:159:27 | string indirection | semmle.label | string indirection |
| test.cpp:163:17:163:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:163:22:163:27 | string | semmle.label | string |
| test.cpp:163:22:163:27 | string indirection | semmle.label | string indirection |
| test.cpp:167:17:167:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:167:22:167:27 | string | semmle.label | string |
| test.cpp:167:22:167:27 | string indirection | semmle.label | string indirection |
| test.cpp:171:17:171:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:171:22:171:27 | string | semmle.label | string |
| test.cpp:171:22:171:27 | string indirection | semmle.label | string indirection |
| test.cpp:175:17:175:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:175:22:175:27 | string | semmle.label | string |
| test.cpp:175:22:175:27 | string indirection | semmle.label | string indirection |
| test.cpp:179:17:179:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:179:22:179:27 | string | semmle.label | string |
| test.cpp:179:22:179:27 | string indirection | semmle.label | string indirection |
| test.cpp:183:17:183:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:183:22:183:27 | string | semmle.label | string |
| test.cpp:183:22:183:27 | string indirection | semmle.label | string indirection |
| test.cpp:187:17:187:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:187:22:187:27 | string | semmle.label | string |
| test.cpp:187:22:187:27 | string indirection | semmle.label | string indirection |
| test.cpp:191:17:191:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:191:22:191:27 | string | semmle.label | string |
| test.cpp:191:22:191:27 | string indirection | semmle.label | string indirection |
| test.cpp:195:17:195:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:195:22:195:27 | string | semmle.label | string |
| test.cpp:195:22:195:27 | string indirection | semmle.label | string indirection |
| test.cpp:199:17:199:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:199:22:199:27 | string | semmle.label | string |
| test.cpp:199:22:199:27 | string indirection | semmle.label | string indirection |
| test.cpp:203:17:203:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:203:22:203:27 | string | semmle.label | string |
| test.cpp:203:22:203:27 | string indirection | semmle.label | string indirection |
| test.cpp:207:17:207:19 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:207:22:207:27 | string | semmle.label | string |
| test.cpp:207:22:207:27 | string indirection | semmle.label | string indirection |
| test.cpp:214:24:214:24 | p | semmle.label | p |
| test.cpp:216:10:216:10 | p | semmle.label | p |
| test.cpp:220:43:220:48 | call to malloc | semmle.label | call to malloc |
| test.cpp:222:15:222:20 | buffer | semmle.label | buffer |
| test.cpp:228:43:228:48 | call to malloc | semmle.label | call to malloc |
| test.cpp:232:10:232:15 | buffer | semmle.label | buffer |
| test.cpp:235:40:235:45 | buffer | semmle.label | buffer |
| test.cpp:236:5:236:26 | ... = ... | semmle.label | ... = ... |
| test.cpp:236:12:236:17 | p_str indirection [post update] [string] | semmle.label | p_str indirection [post update] [string] |
| test.cpp:241:27:241:32 | call to malloc | semmle.label | call to malloc |
| test.cpp:242:16:242:19 | set_string output argument [string] | semmle.label | set_string output argument [string] |
| test.cpp:242:22:242:27 | buffer | semmle.label | buffer |
| test.cpp:243:12:243:14 | str indirection [string] | semmle.label | str indirection [string] |
| test.cpp:243:12:243:21 | string | semmle.label | string |
| test.cpp:243:16:243:21 | string indirection | semmle.label | string indirection |
subpaths
| test.cpp:242:22:242:27 | buffer | test.cpp:235:40:235:45 | buffer | test.cpp:236:12:236:17 | p_str indirection [post update] [string] | test.cpp:242:16:242:19 | set_string output argument [string] |
#select
| test.cpp:42:5:42:11 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:42:18:42:23 | string | This write may overflow $@ by 1 element. | test.cpp:42:18:42:23 | string | string |
| test.cpp:72:9:72:15 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:72:22:72:27 | string | This write may overflow $@ by 1 element. | test.cpp:72:22:72:27 | string | string |
| test.cpp:80:9:80:15 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:80:22:80:27 | string | This write may overflow $@ by 2 elements. | test.cpp:80:22:80:27 | string | string |
| test.cpp:99:5:99:11 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:99:18:99:23 | string | This write may overflow $@ by 1 element. | test.cpp:99:18:99:23 | string | string |
| test.cpp:129:9:129:15 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:129:22:129:27 | string | This write may overflow $@ by 1 element. | test.cpp:129:22:129:27 | string | string |
| test.cpp:137:9:137:15 | call to strncpy | test.cpp:90:19:90:24 | call to malloc | test.cpp:137:22:137:27 | string | This write may overflow $@ by 2 elements. | test.cpp:137:22:137:27 | string | string |
| test.cpp:152:5:152:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:152:18:152:23 | string | This write may overflow $@ by 1 element. | test.cpp:152:18:152:23 | string | string |
| test.cpp:154:5:154:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:154:18:154:23 | string | This write may overflow $@ by 1 element. | test.cpp:154:18:154:23 | string | string |
| test.cpp:156:5:156:11 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:156:18:156:23 | string | This write may overflow $@ by 2 elements. | test.cpp:156:18:156:23 | string | string |
| test.cpp:175:9:175:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:175:22:175:27 | string | This write may overflow $@ by 1 element. | test.cpp:175:22:175:27 | string | string |
| test.cpp:187:9:187:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:187:22:187:27 | string | This write may overflow $@ by 1 element. | test.cpp:187:22:187:27 | string | string |
| test.cpp:195:9:195:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:195:22:195:27 | string | This write may overflow $@ by 1 element. | test.cpp:195:22:195:27 | string | string |
| test.cpp:199:9:199:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:199:22:199:27 | string | This write may overflow $@ by 2 elements. | test.cpp:199:22:199:27 | string | string |
| test.cpp:203:9:203:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:203:22:203:27 | string | This write may overflow $@ by 2 elements. | test.cpp:203:22:203:27 | string | string |
| test.cpp:207:9:207:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:207:22:207:27 | string | This write may overflow $@ by 3 elements. | test.cpp:207:22:207:27 | string | string |
| test.cpp:232:3:232:8 | call to memset | test.cpp:228:43:228:48 | call to malloc | test.cpp:232:10:232:15 | buffer | This write may overflow $@ by 32 elements. | test.cpp:232:10:232:15 | buffer | buffer |
| test.cpp:243:5:243:10 | call to memset | test.cpp:241:27:241:32 | call to malloc | test.cpp:243:12:243:21 | string | This write may overflow $@ by 1 element. | test.cpp:243:16:243:21 | string | string |

View File

@@ -0,0 +1 @@
experimental/Likely Bugs/OverrunWriteProductFlow.ql

View File

@@ -213,7 +213,7 @@ void *memset(void *, int, unsigned);
void call_memset(void *p, unsigned size)
{
memset(p, 0, size); // GOOD
memset(p, 0, size); // GOOD [FALSE POSITIVE]
}
void test_missing_call_context(unsigned char *unrelated_buffer, unsigned size) {
@@ -229,7 +229,7 @@ void repeated_alerts(unsigned size, unsigned offset) {
while(unknown()) {
++size;
}
memset(buffer, 0, size); // BAD [NOT DETECTED]
memset(buffer, 0, size); // BAD
}
void set_string(string_t* p_str, char* buffer) {
@@ -243,25 +243,3 @@ void test_flow_through_setter(unsigned size) {
memset(str.string, 0, size + 1); // BAD
}
void* my_alloc(unsigned size);
void foo(unsigned size) {
int* p = (int*)my_alloc(size); // BAD
memset(p, 0, size + 1);
}
void test6(unsigned long n, char *p) {
while (unknown()) {
n++;
p = (char *)malloc(n);
memset(p, 0, n); // GOOD
}
}
void test7(unsigned n) {
char* p = (char*)malloc(n);
if(!p) {
p = (char*)malloc(++n);
}
memset(p, 0, n); // GOOD [FALSE POSITIVE]
}

View File

@@ -1,35 +0,0 @@
| test.cpp:18:6:18:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition |
| test.cpp:19:6:19:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition |
| test.cpp:20:6:20:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition |
| test.cpp:21:6:21:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition |
| test.cpp:22:6:22:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition |
| test.cpp:23:6:23:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition |
| test.cpp:24:6:24:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition |
| test.cpp:25:6:25:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition |
| test.cpp:27:6:27:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition |
| test.cpp:28:6:28:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition |
| test.cpp:29:6:29:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition |
| test.cpp:30:6:30:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition |
| test.cpp:31:6:31:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition |
| test.cpp:32:6:32:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition |
| test.cpp:33:6:33:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition |
| test.cpp:34:6:34:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition |
| test.cpp:36:6:36:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition |
| test.cpp:37:6:37:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition |
| test.cpp:38:6:38:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition |
| test.cpp:39:6:39:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition |
| test.cpp:40:6:40:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition |
| test.cpp:41:6:41:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition |
| test.cpp:42:6:42:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition |
| test.cpp:43:6:43:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition |
| test.cpp:45:6:45:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition |
| test.cpp:46:6:46:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition |
| test.cpp:47:6:47:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition |
| test.cpp:48:6:48:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition |
| test.cpp:49:6:49:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition |
| test.cpp:50:6:50:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition |
| test.cpp:51:6:51:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition |
| test.cpp:52:6:52:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition |
| test.cpp:54:6:54:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition |
| test.cpp:61:6:61:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:61:6:61:8 | ... + ... | addition |
| test.cpp:62:6:62:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:62:6:62:8 | ... + ... | addition |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql

View File

@@ -1,63 +0,0 @@
int getAnInt();
double getADouble();
unsigned short getAnUnsignedShort();
void test()
{
int a = getAnInt();
int b = getAnInt();
int c = getAnInt();
int x = getAnInt();
int y = getAnInt();
double d = getADouble();
unsigned short a1 = getAnUnsignedShort();
unsigned short b1 = getAnUnsignedShort();
unsigned short c1 = getAnUnsignedShort();
if (a+b>c) a = c-b; // BAD
if (a+b>c) { a = c-b; } // BAD
if (b+a>c) a = c-b; // BAD
if (b+a>c) { a = c-b; } // BAD
if (c>a+b) a = c-b; // BAD
if (c>a+b) { a = c-b; } // BAD
if (c>b+a) a = c-b; // BAD
if (c>b+a) { a = c-b; } // BAD
if (a+b>=c) a = c-b; // BAD
if (a+b>=c) { a = c-b; } // BAD
if (b+a>=c) a = c-b; // BAD
if (b+a>=c) { a = c-b; } // BAD
if (c>=a+b) a = c-b; // BAD
if (c>=a+b) { a = c-b; } // BAD
if (c>=b+a) a = c-b; // BAD
if (c>=b+a) { a = c-b; } // BAD
if (a+b<c) a = c-b; // BAD
if (a+b<c) { a = c-b; } // BAD
if (b+a<c) a = c-b; // BAD
if (b+a<c) { a = c-b; } // BAD
if (c<a+b) a = c-b; // BAD
if (c<a+b) { a = c-b; } // BAD
if (c<b+a) a = c-b; // BAD
if (c<b+a) { a = c-b; } // BAD
if (a+b<=c) a = c-b; // BAD
if (a+b<=c) { a = c-b; } // BAD
if (b+a<=c) a = c-b; // BAD
if (b+a<=c) { a = c-b; } // BAD
if (c<=a+b) a = c-b; // BAD
if (c<=a+b) { a = c-b; } // BAD
if (c<=b+a) a = c-b; // BAD
if (c<=b+a) { a = c-b; } // BAD
if (a+b>d) a = d-b; // BAD
if (a+(double)b>c) a = c-b; // GOOD
if (a+(-x)>c) a = c-(-y); // GOOD
if (a+b>c) { b++; a = c-b; } // GOOD
if (a+d>c) a = c-d; // GOOD
if (a1+b1>c1) a1 = c1-b1; // GOOD
if (a+b<=c) { /* ... */ } else { a = c-b; } // BAD
if (a+b<=c) { return; } a = c-b; // BAD
}

View File

@@ -1,46 +1,37 @@
edges
| test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array |
| test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array |
| test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array |
| test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array |
| test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array |
| test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array |
| test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array |
| test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array |
| test.cpp:66:32:66:32 | p | test.cpp:66:32:66:32 | p |
| test.cpp:66:32:66:32 | p | test.cpp:67:5:67:6 | * ... |
| test.cpp:66:32:66:32 | p | test.cpp:67:6:67:6 | p |
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... |
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p |
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf |
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:26:77:44 | & ... |
nodes
| test.cpp:35:5:35:22 | access to array | semmle.label | access to array |
| test.cpp:35:10:35:12 | buf | semmle.label | buf |
| test.cpp:36:5:36:24 | access to array | semmle.label | access to array |
| test.cpp:36:10:36:12 | buf | semmle.label | buf |
| test.cpp:43:9:43:19 | access to array | semmle.label | access to array |
| test.cpp:43:14:43:16 | buf | semmle.label | buf |
| test.cpp:49:5:49:22 | access to array | semmle.label | access to array |
| test.cpp:49:10:49:12 | buf | semmle.label | buf |
| test.cpp:50:5:50:24 | access to array | semmle.label | access to array |
| test.cpp:50:10:50:12 | buf | semmle.label | buf |
| test.cpp:57:9:57:19 | access to array | semmle.label | access to array |
| test.cpp:57:14:57:16 | buf | semmle.label | buf |
| test.cpp:61:9:61:19 | access to array | semmle.label | access to array |
| test.cpp:61:14:61:16 | buf | semmle.label | buf |
| test.cpp:66:32:66:32 | p | semmle.label | p |
| test.cpp:70:33:70:33 | p | semmle.label | p |
| test.cpp:66:32:66:32 | p | semmle.label | p |
| test.cpp:66:32:66:32 | p | semmle.label | p |
| test.cpp:67:5:67:6 | * ... | semmle.label | * ... |
| test.cpp:67:6:67:6 | p | semmle.label | p |
| test.cpp:72:5:72:15 | access to array | semmle.label | access to array |
| test.cpp:77:26:77:44 | & ... | semmle.label | & ... |
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
| test.cpp:77:27:77:44 | access to array | semmle.label | access to array |
subpaths
#select
| test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
| test.cpp:36:5:36:24 | PointerAdd: access to array | test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:36:5:36:28 | Store: ... = ... | write |
| test.cpp:43:9:43:19 | PointerAdd: access to array | test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:43:9:43:23 | Store: ... = ... | write |
| test.cpp:49:5:49:22 | PointerAdd: access to array | test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:49:5:49:26 | Store: ... = ... | write |
| test.cpp:50:5:50:24 | PointerAdd: access to array | test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:50:5:50:28 | Store: ... = ... | write |
| test.cpp:57:9:57:19 | PointerAdd: access to array | test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:57:9:57:23 | Store: ... = ... | write |
| test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
| test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
| test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
| test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
| test.cpp:36:5:36:24 | access to array | test.cpp:36:5:36:24 | access to array | test.cpp:36:5:36:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:36:5:36:28 | Store: ... = ... | write |
| test.cpp:43:9:43:19 | access to array | test.cpp:43:9:43:19 | access to array | test.cpp:43:9:43:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:43:9:43:23 | Store: ... = ... | write |
| test.cpp:49:5:49:22 | access to array | test.cpp:49:5:49:22 | access to array | test.cpp:49:5:49:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:49:5:49:26 | Store: ... = ... | write |
| test.cpp:50:5:50:24 | access to array | test.cpp:50:5:50:24 | access to array | test.cpp:50:5:50:24 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:50:5:50:28 | Store: ... = ... | write |
| test.cpp:57:9:57:19 | access to array | test.cpp:57:9:57:19 | access to array | test.cpp:57:9:57:19 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:57:9:57:23 | Store: ... = ... | write |
| test.cpp:61:9:61:19 | access to array | test.cpp:61:9:61:19 | access to array | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
| test.cpp:72:5:72:15 | access to array | test.cpp:72:5:72:15 | access to array | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:67:5:67:6 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:27:77:44 | access to array | test.cpp:67:6:67:6 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |

View File

@@ -78,45 +78,3 @@ void testInterproc(BigArray *arr) {
addToPointerAndAssign(arr->buf);
}
#define MAX_SIZE_BYTES 4096
void testCharIndex(BigArray *arr) {
char *charBuf = (char*) arr->buf;
charBuf[MAX_SIZE_BYTES - 1] = 0; // GOOD
charBuf[MAX_SIZE_BYTES] = 0; // BAD [FALSE NEGATIVE]
}
void testEqRefinement() {
int arr[MAX_SIZE];
for(int i = 0; i <= MAX_SIZE; i++) {
if(i != MAX_SIZE) {
arr[i] = 0; // GOOD
}
}
}
void testEqRefinement2() {
int arr[MAX_SIZE];
int n = 0;
for(int i = 0; i <= MAX_SIZE; i++) {
if(n == 0) {
if(i == MAX_SIZE) {
break;
}
n = arr[i]; // GOOD
continue;
}
if (i == MAX_SIZE || n != arr[i]) {
if (i == MAX_SIZE) {
break;
}
n = arr[i]; // GOOD
}
}
}

View File

@@ -649,453 +649,17 @@ edges
| test.cpp:280:13:280:24 | new[] | test.cpp:281:14:281:15 | xs |
| test.cpp:290:13:290:24 | new[] | test.cpp:291:14:291:15 | xs |
| test.cpp:290:13:290:24 | new[] | test.cpp:292:30:292:30 | x |
| test.cpp:304:15:304:26 | new[] | test.cpp:307:5:307:6 | xs |
| test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:6 | xs |
| test.cpp:308:5:308:6 | xs | test.cpp:308:5:308:11 | access to array |
| test.cpp:308:5:308:11 | access to array | test.cpp:308:5:308:29 | Store: ... = ... |
| test.cpp:313:14:313:27 | new[] | test.cpp:314:15:314:16 | xs |
| test.cpp:325:14:325:27 | new[] | test.cpp:326:15:326:16 | xs |
| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... |
| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... |
| test.cpp:326:15:326:16 | xs | test.cpp:338:8:338:15 | * ... |
| test.cpp:326:15:326:16 | xs | test.cpp:341:8:341:17 | * ... |
| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... |
| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... |
| test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... |
| test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... |
| test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs |
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:16 | xs |
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:26 | end |
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:27 | end_plus_one |
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:31 | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:26 | end | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:357:24:357:26 | end | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:16:359:27 | end_plus_one |
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
| test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p |
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
| test.cpp:371:7:371:7 | p | test.cpp:372:15:372:16 | Load: * ... |
| test.cpp:372:16:372:16 | p | test.cpp:372:15:372:16 | Load: * ... |
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:16 | xs |
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:7 | end |
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
| test.cpp:378:15:378:16 | xs | test.cpp:384:14:384:16 | end |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
| test.cpp:381:5:381:7 | end | test.cpp:384:13:384:16 | Load: * ... |
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
| test.cpp:384:14:384:16 | end | test.cpp:384:13:384:16 | Load: * ... |
nodes
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:5:15:5:15 | p | semmle.label | p |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
| test.cpp:6:14:6:15 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:6:15:6:15 | q | semmle.label | q |
| test.cpp:6:15:6:15 | q | semmle.label | q |
| test.cpp:7:16:7:16 | q | semmle.label | q |
| test.cpp:7:16:7:16 | q | semmle.label | q |
| test.cpp:8:14:8:21 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:8:16:8:16 | q | semmle.label | q |
| test.cpp:8:16:8:16 | q | semmle.label | q |
| test.cpp:8:16:8:20 | ... + ... | semmle.label | ... + ... |
| test.cpp:9:16:9:16 | q | semmle.label | q |
| test.cpp:9:16:9:16 | q | semmle.label | q |
| test.cpp:10:16:10:16 | q | semmle.label | q |
| test.cpp:10:16:10:16 | q | semmle.label | q |
| test.cpp:11:16:11:16 | q | semmle.label | q |
| test.cpp:11:16:11:16 | q | semmle.label | q |
| test.cpp:12:16:12:16 | q | semmle.label | q |
| test.cpp:16:15:16:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:17:15:17:15 | p | semmle.label | p |
| test.cpp:17:15:17:22 | ... + ... | semmle.label | ... + ... |
| test.cpp:20:14:20:21 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | semmle.label | ... + ... |
| test.cpp:28:15:28:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:29:15:29:15 | p | semmle.label | p |
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:30:14:30:15 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:30:15:30:15 | q | semmle.label | q |
| test.cpp:30:15:30:15 | q | semmle.label | q |
| test.cpp:31:16:31:16 | q | semmle.label | q |
| test.cpp:31:16:31:16 | q | semmle.label | q |
| test.cpp:32:14:32:21 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:32:16:32:16 | q | semmle.label | q |
| test.cpp:32:16:32:16 | q | semmle.label | q |
| test.cpp:32:16:32:20 | ... + ... | semmle.label | ... + ... |
| test.cpp:33:16:33:16 | q | semmle.label | q |
| test.cpp:33:16:33:16 | q | semmle.label | q |
| test.cpp:34:16:34:16 | q | semmle.label | q |
| test.cpp:34:16:34:16 | q | semmle.label | q |
| test.cpp:35:16:35:16 | q | semmle.label | q |
| test.cpp:35:16:35:16 | q | semmle.label | q |
| test.cpp:36:16:36:16 | q | semmle.label | q |
| test.cpp:40:15:40:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:41:15:41:15 | p | semmle.label | p |
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
| test.cpp:42:14:42:15 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:42:15:42:15 | q | semmle.label | q |
| test.cpp:42:15:42:15 | q | semmle.label | q |
| test.cpp:43:16:43:16 | q | semmle.label | q |
| test.cpp:43:16:43:16 | q | semmle.label | q |
| test.cpp:44:14:44:21 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:44:16:44:16 | q | semmle.label | q |
| test.cpp:44:16:44:16 | q | semmle.label | q |
| test.cpp:44:16:44:20 | ... + ... | semmle.label | ... + ... |
| test.cpp:45:16:45:16 | q | semmle.label | q |
| test.cpp:45:16:45:16 | q | semmle.label | q |
| test.cpp:46:16:46:16 | q | semmle.label | q |
| test.cpp:46:16:46:16 | q | semmle.label | q |
| test.cpp:47:16:47:16 | q | semmle.label | q |
| test.cpp:47:16:47:16 | q | semmle.label | q |
| test.cpp:48:16:48:16 | q | semmle.label | q |
| test.cpp:51:7:51:14 | mk_array indirection | semmle.label | mk_array indirection |
| test.cpp:51:33:51:35 | end | semmle.label | end |
| test.cpp:52:19:52:24 | call to malloc | semmle.label | call to malloc |
| test.cpp:53:5:53:23 | ... = ... | semmle.label | ... = ... |
| test.cpp:53:12:53:16 | begin | semmle.label | begin |
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:60:19:60:26 | call to mk_array | semmle.label | call to mk_array |
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
| test.cpp:62:32:62:34 | end | semmle.label | end |
| test.cpp:62:39:62:39 | p | semmle.label | p |
| test.cpp:66:32:66:34 | end | semmle.label | end |
| test.cpp:66:39:66:39 | p | semmle.label | p |
| test.cpp:67:9:67:14 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:70:31:70:33 | end | semmle.label | end |
| test.cpp:70:38:70:38 | p | semmle.label | p |
| test.cpp:80:9:80:16 | mk_array indirection [begin] | semmle.label | mk_array indirection [begin] |
| test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] |
| test.cpp:82:5:82:28 | ... = ... | semmle.label | ... = ... |
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
| test.cpp:82:17:82:22 | call to malloc | semmle.label | call to malloc |
| test.cpp:83:5:83:30 | ... = ... | semmle.label | ... = ... |
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
| test.cpp:83:15:83:17 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:83:15:83:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:83:19:83:23 | begin | semmle.label | begin |
| test.cpp:83:19:83:23 | begin indirection | semmle.label | begin indirection |
| test.cpp:89:19:89:26 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
| test.cpp:89:19:89:26 | call to mk_array [end] | semmle.label | call to mk_array [end] |
| test.cpp:91:20:91:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:91:24:91:28 | begin | semmle.label | begin |
| test.cpp:91:24:91:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:91:36:91:38 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:91:40:91:42 | end | semmle.label | end |
| test.cpp:91:40:91:42 | end indirection | semmle.label | end indirection |
| test.cpp:91:47:91:47 | p | semmle.label | p |
| test.cpp:95:20:95:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:95:24:95:28 | begin | semmle.label | begin |
| test.cpp:95:24:95:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:95:36:95:38 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:95:40:95:42 | end | semmle.label | end |
| test.cpp:95:40:95:42 | end indirection | semmle.label | end indirection |
| test.cpp:95:47:95:47 | p | semmle.label | p |
| test.cpp:96:9:96:14 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:99:20:99:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:99:24:99:28 | begin | semmle.label | begin |
| test.cpp:99:24:99:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:99:35:99:37 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:99:39:99:41 | end | semmle.label | end |
| test.cpp:99:39:99:41 | end indirection | semmle.label | end indirection |
| test.cpp:99:46:99:46 | p | semmle.label | p |
| test.cpp:104:27:104:29 | arr [begin] | semmle.label | arr [begin] |
| test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] |
| test.cpp:105:20:105:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:105:24:105:28 | begin | semmle.label | begin |
| test.cpp:105:24:105:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:105:36:105:38 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:105:40:105:42 | end | semmle.label | end |
| test.cpp:105:40:105:42 | end indirection | semmle.label | end indirection |
| test.cpp:105:47:105:47 | p | semmle.label | p |
| test.cpp:109:20:109:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:109:24:109:28 | begin | semmle.label | begin |
| test.cpp:109:24:109:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:109:36:109:38 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:109:40:109:42 | end | semmle.label | end |
| test.cpp:109:40:109:42 | end indirection | semmle.label | end indirection |
| test.cpp:109:47:109:47 | p | semmle.label | p |
| test.cpp:110:9:110:14 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:113:20:113:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:113:24:113:28 | begin | semmle.label | begin |
| test.cpp:113:24:113:28 | begin indirection | semmle.label | begin indirection |
| test.cpp:113:35:113:37 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:113:39:113:41 | end | semmle.label | end |
| test.cpp:113:39:113:41 | end indirection | semmle.label | end indirection |
| test.cpp:113:46:113:46 | p | semmle.label | p |
| test.cpp:119:18:119:25 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
| test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] |
| test.cpp:124:15:124:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:125:5:125:17 | ... = ... | semmle.label | ... = ... |
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
| test.cpp:126:15:126:15 | p | semmle.label | p |
| test.cpp:129:11:129:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:129:15:129:19 | begin | semmle.label | begin |
| test.cpp:129:15:129:19 | begin indirection | semmle.label | begin indirection |
| test.cpp:133:11:133:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:133:15:133:19 | begin | semmle.label | begin |
| test.cpp:133:15:133:19 | begin indirection | semmle.label | begin indirection |
| test.cpp:137:11:137:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:137:15:137:19 | begin | semmle.label | begin |
| test.cpp:137:15:137:19 | begin indirection | semmle.label | begin indirection |
| test.cpp:141:10:141:19 | mk_array_p indirection [begin] | semmle.label | mk_array_p indirection [begin] |
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | semmle.label | mk_array_p indirection [end] |
| test.cpp:143:5:143:29 | ... = ... | semmle.label | ... = ... |
| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
| test.cpp:143:18:143:23 | call to malloc | semmle.label | call to malloc |
| test.cpp:144:5:144:32 | ... = ... | semmle.label | ... = ... |
| test.cpp:144:10:144:12 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
| test.cpp:144:16:144:18 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:144:16:144:32 | ... + ... | semmle.label | ... + ... |
| test.cpp:144:21:144:25 | begin | semmle.label | begin |
| test.cpp:144:21:144:25 | begin indirection | semmle.label | begin indirection |
| test.cpp:150:20:150:29 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
| test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
| test.cpp:152:20:152:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:152:25:152:29 | begin | semmle.label | begin |
| test.cpp:152:25:152:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:152:49:152:49 | p | semmle.label | p |
| test.cpp:156:20:156:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:156:25:156:29 | begin | semmle.label | begin |
| test.cpp:156:25:156:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:156:37:156:39 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:156:42:156:44 | end | semmle.label | end |
| test.cpp:156:42:156:44 | end indirection | semmle.label | end indirection |
| test.cpp:156:49:156:49 | p | semmle.label | p |
| test.cpp:157:9:157:14 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:160:20:160:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:160:25:160:29 | begin | semmle.label | begin |
| test.cpp:160:25:160:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:160:48:160:48 | p | semmle.label | p |
| test.cpp:165:29:165:31 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:165:29:165:31 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:166:20:166:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:166:25:166:29 | begin | semmle.label | begin |
| test.cpp:166:25:166:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:166:37:166:39 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:166:42:166:44 | end | semmle.label | end |
| test.cpp:166:42:166:44 | end indirection | semmle.label | end indirection |
| test.cpp:166:49:166:49 | p | semmle.label | p |
| test.cpp:170:20:170:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:170:25:170:29 | begin | semmle.label | begin |
| test.cpp:170:25:170:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:170:37:170:39 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:170:42:170:44 | end | semmle.label | end |
| test.cpp:170:42:170:44 | end indirection | semmle.label | end indirection |
| test.cpp:170:49:170:49 | p | semmle.label | p |
| test.cpp:171:9:171:14 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:174:20:174:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
| test.cpp:174:25:174:29 | begin | semmle.label | begin |
| test.cpp:174:25:174:29 | begin indirection | semmle.label | begin indirection |
| test.cpp:174:36:174:38 | arr indirection [end] | semmle.label | arr indirection [end] |
| test.cpp:174:41:174:43 | end | semmle.label | end |
| test.cpp:174:41:174:43 | end indirection | semmle.label | end indirection |
| test.cpp:174:48:174:48 | p | semmle.label | p |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
| test.cpp:188:15:188:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:189:15:189:15 | p | semmle.label | p |
| test.cpp:194:23:194:28 | call to malloc | semmle.label | call to malloc |
| test.cpp:195:17:195:17 | p | semmle.label | p |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:197:8:197:8 | p | semmle.label | p |
| test.cpp:197:20:197:22 | end | semmle.label | end |
| test.cpp:201:5:201:5 | p | semmle.label | p |
| test.cpp:201:5:201:12 | access to array | semmle.label | access to array |
| test.cpp:201:5:201:19 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:205:23:205:28 | call to malloc | semmle.label | call to malloc |
| test.cpp:206:17:206:17 | p | semmle.label | p |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:208:15:208:15 | p | semmle.label | p |
| test.cpp:209:12:209:14 | end | semmle.label | end |
| test.cpp:213:5:213:6 | * ... | semmle.label | * ... |
| test.cpp:213:5:213:13 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:213:6:213:6 | q | semmle.label | q |
| test.cpp:213:6:213:6 | q | semmle.label | q |
| test.cpp:221:17:221:22 | call to malloc | semmle.label | call to malloc |
| test.cpp:222:5:222:5 | p | semmle.label | p |
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
| test.cpp:232:3:232:9 | newname | semmle.label | newname |
| test.cpp:232:3:232:16 | access to array | semmle.label | access to array |
| test.cpp:232:3:232:20 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
| test.cpp:239:5:239:11 | newname | semmle.label | newname |
| test.cpp:239:5:239:18 | access to array | semmle.label | access to array |
| test.cpp:239:5:239:22 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:248:24:248:30 | call to realloc | semmle.label | call to realloc |
| test.cpp:249:9:249:9 | p | semmle.label | p |
| test.cpp:250:22:250:22 | p | semmle.label | p |
| test.cpp:254:9:254:9 | p | semmle.label | p |
| test.cpp:254:9:254:12 | access to array | semmle.label | access to array |
| test.cpp:254:9:254:16 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
| test.cpp:261:14:261:15 | xs | semmle.label | xs |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:262:26:262:28 | end | semmle.label | end |
| test.cpp:262:26:262:28 | end | semmle.label | end |
| test.cpp:262:31:262:31 | x | semmle.label | x |
| test.cpp:264:13:264:14 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:264:14:264:14 | x | semmle.label | x |
| test.cpp:264:14:264:14 | x | semmle.label | x |
| test.cpp:270:13:270:24 | new[] | semmle.label | new[] |
| test.cpp:271:14:271:15 | xs | semmle.label | xs |
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
| test.cpp:272:26:272:28 | end | semmle.label | end |
| test.cpp:272:26:272:28 | end | semmle.label | end |
| test.cpp:272:31:272:31 | x | semmle.label | x |
| test.cpp:272:31:272:31 | x | semmle.label | x |
| test.cpp:274:5:274:6 | * ... | semmle.label | * ... |
| test.cpp:274:5:274:10 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:274:6:274:6 | x | semmle.label | x |
| test.cpp:274:6:274:6 | x | semmle.label | x |
| test.cpp:280:13:280:24 | new[] | semmle.label | new[] |
| test.cpp:281:14:281:15 | xs | semmle.label | xs |
| test.cpp:290:13:290:24 | new[] | semmle.label | new[] |
| test.cpp:291:14:291:15 | xs | semmle.label | xs |
| test.cpp:292:30:292:30 | x | semmle.label | x |
| test.cpp:304:15:304:26 | new[] | semmle.label | new[] |
| test.cpp:307:5:307:6 | xs | semmle.label | xs |
| test.cpp:308:5:308:6 | xs | semmle.label | xs |
| test.cpp:308:5:308:11 | access to array | semmle.label | access to array |
| test.cpp:308:5:308:29 | Store: ... = ... | semmle.label | Store: ... = ... |
| test.cpp:313:14:313:27 | new[] | semmle.label | new[] |
| test.cpp:314:15:314:16 | xs | semmle.label | xs |
| test.cpp:325:14:325:27 | new[] | semmle.label | new[] |
| test.cpp:326:15:326:16 | xs | semmle.label | xs |
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:338:8:338:15 | * ... | semmle.label | * ... |
| test.cpp:341:8:341:17 | * ... | semmle.label | * ... |
| test.cpp:342:8:342:17 | * ... | semmle.label | * ... |
| test.cpp:347:14:347:27 | new[] | semmle.label | new[] |
| test.cpp:348:15:348:16 | xs | semmle.label | xs |
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
| test.cpp:356:15:356:16 | xs | semmle.label | xs |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:26 | end | semmle.label | end |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
| test.cpp:358:14:358:26 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
| test.cpp:359:14:359:32 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:359:16:359:27 | end_plus_one | semmle.label | end_plus_one |
| test.cpp:359:16:359:31 | ... + ... | semmle.label | ... + ... |
| test.cpp:363:14:363:27 | new[] | semmle.label | new[] |
| test.cpp:365:15:365:15 | p | semmle.label | p |
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
| test.cpp:371:7:371:7 | p | semmle.label | p |
| test.cpp:372:15:372:16 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:372:16:372:16 | p | semmle.label | p |
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
| test.cpp:378:15:378:16 | xs | semmle.label | xs |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
| test.cpp:381:5:381:7 | end | semmle.label | end |
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
| test.cpp:384:13:384:16 | Load: * ... | semmle.label | Load: * ... |
| test.cpp:384:14:384:16 | end | semmle.label | end |
subpaths
#select
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:20:14:20:21 | Load: * ... | test.cpp:16:15:16:20 | call to malloc | test.cpp:20:14:20:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:16:15:16:20 | call to malloc | call to malloc | test.cpp:17:19:17:22 | size | size |
| test.cpp:30:14:30:15 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:30:14:30:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:42:14:42:15 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:67:9:67:14 | Store: ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
| test.cpp:96:9:96:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
@@ -1108,8 +672,3 @@ subpaths
| test.cpp:254:9:254:16 | Store: ... = ... | test.cpp:248:24:248:30 | call to realloc | test.cpp:254:9:254:16 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:248:24:248:30 | call to realloc | call to realloc | test.cpp:254:11:254:11 | i | i |
| test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
| test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
| test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... |
| test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
| test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
| test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size |
| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size |

View File

@@ -293,93 +293,4 @@ void test20(unsigned len)
{
*x = 0; // GOOD
}
}
void* test21_get(int n);
void test21() {
int n = 0;
while (test21_get(n)) n+=2;
void** xs = new void*[n];
for (int i = 0; i < n; i += 2) {
xs[i] = test21_get(i); // GOOD
xs[i+1] = test21_get(i+1); // GOOD [FALSE POSITIVE]
}
}
void test22(unsigned size, int val) {
char *xs = new char[size];
char *end = xs + size; // GOOD
char **current = &end;
do {
if (*current - xs < 1) // GOOD
return;
*--(*current) = 0; // GOOD
val >>= 8;
} while (val > 0);
}
void test23(unsigned size, int val) {
char *xs = new char[size];
char *end = xs + size;
char **current = &end;
if (val < 1) {
if(*current - xs < 1)
return;
*--(*current) = 0; // GOOD
return;
}
if (val < 2) {
if(*current - xs < 2)
return;
*--(*current) = 0; // GOOD
*--(*current) = 0; // GOOD
}
}
void test24(unsigned size) {
char *xs = new char[size];
char *end = xs + size;
if (xs < end) {
int val = *xs++; // GOOD
}
}
void test25(unsigned size) {
char *xs = new char[size];
char *end = xs + size;
char *end_plus_one = end + 1;
int val1 = *end_plus_one; // BAD
int val2 = *(end_plus_one + 1); // BAD
}
void test26(unsigned size) {
char *xs = new char[size];
char *p = xs;
char *end = p + size;
if (p + 4 <= end) {
p += 4;
}
if (p < end) {
int val = *p; // GOOD [FALSE POSITIVE]
}
}
void test27(unsigned size, bool b) {
char *xs = new char[size];
char *end = xs + size;
if (b) {
end++;
}
int val = *end; // BAD
}
}

View File

@@ -1,4 +1,2 @@
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:9,8-47)
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:20,49-74)
failures
testFailures

View File

@@ -38,10 +38,12 @@ predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag
)
}
module IRDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = ["ir-path", "ir-sink"] }
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element elem, TaintedWithPath::PathNode node, int n |
irTaint(_, node, tag) and
elem = getElementFromPathNode(node) and
@@ -65,10 +67,12 @@ module IRDefaultTaintTrackingTest implements TestSig {
}
}
module AstTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ast" }
class AstTaintTrackingTest extends InlineExpectationsTest {
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ast" and
astTaint(source, tainted) and
@@ -96,5 +100,3 @@ module AstTaintTrackingTest implements TestSig {
)
}
}
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>

View File

@@ -1,4 +1,2 @@
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:10,8-47)
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:21,3-28)
failures
testFailures

View File

@@ -29,10 +29,12 @@ predicate irTaint(Expr source, Element sink) {
TaintedWithPath::taintedWithPath(source, sink, _, _)
}
module IRDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ir" }
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ir" and
irTaint(source, tainted) and
@@ -53,10 +55,12 @@ module IRDefaultTaintTrackingTest implements TestSig {
}
}
module AstTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ast" }
class AstTaintTrackingTest extends InlineExpectationsTest {
AstTaintTrackingTest() { this = "ASTTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ast" and
astTaint(source, tainted) and
@@ -76,5 +80,3 @@ module AstTaintTrackingTest implements TestSig {
)
}
}
import MakeTest<MergeTests<IRDefaultTaintTrackingTest, AstTaintTrackingTest>>

View File

@@ -1,4 +1,2 @@
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:8,3-47)
WARNING: Predicate taintedIncludingGlobalVars has been deprecated and may be removed in future (global.ql:12,3-53)
failures
testFailures

View File

@@ -12,10 +12,12 @@ predicate irTaint(Expr source, Element sink, string globalVar) {
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
}
module IRGlobalDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ir" }
class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
IRGlobalDefaultTaintTrackingTest() { this = "IRGlobalDefaultTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element tainted |
tag = "ir" and
irTaint(_, tainted, value) and
@@ -25,10 +27,12 @@ module IRGlobalDefaultTaintTrackingTest implements TestSig {
}
}
module AstGlobalDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ast" }
class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
AstGlobalDefaultTaintTrackingTest() { this = "ASTGlobalDefaultTaintTrackingTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element tainted |
tag = "ast" and
astTaint(_, tainted, value) and
@@ -37,5 +41,3 @@ module AstGlobalDefaultTaintTrackingTest implements TestSig {
)
}
}
import MakeTest<MergeTests<IRGlobalDefaultTaintTrackingTest, AstGlobalDefaultTaintTrackingTest>>

View File

@@ -1,7 +1,7 @@
// semmle-extractor-options: --edg --clang
int source();
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
void sink(int); void sink(const int *); void sink(int **);
struct twoIntFields {
int m1, m2;
@@ -19,8 +19,7 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
sink(sourceArray1[0]); // no flow
sink(*sourceArray1); // no flow
sink(&sourceArray1); // $ ast // [should probably be taint only]
indirect_sink(&sourceArray1); // $ ast,ir
sink(&sourceArray1); // $ ast,ir // [should probably be taint only]
sink(sourceStruct1.m1); // no flow
sink(sourceStruct1_ptr->m1); // no flow
@@ -49,6 +48,5 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
int stackArray[2] = { source(), source() };
stackArray[0] = source();
sink(stackArray); // $ ast,ir
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
sink(stackArray); // $ ast ir ir=49:25 ir=49:35 ir=50:19
}

View File

@@ -28,10 +28,9 @@ postWithInFlow
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:9:22:20 | sourceArray1 [inner post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:23:18:23:29 | sourceArray1 [inner post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:29:22:29:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:51:3:51:12 | stackArray [inner post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:51:3:51:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:12 | stackArray [inner post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:61:3:61:14 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:24:78:37 | call to allocateBottom [inner post update] | PostUpdateNode should not be the target of local flow. |
@@ -126,8 +125,6 @@ postWithInFlow
| test.cpp:681:3:681:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:689:3:689:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:694:4:694:6 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:704:23:704:25 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition

View File

@@ -5,10 +5,12 @@ module AstTest {
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
module AstParameterDefTest implements TestSig {
string getARelevantTag() { result = "ast-def" }
class AstParameterDefTest extends InlineExpectationsTest {
AstParameterDefTest() { this = "AstParameterDefTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ast-def" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Function f, Parameter p, RefParameterFinalValueNode n |
p.isNamed() and
n.getParameter() = p and
@@ -31,10 +33,12 @@ module IRTest {
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
module IRParameterDefTest implements TestSig {
string getARelevantTag() { result = "ir-def" }
class IRParameterDefTest extends InlineExpectationsTest {
IRParameterDefTest() { this = "IRParameterDefTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ir-def" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Function f, Parameter p, FinalParameterNode n |
p.isNamed() and
n.getParameter() = p and
@@ -47,5 +51,3 @@ module IRTest {
}
}
}
import MakeTest<MergeTests<AstTest::AstParameterDefTest, IRTest::IRParameterDefTest>>

View File

@@ -5,10 +5,12 @@ module AstTest {
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
module AstMultipleOutNodesTest implements TestSig {
string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
class AstMultipleOutNodesTest extends InlineExpectationsTest {
AstMultipleOutNodesTest() { this = "AstMultipleOutNodesTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlowCall call, int n, ReturnKind kind |
call.getLocation() = location and
n = strictcount(getAnOutNode(call, kind)) and
@@ -25,10 +27,12 @@ module IRTest {
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
module IRMultipleOutNodesTest implements TestSig {
string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
class IRMultipleOutNodesTest extends InlineExpectationsTest {
IRMultipleOutNodesTest() { this = "IRMultipleOutNodesTest" }
predicate hasActualResult(Location location, string element, string tag, string value) {
override string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlowCall call, int n, ReturnKind kind |
call.getLocation() = location and
n = strictcount(getAnOutNode(call, kind)) and
@@ -40,5 +44,3 @@ module IRTest {
}
}
}
import MakeTest<MergeTests<AstTest::AstMultipleOutNodesTest, IRTest::IRMultipleOutNodesTest>>

View File

@@ -1,5 +1,5 @@
int source();
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
void sink(int); void sink(const int *); void sink(int **);
void intraprocedural_with_local_flow() {
int t2;
@@ -626,7 +626,7 @@ void test_def_via_phi_read(bool b)
use(buffer);
}
intPointerSource(buffer);
indirect_sink(buffer); // $ ast,ir
sink(buffer); // $ ast,ir
}
void test_static_local_1() {
@@ -690,16 +690,3 @@ void test_static_local_9() {
s = 0;
}
void increment_buf(int** buf) { // $ ast-def=buf ir-def=*buf ir-def=**buf
*buf += 10;
sink(buf); // $ SPURIOUS: ast
}
void call_increment_buf(int** buf) { // $ ast-def=buf
increment_buf(buf);
}
void test_conflation_regression(int* source) { // $ ast-def=source
int* buf = source;
call_increment_buf(&buf);
}

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -16,8 +16,10 @@ module AstTest {
}
/** Common data flow configuration to be used by tests. */
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
class AstTestAllocationConfig extends DataFlow::Configuration {
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
@@ -30,20 +32,18 @@ module AstTest {
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = ["sink", "indirect_sink"] and
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
predicate isBarrier(DataFlow::Node barrier) {
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
}
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
}
module IRTest {
@@ -67,8 +67,10 @@ module IRTest {
}
/** Common data flow configuration to be used by tests. */
module IRTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
class IRTestAllocationConfig extends DataFlow::Configuration {
IRTestAllocationConfig() { this = "IRTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
@@ -80,17 +82,14 @@ module IRTest {
exists(source.asUninitialized())
}
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = e
or
call.getTarget().getName() = "indirect_sink" and
sink.asIndirectExpr() = e
call.getAnArgument() in [sink.asExpr(), sink.asIndirectExpr()]
)
}
predicate isBarrier(DataFlow::Node barrier) {
override predicate isBarrier(DataFlow::Node barrier) {
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
)
@@ -100,8 +99,4 @@ module IRTest {
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
}
}
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

Some files were not shown because too many files have changed in this diff Show More