Merge branch 'main' into jcogs33/update-javascript-sink-kinds

This commit is contained in:
Jami
2023-06-01 14:09:10 -04:00
committed by GitHub
1019 changed files with 61542 additions and 25712 deletions

View File

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

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('ql/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo
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('ruby/extractor/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
- uses: actions/cache@v3
if: steps.cache-extractor.outputs.cache-hit != 'true'
with:

View File

@@ -16,6 +16,7 @@ on:
branches:
- main
- rc/*
- codeql-cli-*
push:
paths:
- "swift/**"
@@ -30,6 +31,7 @@ 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,4 +17,6 @@ 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,6 +22,22 @@
"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

@@ -40,3 +40,6 @@ 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

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

View File

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

View File

@@ -1,3 +1,19 @@
## 0.7.2
### New Features
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
### Major Analysis Improvements
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
### Minor Analysis Improvements
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
## 0.7.1
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.

View File

@@ -0,0 +1,15 @@
## 0.7.2
### New Features
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
### Major Analysis Improvements
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
### Minor Analysis Improvements
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.1
lastReleaseVersion: 0.7.2

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.7.2-dev
version: 0.7.3-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

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().splitAt("(", 0) }
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
/** Holds if the macro has name `name`. */
predicate hasName(string name) { this.getName() = name }

View File

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

View File

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

View File

@@ -210,8 +210,8 @@ class IndirectOperand extends Node {
this.(RawIndirectOperand).getOperand() = operand and
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
or
this.(OperandNode).getOperand() =
Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex)
nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex),
indirectionIndex - 1)
}
/** Gets the underlying operand. */
@@ -250,8 +250,8 @@ class IndirectInstruction extends Node {
this.(RawIndirectInstruction).getInstruction() = instr and
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
or
this.(InstructionNode).getInstruction() =
Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex)
nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex),
indirectionIndex - 1)
}
/** Gets the underlying instruction. */

View File

@@ -1640,8 +1640,15 @@ 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
private module ExprFlowCached {
module ExprFlowCached {
/**
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
* `e` is the result of loading from the `PointerArithmeticInstruction`.
@@ -1692,7 +1699,8 @@ private module ExprFlowCached {
* `x[i]` steps to the expression `x[i - 1]` without traversing the
* entire chain.
*/
private Expr asExpr(Node n) {
cached
Expr asExprInternal(Node n) {
isIndirectBaseOfArrayAccess(n, result)
or
not isIndirectBaseOfArrayAccess(n, _) and
@@ -1704,7 +1712,7 @@ private module ExprFlowCached {
* dataflow step.
*/
private predicate localStepFromNonExpr(Node n1, Node n2) {
not exists(asExpr(n1)) and
not exists(asExprInternal(n1)) and
localFlowStep(n1, n2)
}
@@ -1715,7 +1723,7 @@ private module ExprFlowCached {
pragma[nomagic]
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
localStepFromNonExpr*(n1, n2) and
e2 = asExpr(n2)
e2 = asExprInternal(n2)
}
/**
@@ -1726,7 +1734,7 @@ private module ExprFlowCached {
exists(Node mid |
localFlowStep(n1, mid) and
localStepsToExpr(mid, n2, e2) and
e1 = asExpr(n1)
e1 = asExprInternal(n1)
)
}

View File

@@ -60,7 +60,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
}
private DataFlow::Node getNodeForExpr(Expr node) {
result = DataFlow::exprNode(node)
node = DataFlow::ExprFlowCached::asExprInternal(result)
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, _) |
node = DataFlow::exprNode(source)
source = DataFlow::ExprFlowCached::asExprInternal(node)
or
// This case goes together with the similar (but not identical) rule in
// `getNodeForSource`.

View File

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

View File

@@ -1,119 +1,44 @@
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(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)
private string getFromFlow(Node node2, int order1, int order2) {
exists(Node node1 |
simpleLocalFlowStep(node1, node2) and
result = nodeId(node1, order1, order2)
)
}
/**
* Gets the local dataflow from this node to other nodes in the same function.
*/
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)
private string getToFlow(Node node1, int order1, int order2) {
exists(Node node2 |
simpleLocalFlowStep(node1, node2) and
result = nodeId(node2, order1, order2)
)
}
/**
* Gets the properties of the dataflow node `node`.
*/
private string getNodeProperty(DataFlow::Node node, string key) {
private string getNodeProperty(Node node, string key) {
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
// 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) + "->@" and to = false
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
or
flow = "@->" + getToFlow(node, order1, order2) and to = true
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
|
flow, ", " order by to, order1, order2, flow
)
or
// Is this node a dataflow sink?
key = "sink" and
any(DataFlow::Configuration cfg).isSink(node) and
result = "true"
or
// Is this node a dataflow source?
key = "source" and
any(DataFlow::Configuration cfg).isSource(node) and
result = "true"
or
// Is this node a dataflow barrier, and if so, what kind?
key = "barrier" and
result =
strictconcat(string kind |
any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full"
or
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
or
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
|
kind, ", "
)
// or
// // Is there partial flow from a source to this node?
// // This property will only be emitted if partial flow is enabled by overriding
// // `DataFlow::Configuration::explorationLimit()`.
// key = "pflow" and
// result =
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
// int order1, int order2 |
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
// destNode.getNode() = node and
// // Only print flow from a source in the same function.
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
// |
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
// order by
// order1, order2, dist desc
// )
}
/**
@@ -121,16 +46,21 @@ private string getNodeProperty(DataFlow::Node node, string key) {
*/
class LocalFlowPropertyProvider extends IRPropertyProvider {
override string getOperandProperty(Operand operand, string key) {
exists(DataFlow::Node node |
operand = node.asOperand() and
exists(Node node |
operand = [node.asOperand(), node.(RawIndirectOperand).getOperand()] and
result = getNodeProperty(node, key)
)
}
override string getInstructionProperty(Instruction instruction, string key) {
exists(DataFlow::Node node |
instruction = node.asInstruction() and
exists(Node node |
instruction = [node.asInstruction(), node.(RawIndirectInstruction).getInstruction()]
|
result = getNodeProperty(node, key)
)
}
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
}

View File

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

View File

@@ -3,37 +3,59 @@
*/
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 string stars(int k) {
k =
[0 .. max([
any(RawIndirectInstruction n).getIndirectionIndex(),
any(RawIndirectOperand n).getIndirectionIndex()
]
)] and
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
string starsForNode(Node node) {
result = stars(node.(IndirectInstruction).getIndirectionIndex())
or
result = stars(node.(IndirectOperand).getIndirectionIndex())
or
not node instanceof IndirectInstruction and
not node instanceof IndirectOperand and
result = ""
}
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
stars = starsForNode(n)
}
private Operand getOperand(Node n, string stars) {
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
stars = starsForNode(n)
}
/**
* Gets a short ID for an IR dataflow node.
* - 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(DataFlow::Node node, int order1, int order2) {
exists(Instruction instruction | instruction = node.asInstruction() |
result = instruction.getResultId() and
string nodeId(Node node, int order1, int order2) {
exists(Instruction instruction, string stars | instruction = getInstruction(node, stars) |
result = stars + instruction.getResultId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
exists(Operand operand, Instruction instruction |
operand = node.asOperand() and
exists(Operand operand, Instruction instruction, string stars |
operand = getOperand(node, stars) and
instruction = operand.getUse()
|
result = instruction.getResultId() + "." + operand.getDumpId() and
result = stars + 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

@@ -1,10 +1,29 @@
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
/**
* 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
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.
@@ -70,6 +89,9 @@ 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;
@@ -138,6 +160,7 @@ module ProductFlow {
import GlobalWithState<StateConfig>
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState1;
@@ -247,6 +270,9 @@ 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;
@@ -260,6 +286,7 @@ 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
) {
@@ -290,9 +317,9 @@ module ProductFlow {
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
}
module Flow1 = DataFlow::GlobalWithState<Config1>;
private module Flow1 = DataFlow::GlobalWithState<Config1>;
module Config2 implements DataFlow::StateConfigSig {
private module Config2 implements DataFlow::StateConfigSig {
class FlowState = FlowState2;
predicate isSource(DataFlow::Node source, FlowState state) {
@@ -322,27 +349,90 @@ module ProductFlow {
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
}
module Flow2 = DataFlow::GlobalWithState<Config2>;
private module Flow2 = DataFlow::GlobalWithState<Config2>;
private predicate isSourcePair(Flow1::PathNode node1, Flow2::PathNode node2) {
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
}
private predicate isSinkPair(Flow1::PathNode node1, Flow2::PathNode node2) {
Config::isSinkPair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState())
}
pragma[assume_small_delta]
pragma[nomagic]
private predicate fwdReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
isSourcePair(node1, node2)
or
fwdIsSuccessor(_, _, node1, node2)
}
pragma[nomagic]
private predicate reachableInterprocEntry(
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
private predicate fwdIsSuccessorExit(
Flow1::PathNode mid1, Flow2::PathNode mid2, Flow1::PathNode succ1, Flow2::PathNode succ2
) {
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
node1 = source1 and
node2 = source2
isSinkPair(mid1, mid2) and
succ1 = mid1 and
succ2 = mid2
or
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)
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)
)
}
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()) =
@@ -474,11 +564,14 @@ module ProductFlow {
private predicate reachable(
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
) {
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)
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
)
}
}

View File

@@ -657,24 +657,16 @@ 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(
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
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
exists(DefOrUse defOrUse, Node adjusted |
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
nodeToDefOrUse(adjusted, defOrUse, _) 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
@@ -719,14 +711,19 @@ predicate ssaFlow(Node nodeFrom, Node nodeTo) {
)
}
private predicate isArgumentOfCallable(DataFlowCall call, ArgumentNode arg) {
arg.argumentOf(call, _)
}
/** Holds if there is def-use or use-use flow from `pun` to `nodeTo`. */
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
exists(Node preUpdate, Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
exists(UseOrPhi use, Node preUpdate |
adjustForPointerArith(pun, use) and
useToNode(use, nodeTo) and
preUpdate = pun.getPreUpdateNode() and
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain)
|
if uncertain = true
then preUpdate = [nFrom, getAPriorDefinition(defOrUse)]
else preUpdate = nFrom
not exists(DataFlowCall call |
isArgumentOfCallable(call, preUpdate) and isArgumentOfCallable(call, nodeTo)
)
)
}

View File

@@ -77,4 +77,16 @@ 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

@@ -42,6 +42,14 @@ 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))
}
@@ -84,7 +92,9 @@ 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) { shouldPrintFunction(instr.getEnclosingFunction()) }
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
/**
* A node to be emitted in the IR graph.
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand()
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

View File

@@ -77,4 +77,16 @@ 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

@@ -42,6 +42,14 @@ 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))
}
@@ -84,7 +92,9 @@ 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) { shouldPrintFunction(instr.getEnclosingFunction()) }
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
/**
* A node to be emitted in the IR graph.
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand()
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

View File

@@ -77,4 +77,16 @@ 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

@@ -42,6 +42,14 @@ 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))
}
@@ -84,7 +92,9 @@ 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) { shouldPrintFunction(instr.getEnclosingFunction()) }
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
}
/**
* A node to be emitted in the IR graph.
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand()
operand = instr.getAnOperand() and
shouldPrintOperand(operand)
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by

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, d1) and
boundedUpper(e, b, d2) and
boundedLower(e, b, d2) and
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
)

View File

@@ -1,3 +1,7 @@
## 0.6.2
No user-facing changes.
## 0.6.1
### New Queries

View File

@@ -4,16 +4,17 @@
* 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
* experimental
* external/cwe/cwe-119
* external/cwe/cwe-131
*/
import cpp
import experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.ArrayFunction
@@ -122,13 +123,9 @@ module ValidState {
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
exists(AddInstruction add, Operand op, int delta |
add.hasOperands(node1.asOperand(), op) and
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
node2.asInstruction() = add and
state1 = [false, true] and
state2 = state1.booleanNot()
)
isAdditionalFlowStep2(node1, node2, _) and
state1 = [false, true] and
state2 = state1.booleanNot()
}
predicate includeHiddenNodes() { any() }

View File

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

View File

@@ -0,0 +1,3 @@
## 0.6.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.1
lastReleaseVersion: 0.6.2

View File

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

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 PointerArithmeticToDerefFlow::PathGraph
import FieldAddressToDerefFlow::PathGraph
pragma[nomagic]
Instruction getABoundIn(SemBound b, IRFunction func) {
@@ -42,21 +42,6 @@ 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
@@ -93,38 +78,96 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
)
}
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
)
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
}
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
isConstantSizeOverflowSource(_, source.asInstruction(), _)
pointerArithOverflow0(source.asInstruction(), _, _, _, _)
}
pragma[inline]
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
}
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, PointerArithmeticToDerefFlow::PathNode source,
PointerArithmeticToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
where
PointerArithmeticToDerefFlow::flowPath(source, sink) and
FieldAddressToDerefFlow::flowPath(source, sink) and
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
isConstantSizeOverflowSource(f, source.getNode().asInstruction(), delta)
select source, source, sink,
source.getState() = FieldAddressToDerefConfig::TArray(f) and
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
pointerArithOverflow(pai, f, _, _, delta)
select pai, 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 experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.ir.dataflow.internal.ProductFlow
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
@@ -48,44 +48,23 @@ bindingset[b]
pragma[inline_late]
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
/**
* 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, _)
)
}
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) {
hasSizeImpl(alloc.getSizeExpr(), n, state)
exists(VariableAccess va, Expr size, int delta |
size = alloc.getSizeExpr() and
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
va = unique( | | getAVariableAccess(size)) and
// Compute `delta` as the constant difference between `x` and `x + 1`.
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
n.asConvertedExpr() = va.getFullyConverted() and
state = delta
)
}
/**
@@ -102,8 +81,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
* ```
*
* We do this by splitting the task up into two configurations:
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
*
* Finally, the range-analysis library will find a load from (or store to) an address that
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
@@ -201,13 +180,13 @@ predicate isSinkImpl(
}
/**
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
* reads from an address that non-strictly upper-bounds `sink`.
*/
pragma[inline]
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
exists(AddressOperand addr, int delta |
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
exists(AddressOperand addr |
bounded1(addr.getDef(), sink.asInstruction(), delta) and
delta >= 0 and
i.getAnOperand() = addr
@@ -222,13 +201,13 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
/**
* A configuration to track flow from a pointer-arithmetic operation found
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
* by `AllocToInvalidPointerConfig` 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)
@@ -258,17 +237,17 @@ predicate invalidPointerToDerefSource(
}
newtype TMergedPathNode =
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
// The path nodes computed by `InvalidPointerToDerefConf`
// The path nodes computed by `InvalidPointerToDerefConfig`
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` 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, _)
isInvalidPointerDerefSink(n, i, _, _)
)
}
@@ -342,12 +321,30 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
or
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
or
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _, _)
}
query predicate nodes(MergedPathNode n, string key, string val) {
AllocToInvalidPointerFlow::PathGraph1::nodes(n.asPathNode1(), key, val)
or
InvalidPointerToDerefFlow::PathGraph::nodes(n.asPathNode3(), key, val)
or
key = "semmle.label" and val = n.asSinkNode().toString()
}
query predicate subpaths(
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
) {
AllocToInvalidPointerFlow::PathGraph1::subpaths(arg.asPathNode1(), par.asPathNode1(),
ret.asPathNode1(), out.asPathNode1())
or
InvalidPointerToDerefFlow::PathGraph::subpaths(arg.asPathNode3(), par.asPathNode3(),
ret.asPathNode3(), out.asPathNode3())
}
/**
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
* Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
* of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
*/
predicate joinOn1(
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
@@ -358,37 +355,37 @@ predicate joinOn1(
}
/**
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
* Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
* that dereferences `p1`. The string `operation` describes whether the `i` is
* a `StoreInstruction` or `LoadInstruction`.
*/
pragma[inline]
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
isInvalidPointerDerefSink(p1.getNode(), i, operation)
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation, int delta) {
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
}
predicate hasFlowPath(
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
PointerArithmeticInstruction pai, string operation
PointerArithmeticInstruction pai, string operation, int delta
) {
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)
joinOn2(sink3, sink.asSinkNode(), operation, delta)
)
}
from
MergedPathNode source, MergedPathNode sink, int k, string kstr,
MergedPathNode source, MergedPathNode sink, int k2, int k3, string kstr,
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
Expr offset, DataFlow::Node n
where
hasFlowPath(source, sink, source3, pai, operation) and
invalidPointerToDerefSource(pai, source3.getNode(), k) and
hasFlowPath(source, sink, source3, pai, operation, k3) and
invalidPointerToDerefSource(pai, source3.getNode(), k2) and
offset = pai.getRight().getUnconvertedResultExpression() and
n = source.asPathNode1().getNode() and
if k = 0 then kstr = "" else kstr = " + " + k
if (k2 + k3) = 0 then kstr = "" else kstr = " + " + (k2 + k3)
select sink, source, sink,
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
".", n, n.toString(), offset, offset.toString()

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.6.2-dev
version: 0.6.3-dev
groups:
- cpp
- queries

View File

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

View File

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

View File

@@ -1,37 +1,46 @@
edges
| 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: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:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
| test.cpp:77:27:77:44 | access to array | test.cpp:77:26:77:44 | & ... |
| 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 |
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: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:70:33:70:33 | 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:27:77:44 | access to array | semmle.label | access to array |
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
subpaths
#select
| test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
| test.cpp: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 |
| 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 |

View File

@@ -78,3 +78,45 @@ 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

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

View File

@@ -304,7 +304,71 @@ void test21() {
void** xs = new void*[n];
for (int i = 0; i < n; i += 2) {
xs[i] = test21_get(i);
xs[i+1] = test21_get(i+1);
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 [FALSE POSITIVE]
return;
}
if (val < 2) {
if(*current - xs < 2)
return;
*--(*current) = 0; // GOOD [FALSE POSITIVE]
*--(*current) = 0; // GOOD
}
}
void test24(unsigned size) {
char *xs = new char[size];
char *end = xs + size;
if (xs < end) {
int val = *xs++; // GOOD [FALSE POSITIVE]
}
}
void test25(unsigned size) {
char *xs = new char[size];
char *end = xs + size;
char *end_plus_one = end + 1;
int val1 = *end_plus_one; // BAD
int val2 = *(end_plus_one + 1); // BAD
}
void test26(unsigned size) {
char *xs = new char[size];
char *p = xs;
char *end = p + size;
if (p + 4 <= end) {
p += 4;
}
if (p < end) {
int val = *p; // GOOD [FALSE POSITIVE]
}
}

View File

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

View File

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

View File

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

View File

@@ -12,12 +12,10 @@ predicate irTaint(Expr source, Element sink, string globalVar) {
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
}
class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
IRGlobalDefaultTaintTrackingTest() { this = "IRGlobalDefaultTaintTrackingTest" }
module IRGlobalDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ir" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element tainted |
tag = "ir" and
irTaint(_, tainted, value) and
@@ -27,12 +25,10 @@ class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
}
}
class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
AstGlobalDefaultTaintTrackingTest() { this = "ASTGlobalDefaultTaintTrackingTest" }
module AstGlobalDefaultTaintTrackingTest implements TestSig {
string getARelevantTag() { result = "ast" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element tainted |
tag = "ast" and
astTaint(_, tainted, value) and
@@ -41,3 +37,5 @@ class AstGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
)
}
}
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 sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
struct twoIntFields {
int m1, m2;
@@ -19,7 +19,8 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
sink(sourceArray1[0]); // no flow
sink(*sourceArray1); // no flow
sink(&sourceArray1); // $ ast,ir // [should probably be taint only]
sink(&sourceArray1); // $ ast // [should probably be taint only]
indirect_sink(&sourceArray1); // $ ast,ir
sink(sourceStruct1.m1); // no flow
sink(sourceStruct1_ptr->m1); // no flow
@@ -48,5 +49,6 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr
int stackArray[2] = { source(), source() };
stackArray[0] = source();
sink(stackArray); // $ ast ir ir=49:25 ir=49:35 ir=50:19
sink(stackArray); // $ ast,ir
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
}

View File

@@ -28,9 +28,10 @@ postWithInFlow
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp: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: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. |
| 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. |
| 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. |

View File

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

View File

@@ -5,12 +5,10 @@ module AstTest {
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
class AstMultipleOutNodesTest extends InlineExpectationsTest {
AstMultipleOutNodesTest() { this = "AstMultipleOutNodesTest" }
module AstMultipleOutNodesTest implements TestSig {
string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
override string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
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
@@ -27,12 +25,10 @@ module IRTest {
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
class IRMultipleOutNodesTest extends InlineExpectationsTest {
IRMultipleOutNodesTest() { this = "IRMultipleOutNodesTest" }
module IRMultipleOutNodesTest implements TestSig {
string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
override string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
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
@@ -44,3 +40,5 @@ 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 sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
void intraprocedural_with_local_flow() {
int t2;
@@ -626,7 +626,7 @@ void test_def_via_phi_read(bool b)
use(buffer);
}
intPointerSource(buffer);
sink(buffer); // $ ast,ir
indirect_sink(buffer); // $ ast,ir
}
void test_static_local_1() {
@@ -692,7 +692,7 @@ void test_static_local_9() {
void increment_buf(int** buf) { // $ ast-def=buf ir-def=*buf ir-def=**buf
*buf += 10;
sink(buf); // $ SPURIOUS: ast,ir // should only be flow to the indirect argument, but there's also flow to the non-indirect argument
sink(buf); // $ SPURIOUS: ast
}
void call_increment_buf(int** buf) { // $ ast-def=buf

View File

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

View File

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

View File

@@ -1,10 +1,8 @@
private import semmle.code.cpp.dataflow.DataFlow
private import DataFlow
class AstConf extends Configuration {
AstConf() { this = "ASTFieldFlowConf" }
override predicate isSource(Node src) {
module AstConfig implements ConfigSig {
predicate isSource(Node src) {
src.asExpr() instanceof NewExpr
or
src.asExpr().(Call).getTarget().hasName("user_input")
@@ -15,14 +13,14 @@ class AstConf extends Configuration {
)
}
override predicate isSink(Node sink) {
predicate isSink(Node sink) {
exists(Call c |
c.getTarget().hasName("sink") and
c.getAnArgument() = sink.asExpr()
)
}
override predicate isAdditionalFlowStep(Node a, Node b) {
predicate isAdditionalFlowStep(Node a, Node b) {
b.asPartialDefinition() =
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
.getQualifier()
@@ -31,5 +29,4 @@ class AstConf extends Configuration {
}
}
/** DEPRECATED: Alias for AstConf */
deprecated class ASTConf = AstConf;
module AstFlow = Global<AstConfig>;

View File

@@ -1,10 +1,8 @@
private import semmle.code.cpp.ir.dataflow.DataFlow
private import DataFlow
class IRConf extends Configuration {
IRConf() { this = "IRFieldFlowConf" }
override predicate isSource(Node src) {
module IRConfig implements ConfigSig {
predicate isSource(Node src) {
src.asExpr() instanceof NewExpr
or
src.asExpr().(Call).getTarget().hasName("user_input")
@@ -15,14 +13,14 @@ class IRConf extends Configuration {
)
}
override predicate isSink(Node sink) {
predicate isSink(Node sink) {
exists(Call c |
c.getTarget().hasName("sink") and
c.getAnArgument() = [sink.asExpr(), sink.asIndirectExpr(), sink.asConvertedExpr()]
)
}
override predicate isAdditionalFlowStep(Node a, Node b) {
predicate isAdditionalFlowStep(Node a, Node b) {
b.asPartialDefinition() =
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
.getQualifier()
@@ -30,3 +28,5 @@ class IRConf extends Configuration {
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
}
}
module IRFlow = Global<IRConfig>;

View File

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

View File

@@ -1,9 +1,11 @@
import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import ASTConfiguration
import ASTConfiguration
}
module IRTest {
private import IRConfiguration
import IRConfiguration
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -4,8 +4,8 @@
import semmle.code.cpp.ir.dataflow.DataFlow
import IRConfiguration
import DataFlow::PathGraph
import IRFlow::PathGraph
from DataFlow::PathNode src, DataFlow::PathNode sink, IRConf conf
where conf.hasFlowPath(src, sink)
from IRFlow::PathNode src, IRFlow::PathNode sink
where IRFlow::flowPath(src, sink)
select sink, src, sink, sink + " flows from $@", src, src.toString()

View File

@@ -4,8 +4,8 @@
import semmle.code.cpp.dataflow.DataFlow
import ASTConfiguration
import DataFlow::PathGraph
import AstFlow::PathGraph
from DataFlow::PathNode src, DataFlow::PathNode sink, AstConf conf
where conf.hasFlowPath(src, sink)
from AstFlow::PathNode src, AstFlow::PathNode sink
where AstFlow::flowPath(src, sink)
select sink, src, sink, sink + " flows from $@", src, src.toString()

View File

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

View File

@@ -3,37 +3,39 @@ import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import semmle.code.cpp.dataflow.TaintTracking
class AstSmartPointerTaintConfig extends TaintTracking::Configuration {
AstSmartPointerTaintConfig() { this = "ASTSmartPointerTaintConfig" }
override predicate isSource(DataFlow::Node source) {
module AstSmartPointerTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
}
module AstFlow = TaintTracking::Global<AstSmartPointerTaintConfig>;
}
module IRTest {
private import semmle.code.cpp.ir.dataflow.TaintTracking
class IRSmartPointerTaintConfig extends TaintTracking::Configuration {
IRSmartPointerTaintConfig() { this = "IRSmartPointerTaintConfig" }
override predicate isSource(DataFlow::Node source) {
module IRSmartPointerTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
}
module IRFlow = TaintTracking::Global<IRSmartPointerTaintConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

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

View File

@@ -4,12 +4,10 @@ import cpp
import TestUtilities.InlineExpectationsTest
import semmle.code.cpp.security.FlowSources
class LocalFlowSourceTest extends InlineExpectationsTest {
LocalFlowSourceTest() { this = "LocalFlowSourceTest" }
module LocalFlowSourceTest implements TestSig {
string getARelevantTag() { result = "local_source" }
override string getARelevantTag() { result = "local_source" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "local_source" and
exists(LocalFlowSource node, int n |
n =
@@ -30,3 +28,5 @@ class LocalFlowSourceTest extends InlineExpectationsTest {
)
}
}
import MakeTest<LocalFlowSourceTest>

View File

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

View File

@@ -4,12 +4,10 @@ import cpp
import TestUtilities.InlineExpectationsTest
import semmle.code.cpp.security.FlowSources
class RemoteFlowSourceTest extends InlineExpectationsTest {
RemoteFlowSourceTest() { this = "RemoteFlowSourceTest" }
module RemoteFlowSourceTest implements TestSig {
string getARelevantTag() { result = "remote_source" }
override string getARelevantTag() { result = "remote_source" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "remote_source" and
exists(RemoteFlowSource node, int n |
n =
@@ -31,12 +29,10 @@ class RemoteFlowSourceTest extends InlineExpectationsTest {
}
}
class RemoteFlowSinkTest extends InlineExpectationsTest {
RemoteFlowSinkTest() { this = "RemoteFlowSinkTest" }
module RemoteFlowSinkTest implements TestSig {
string getARelevantTag() { result = "remote_sink" }
override string getARelevantTag() { result = "remote_sink" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "remote_sink" and
exists(RemoteFlowSink node, int n |
n =
@@ -57,3 +53,5 @@ class RemoteFlowSinkTest extends InlineExpectationsTest {
)
}
}
import MakeTest<MergeTests<RemoteFlowSourceTest, RemoteFlowSinkTest>>

View File

@@ -8090,20 +8090,20 @@
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:539:8:539:9 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:540:2:540:2 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:532:8:532:9 | vs | |
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:533:2:533:2 | vs | |
| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT |
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT |
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT |
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | |
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | |
@@ -8128,5 +8128,5 @@
| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT |
| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT |
| vector.cpp:539:8:539:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
| vector.cpp:539:8:539:9 | vs | vector.cpp:539:10:539:10 | call to operator[] | TAINT |
| vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
| vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT |

View File

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

View File

@@ -43,10 +43,8 @@ module AstTest {
private import semmle.code.cpp.models.interfaces.Taint
/** Common data flow configuration to be used by tests. */
class AstTestAllocationConfig extends TaintTracking::Configuration {
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
@@ -60,17 +58,19 @@ module AstTest {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
override predicate isSanitizer(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
}
}
module AstFlow = TaintTracking::Global<AstTestAllocationConfig>;
}
module IRTest {
@@ -78,10 +78,8 @@ module IRTest {
private import semmle.code.cpp.ir.dataflow.TaintTracking
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends TaintTracking::Configuration {
TestAllocationConfig() { this = "TestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module TestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr().(FunctionCall).getTarget().getName() = "source"
@@ -94,21 +92,25 @@ module IRTest {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
[sink.asExpr(), sink.asIndirectExpr()] = call.getAnArgument()
)
}
override predicate isSanitizer(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
// allow arbitrary reads at sinks
this.isSink(node) and
isSink(node) and
c.(DataFlow::FieldContent).getField().getDeclaringType() = node.getType().getUnspecifiedType()
}
}
module IRFlow = TaintTracking::Global<TestAllocationConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -523,19 +523,12 @@ void test_vector_iterator() {
sink(vs[1]);
sink(vs[source()]); // $ MISSING: ast,ir
it = vs.begin(); // (1)
it = vs.begin();
sink(*it);
it += 1;
sink(*it);
it += source(); // (2)
sink(*it); // $ ast,ir // (3)
// This FP happens because of the following flows:
// 1. There's a write to the iterator at (2)
// 2. This write propagates to `it` on the next line at (3)
// 3. There's a taint step from `it` to `*it` at (3)
// 4. The `*it` is seen as a use of `vs` because of (1).
// 5. There's use-use flow from `*it` at (3) (which is a use of `vs`) to `vs` at (4)
// 6. There's a taint step from vs to vs[1]
sink(vs[1]); // $ SPURIOUS: ir // (4)
it += source();
sink(*it); // $ ast,ir
sink(vs[1]); // clean
}
}

View File

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

View File

@@ -12,12 +12,10 @@ import TestUtilities.InlineExpectationsTest
module ModulusAnalysisInstantiated =
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
class ModulusAnalysisTest extends InlineExpectationsTest {
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
module ModulusAnalysisTest implements TestSig {
string getARelevantTag() { result = "mod" }
override string getARelevantTag() { result = "mod" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(SemExpr e, IR::CallInstruction call |
getSemanticExpr(call.getArgument(0)) = e and
call.getStaticCallTarget().hasName("mod") and
@@ -29,6 +27,8 @@ class ModulusAnalysisTest extends InlineExpectationsTest {
}
}
import MakeTest<ModulusAnalysisTest>
private string getAModString(SemExpr e) {
exists(SemBound b, int delta, int mod |
ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and

View File

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

View File

@@ -21,12 +21,10 @@ module Raw {
result = getOperandMemoryLocation(instr.getAnOperand())
}
class RawPointsToTest extends InlineExpectationsTest {
RawPointsToTest() { this = "RawPointsToTest" }
module RawPointsToTest implements TestSig {
string getARelevantTag() { result = "raw" }
override string getARelevantTag() { result = "raw" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Instruction instr, MemoryLocation memLocation |
memLocation = getAMemoryAccess(instr) and
tag = "raw" and
@@ -49,12 +47,10 @@ module UnaliasedSsa {
result = getOperandMemoryLocation(instr.getAnOperand())
}
class UnaliasedSsaPointsToTest extends InlineExpectationsTest {
UnaliasedSsaPointsToTest() { this = "UnaliasedSSAPointsToTest" }
module UnaliasedSsaPointsToTest implements TestSig {
string getARelevantTag() { result = "ussa" }
override string getARelevantTag() { result = "ussa" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Instruction instr, MemoryLocation memLocation |
memLocation = getAMemoryAccess(instr) and
not memLocation.getVirtualVariable() instanceof AliasedVirtualVariable and
@@ -69,3 +65,5 @@ module UnaliasedSsa {
}
}
}
import MakeTest<MergeTests<Raw::RawPointsToTest, UnaliasedSsa::UnaliasedSsaPointsToTest>>

View File

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

View File

@@ -2,12 +2,10 @@ import cpp
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
import TestUtilities.InlineExpectationsTest
class RangeAnalysisTest extends InlineExpectationsTest {
RangeAnalysisTest() { this = "RangeAnalysisTest" }
module RangeAnalysisTest implements TestSig {
string getARelevantTag() { result = "overflow" }
override string getARelevantTag() { result = "overflow" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr e |
tag = "overflow" and
element = e.toString() and
@@ -21,3 +19,5 @@ class RangeAnalysisTest extends InlineExpectationsTest {
)
}
}
import MakeTest<RangeAnalysisTest>

View File

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

View File

@@ -5,12 +5,10 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest
class RangeAnalysisTest extends InlineExpectationsTest {
RangeAnalysisTest() { this = "RangeAnalysisTest" }
module RangeAnalysisTest implements TestSig {
string getARelevantTag() { result = "range" }
override string getARelevantTag() { result = "range" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(SemExpr e, IR::CallInstruction call |
getSemanticExpr(call.getArgument(0)) = e and
call.getStaticCallTarget().hasName("range") and
@@ -22,6 +20,8 @@ class RangeAnalysisTest extends InlineExpectationsTest {
}
}
import MakeTest<RangeAnalysisTest>
private string getDirectionString(boolean d) {
result = "<=" and d = true
or
@@ -40,14 +40,7 @@ bindingset[delta]
private string getBoundString(SemBound b, float delta) {
b instanceof SemZeroBound and result = delta.toString()
or
result =
strictconcat(b.(SemSsaBound)
.getAVariable()
.(SemanticExprConfig::SsaVariable)
.asInstruction()
.getAst()
.toString(), ":"
) + getOffsetString(delta)
result = strictconcat(b.(SemSsaBound).getAVariable().toString(), " | ") + getOffsetString(delta)
}
private string getARangeString(SemExpr e) {

View File

@@ -8,7 +8,7 @@ int test1(struct List* p) {
int count = 0;
for (; p; p = p->next) {
count = count+1;
range(count); // $ range===count:p+1
range(count); // $ range="==Phi: p | Store: count+1"
}
range(count);
return count;
@@ -18,7 +18,7 @@ int test2(struct List* p) {
int count = 0;
for (; p; p = p->next) {
count = (count+1) % 10;
range(count); // $ range=<=9 range=>=-9 range=<=count:p+1
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1"
}
range(count); // $ range=>=-9 range=<=9
return count;
@@ -29,7 +29,7 @@ int test3(struct List* p) {
for (; p; p = p->next) {
range(count++); // $ range=>=-9 range=<=9
count = count % 10;
range(count); // $ range=<=9 range=>=-9 range="<=... +++0" range=<=count:p+1
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1"
}
range(count); // $ range=>=-9 range=<=9
return count;
@@ -42,11 +42,11 @@ int test4() {
range(i); // $ range=<=1 range=>=0
range(total);
total += i;
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
}
range(total); // $ MISSING: range=>=0
range(i); // $ range===2
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
return total + i;
}
@@ -57,11 +57,11 @@ int test5() {
range(i); // $ range=<=1 range=>=0
range(total); // $ MISSING: range=>=0
total += i;
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
}
range(total); // $ MISSING: range=>=0
range(i); // $ range===2
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
return total + i;
}
@@ -72,7 +72,7 @@ int test6() {
range(i); // $ range=<=1 range=>=0
range(total); // $ MISSING: range=>=0
total += i;
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
}
return total + i;
}
@@ -93,12 +93,12 @@ int test8(int x, int y) {
if (-1000 < y && y < 10) {
range(y); // $ range=<=9 range=>=-999
if (x < y-2) {
range(x); // $ range=<=6 range=<=y-3
range(y); // $ range=<=9 range=>=-999 range=>=x+3
range(x); // $ range=<=6 range="<=InitializeParameter: y | Store: y-3"
range(y); // $ range=<=9 range=>=-999 range=">=InitializeParameter: x | Store: x+3"
return x;
}
range(x); // $ range=>=-1001 range=>=y-2
range(y); // $ range=<=9 range=<=x+2 range=>=-999
range(x); // $ range=>=-1001 range=">=InitializeParameter: y | Store: y-2"
range(y); // $ range=<=9 range="<=InitializeParameter: x | Store: x+2" range=>=-999
}
range(x);
range(y);
@@ -127,12 +127,12 @@ int test10(int x, int y) {
if (y > 7) {
range(y); // $ range=>=8
if (x < y) {
range(x); // $ range=<=y-1
range(y); // $ range=>=8 range=>=x+1
range(x); // $ range="<=InitializeParameter: y-1"
range(y); // $ range=>=8 range=">=InitializeParameter: x | Store: x+1"
return 0;
}
range(x); // $ range=>=8 range=>=y+0
range(y); // $ range=<=x+0 range=>=8
range(x); // $ range=>=8 range=">=InitializeParameter: y+0"
range(y); // $ range="<=InitializeParameter: x | Store: x+0" range=>=8
return x;
}
range(y); // $ range=<=7
@@ -145,7 +145,7 @@ int test11(char *p) {
range(*p);
if (c != '\0') {
*p++ = '\0';
range(p); // $ range===p+1
range(p); // $ range="==InitializeParameter: p+1"
range(*p);
}
if (c == ':') {
@@ -155,7 +155,7 @@ int test11(char *p) {
if (c != '\0') {
range(c);
*p++ = '\0';
range(p); // $ range=<=p+2 range===c+1 range=>=p+1
range(p); // $ range="<=InitializeParameter: p+2" range="==Phi: c+1" range=">=InitializeParameter: p+1"
}
if (c != ',') {
return 1;
@@ -193,7 +193,7 @@ int test13(char c, int i) {
unsigned int y = x-1; // $ overflow=-
range(y); // $ range===-1 overflow=-
int z = i+1; // $ overflow=+
range(z); // $ range===i+1
range(z); // $ range="==InitializeParameter: i+1"
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
@@ -245,7 +245,7 @@ int test_unary(int a) {
range(c); // $ range=<=0 range=>=-11
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
total += b+c;
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
range(total); // $ range="<=Phi: 0+11" range=<=19 range=">=Phi: 0-11" range=>=-19
}
if (-7 <= a && a <= 11) {
range(a); // $ range=<=11 range=>=-7
@@ -255,7 +255,7 @@ int test_unary(int a) {
range(c); // $ range=<=7 range=>=-11
range(b+c); // $ range=<=18 range=>=-18
total += b+c;
range(total); // $ range="<=- ...+18" range=">=- ...-18" range=<=0+29 range=<=37 range=>=0-29 range=>=-37
range(total); // $ range="<=Phi: - ...+18" range=">=Phi: - ...-18" range="<=Phi: 0+29" range=<=37 range=">=Phi: 0-29" range=>=-37
}
if (-7 <= a && a <= 1) {
range(a); // $ range=<=1 range=>=-7
@@ -265,7 +265,7 @@ int test_unary(int a) {
range(c); // $ range=<=7 range=>=-1
range(b+c); // $ range=<=8 range=>=-8
total += b+c;
range(total); // $ range="<=- ...+8" range="<=- ...+26" range=">=- ...-8" range=">=- ...-26" range=<=0+37 range=<=45 range=>=0-37 range=>=-45
range(total); // $ range="<=Phi: - ...+8" range="<=Phi: - ...+26" range=">=Phi: - ...-8" range=">=Phi: - ...-26" range="<=Phi: 0+37" range=<=45 range=">=Phi: 0-37" range=>=-45
}
if (-7 <= a && a <= 0) {
range(a); // $ range=<=0 range=>=-7
@@ -275,7 +275,7 @@ int test_unary(int a) {
range(c); // $ range=<=7 range=>=0
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
total += b+c;
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
range(total); // $ range="<=Phi: - ...+7" range="<=Phi: - ...+15" range="<=Phi: - ...+33" range=">=Phi: - ...-7" range=">=Phi: - ...-15" range=">=Phi: - ...-33" range="<=Phi: 0+44" range=<=52 Unexpected result: range=">=Phi: 0-44" range=>=-52
}
if (-7 <= a && a <= -2) {
range(a); // $ range=<=-2 range=>=-7
@@ -285,9 +285,9 @@ int test_unary(int a) {
range(c); // $ range=<=7 range=>=2
range(b+c); // $ range=<=5 range=>=-5
total += b+c;
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
}
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
return total;
}
@@ -310,7 +310,7 @@ int test_mult01(int a, int b) {
int r = a*b; // 0 .. 253
range(r); // $ range=<=253 range=>=0
total += r;
range(total); // $ range=<=3+253 range=<=506 range=>=0 range=>=3+0
range(total); // $ range="<=Phi: 3+253" range=<=506 range=>=0 range=">=Phi: 3+0"
}
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=>=3-143
range(total); // $ range=">=Phi: 3-143"
}
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
range(a); // $ range=<=11 range=>=3
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
int r = a*b; // -143 .. -21
range(r); // $ range=<=-21 range=>=-143
total += r;
range(total); // $ range=>=3-143 range=>=3-286
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
}
range(total); // $ range=>=3-143 range=>=3-286
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
return total;
}
@@ -358,7 +358,7 @@ int test_mult02(int a, int b) {
int r = a*b; // 0 .. 253
range(r); // $ range=<=253 range=>=0
total += r;
range(total); // $ range=>=0 range=>=0+0 range=<=0+253 range=<=506
range(total); // $ range=>=0 range=">=Phi: 0+0" range="<=Phi: 0+253" range=<=506
}
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=0
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=>=0-143
range(total); // $ range=">=Phi: 0-143"
}
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
range(a); // $ range=<=11 range=>=0
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
int r = a*b; // -143 .. 0
range(r); // $ range=<=0 range=>=-143
total += r;
range(total); // $ range=>=0-143 range=>=0-286
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
}
range(total); // $range=>=0-143 range=>=0-286
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
return total;
}
@@ -453,7 +453,7 @@ int test_mult04(int a, int b) {
int r = a*b; // -391 .. 0
range(r); // $ range=<=0 range=>=-391
total += r;
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
}
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
range(a); // $ range=<=0 range=>=-17
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=- ...+221"
range(total); // $ range="<=Phi: - ...+221"
}
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
range(a); // $ range=<=0 range=>=-17
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
}
range(total); // $ range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
return total;
}
@@ -501,7 +501,7 @@ int test_mult05(int a, int b) {
int r = a*b; // -391 .. 0
range(r); // $ range=<=0 range=>=-391
total += r;
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
}
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
range(a); // $ range=<=-2 range=>=-17
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=- ...+221"
range(total); // $ range="<=Phi: - ...+221"
}
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
range(a); // $ range=<=-2 range=>=-17
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
int r = a*b; // 14 .. 221
range(r); // $ range=<=221 range=>=14
total += r;
range(total); // $ range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
}
range(total); // $ range="<=- ...+221" range="<=- ...+442"
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
return total;
}
@@ -541,7 +541,7 @@ int test16(int x) {
while (i < 3) {
range(i); // $ range=<=2 range=>=0
i++;
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
range(i); // $ range=<=3 range=>=1 range="==Phi: i | Store: ... = ...+1"
}
range(d);
d = i;
@@ -640,14 +640,14 @@ unsigned int test_comma01(unsigned int x) {
unsigned int y1;
unsigned int y2;
y1 = (++y, y);
range(y1); // $ range=<=101 range="==... ? ... : ...+1"
range(y1); // $ range=<=101 range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+1"
y2 = (y++,
range(y), // $ range=<=102 range="==++ ...:... = ...+1" range="==... ? ... : ...+2"
range(y), // $ range=<=102 range="==Store: ++ ... | Store: ... = ...+1" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+2"
y += 3,
range(y), // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
range(y), // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
y);
range(y2); // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
range(y1 + y2); // $ range=<=206 range="<=... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
range(y2); // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" Unexpected result: range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
range(y1 + y2); // $ range=<=206 range="<=Phi: ... ? ... : ... | Store: ... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
return y1 + y2;
}
@@ -672,7 +672,7 @@ void test17() {
range(i); // $ range===50
i = 20 + (j -= 10);
range(i); // $ range="==... += ...:... = ...+10" range===60
range(i); // $ range="==Store: ... += ... | Store: ... = ...+10" range===60
}
// Tests for unsigned multiplication.
@@ -693,7 +693,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
int r = a*b; // 0 .. 253
range(r);// $ range=>=0 range=<=253
total += r;
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range=<=506 range="<=Phi: (unsigned int)...+253"
}
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
@@ -701,9 +701,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
int r = a*b; // 39 .. 253
range(r); // $ range=>=39 range=<=253
total += r;
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
range(total); // $ range=>=39 range=<=759 range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+39"
}
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
return total;
}
@@ -722,16 +722,16 @@ int test_unsigned_mult02(unsigned b) {
int r = 11*b; // 0 .. 253
range(r); // $ range=>=0 range=<=253
total += r;
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range="<=Phi: (unsigned int)...+253" range=<=506
}
if (13 <= b && b <= 23) {
range(b); // $ range=<=23 range=>=13
int r = 11*b; // 143 .. 253
range(r); // $ range=>=143 range=<=253
total += r;
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
range(total); // $ range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+143" range=>=143 range=<=759
}
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
return total;
}
@@ -851,7 +851,7 @@ int notequal_type_endpoint(unsigned n) {
n--; // 1 ..
}
range(n); // $ range=<=n+0 // 0 .. 0
range(n); // $ range="<=InitializeParameter: n+0" // 0 .. 0
}
void notequal_refinement(short n) {
@@ -946,7 +946,7 @@ void widen_recursive_expr() {
for (s = 0; s < 10; s++) {
range(s); // $ range=<=9 range=>=0
int result = s + s;
range(result); // $ range=<=18 range=<=s+9 range=>=0 range=>=s+0
range(result); // $ range=<=18 Unexpected result: range="<=Phi: s+9" range=>=0 Unexpected result: range=">=Phi: s+0"
}
}
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
void test_mod_ternary(int s, bool b) {
int s2 = s % (b ? 5 : 500);
range(s2); // $ range=>=-499 range=<=499 range="<=... ? ... : ...-1"
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1"
}
void test_mod_ternary2(int s, bool b1, bool b2) {

View File

@@ -16,8 +16,8 @@
int sum = x + y; // $ overflow=+-
} else {
if (y > 300) {
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
range(y); // $ range=>=301 range=<=399 range===x-1
range(x); // $ range=>=302 range=<=400 range="<=InitializeParameter: y+1" MISSING: range===y+1
range(y); // $ range=>=301 range=<=399 range="==InitializeParameter: x | Store: x-1"
int sum = x + y;
}
}
@@ -39,9 +39,9 @@
}
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
range(x); // $ range===349 range===y+1 range===z-1
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
range(x); // $ range===349 range="==InitializeParameter: y+1" range="==InitializeParameter: z-1"
range(y); // $ range===348 range=">=InitializeParameter: x | Store: x-1" range="==InitializeParameter: z-2" MISSING: range===x-1
range(z); // $ range===350 range="<=InitializeParameter: y+2" MISSING: range===x+1 range===y+2
return x + y + z;
}
}
@@ -56,6 +56,17 @@
while (f3_get(n)) n+=2;
for (int i = 0; i < n; i += 2) {
range(i); // $ range=>=0 SPURIOUS: range="<=call to f3_get-1" range="<=call to f3_get-2"
range(i); // $ range=>=0 SPURIOUS: range="<=Phi: call to f3_get-1" range="<=Phi: call to f3_get-2"
}
}
int f4(int x) {
for (int i = 0; i <= 100; i++) {
range(i); // $ range=<=100 range=>=0
if(i == 100) {
range(i); // $ range===100
} else {
range(i); // $ range=<=99 range=>=0
}
}
}

View File

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

View File

@@ -11,12 +11,10 @@ import TestUtilities.InlineExpectationsTest
module SignAnalysisInstantiated =
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
class SignAnalysisTest extends InlineExpectationsTest {
SignAnalysisTest() { this = "SignAnalysisTest" }
module SignAnalysisTest implements TestSig {
string getARelevantTag() { result = "sign" }
override string getARelevantTag() { result = "sign" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(SemExpr e, IR::CallInstruction call |
getSemanticExpr(call.getArgument(0)) = e and
call.getStaticCallTarget().hasName("sign") and
@@ -28,6 +26,8 @@ class SignAnalysisTest extends InlineExpectationsTest {
}
}
import MakeTest<SignAnalysisTest>
private string getASignString(SemExpr e) {
result = strictconcat(SignAnalysisInstantiated::semExprSign(e).toString(), "")
}

View File

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

View File

@@ -2,12 +2,10 @@ private import cpp
private import semmle.code.cpp.ir.implementation.raw.IR
import TestUtilities.InlineExpectationsTest
class IRTypesTest extends InlineExpectationsTest {
IRTypesTest() { this = "IRTypesTest" }
module IRTypesTest implements TestSig {
string getARelevantTag() { result = "irtype" }
override string getARelevantTag() { result = "irtype" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRUserVariable irVar |
location = irVar.getLocation() and
element = irVar.toString() and
@@ -16,3 +14,5 @@ class IRTypesTest extends InlineExpectationsTest {
)
}
}
import MakeTest<IRTypesTest>

View File

@@ -23,8 +23,6 @@ edges
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
@@ -61,7 +59,6 @@ nodes
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
| test_free.cpp:241:10:241:10 | b | semmle.label | b |
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
@@ -92,8 +89,6 @@ subpaths
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |

View File

@@ -1,29 +1,16 @@
edges
| tests.cpp:26:15:26:23 | badSource indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
| tests.cpp:26:32:26:35 | data indirection | tests.cpp:26:15:26:23 | badSource indirection |
| tests.cpp:26:32:26:35 | data indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:38:39:38:49 | environment indirection |
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | badSource indirection |
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | badSource indirection |
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:51:22:51:25 | badSource output argument |
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:51:12:51:20 | call to badSource indirection | tests.cpp:53:16:53:19 | data indirection |
| tests.cpp:51:22:51:25 | badSource output argument | tests.cpp:51:22:51:25 | data indirection |
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:26:32:26:35 | data indirection |
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
nodes
| tests.cpp:26:15:26:23 | badSource indirection | semmle.label | badSource indirection |
| tests.cpp:26:15:26:23 | badSource indirection | semmle.label | badSource indirection |
| tests.cpp:26:32:26:35 | data indirection | semmle.label | data indirection |
| tests.cpp:33:34:33:39 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
| tests.cpp:38:39:38:49 | environment indirection | semmle.label | environment indirection |
| tests.cpp:51:12:51:20 | call to badSource indirection | semmle.label | call to badSource indirection |
| tests.cpp:51:22:51:25 | badSource output argument | semmle.label | badSource output argument |
| tests.cpp:51:22:51:25 | data indirection | semmle.label | data indirection |
| tests.cpp:53:16:53:19 | data indirection | semmle.label | data indirection |
subpaths
| tests.cpp:51:22:51:25 | data indirection | tests.cpp:26:32:26:35 | data indirection | tests.cpp:26:15:26:23 | badSource indirection | tests.cpp:51:12:51:20 | call to badSource indirection |
#select
| tests.cpp:53:16:53:19 | data | tests.cpp:33:34:33:39 | call to getenv indirection | tests.cpp:53:16:53:19 | data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | tests.cpp:33:34:33:39 | call to getenv indirection | user input (an environment variable) | tests.cpp:38:25:38:36 | strncat output argument | strncat output argument |

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